mirror of
https://github.com/hwchase17/langchain.git
synced 2026-07-01 06:42:37 +00:00
feat(standard-tests): validate tool call chunks during streaming (#34707)
As a LangChain user streaming a tool-calling model, I expect each streamed chunk to expose structured `tool_call_chunk` content blocks so I can render or process tool calls live, instead of waiting for the final aggregated message. This adds `tool_call_streaming` to `ModelProfile` and uses it in the standard chat-model tool-calling tests. When a model profile opts in, `test_tool_calling` and `test_tool_calling_async` now validate that at least one streamed chunk includes a `tool_call_chunk` block via `content_blocks`, while preserving the existing final-message validation. This keeps the contract profile-gated so providers can opt in once their streaming chunk shape is verified. This PR opts in the providers verified by smoke testing with straightforward profile coverage: OpenAI, Anthropic, Fireworks, HuggingFace, OpenRouter, DeepSeek, and xAI. The generated profile artifacts are refreshed so runtime profiles expose the new capability flag. Perplexity Responses also passed the smoke test, but its current profile data is for the `sonar` family while the Responses smoke path used a routed model string. That profile strategy is left as follow-up. MistralAI currently streams `.tool_call_chunks`, but its content-block translator exposes a complete `tool_call` block instead of `tool_call_chunk`, so it also stays out of this flag until that integration is fixed.
This commit is contained in:
@@ -113,6 +113,12 @@ class ModelProfile(TypedDict, total=False):
|
||||
tool_choice: bool
|
||||
"""Whether the model supports [tool choice](https://docs.langchain.com/oss/python/langchain/models#forcing-tool-calls)."""
|
||||
|
||||
tool_call_streaming: bool
|
||||
"""Whether the model returns properly structured `tool_call_chunks` when streaming.
|
||||
|
||||
Only meaningful when `tool_calling` is `True`.
|
||||
"""
|
||||
|
||||
# --- Structured output ---
|
||||
structured_output: bool
|
||||
"""Whether the model supports native [structured output](https://docs.langchain.com/oss/python/langchain/models#structured-outputs)."""
|
||||
|
||||
@@ -126,6 +126,7 @@ def _model_data_to_profile(model_data: dict[str, Any]) -> dict[str, Any]:
|
||||
"reasoning_output": model_data.get("reasoning"),
|
||||
"tool_calling": model_data.get("tool_call"),
|
||||
"tool_choice": model_data.get("tool_choice"),
|
||||
"tool_call_streaming": model_data.get("tool_call_streaming"),
|
||||
"structured_output": model_data.get("structured_output"),
|
||||
"attachment": model_data.get("attachment"),
|
||||
"temperature": model_data.get("temperature"),
|
||||
|
||||
@@ -41,6 +41,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-3-5-haiku-latest": {
|
||||
"name": "Claude Haiku 3.5 (latest)",
|
||||
@@ -66,6 +67,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-3-5-sonnet-20240620": {
|
||||
"name": "Claude Sonnet 3.5",
|
||||
@@ -92,6 +94,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-3-5-sonnet-20241022": {
|
||||
"name": "Claude Sonnet 3.5 v2",
|
||||
@@ -118,6 +121,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-3-7-sonnet-20250219": {
|
||||
"name": "Claude Sonnet 3.7",
|
||||
@@ -144,6 +148,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-3-haiku-20240307": {
|
||||
"name": "Claude Haiku 3",
|
||||
@@ -170,6 +175,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-3-opus-20240229": {
|
||||
"name": "Claude Opus 3",
|
||||
@@ -196,6 +202,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-3-sonnet-20240229": {
|
||||
"name": "Claude Sonnet 3",
|
||||
@@ -222,6 +229,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-fable-5": {
|
||||
"name": "Claude Fable 5",
|
||||
@@ -247,6 +255,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-haiku-4-5": {
|
||||
"name": "Claude Haiku 4.5 (latest)",
|
||||
@@ -272,6 +281,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-haiku-4-5-20251001": {
|
||||
"name": "Claude Haiku 4.5",
|
||||
@@ -297,6 +307,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-opus-4-0": {
|
||||
"name": "Claude Opus 4 (latest)",
|
||||
@@ -322,6 +333,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-opus-4-1": {
|
||||
"name": "Claude Opus 4.1 (latest)",
|
||||
@@ -347,6 +359,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-opus-4-1-20250805": {
|
||||
"name": "Claude Opus 4.1",
|
||||
@@ -372,6 +385,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-opus-4-20250514": {
|
||||
"name": "Claude Opus 4",
|
||||
@@ -397,6 +411,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-opus-4-5": {
|
||||
"name": "Claude Opus 4.5 (latest)",
|
||||
@@ -422,6 +437,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-opus-4-5-20251101": {
|
||||
"name": "Claude Opus 4.5",
|
||||
@@ -447,6 +463,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-opus-4-6": {
|
||||
"name": "Claude Opus 4.6",
|
||||
@@ -472,6 +489,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-opus-4-7": {
|
||||
"name": "Claude Opus 4.7",
|
||||
@@ -497,6 +515,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-opus-4-8": {
|
||||
"name": "Claude Opus 4.8",
|
||||
@@ -522,6 +541,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-sonnet-4-0": {
|
||||
"name": "Claude Sonnet 4 (latest)",
|
||||
@@ -547,6 +567,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-sonnet-4-20250514": {
|
||||
"name": "Claude Sonnet 4",
|
||||
@@ -572,6 +593,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-sonnet-4-5": {
|
||||
"name": "Claude Sonnet 4.5 (latest)",
|
||||
@@ -597,6 +619,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-sonnet-4-5-20250929": {
|
||||
"name": "Claude Sonnet 4.5",
|
||||
@@ -622,6 +645,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"claude-sonnet-4-6": {
|
||||
"name": "Claude Sonnet 4.6",
|
||||
@@ -647,5 +671,6 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"structured_output": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ pdf_inputs = true
|
||||
pdf_tool_message = true
|
||||
image_tool_message = true
|
||||
structured_output = false
|
||||
tool_call_streaming = true
|
||||
|
||||
[overrides."claude-haiku-4-5"]
|
||||
structured_output = true
|
||||
|
||||
@@ -35,6 +35,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"deepseek-reasoner": {
|
||||
"name": "DeepSeek Reasoner",
|
||||
@@ -55,6 +56,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"deepseek-v4-flash": {
|
||||
"name": "DeepSeek V4 Flash",
|
||||
@@ -76,6 +78,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"deepseek-v4-pro": {
|
||||
"name": "DeepSeek V4 Pro",
|
||||
@@ -97,5 +100,6 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
provider = "deepseek"
|
||||
|
||||
[overrides]
|
||||
tool_call_streaming = true
|
||||
@@ -36,6 +36,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/models/deepseek-v4-pro": {
|
||||
"name": "DeepSeek V4 Pro",
|
||||
@@ -57,6 +58,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/models/glm-5p1": {
|
||||
"name": "GLM 5.1",
|
||||
@@ -77,6 +79,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/models/gpt-oss-120b": {
|
||||
"name": "GPT OSS 120B",
|
||||
@@ -97,6 +100,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/models/gpt-oss-20b": {
|
||||
"name": "GPT OSS 20B",
|
||||
@@ -117,6 +121,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/models/kimi-k2p5": {
|
||||
"name": "Kimi K2.5",
|
||||
@@ -137,6 +142,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/models/kimi-k2p6": {
|
||||
"name": "Kimi K2.6",
|
||||
@@ -157,6 +163,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/models/minimax-m2p5": {
|
||||
"name": "MiniMax-M2.5",
|
||||
@@ -177,6 +184,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/models/minimax-m2p7": {
|
||||
"name": "MiniMax-M2.7",
|
||||
@@ -197,6 +205,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/models/qwen3p6-plus": {
|
||||
"name": "Qwen 3.6 Plus",
|
||||
@@ -217,6 +226,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/routers/glm-5p1-fast": {
|
||||
"name": "GLM 5.1 Fast",
|
||||
@@ -237,6 +247,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/routers/kimi-k2p6-fast": {
|
||||
"name": "Kimi K2.6 Fast",
|
||||
@@ -257,6 +268,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"accounts/fireworks/routers/kimi-k2p6-turbo": {
|
||||
"name": "Kimi K2.6 Turbo",
|
||||
@@ -277,5 +289,6 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
provider = "fireworks-ai"
|
||||
|
||||
[overrides]
|
||||
tool_call_streaming = true
|
||||
@@ -35,6 +35,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"MiniMaxAI/MiniMax-M2.5": {
|
||||
"name": "MiniMax-M2.5",
|
||||
@@ -55,6 +56,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"MiniMaxAI/MiniMax-M2.7": {
|
||||
"name": "MiniMax-M2.7",
|
||||
@@ -76,6 +78,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"Qwen/Qwen3-235B-A22B-Thinking-2507": {
|
||||
"name": "Qwen3-235B-A22B-Thinking-2507",
|
||||
@@ -96,6 +99,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"Qwen/Qwen3-Coder-480B-A35B-Instruct": {
|
||||
"name": "Qwen3-Coder-480B-A35B-Instruct",
|
||||
@@ -116,6 +120,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"Qwen/Qwen3-Coder-Next": {
|
||||
"name": "Qwen3-Coder-Next",
|
||||
@@ -136,6 +141,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"Qwen/Qwen3-Embedding-4B": {
|
||||
"name": "Qwen 3 Embedding 4B",
|
||||
@@ -156,6 +162,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": False,
|
||||
"attachment": False,
|
||||
"temperature": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"Qwen/Qwen3-Embedding-8B": {
|
||||
"name": "Qwen 3 Embedding 8B",
|
||||
@@ -176,6 +183,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": False,
|
||||
"attachment": False,
|
||||
"temperature": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"Qwen/Qwen3-Next-80B-A3B-Instruct": {
|
||||
"name": "Qwen3-Next-80B-A3B-Instruct",
|
||||
@@ -196,6 +204,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"Qwen/Qwen3-Next-80B-A3B-Thinking": {
|
||||
"name": "Qwen3-Next-80B-A3B-Thinking",
|
||||
@@ -216,6 +225,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"Qwen/Qwen3.5-397B-A17B": {
|
||||
"name": "Qwen3.5-397B-A17B",
|
||||
@@ -236,6 +246,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"XiaomiMiMo/MiMo-V2-Flash": {
|
||||
"name": "MiMo-V2-Flash",
|
||||
@@ -256,6 +267,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"deepseek-ai/DeepSeek-R1-0528": {
|
||||
"name": "DeepSeek-R1-0528",
|
||||
@@ -276,6 +288,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"deepseek-ai/DeepSeek-V3.2": {
|
||||
"name": "DeepSeek-V3.2",
|
||||
@@ -296,6 +309,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"deepseek-ai/DeepSeek-V4-Pro": {
|
||||
"name": "DeepSeek V4 Pro",
|
||||
@@ -317,6 +331,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"moonshotai/Kimi-K2-Instruct": {
|
||||
"name": "Kimi-K2-Instruct",
|
||||
@@ -337,6 +352,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"moonshotai/Kimi-K2-Instruct-0905": {
|
||||
"name": "Kimi-K2-Instruct-0905",
|
||||
@@ -357,6 +373,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"moonshotai/Kimi-K2-Thinking": {
|
||||
"name": "Kimi-K2-Thinking",
|
||||
@@ -377,6 +394,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"moonshotai/Kimi-K2.5": {
|
||||
"name": "Kimi-K2.5",
|
||||
@@ -397,6 +415,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"moonshotai/Kimi-K2.6": {
|
||||
"name": "Kimi-K2.6",
|
||||
@@ -417,6 +436,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"zai-org/GLM-4.7": {
|
||||
"name": "GLM-4.7",
|
||||
@@ -437,6 +457,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"zai-org/GLM-4.7-Flash": {
|
||||
"name": "GLM-4.7-Flash",
|
||||
@@ -457,6 +478,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"zai-org/GLM-5": {
|
||||
"name": "GLM-5",
|
||||
@@ -477,6 +499,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"zai-org/GLM-5.1": {
|
||||
"name": "GLM-5.1",
|
||||
@@ -497,5 +520,6 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": True,
|
||||
"attachment": False,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
provider = "huggingface"
|
||||
|
||||
[overrides]
|
||||
tool_call_streaming = true
|
||||
@@ -40,6 +40,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-3.5-turbo": {
|
||||
"name": "GPT-3.5-turbo",
|
||||
@@ -66,6 +67,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": False,
|
||||
"image_tool_message": False,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-4": {
|
||||
"name": "GPT-4",
|
||||
@@ -92,6 +94,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-4-turbo": {
|
||||
"name": "GPT-4 Turbo",
|
||||
@@ -118,6 +121,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-4.1": {
|
||||
"name": "GPT-4.1",
|
||||
@@ -144,6 +148,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-4.1-mini": {
|
||||
"name": "GPT-4.1 mini",
|
||||
@@ -170,6 +175,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-4.1-nano": {
|
||||
"name": "GPT-4.1 nano",
|
||||
@@ -196,6 +202,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-4o": {
|
||||
"name": "GPT-4o",
|
||||
@@ -222,6 +229,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-4o-2024-05-13": {
|
||||
"name": "GPT-4o (2024-05-13)",
|
||||
@@ -248,6 +256,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-4o-2024-08-06": {
|
||||
"name": "GPT-4o (2024-08-06)",
|
||||
@@ -274,6 +283,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-4o-2024-11-20": {
|
||||
"name": "GPT-4o (2024-11-20)",
|
||||
@@ -300,6 +310,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-4o-mini": {
|
||||
"name": "GPT-4o mini",
|
||||
@@ -326,6 +337,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5": {
|
||||
"name": "GPT-5",
|
||||
@@ -352,6 +364,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5-chat-latest": {
|
||||
"name": "GPT-5 Chat (latest)",
|
||||
@@ -378,6 +391,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5-codex": {
|
||||
"name": "GPT-5-Codex",
|
||||
@@ -404,6 +418,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5-mini": {
|
||||
"name": "GPT-5 Mini",
|
||||
@@ -430,6 +445,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5-nano": {
|
||||
"name": "GPT-5 Nano",
|
||||
@@ -456,6 +472,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5-pro": {
|
||||
"name": "GPT-5 Pro",
|
||||
@@ -482,6 +499,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.1": {
|
||||
"name": "GPT-5.1",
|
||||
@@ -508,6 +526,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.1-chat-latest": {
|
||||
"name": "GPT-5.1 Chat",
|
||||
@@ -534,6 +553,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.1-codex": {
|
||||
"name": "GPT-5.1 Codex",
|
||||
@@ -560,6 +580,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.1-codex-max": {
|
||||
"name": "GPT-5.1 Codex Max",
|
||||
@@ -586,6 +607,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.1-codex-mini": {
|
||||
"name": "GPT-5.1 Codex mini",
|
||||
@@ -612,6 +634,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.2": {
|
||||
"name": "GPT-5.2",
|
||||
@@ -638,6 +661,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.2-chat-latest": {
|
||||
"name": "GPT-5.2 Chat",
|
||||
@@ -664,6 +688,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.2-codex": {
|
||||
"name": "GPT-5.2 Codex",
|
||||
@@ -690,6 +715,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.2-pro": {
|
||||
"name": "GPT-5.2 Pro",
|
||||
@@ -716,6 +742,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.3-chat-latest": {
|
||||
"name": "GPT-5.3 Chat (latest)",
|
||||
@@ -742,6 +769,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.3-codex": {
|
||||
"name": "GPT-5.3 Codex",
|
||||
@@ -768,6 +796,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.3-codex-spark": {
|
||||
"name": "GPT-5.3 Codex Spark",
|
||||
@@ -794,6 +823,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.4": {
|
||||
"name": "GPT-5.4",
|
||||
@@ -820,6 +850,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.4-mini": {
|
||||
"name": "GPT-5.4 mini",
|
||||
@@ -846,6 +877,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.4-nano": {
|
||||
"name": "GPT-5.4 nano",
|
||||
@@ -872,6 +904,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.4-pro": {
|
||||
"name": "GPT-5.4 Pro",
|
||||
@@ -898,6 +931,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.5": {
|
||||
"name": "GPT-5.5",
|
||||
@@ -924,6 +958,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-5.5-pro": {
|
||||
"name": "GPT-5.5 Pro",
|
||||
@@ -950,6 +985,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-image-1": {
|
||||
"name": "gpt-image-1",
|
||||
@@ -975,6 +1011,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-image-1-mini": {
|
||||
"name": "gpt-image-1-mini",
|
||||
@@ -1000,6 +1037,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"gpt-image-1.5": {
|
||||
"name": "gpt-image-1.5",
|
||||
@@ -1025,6 +1063,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"o1": {
|
||||
"name": "o1",
|
||||
@@ -1051,6 +1090,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"o1-pro": {
|
||||
"name": "o1-pro",
|
||||
@@ -1077,6 +1117,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"o3": {
|
||||
"name": "o3",
|
||||
@@ -1103,6 +1144,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"o3-deep-research": {
|
||||
"name": "o3-deep-research",
|
||||
@@ -1128,6 +1170,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"o3-mini": {
|
||||
"name": "o3-mini",
|
||||
@@ -1154,6 +1197,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"o3-pro": {
|
||||
"name": "o3-pro",
|
||||
@@ -1180,6 +1224,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"o4-mini": {
|
||||
"name": "o4-mini",
|
||||
@@ -1206,6 +1251,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"o4-mini-deep-research": {
|
||||
"name": "o4-mini-deep-research",
|
||||
@@ -1231,6 +1277,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"text-embedding-3-large": {
|
||||
"name": "text-embedding-3-large",
|
||||
@@ -1256,6 +1303,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"text-embedding-3-small": {
|
||||
"name": "text-embedding-3-small",
|
||||
@@ -1281,6 +1329,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"text-embedding-ada-002": {
|
||||
"name": "text-embedding-ada-002",
|
||||
@@ -1306,5 +1355,6 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"pdf_tool_message": True,
|
||||
"image_tool_message": True,
|
||||
"tool_choice": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ pdf_inputs = true
|
||||
pdf_tool_message = true
|
||||
image_tool_message = true
|
||||
tool_choice = true
|
||||
tool_call_streaming = true
|
||||
|
||||
[overrides."gpt-3.5-turbo"]
|
||||
image_url_inputs = false
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
provider = "openrouter"
|
||||
|
||||
[overrides]
|
||||
tool_call_streaming = true
|
||||
@@ -42,9 +42,9 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"last_updated": "2025-09-01",
|
||||
"open_weights": False,
|
||||
"max_input_tokens": 128000,
|
||||
"max_output_tokens": 8192,
|
||||
"max_output_tokens": 32768,
|
||||
"text_inputs": True,
|
||||
"image_inputs": True,
|
||||
"image_inputs": False,
|
||||
"audio_inputs": False,
|
||||
"video_inputs": False,
|
||||
"text_outputs": True,
|
||||
|
||||
@@ -1,13 +1 @@
|
||||
provider = "perplexity"
|
||||
|
||||
[overrides."sonar-deep-research"]
|
||||
max_input_tokens = 128000
|
||||
max_output_tokens = 8192
|
||||
image_inputs = true
|
||||
audio_inputs = false
|
||||
video_inputs = false
|
||||
image_outputs = false
|
||||
audio_outputs = false
|
||||
video_outputs = false
|
||||
reasoning_output = true
|
||||
tool_calling = false
|
||||
|
||||
@@ -37,6 +37,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"grok-4.20-0309-reasoning": {
|
||||
"name": "Grok 4.20 (Reasoning)",
|
||||
@@ -59,6 +60,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"grok-4.20-multi-agent-0309": {
|
||||
"name": "Grok 4.20 Multi-Agent",
|
||||
@@ -81,6 +83,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"grok-4.3": {
|
||||
"name": "Grok 4.3",
|
||||
@@ -103,6 +106,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"grok-build-0.1": {
|
||||
"name": "Grok Build 0.1",
|
||||
@@ -125,6 +129,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"structured_output": True,
|
||||
"attachment": True,
|
||||
"temperature": True,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"grok-imagine-image": {
|
||||
"name": "Grok Imagine Image",
|
||||
@@ -146,6 +151,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": False,
|
||||
"attachment": True,
|
||||
"temperature": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"grok-imagine-image-quality": {
|
||||
"name": "Grok Imagine Image Quality",
|
||||
@@ -167,6 +173,7 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": False,
|
||||
"attachment": True,
|
||||
"temperature": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
"grok-imagine-video": {
|
||||
"name": "Grok Imagine Video",
|
||||
@@ -188,5 +195,6 @@ _PROFILES: dict[str, dict[str, Any]] = {
|
||||
"tool_calling": False,
|
||||
"attachment": True,
|
||||
"temperature": False,
|
||||
"tool_call_streaming": True,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
provider = "xai"
|
||||
|
||||
[overrides]
|
||||
tool_call_streaming = true
|
||||
@@ -134,6 +134,22 @@ def _validate_tool_call_message(message: BaseMessage) -> None:
|
||||
assert content_tool_call["id"] is not None
|
||||
|
||||
|
||||
def _validate_tool_call_chunk(chunk: AIMessageChunk) -> bool:
|
||||
"""Check whether a streaming chunk contains valid `tool_call_chunk` blocks.
|
||||
|
||||
Returns:
|
||||
`True` if at least one `tool_call_chunk` block was found.
|
||||
"""
|
||||
found = False
|
||||
for block in chunk.content_blocks:
|
||||
if block.get("type") == "tool_call_chunk":
|
||||
found = True
|
||||
assert "name" in block, "tool_call_chunk block missing 'name' field"
|
||||
assert "args" in block, "tool_call_chunk block missing 'args' field"
|
||||
assert "id" in block, "tool_call_chunk block missing 'id' field"
|
||||
return found
|
||||
|
||||
|
||||
def _validate_tool_call_message_no_args(message: BaseMessage) -> None:
|
||||
assert isinstance(message, AIMessage)
|
||||
assert len(message.tool_calls) == 1
|
||||
@@ -1666,6 +1682,10 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
Otherwise, in the case that only one tool is bound, ensure that
|
||||
`tool_choice` supports the string `'any'` to force calling that tool.
|
||||
|
||||
If `tool_call_streaming = true` is set in the model's profile
|
||||
augmentations, individual chunks are also validated to contain
|
||||
`tool_call_chunk` blocks in `content_blocks`.
|
||||
|
||||
"""
|
||||
if not self.has_tool_calling:
|
||||
pytest.skip("Test requires tool calling.")
|
||||
@@ -1680,13 +1700,28 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
result = model_with_tools.invoke(query)
|
||||
_validate_tool_call_message(result)
|
||||
|
||||
tool_call_streaming = (
|
||||
model.profile.get("tool_call_streaming", False) if model.profile else False
|
||||
)
|
||||
|
||||
# Test stream
|
||||
full: BaseMessage | None = None
|
||||
found_tool_call_chunk = False
|
||||
for chunk in model_with_tools.stream(query):
|
||||
if tool_call_streaming and isinstance(chunk, AIMessageChunk):
|
||||
found_tool_call_chunk |= _validate_tool_call_chunk(chunk)
|
||||
full = chunk if full is None else full + chunk # type: ignore[assignment]
|
||||
assert isinstance(full, AIMessage)
|
||||
_validate_tool_call_message(full)
|
||||
|
||||
if tool_call_streaming:
|
||||
assert found_tool_call_chunk, (
|
||||
"Expected to find 'tool_call_chunk' blocks in content_blocks of at "
|
||||
"least one chunk during streaming, but none were found. If this "
|
||||
"model does not support streaming tool calls, set "
|
||||
"tool_call_streaming=false in the model's profile augmentations."
|
||||
)
|
||||
|
||||
async def test_tool_calling_async(self, model: BaseChatModel) -> None:
|
||||
"""Test that the model generates tool calls.
|
||||
|
||||
@@ -1728,6 +1763,8 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
Otherwise, in the case that only one tool is bound, ensure that
|
||||
`tool_choice` supports the string `'any'` to force calling that tool.
|
||||
|
||||
See `test_tool_calling` for `tool_call_streaming` profile configuration.
|
||||
|
||||
"""
|
||||
if not self.has_tool_calling:
|
||||
pytest.skip("Test requires tool calling.")
|
||||
@@ -1742,13 +1779,28 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
result = await model_with_tools.ainvoke(query)
|
||||
_validate_tool_call_message(result)
|
||||
|
||||
tool_call_streaming = (
|
||||
model.profile.get("tool_call_streaming", False) if model.profile else False
|
||||
)
|
||||
|
||||
# Test astream
|
||||
full: BaseMessage | None = None
|
||||
found_tool_call_chunk = False
|
||||
async for chunk in model_with_tools.astream(query):
|
||||
if tool_call_streaming and isinstance(chunk, AIMessageChunk):
|
||||
found_tool_call_chunk |= _validate_tool_call_chunk(chunk)
|
||||
full = chunk if full is None else full + chunk # type: ignore[assignment]
|
||||
assert isinstance(full, AIMessage)
|
||||
_validate_tool_call_message(full)
|
||||
|
||||
if tool_call_streaming:
|
||||
assert found_tool_call_chunk, (
|
||||
"Expected to find 'tool_call_chunk' blocks in content_blocks of at "
|
||||
"least one chunk during streaming, but none were found. If this "
|
||||
"model does not support streaming tool calls, set "
|
||||
"tool_call_streaming=false in the model's profile augmentations."
|
||||
)
|
||||
|
||||
def test_bind_runnables_as_tools(self, model: BaseChatModel) -> None:
|
||||
"""Test bind runnables as tools.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user