Repository navigation
fix: pass AI Config model parameters through to every provider handler #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
9ad50a5
beabd79
2e91885
d51199d
8144a3d
c25d33b
828279f
38d463a
5a43f72
5314cb5
d681399
4a233d7
fba3d67
1a1539e
175050b
372c2ae
9055c2a
a2a7d73
956315c
fba0880
4b03acd
f9b1bf5
1c60bdf
4e92432
8c1f9f7
7cfb3a7
52bf2d2
c76acd5
db839fe
2d52270
27ff2c4
3237589
a125877
b1438bb
af122f9
a9f986f
fa5673d
040055d
b1ed895
52ccc87
cf544b1
c61668c
b7cecca
bfcd09b
172a7ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,6 +53,8 @@ | |
| ) | ||
| from launchdarkly_ai_server.agui import TurnEmitter | ||
| from launchdarkly_ai_server.lifecycle import effective_capture_content | ||
| from launchdarkly_ai_server.parameter_forwarding import select_forwarded_parameters | ||
| from launchdarkly_ai_server.utils import model_parameters | ||
|
|
||
| from ._version import PACKAGE_NAME, __version__ | ||
| from .spans import ( | ||
|
|
@@ -73,6 +75,94 @@ | |
| tool_display_name, | ||
| ) | ||
|
|
||
| #: Every field ``ClaudeAgentOptions`` declares, classified by hand into exactly one of: forwarded | ||
| #: (below), handler-owned (``model``, ``allowed_tools``, ``mcp_servers``, ``hooks``, ``tools``, | ||
| #: ``system_prompt``, set by each call site itself), or excluded (below). | ||
| #: ``TestClaudeAgentOptionsAcceptsExactlyTheseFields`` in this package's tests asserts this | ||
| #: classification stays exhaustive as the SDK's own dataclass changes. | ||
| #: | ||
| #: Only model and run settings are forwarded: how the model thinks, how long the run may go, and | ||
| #: what it may spend. Everything that configures the host process the SDK launches (its binary, | ||
| #: environment, working directory, file access, permissions, settings files, plugins, sandbox, | ||
| #: session state) stays under the application's control, never a config's. | ||
| #: | ||
| #: This is the cross-SDK list for Claude Agents (TESTING.md section 1.12), shared with the native | ||
| #: graph through :func:`_options_parameters`. | ||
| #: | ||
| #: The SDK offers no ``temperature``/``top_p``/``top_k``/``max_tokens``/``stop_sequences``/ | ||
| #: ``tool_choice``/``metadata``, all of which the LaunchDarkly UI's model parameters panel offers | ||
| #: for other providers; they are dropped like any other key not listed here. | ||
| _CLAUDE_AGENT_OPTIONS_FORWARDED_KEYS = frozenset( | ||
| { | ||
| "betas", | ||
| "effort", | ||
| "fallback_model", | ||
| "max_budget_usd", | ||
| "max_thinking_tokens", | ||
| "max_turns", | ||
| "output_format", | ||
| "thinking", | ||
| } | ||
| ) | ||
|
|
||
| #: Forwarded keys whose value must be an object. A config value of any other type is malformed | ||
| #: and dropped rather than passed to ``ClaudeAgentOptions``. | ||
| _CLAUDE_AGENT_OPTIONS_MAPPING_KEYS = frozenset({"output_format", "thinking"}) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incomplete thinking objects crash Claude AgentsHigh Severity
Additional Locations (1)Reviewed by Cursor Bugbot for commit 172a7ac. Configure here. |
||
|
|
||
| #: Accepted by ``ClaudeAgentOptions`` but never forwarded, and why: | ||
| #: * ``cli_path``, ``env``, ``cwd``, ``add_dirs``, ``settings``, ``setting_sources``, ``plugins``, | ||
| #: ``skills``, ``sandbox``, ``user``, ``extra_args``: which binary runs, with what environment, | ||
| #: as which user, with what files, settings, plugins, and CLI arguments. A config that could set | ||
| #: these could run code on, or read files from, the host. | ||
| #: * ``permission_mode``, ``permission_prompt_tool_name``, ``can_use_tool``, ``disallowed_tools``, | ||
| #: ``strict_mcp_config``, ``agents``: what the agent is allowed to do and which tools or | ||
| #: subagents it gets. The handler wires tools and permissions itself. | ||
| #: * ``resume``, ``session_id``, ``fork_session``, ``continue_conversation``, ``session_store``, | ||
| #: ``session_store_flush``, ``enable_file_checkpointing``: session state on the host. | ||
| #: * ``stderr``, ``debug_stderr``, ``include_partial_messages``, ``include_hook_events``, | ||
| #: ``max_buffer_size``, ``load_timeout_ms``: process I/O and transport plumbing, including the | ||
| #: streamed message shape the handler reads. | ||
| #: * ``task_budget``: not one of the agreed run settings yet; ``max_turns`` and ``max_budget_usd`` | ||
| #: cover run limits. | ||
| #: | ||
| #: Named for the drift test and for review, not read at runtime: the forwarded list above already | ||
| #: leaves these out, so nothing needs to subtract them again. | ||
| _CLAUDE_AGENT_OPTIONS_EXCLUDED_KEYS = frozenset( | ||
| { | ||
| "add_dirs", | ||
| "agents", | ||
| "can_use_tool", | ||
| "cli_path", | ||
|
jeffdupont marked this conversation as resolved.
|
||
| "continue_conversation", | ||
| "cwd", | ||
| "debug_stderr", | ||
| "disallowed_tools", | ||
| "enable_file_checkpointing", | ||
| "env", | ||
| "extra_args", | ||
| "fork_session", | ||
| "include_hook_events", | ||
| "include_partial_messages", | ||
| "load_timeout_ms", | ||
| "max_buffer_size", | ||
| "permission_mode", | ||
| "permission_prompt_tool_name", | ||
| "plugins", | ||
| "resume", | ||
| "sandbox", | ||
| "session_id", | ||
| "session_store", | ||
| "session_store_flush", | ||
| "setting_sources", | ||
| "settings", | ||
| "skills", | ||
| "stderr", | ||
| "strict_mcp_config", | ||
| "task_budget", | ||
| "user", | ||
| } | ||
| ) | ||
|
cursor[bot] marked this conversation as resolved.
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # Tool wiring | ||
| # --------------------------------------------------------------------------- | ||
|
|
@@ -504,6 +594,18 @@ def _raise_if_run_failed(message: Any) -> None: | |
| ) | ||
|
|
||
|
|
||
| def _options_parameters(config: AiConfigRep) -> dict[str, Any]: | ||
| """The config's ``model.parameters`` that become ``ClaudeAgentOptions`` fields: only | ||
| :data:`_CLAUDE_AGENT_OPTIONS_FORWARDED_KEYS`, with malformed object values dropped. The handler | ||
| and the native graph both call this, so they forward the same keys. | ||
| """ | ||
| return select_forwarded_parameters( | ||
| model_parameters(config), | ||
| _CLAUDE_AGENT_OPTIONS_FORWARDED_KEYS, | ||
| mapping_keys=_CLAUDE_AGENT_OPTIONS_MAPPING_KEYS, | ||
| ) | ||
|
|
||
|
|
||
| def _build_query_options( | ||
| config: AiConfigRep, | ||
| system_prompt: str | None, | ||
|
|
@@ -514,7 +616,9 @@ def _build_query_options( | |
| **extra: Any, | ||
| ) -> ClaudeAgentOptions: | ||
| all_allowed = [*mcp_allowed_tools, *native_tool_names] | ||
| params = _options_parameters(config) | ||
| kwargs: dict[str, Any] = { | ||
| **params, | ||
|
cursor[bot] marked this conversation as resolved.
|
||
| "model": config["model"]["name"], | ||
| "allowed_tools": all_allowed if all_allowed else [], | ||
| "mcp_servers": {TOOL_MCP_NAME: tool_mcp} if tool_mcp else {}, | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This checks that
thinkingis a mapping but not its shape.claude_agent_sdk0.2.110 readst["type"]and thent["budget_tokens"]straight away when it builds the CLI command. So{"budget_tokens": 1024}raisesKeyError: 'type', and{"type": "enabled"}raisesKeyError: 'budget_tokens'. Both configs ran before this PR. Couldthinkingbe dropped unless it has a knowntype(andbudget_tokensforenabled), as §1.12 and js #118 do?