Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/claude_agent_sdk/_internal/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,26 @@ async def _process_query_inner(
) -> AsyncGenerator[Message, None]:
# Validate and configure permission settings (matching TypeScript SDK logic)
configured_options = options

# When agents are defined with model specifications but no global model is set,
# infer a global model to ensure the CLI respects user-specified models rather
# than falling back to its default (which may differ from agent specifications).
if options.agents and options.model is None:
agent_models = {
agent_def.model
for agent_def in options.agents.values()
if agent_def.model is not None and agent_def.model != "inherit"
}
if agent_models:
# If all agents use the same model, use that as the global default
if len(agent_models) == 1:
inferred_model = agent_models.pop()
else:
# Multiple models specified: use the first non-inherit model as fallback
# This ensures at least one user-specified model is used globally
inferred_model = next(iter(agent_models))
configured_options = replace(options, model=inferred_model)

if options.can_use_tool:
# canUseTool callback requires streaming mode (AsyncIterable prompt)
if isinstance(prompt, str):
Expand Down
25 changes: 22 additions & 3 deletions src/claude_agent_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,27 @@ async def _connect_inner(
from ._internal.transport.subprocess_cli import SubprocessCLITransport

# Validate and configure permission settings (matching TypeScript SDK logic)
options = self.options

# When agents are defined with model specifications but no global model is set,
# infer a global model to ensure the CLI respects user-specified models rather
# than falling back to its default (which may differ from agent specifications).
if options.agents and options.model is None:
agent_models = {
agent_def.model
for agent_def in options.agents.values()
if agent_def.model is not None and agent_def.model != "inherit"
}
if agent_models:
# If all agents use the same model, use that as the global default
if len(agent_models) == 1:
inferred_model = agent_models.pop()
else:
# Multiple models specified: use the first non-inherit model as fallback
# This ensures at least one user-specified model is used globally
inferred_model = next(iter(agent_models))
options = replace(options, model=inferred_model)

if self.options.can_use_tool:
# canUseTool callback requires streaming mode (AsyncIterable prompt)
if isinstance(prompt, str):
Expand All @@ -173,9 +194,7 @@ async def _connect_inner(
)

# Automatically set permission_prompt_tool_name to "stdio" for control protocol
options = replace(self.options, permission_prompt_tool_name="stdio")
else:
options = self.options
options = replace(options, permission_prompt_tool_name="stdio")

if self._materialized is not None:
options = apply_materialized_options(options, self._materialized)
Expand Down