Compare commits

..
7 Commits
25 changed files with 457 additions and 6 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ agents while handling coordination and final reporting.
## Pro-Tip: Use an IDE MCP Server for Improved Performance
Many modern IDEs now include MCP servers that let LLMs perform operations within the IDE itself and use IDE tools. Using
an IDE's MCP server dramatically improves the performance of coding agents. So if you have an IDE, try adding that MCP
server to your config (see the [MCP Server docs](../../../docs/function-calling/MCP-SERVERS.md) to see how to configure
server to your config (see the [MCP Server docs](https://github.com/Dark-Alex-17/coyote/wiki/MCP-Servers) to see how to configure
them), and modify the agent definition to look like this:
```yaml
+1 -1
View File
@@ -16,7 +16,7 @@ one file while communicating with sibling agents to catch issues that span multi
## Pro-Tip: Use an IDE MCP Server for Improved Performance
Many modern IDEs now include MCP servers that let LLMs perform operations within the IDE itself and use IDE tools. Using
an IDE's MCP server dramatically improves the performance of coding agents. So if you have an IDE, try adding that MCP
server to your config (see the [MCP Server docs](../../../docs/function-calling/MCP-SERVERS.md) to see how to configure
server to your config (see the [MCP Server docs](https://github.com/Dark-Alex-17/coyote/wiki/MCP-Servers) to see how to configure
them), and modify the agent definition to look like this:
```yaml
+2
View File
@@ -13,6 +13,8 @@
model: openai:gpt-4o # Specify the LLM to use
temperature: null # Set default temperature parameter, range (0, 1)
top_p: null # Set default top-p parameter, with a range of (0, 1) or (0, 2) depending on the model
reasoning_effort: null # Reasoning effort level for models that support it (e.g. low, medium, high).
# Only valid when the agent's model declares reasoning_levels.
agent_session: null # Set a session to use when starting the agent. (e.g. temp, default); defaults to globally set agent_session
name: <agent-name> # Name of the agent, used in the UI and logs
description: <description> # Description of the agent, used in the UI
+2
View File
@@ -2,6 +2,8 @@
model: openai:gpt-4o # Specify the LLM to use
temperature: null # Set default temperature parameter (0, 1)
top_p: null # Set default top-p parameter, with a range of (0, 1) or (0, 2) depending on the model
reasoning_effort: null # Reasoning effort level for models that support it (e.g. low, medium, high).
# Only valid when the active model declares reasoning_levels. See the Clients docs.
# ---- Behavior ----
stream: true # Controls whether to use the stream-style APIs when querying for completions from LLM clients.
+2
View File
@@ -8,6 +8,8 @@ name: <role-name> # The name of the role
model: openai:gpt-4o # The model to use for this role
temperature: 0.2 # The temperature to use for this role when querying the model
top_p: 0 # The top_p to use for this role when querying the model
reasoning_effort: null # Reasoning effort level for models that support it (e.g. low, medium, high).
# Only valid when the role's model declares reasoning_levels.
enabled_tools: # Tools to enable for this role. Accepts a YAML list (preferred)
- fs_ls # or a comma-separated string (e.g. `enabled_tools: fs_ls,fs_cat`).
- fs_cat # Use `all` to enable every visible tool.
+3
View File
@@ -33,6 +33,8 @@ version: "1.0" # Graph schema version. Only "1.0" is accepte
model: claude:claude-sonnet-4-6 # Default model for `llm` nodes that don't override it
temperature: 0.0 # Default sampling temperature for `llm` nodes
top_p: null # Default sampling top-p for `llm` nodes
reasoning_effort: null # Default reasoning effort for `llm` nodes that don't override it.
# Only valid when the model declares reasoning_levels.
global_tools: # Tool universe an `llm` node's `tools:` whitelist draws from
- web_search_coyote.sh
@@ -394,6 +396,7 @@ nodes:
- mcp:ddg-search # `mcp:<server>` includes that server's functions
model: claude:claude-haiku-4-5 # Optional per-node model override
temperature: 0.3 # Optional per-node sampling override
reasoning_effort: null # Optional per-node reasoning effort override (e.g. low, medium, high)
max_attempts: 2 # Retry count on transient errors only. Default 1.
max_iterations: 10 # Tool-call-loop turn cap. Default 10.
fallback: review # Route here if all attempts fail
+201
View File
@@ -10,6 +10,8 @@
output_price: 30
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh, max]
default_reasoning_effort: medium
- name: gpt-5.6-terra
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -17,6 +19,8 @@
output_price: 30
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh, max]
default_reasoning_effort: medium
- name: gpt-5.6-luna
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -24,6 +28,8 @@
output_price: 30
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh, max]
default_reasoning_effort: medium
- name: gpt-5.5
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -31,6 +37,8 @@
output_price: 30
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh]
default_reasoning_effort: medium
- name: gpt-5.5-pro
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -38,6 +46,8 @@
output_price: 180
supports_vision: true
supports_function_calling: true
reasoning_levels: [medium, high, xhigh]
default_reasoning_effort: high
- name: gpt-5.4
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -45,6 +55,8 @@
output_price: 15
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh]
default_reasoning_effort: none
- name: gpt-5.4-pro
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -52,6 +64,8 @@
output_price: 180
supports_vision: true
supports_function_calling: true
reasoning_levels: [medium, high, xhigh]
default_reasoning_effort: medium
- name: gpt-5.4-mini
max_input_tokens: 400000
max_output_tokens: 128000
@@ -59,6 +73,8 @@
output_price: 4.5
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh]
default_reasoning_effort: none
- name: gpt-5.4-nano
max_input_tokens: 400000
max_output_tokens: 128000
@@ -66,6 +82,8 @@
output_price: 1.25
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh]
default_reasoning_effort: none
- name: gpt-5.3-codex
max_input_tokens: 400000
max_output_tokens: 128000
@@ -73,6 +91,8 @@
output_price: 14
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh]
default_reasoning_effort: medium
- name: chat-latest
max_input_tokens: 400000
max_output_tokens: 128000
@@ -87,6 +107,17 @@
output_price: 14
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh]
default_reasoning_effort: none
- name: gpt-5.2-pro
max_input_tokens: 400000
max_output_tokens: 128000
input_price: 21
output_price: 168
supports_vision: true
supports_function_calling: true
reasoning_levels: [medium, high, xhigh]
default_reasoning_effort: medium
- name: gpt-5.1
max_input_tokens: 400000
max_output_tokens: 128000
@@ -94,6 +125,8 @@
output_price: 10
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high]
default_reasoning_effort: none
- name: gpt-5.1-chat-latest
max_input_tokens: 400000
max_output_tokens: 128000
@@ -101,6 +134,8 @@
output_price: 10
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high]
default_reasoning_effort: none
- name: gpt-5
max_input_tokens: 400000
max_output_tokens: 128000
@@ -108,6 +143,8 @@
output_price: 10
supports_vision: true
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: medium
- name: gpt-5-chat-latest
max_input_tokens: 400000
max_output_tokens: 128000
@@ -115,6 +152,8 @@
output_price: 10
supports_vision: true
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: medium
- name: gpt-5-mini
max_input_tokens: 400000
max_output_tokens: 128000
@@ -172,6 +211,8 @@
supports_vision: true
supports_function_calling: true
system_prompt_prefix: Formatting re-enabled
reasoning_levels: [low, medium, high]
default_reasoning_effort: medium
patch:
body:
max_tokens: null
@@ -285,18 +326,24 @@
input_price: 0.2
output_price: 1.5
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: medium
- name: gemini-3-flash-preview
max_input_tokens: 1048576
max_output_tokens: 65536
input_price: 0.2
output_price: 1.5
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: high
- name: gemini-3.1-flash-lite
max_input_tokens: 1048576
max_output_tokens: 65536
input_price: 0.2
output_price: 1.5
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: minimal
- name: gemini-3.1-pro-preview
max_input_tokens: 1048576
max_output_tokens: 65535
@@ -304,6 +351,8 @@
output_price: 2.5
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high]
default_reasoning_effort: high
- name: gemini-2.5-flash
max_input_tokens: 1048576
max_output_tokens: 65536
@@ -311,6 +360,8 @@
output_price: 0
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high]
default_reasoning_effort: low
- name: gemini-2.5-pro
max_input_tokens: 1048576
max_output_tokens: 65536
@@ -318,6 +369,8 @@
output_price: 0
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high]
default_reasoning_effort: high
- name: gemini-2.5-flash-lite
max_input_tokens: 1000000
max_output_tokens: 64000
@@ -329,10 +382,14 @@
max_input_tokens: 1048576
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, high]
default_reasoning_level: high
- name: gemini-3-flash-preview
max_input_tokens: 1048576
supports_vision: true
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_level: high
- name: gemma-3-27b-it
max_input_tokens: 131072
max_output_tokens: 8192
@@ -358,6 +415,8 @@
output_price: 50
supports_function_calling: true
supports_vision: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: claude-opus-4-8
max_input_tokens: 1000000
max_output_tokens: 128000
@@ -366,6 +425,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: claude-opus-4-7
max_input_tokens: 1000000
max_output_tokens: 128000
@@ -374,6 +435,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: claude-opus-4-6
max_input_tokens: 200000
max_output_tokens: 8192
@@ -382,6 +445,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, max]
default_reasoning_effort: high
- name: claude-opus-4-6:thinking
real_name: claude-opus-4-6
max_input_tokens: 200000
@@ -406,6 +471,8 @@
output_price: 15
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: claude-sonnet-4-6
max_input_tokens: 200000
max_output_tokens: 8192
@@ -414,6 +481,8 @@
output_price: 15
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, max]
default_reasoning_effort: high
- name: claude-sonnet-4-6:thinking
real_name: claude-sonnet-4-6
max_input_tokens: 200000
@@ -856,18 +925,24 @@
input_price: 0.2
output_price: 1.5
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: medium
- name: gemini-3-flash-preview
max_input_tokens: 1048576
max_output_tokens: 65536
input_price: 0.2
output_price: 1.5
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: high
- name: gemini-3.1-flash-lite
max_input_tokens: 1048576
max_output_tokens: 65536
input_price: 0.2
output_price: 1.5
supports_function_calling: true
reasoning_levels: [minimal, high]
default_reasoning_effort: minimal
- name: gemini-3.1-pro-preview
max_input_tokens: 1048576
max_output_tokens: 65536
@@ -875,6 +950,8 @@
output_price: 12
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high]
default_reasoning_effort: high
- name: gemini-2.5-flash
max_input_tokens: 1048576
max_output_tokens: 65535
@@ -882,6 +959,8 @@
output_price: 2.5
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high]
default_reasoning_effort: medium
- name: gemini-2.5-pro
max_input_tokens: 1048576
max_output_tokens: 65536
@@ -889,6 +968,8 @@
output_price: 10
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high]
default_reasoning_effort: high
- name: gemini-2.5-flash-lite
max_input_tokens: 1048576
max_output_tokens: 65536
@@ -900,10 +981,14 @@
max_input_tokens: 1048576
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, high]
default_reasoning_effort: high
- name: gemini-3-flash-preview
max_input_tokens: 1048576
supports_vision: true
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: high
- name: claude-fable-5
max_input_tokens: 1000000
max_output_tokens: 128000
@@ -912,6 +997,8 @@
output_price: 50
supports_function_calling: true
supports_vision: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: claude-opus-4-8
max_input_tokens: 1000000
max_output_tokens: 128000
@@ -920,6 +1007,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: claude-opus-4-7
max_input_tokens: 1000000
max_output_tokens: 128000
@@ -928,6 +1017,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: claude-opus-4-6
max_input_tokens: 200000
max_output_tokens: 8192
@@ -959,6 +1050,8 @@
output_price: 15
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: claude-sonnet-4-6
max_input_tokens: 200000
max_output_tokens: 8192
@@ -967,6 +1060,8 @@
output_price: 15
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, max]
default_reasoning_effort: high
- name: claude-sonnet-4-6:thinking
real_name: claude-sonnet-4-6
max_input_tokens: 200000
@@ -1099,6 +1194,8 @@
output_price: 50
supports_function_calling: true
supports_vision: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: us.anthropic.claude-opus-4-8
max_input_tokens: 1000000
max_output_tokens: 128000
@@ -1107,6 +1204,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: us.anthropic.claude-opus-4-7
max_input_tokens: 1000000
max_output_tokens: 128000
@@ -1115,6 +1214,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: us.anthropic.claude-opus-4-6-v1
max_input_tokens: 200000
max_output_tokens: 8192
@@ -1123,6 +1224,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, max]
default_reasoning_effort: high
- name: us.anthropic.claude-opus-4-6-v1:thinking
real_name: us.anthropic.claude-opus-4-6-v1
max_input_tokens: 200000
@@ -1148,6 +1251,8 @@
output_price: 15
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: us.anthropic.claude-sonnet-4-6
max_input_tokens: 200000
max_output_tokens: 8192
@@ -1156,6 +1261,8 @@
output_price: 15
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, max]
default_reasoning_effort: high
- name: us.anthropic.claude-sonnet-4-6:thinking
real_name: us.anthropic.claude-sonnet-4-6
max_input_tokens: 200000
@@ -1672,6 +1779,8 @@
output_price: 30
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh, max]
default_reasoning_effort: medium
- name: openai/gpt-5.6-terra
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -1679,6 +1788,8 @@
output_price: 30
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh, max]
default_reasoning_effort: medium
- name: openai/gpt-5.6-luna
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -1686,6 +1797,8 @@
output_price: 30
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh, max]
default_reasoning_effort: medium
- name: openai/gpt-5.5
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -1693,6 +1806,8 @@
output_price: 30
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh]
default_reasoning_effort: medium
- name: openai/gpt-5.5-pro
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -1700,6 +1815,8 @@
output_price: 180
supports_vision: true
supports_function_calling: true
reasoning_levels: [medium, high, xhigh]
default_reasoning_effort: high
- name: openai/gpt-5.4
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -1707,6 +1824,8 @@
output_price: 15
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh]
default_reasoning_effort: none
- name: openai/gpt-5.4-pro
max_input_tokens: 1050000
max_output_tokens: 128000
@@ -1714,6 +1833,8 @@
output_price: 180
supports_vision: true
supports_function_calling: true
reasoning_levels: [medium, high, xhigh]
default_reasoning_effort: medium
- name: openai/gpt-5.4-mini
max_input_tokens: 400000
max_output_tokens: 128000
@@ -1721,6 +1842,8 @@
output_price: 4.5
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh]
default_reasoning_effort: none
- name: openai/gpt-5.4-nano
max_input_tokens: 400000
max_output_tokens: 128000
@@ -1728,6 +1851,8 @@
output_price: 1.25
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh]
default_reasoning_effort: none
- name: openai/gpt-5.3-codex
max_input_tokens: 400000
max_output_tokens: 128000
@@ -1735,6 +1860,8 @@
output_price: 14
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh]
default_reasoning_effort: medium
- name: openai/gpt-5.2
max_input_tokens: 400000
max_output_tokens: 128000
@@ -1742,6 +1869,17 @@
output_price: 14
supports_vision: true
supports_function_calling: true
reasoning_levels: [none, low, medium, high, xhigh]
default_reasoning_effort: none
- name: openai/gpt-5.2-pro
max_input_tokens: 400000
max_output_tokens: 128000
input_price: 21
output_price: 168
supports_vision: true
supports_function_calling: true
reasoning_levels: [medium, high, xhigh]
default_reasoning_effort: medium
- name: openai/gpt-5
max_input_tokens: 400000
max_output_tokens: 128000
@@ -1749,6 +1887,8 @@
output_price: 10
supports_vision: true
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: medium
- name: openai/gpt-5-mini
max_input_tokens: 400000
max_output_tokens: 128000
@@ -1786,18 +1926,67 @@
input_price: 0.04
output_price: 0.16
supports_function_calling: true
- name: google/gemini-3.5-flash
max_input_tokens: 1048576
max_output_tokens: 65536
input_price: 0.2
output_price: 1.5
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: medium
- name: google/gemini-3-flash-preview
max_input_tokens: 1048576
max_output_tokens: 65536
input_price: 0.2
output_price: 1.5
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: high
- name: google/gemini-3.1-flash-lite
max_input_tokens: 1048576
max_output_tokens: 65536
input_price: 0.2
output_price: 1.5
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_effort: minimal
- name: google/gemini-3.1-pro-preview
max_input_tokens: 1048576
max_output_tokens: 65535
input_price: 0.3
output_price: 2.5
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high]
default_reasoning_effort: high
- name: google/gemini-3-pro-preview
max_input_tokens: 1048576
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, high]
default_reasoning_level: high
- name: google/gemini-3-flash-preview
max_input_tokens: 1048576
supports_vision: true
supports_function_calling: true
reasoning_levels: [minimal, low, medium, high]
default_reasoning_level: high
- name: google/gemini-2.5-flash
max_input_tokens: 1048576
input_price: 0.3
output_price: 2.5
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high]
default_reasoning_effort: low
- name: google/gemini-2.5-pro
max_input_tokens: 1048576
input_price: 1.25
output_price: 10
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high]
default_reasoning_effort: high
- name: google/gemini-2.5-flash-lite
max_input_tokens: 1048576
input_price: 0.3
@@ -1827,6 +2016,8 @@
output_price: 50
supports_function_calling: true
supports_vision: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: anthropic/claude-opus-4-8
max_input_tokens: 1000000
max_output_tokens: 128000
@@ -1835,6 +2026,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: anthropic/claude-opus-4-7
max_input_tokens: 1000000
max_output_tokens: 128000
@@ -1843,6 +2036,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: anthropic/claude-opus-4.6
max_input_tokens: 200000
max_output_tokens: 8192
@@ -1851,6 +2046,8 @@
output_price: 25
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, max]
default_reasoning_effort: high
- name: anthropic/claude-sonnet-5
max_input_tokens: 1000000
max_output_tokens: 128000
@@ -1859,6 +2056,8 @@
output_price: 15
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, xhigh, max]
default_reasoning_effort: high
- name: anthropic/claude-sonnet-4.6
max_input_tokens: 200000
max_output_tokens: 8192
@@ -1867,6 +2066,8 @@
output_price: 15
supports_vision: true
supports_function_calling: true
reasoning_levels: [low, medium, high, max]
default_reasoning_effort: high
- name: anthropic/claude-opus-4.5
max_input_tokens: 200000
max_output_tokens: 8192
+4
View File
@@ -325,6 +325,7 @@ fn build_chat_completions_body(data: ChatCompletionsData, model: &Model) -> Resu
mut messages,
temperature,
top_p,
reasoning_effort,
functions,
stream: _,
} = data;
@@ -457,6 +458,9 @@ fn build_chat_completions_body(data: ChatCompletionsData, model: &Model) -> Resu
if let Some(v) = top_p {
body["inferenceConfig"]["topP"] = v.into();
}
if let Some(v) = reasoning_effort {
body["additionalModelRequestFields"] = json!({ "output_config": { "effort": v } });
}
if let Some(functions) = functions {
let tools: Vec<_> = functions
.iter()
+4
View File
@@ -251,6 +251,7 @@ pub fn claude_build_chat_completions_body(
mut messages,
temperature,
top_p,
reasoning_effort,
functions,
stream,
} = data;
@@ -369,6 +370,9 @@ pub fn claude_build_chat_completions_body(
if let Some(v) = top_p {
body["top_p"] = v.into();
}
if let Some(v) = reasoning_effort {
body["output_config"] = json!({ "effort": v });
}
if stream {
body["stream"] = true.into();
}
+1
View File
@@ -286,6 +286,7 @@ pub struct ChatCompletionsData {
pub messages: Vec<Message>,
pub temperature: Option<f64>,
pub top_p: Option<f64>,
pub reasoning_effort: Option<String>,
pub functions: Option<Vec<FunctionDeclaration>>,
pub stream: bool,
}
+12
View File
@@ -289,6 +289,14 @@ impl Model {
}
Ok(())
}
pub fn reasoning_levels(&self) -> &[String] {
&self.data.reasoning_levels
}
pub fn default_reasoning_effort(&self) -> Option<&str> {
self.data.default_reasoning_effort.as_deref()
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
@@ -316,6 +324,10 @@ pub struct ModelData {
pub supports_vision: bool,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub supports_function_calling: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub reasoning_levels: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_reasoning_effort: Option<String>,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
no_stream: bool,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
+8
View File
@@ -356,6 +356,7 @@ pub fn openai_build_chat_completions_body(data: ChatCompletionsData, model: &Mod
messages,
temperature,
top_p,
reasoning_effort,
functions,
stream,
} = data;
@@ -454,6 +455,9 @@ pub fn openai_build_chat_completions_body(data: ChatCompletionsData, model: &Mod
if let Some(v) = top_p {
body["top_p"] = v.into();
}
if let Some(v) = reasoning_effort {
body["reasoning_effort"] = v.into();
}
if stream {
body["stream"] = true.into();
}
@@ -534,6 +538,7 @@ pub fn openai_build_responses_body(data: ChatCompletionsData, model: &Model) ->
messages,
temperature,
top_p,
reasoning_effort,
functions,
stream,
} = data;
@@ -590,6 +595,9 @@ pub fn openai_build_responses_body(data: ChatCompletionsData, model: &Model) ->
if let Some(v) = top_p {
body["top_p"] = v.into();
}
if let Some(v) = reasoning_effort {
body["reasoning"] = json!({ "effort": v });
}
if stream {
body["stream"] = true.into();
}
+4
View File
@@ -334,6 +334,7 @@ pub fn gemini_build_chat_completions_body(
mut messages,
temperature,
top_p,
reasoning_effort,
functions,
stream: _,
} = data;
@@ -426,6 +427,9 @@ pub fn gemini_build_chat_completions_body(
if let Some(v) = top_p {
body["generationConfig"]["topP"] = v.into();
}
if let Some(v) = reasoning_effort {
body["generation_config"]["thinking_level"] = v.into();
}
if let Some(functions) = functions {
// Gemini doesn't support functions with parameters that have empty properties, so we need to patch it.
+14
View File
@@ -575,6 +575,10 @@ impl RoleLike for Agent {
self.config.top_p
}
fn reasoning_effort(&self) -> Option<String> {
self.config.reasoning_effort.clone()
}
fn enabled_tools(&self) -> Option<Vec<String>> {
None
}
@@ -596,6 +600,10 @@ impl RoleLike for Agent {
self.config.top_p = value;
}
fn set_reasoning_effort(&mut self, value: Option<String>) {
self.config.reasoning_effort = value;
}
fn set_enabled_tools(&mut self, value: Option<Vec<String>>) {
match value {
Some(tools) => {
@@ -637,6 +645,8 @@ pub struct AgentConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub top_p: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning_effort: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub agent_session: Option<String>,
#[serde(default)]
pub auto_continue: bool,
@@ -732,6 +742,7 @@ impl AgentConfig {
model_id: graph.model.clone(),
temperature: graph.temperature,
top_p: graph.top_p,
reasoning_effort: graph.reasoning_effort.clone(),
description: graph.description.clone(),
global_tools: graph.global_tools.clone(),
mcp_servers: graph.mcp_servers.clone(),
@@ -766,6 +777,9 @@ impl AgentConfig {
if let Some(v) = read_env_value::<f64>(&with_prefix("top_p")) {
self.top_p = v;
}
if let Some(v) = read_env_value::<String>(&with_prefix("reasoning_effort")) {
self.reasoning_effort = v;
}
if let Ok(v) = env::var(with_prefix("global_tools"))
&& let Ok(v) = serde_json::from_str(&v)
{
+33 -1
View File
@@ -1,4 +1,4 @@
use crate::client::{ClientConfig, list_models};
use crate::client::{ClientConfig, Model, ModelType, list_models};
use crate::render::{MarkdownRender, RenderOptions};
use crate::utils::{IS_STDOUT_TERMINAL, NO_COLOR, decode_bin, get_env_name};
@@ -21,6 +21,7 @@ pub struct AppConfig {
pub model_id: String,
pub temperature: Option<f64>,
pub top_p: Option<f64>,
pub reasoning_effort: Option<String>,
pub dry_run: bool,
pub stream: bool,
@@ -100,6 +101,7 @@ impl Default for AppConfig {
model_id: Default::default(),
temperature: None,
top_p: None,
reasoning_effort: None,
dry_run: false,
stream: true,
@@ -177,6 +179,7 @@ impl AppConfig {
model_id: config.model_id,
temperature: config.temperature,
top_p: config.top_p,
reasoning_effort: None,
dry_run: config.dry_run,
stream: config.stream,
@@ -253,6 +256,7 @@ impl AppConfig {
app_config.setup_document_loaders();
app_config.setup_user_agent();
app_config.resolve_model()?;
app_config.validate_reasoning_effort()?;
Ok(app_config)
}
@@ -273,6 +277,31 @@ impl AppConfig {
Ok(())
}
fn validate_reasoning_effort(&self) -> Result<()> {
let Some(ref effort) = self.reasoning_effort else {
return Ok(());
};
let model = Model::retrieve_model(self, &self.model_id, ModelType::Chat)?;
let levels = model.reasoning_levels();
if levels.is_empty() {
bail!(
"reasoning_effort '{}' is configured but the model does not support reasoning effort",
effort
);
}
if !levels.iter().any(|l| l == effort) {
bail!(
"reasoning_effort '{}' is not valid for the model. Supported levels: {}",
effort,
levels.join(", ")
);
}
Ok(())
}
pub fn resolve_model(&mut self) -> Result<()> {
if self.model_id.is_empty() {
let models = list_models(self, crate::client::ModelType::Chat);
@@ -426,6 +455,9 @@ impl AppConfig {
if let Some(v) = super::read_env_value::<f64>(&get_env_name("top_p")) {
self.top_p = v;
}
if let Some(v) = super::read_env_value::<String>(&get_env_name("reasoning_effort")) {
self.reasoning_effort = v;
}
if let Some(Some(v)) = super::read_env_bool(&get_env_name("dry_run")) {
self.dry_run = v;
+5
View File
@@ -253,6 +253,10 @@ impl Input {
patch_messages(&mut messages, model);
model.guard_max_input_tokens(&messages)?;
let (temperature, top_p) = (self.role().temperature(), self.role().top_p());
let reasoning_effort = self
.role()
.reasoning_effort()
.or_else(|| model.default_reasoning_effort().map(|s| s.to_string()));
let functions = if model.supports_function_calling() {
let fns = self.functions.clone();
if let Some(vec) = &fns {
@@ -268,6 +272,7 @@ impl Input {
messages,
temperature,
top_p,
reasoning_effort,
functions,
stream,
})
+93
View File
@@ -969,6 +969,16 @@ impl RequestContext {
}
}
pub fn set_reasoning_effort_on_role_like(&mut self, value: Option<String>) -> bool {
match self.role_like_mut() {
Some(role_like) => {
role_like.set_reasoning_effort(value);
true
}
None => false,
}
}
pub fn set_enabled_tools_on_role_like(&mut self, value: Option<Vec<String>>) -> bool {
match self.role_like_mut() {
Some(role_like) => {
@@ -1121,6 +1131,10 @@ impl RequestContext {
super::format_option_value(&role.temperature()),
),
("top_p", super::format_option_value(&role.top_p())),
(
"reasoning_effort",
super::format_option_value(&role.reasoning_effort()),
),
(
"enabled_tools",
super::format_option_value(&role.enabled_tools().map(|v| v.join(","))),
@@ -2009,6 +2023,24 @@ impl RequestContext {
self.update_app_config(|app| app.top_p = value);
}
}
"reasoning_effort" => {
let value: Option<String> = super::parse_value(value)?;
if let Some(ref level) = value {
let levels = self.current_model().reasoning_levels();
if levels.is_empty() {
bail!("The current model does not support reasoning effort configuration");
}
if !levels.iter().any(|l| l == level) {
bail!(
"Invalid reasoning effort '{level}'. Supported levels for this model: {}",
levels.join(", ")
);
}
}
if !self.set_reasoning_effort_on_role_like(value.clone()) {
self.update_app_config(|app| app.reasoning_effort = value);
}
}
"enabled_tools" => {
let raw: Option<String> = super::parse_value(value)?;
let parsed: Option<Vec<String>> = raw.map(|s| super::csv_to_vec(&s));
@@ -2303,6 +2335,10 @@ impl RequestContext {
super::map_completion_values(values)
}
".macro" => super::map_completion_values(paths::list_macros()),
".reasoning" => {
let levels = self.current_model().reasoning_levels();
levels.iter().map(|v| (v.clone(), None)).collect()
}
".starter" => match &self.agent {
Some(agent) => agent
.conversation_starters()
@@ -2338,6 +2374,9 @@ impl RequestContext {
"save",
"highlight",
];
if !self.current_model().reasoning_levels().is_empty() {
values.push("reasoning_effort");
}
values.sort_unstable();
values
.into_iter()
@@ -2507,6 +2546,10 @@ impl RequestContext {
}
"skill_instructions" => vec!["null".to_string()],
"memory" => super::complete_bool(self.should_inject_memory()),
"reasoning_effort" => {
let levels = self.current_model().reasoning_levels();
levels.to_vec()
}
_ => vec![],
};
values = candidates.into_iter().map(|v| (v, None)).collect();
@@ -2704,6 +2747,22 @@ impl RequestContext {
None
};
if let Some(ref effort) = role.reasoning_effort() {
let levels = role.model().reasoning_levels();
if levels.is_empty() {
bail!(
"Role has reasoning_effort '{}' configured but the model does not support reasoning effort",
effort
);
}
if !levels.iter().any(|l| l == effort) {
bail!(
"Role's reasoning_effort '{}' is not valid for the model. Supported levels: {}",
effort,
levels.join(", ")
);
}
}
self.use_role_obj(role)?;
self.rebuild_tool_scope(app, mcp_servers, abort_signal)
.await
@@ -2759,6 +2818,23 @@ impl RequestContext {
None
};
if let Some(ref effort) = session.reasoning_effort() {
let levels = session.model().reasoning_levels();
if levels.is_empty() {
bail!(
"Session has reasoning_effort '{}' configured but the model does not support reasoning effort",
effort
);
}
if !levels.iter().any(|l| l == effort) {
bail!(
"Session's reasoning_effort '{}' is not valid for the model. Supported levels: {}",
effort,
levels.join(", ")
);
}
}
self.rebuild_tool_scope(app, mcp_servers, abort_signal.clone())
.await?;
@@ -2813,6 +2889,23 @@ impl RequestContext {
)
.await?;
if let Some(ref effort) = agent.reasoning_effort() {
let levels = agent.model().reasoning_levels();
if levels.is_empty() {
bail!(
"Agent has reasoning_effort '{}' configured but the model does not support reasoning effort",
effort
);
}
if !levels.iter().any(|l| l == effort) {
bail!(
"Agent's reasoning_effort '{}' is not valid for the model. Supported levels: {}",
effort,
levels.join(", ")
);
}
}
let is_graph_agent = graph::agent_has_graph(agent_name);
if is_graph_agent && session_name.is_some() {
bail!(
+21
View File
@@ -32,7 +32,9 @@ pub trait RoleLike {
fn enabled_mcp_servers(&self) -> Option<Vec<String>>;
fn set_model(&mut self, model: Model);
fn set_temperature(&mut self, value: Option<f64>);
fn reasoning_effort(&self) -> Option<String>;
fn set_top_p(&mut self, value: Option<f64>);
fn set_reasoning_effort(&mut self, value: Option<String>);
fn set_enabled_tools(&mut self, value: Option<Vec<String>>);
fn set_enabled_mcp_servers(&mut self, value: Option<Vec<String>>);
}
@@ -51,6 +53,8 @@ pub struct Role {
temperature: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
top_p: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
reasoning_effort: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
@@ -116,6 +120,9 @@ impl Role {
"model" => role.model_id = value.as_str().map(|v| v.to_string()),
"temperature" => role.temperature = value.as_f64(),
"top_p" => role.top_p = value.as_f64(),
"reasoning_effort" => {
role.reasoning_effort = value.as_str().map(|v| v.to_string())
}
"enabled_tools" => role.enabled_tools = parse_string_or_array(value),
"enabled_mcp_servers" => {
role.enabled_mcp_servers = parse_string_or_array(value)
@@ -170,6 +177,9 @@ impl Role {
if let Some(top_p) = self.top_p() {
metadata.push(format!("top_p: {top_p}"));
}
if let Some(reasoning_effort) = self.reasoning_effort() {
metadata.push(format!("reasoning_effort: {reasoning_effort}"));
}
if let Some(enabled_tools) = &self.enabled_tools {
let inline = serde_json::to_string(enabled_tools).unwrap_or_else(|_| "[]".to_string());
metadata.push(format!("enabled_tools: {inline}"));
@@ -256,6 +266,9 @@ impl Role {
enabled_tools,
enabled_mcp_servers,
);
if let Some(v) = role_like.reasoning_effort() {
self.set_reasoning_effort(Some(v));
}
}
pub fn batch_set(
@@ -410,6 +423,10 @@ impl RoleLike for Role {
self.top_p
}
fn reasoning_effort(&self) -> Option<String> {
self.reasoning_effort.clone()
}
fn enabled_tools(&self) -> Option<Vec<String>> {
self.enabled_tools.clone()
}
@@ -433,6 +450,10 @@ impl RoleLike for Role {
self.top_p = value;
}
fn set_reasoning_effort(&mut self, value: Option<String>) {
self.reasoning_effort = value;
}
fn set_enabled_tools(&mut self, value: Option<Vec<String>>) {
self.enabled_tools = value;
}
+14
View File
@@ -24,6 +24,8 @@ pub struct Session {
temperature: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
top_p: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
reasoning_effort: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
@@ -401,6 +403,7 @@ impl Session {
self.model_id = role.model().id();
self.temperature = role.temperature();
self.top_p = role.top_p();
self.reasoning_effort = role.reasoning_effort();
self.enabled_tools = role.enabled_tools();
self.enabled_mcp_servers = role.enabled_mcp_servers();
self.model = role.model().clone();
@@ -792,6 +795,10 @@ impl RoleLike for Session {
self.top_p
}
fn reasoning_effort(&self) -> Option<String> {
self.reasoning_effort.clone()
}
fn enabled_tools(&self) -> Option<Vec<String>> {
self.enabled_tools.clone()
}
@@ -823,6 +830,13 @@ impl RoleLike for Session {
}
}
fn set_reasoning_effort(&mut self, value: Option<String>) {
if self.reasoning_effort != value {
self.reasoning_effort = value;
self.dirty = true;
}
}
fn set_enabled_tools(&mut self, value: Option<Vec<String>>) {
if self.enabled_tools != value {
self.enabled_tools = value;
+4
View File
@@ -329,6 +329,9 @@ fn build_inline_role(
if let Some(p) = node.top_p {
role.set_top_p(Some(p));
}
if let Some(v) = &node.reasoning_effort {
role.set_reasoning_effort(Some(v.clone()));
}
if node.tools.as_deref().unwrap_or_default().is_empty() {
role.set_enabled_tools(Some(Vec::new()));
@@ -499,6 +502,7 @@ mod tests {
model: None,
temperature: None,
top_p: None,
reasoning_effort: None,
fallback: None,
max_attempts: 1,
max_iterations: 10,
+6
View File
@@ -25,6 +25,9 @@ pub struct Graph {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub top_p: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reasoning_effort: Option<String>,
#[serde(default)]
pub global_tools: Vec<String>,
@@ -288,6 +291,9 @@ pub struct LlmNode {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub top_p: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reasoning_effort: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub fallback: Option<String>,
+2
View File
@@ -946,6 +946,7 @@ mod tests {
model: None,
temperature: None,
top_p: None,
reasoning_effort: None,
global_tools: Vec::new(),
mcp_servers: Vec::new(),
skills_enabled: None,
@@ -1048,6 +1049,7 @@ mod tests {
model: None,
temperature: None,
top_p: None,
reasoning_effort: None,
fallback: fallback.map(String::from),
max_attempts: 1,
max_iterations: 10,
+1
View File
@@ -362,6 +362,7 @@ pub async fn extract_entities(
messages,
temperature: Some(0.0),
top_p: None,
reasoning_effort: None,
functions: None,
stream: false,
};
+2
View File
@@ -31,6 +31,7 @@ impl Completer for ReplCompleter {
let ctx = self.ctx.read();
let state = ctx.state();
let model_has_reasoning = !ctx.current_model().reasoning_levels().is_empty();
let command_filter = parts
.iter()
@@ -44,6 +45,7 @@ impl Completer for ReplCompleter {
.filter(|cmd| {
cmd.is_valid(state)
&& (command_filter.len() == 1 || cmd.name.starts_with(&command_filter[..2]))
&& (cmd.name != ".reasoning" || model_has_reasoning)
})
.collect();
let commands = fuzzy_filter(commands, |v| v.name, &command_filter);
+17 -3
View File
@@ -52,7 +52,7 @@ pub const DEFAULT_CONTINUATION_PROMPT: &str = indoc! {"
4. Continue with the next pending item now. Call tools immediately."
};
static REPL_COMMANDS: LazyLock<[ReplCommand; 51]> = LazyLock::new(|| {
static REPL_COMMANDS: LazyLock<[ReplCommand; 52]> = LazyLock::new(|| {
[
ReplCommand::new(".help", "Show this help guide", AssertState::pass()),
ReplCommand::new(".info", "Show system info", AssertState::pass()),
@@ -259,6 +259,11 @@ static REPL_COMMANDS: LazyLock<[ReplCommand; 51]> = LazyLock::new(|| {
),
ReplCommand::new(".copy", "Copy last response", AssertState::pass()),
ReplCommand::new(".set", "Modify runtime settings", AssertState::pass()),
ReplCommand::new(
".reasoning",
"Set the reasoning effort level for the current model",
AssertState::pass(),
),
ReplCommand::new(
".delete",
"Delete roles, sessions, RAGs, or agents",
@@ -1070,6 +1075,15 @@ pub async fn run_repl_command(
println!("Usage: .set <key> <value>...")
}
},
".reasoning" => match args {
Some(level) => {
let set_args = format!("reasoning_effort {level}");
ctx.update(&set_args, abort_signal).await?;
}
None => {
println!("Usage: .reasoning <level>")
}
},
".delete" => match args {
Some(args) => {
ctx.delete(args)?;
@@ -1600,8 +1614,8 @@ mod tests {
}
#[test]
fn repl_commands_has_50_entries() {
assert_eq!(REPL_COMMANDS.len(), 50);
fn repl_commands_has_52_entries() {
assert_eq!(REPL_COMMANDS.len(), 52);
}
#[test]