Commit graph

4 commits

Author SHA1 Message Date
morluto
41157205c1
fix(config): reject fractional session and tool-call limits (#6920)
* fix(config): reject fractional session and tool-call limits

* fix(config): validate persisted session turn limits
2026-07-15 04:56:52 +00:00
juhuan
85c1c0741c
feat(sdk): expose transport and query options in both SDKs (#6491)
* feat(sdk): expose transport and query options in both SDKs

Consolidated PR covering pure SDK-side option additions:

- fork_session (--fork-session)
- max_tool_calls (--max-tool-calls)
- max_subagent_depth (--max-subagent-depth)
- agents (via initialize control request)
- include_directories (--include-directories)
- extra_args (pass-through CLI flags)
- extensions (--extensions)
- allowed_mcp_server_names (--allowed-mcp-server-names)
- mcp_servers (Python SDK, via initialize control request)
- fallback_model (--fallback-model, max 3)
- proxy (--proxy, deprecated)
- sandbox (--sandbox)
- safe_mode (--safe-mode)
- insecure (--insecure)
- worktree (--worktree)
- disabled_slash_commands (--disabled-slash-commands)

All options implemented in both Python SDK and TypeScript SDK
with validation and unit tests.

* fix(sdk): expand extraArgs blocklist and add TS SDK tests

- Expand reserved CLI flags blocklist from 3 to 34 flags, covering all
  SDK-managed options and security-sensitive flags (--model, --auth-type,
  --approval-mode, --insecure, --dangerously-skip-permissions, etc.)
- Add Zod refine validation for extraArgs in TS SDK (previously no validation)
- Update extraArgs JSDoc to document security implications
- Add 12 ProcessTransport tests for new CLI argument building
- Add queryOptionsSchema.test.ts with 20 validation tests
- Add createQuery.test.ts option passthrough test for all new fields
- Add Python parametrized tests for expanded blocklist

* fix(sdk): address review feedback for consolidated options

Security fixes:
- Fix --flag=value bypass: split on = before checking reserved flags
- Add missing dangerous flags: --yolo/-y, --openai-base-url, --openai-api-key,
  --mcp-config, --prompt, --add-dir, --input-file, --json-schema/fd/file
- Remove ghost flags (--dangerously-skip-permissions, --allow-dangerously-skip-permissions)

Bug fixes:
- Fix Python mcp_servers key: snake_case -> camelCase (mcpServers)
- Remove duplicate agents declarations in Zod schema and types.ts
- Add maxToolCalls range validation (.int().min(-1)) in Zod schema
- Fix agents validation cross-SDK: reject empty strings in TS (matching Python)

Tests:
- Add --flag=value bypass tests (both SDKs)
- Add tests for new dangerous flags
- Add maxToolCalls range validation tests
- Add agents empty-string rejection test

* fix(sdk): add short flag aliases, fix zod validator, add forkSession validation

- Add short flag aliases (-m, -p, -i, -s, -e, -o, -c, -r) to reserved
  CLI flags blocklist in both Python and TS SDKs to prevent blocklist
  bypass via short flags
- Fix z.custom validator for agents: move error message from && chain
  to 2nd argument so Zod produces the descriptive error on failure
- Fix TS2345: coerce split('=')[0] with ?? '' for noUncheckedIndexedAccess
- Add forkSession prerequisite validation: requires resume to be set,
  matching CLI behavior that rejects --fork-session without --resume
- Remove dead agents field from TransportOptions (agents flow through
  initialize payload, not transport CLI args)
- Add tests for short flags, forkSession validation in both SDKs

* fix(sdk): add --no-* negation flags, comma validation, fork session ID fix

- Add --no-sandbox, --no-safe-mode, --no-insecure, --no-worktree,
  --sandbox-image, --sandbox-session-id to reserved CLI flags blocklist
  in both SDKs to prevent yargs boolean negation bypass
- Add per-element comma validation for comma-joined list fields
  (includeDirectories, extensions, allowedMcpServerNames,
  fallbackModel, disabledSlashCommands) to prevent CLI comma-split
  injection
- Add min(1) validation for extraArgs items to reject empty strings
- Fix fork_session validation to also accept continue_session (not just
  resume), matching CLI behavior
- Allow session_id with resume when fork_session is True
- Fix fork session ID mismatch: generate new UUID for forked session
  instead of reusing resume (source) session ID, so getSessionId()
  returns the correct forked session ID

* fix(sdk): add fork session ID test assertions and mcp_servers validation

- Add assertions to forkSession test verifying sessionId is a new UUID
  different from the resume value
- Add test for forkSession with explicit sessionId
- Add structural validation for mcp_servers in Python SDK to reject
  non-mapping configs before sending to CLI

* fix: fork session ID discarded by Query constructor

Query.ts:97 used `options.resume ?? options.sessionId` which always
picked resume when forkSession was true, ignoring the new fork UUID
generated in createQuery.ts. Now uses fork UUID when forkSession is true.

Python SDK: query() now generates a fresh UUID for fork_session instead
of reusing the resume (source) session ID. _session_id_locked is False
for fork sessions, allowing the CLI to correct the session ID via
control responses.

* fix: mypy type error in fork_session session_id annotation

Add explicit `str | None` type annotation to session_id variable
to resolve mypy error where fork branch inferred `str` but else
branch assigns `str | None`.

* test: address review suggestions for test coverage and validation

- Add comma validation negative tests for all 5 list fields (both SDKs)
- Add maxSubagentDepth boundary tests (0, 101, 1, 100) for TS SDK
- Add from_mapping tests for all new fields and default values (Python)
- Add ProcessTransport negative test verifying flags absent when unset
- Remove --no-worktree dead code from RESERVED_CLI_FLAGS (both SDKs)
- Add --fork-session and other new flags to reserved-flags test list
- Add continue field to TS schema to match TransportOptions type
- Fix forkSession refine to accept resume OR continue (matching Python)

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
2026-07-12 07:10:45 +00:00
juhuan
8e6a572562
feat(sdk): add control request methods for effort, models, usage, context (#6492)
Some checks are pending
E2E Tests / web-shell Browser Regression (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
SDK Python / Classify PR (push) Waiting to run
SDK Python / SDK Python (3.10) (push) Blocked by required conditions
SDK Python / SDK Python (3.11) (push) Blocked by required conditions
SDK Python / SDK Python (3.12) (push) Blocked by required conditions
* feat(sdk): add control request methods for effort, models, usage, context

Add 4 control request methods across CLI, Python SDK, and TypeScript SDK:

- set_effort: Set reasoning effort tier (low/medium/high/xhigh/max) at
  runtime via config.setReasoningEffort(), also accept initial effort
  in initialize payload
- get_available_models: Return models available for current auth type
  via config.getAvailableModels()
- get_usage_info: Return usage dashboard data via loadUsageDashboard()
  with optional range filter (today/week/month/all)
- get_context_usage: Add Python SDK method (TS SDK already has it)

CLI: Add request types, dispatcher routing, and SystemController handlers
with capability flags (can_set_effort, can_get_available_models,
can_get_usage_info).

TS SDK: Add ControlRequestType enum values, protocol interfaces,
QueryOptions.effort field, Zod schema, and Query methods.
Python SDK: Add Effort type, validation, protocol TypedDicts, and
Query methods.

* fix(sdk): address CI feedback for control request methods

- Fix TransportOptions.effort type to literal union instead of string
- Fix Python CLIControlGetUsageInfoRequest.range to Literal type
- Remove redundant signal.aborted checks in handleGetUsageInfo
- Add Python SDK tests for set_effort, get_available_models, get_context_usage, get_usage_info, effort in initialize
- Add TS SDK tests for setEffort, getAvailableModels, getUsageInfo

* fix(sdk): address review feedback for control request methods

- Remove dead effort field from TransportOptions (flows via QueryOptions)
- Throw on invalid effort in handleInitialize (matching handleSetEffort)
- Wrap setReasoningEffort in try/catch (matching addMcpServers pattern)
- Sanitize get_available_models response to exclude baseUrl/envKey
- Rename Python get_usage_info(range=) to time_range= to avoid shadowing built-in
- Use Effort type alias and Literal type in Python set_effort/get_usage_info
- Make set_effort/setEffort return None/void to match set_model/setModel
- Add TS test for effort in initialize payload

* fix(cli): add effort read-back check and CLI-level unit tests

- Add read-back check after setReasoningEffort() in both handleSetEffort
  and handleInitialize to detect silent no-op when thinking is disabled
- Return applied flag in set_effort response so SDK consumers can detect
  when effort was not applied
- Remove user input from error messages to match handleSetModel convention
- Add unit tests for set_effort, get_available_models, get_usage_info, and
  initialize with effort handlers

* fix(sdk): surface applied flag from setEffort, move effort validation before side effects

- Move effort validation in handleInitialize before MCP servers and
  subagents processing to prevent config-mutating side effects if
  effort is invalid
- Return applied boolean from setEffort/set_effort so SDK consumers can
  detect when effort was a no-op (thinking disabled)
- Fix spread order in handleGetUsageInfo to prevent subtype overwrite
- Update JSDoc to reflect actual behavior
2026-07-11 10:08:12 +00:00
jinye
e384338145
feat(SDK) Add Python SDK implementation for #3010 (#3494)
* Codex worktree snapshot: startup-cleanup

Co-authored-by: Codex

* Add Python SDK real smoke test

Adds a repository-only real E2E smoke script for the Python SDK, plus npm and developer documentation entry points.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk-python): address review findings — bugs, type safety, and test coverage

- Fix prepare_spawn_info: JS files now use "node" instead of sys.executable
- Fix protocol.py: correct total=False misuse on 7 TypedDicts (required fields were optional)
- Fix query.py: add _closed guard in _ensure_started, suppress exceptions in close()
- Fix sync_query.py: prevent close() deadlock, add context manager, add timeouts
- Fix transport.py: handle malformed JSON lines, add _closed guard in start()
- Fix validation.py: use uuid.RFC_4122 instead of magic UUID
- Fix __init__.py: export TextBlock, widen query_sync signature
- Remove dead code: ensure_not_aborted, write_json_line, _thread_error
- Add 12 new tests (29 → 41): context managers, JSON skip, closed guards, spawn info, timeouts

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk-python): address wenshao review — session_id, bool validation, debug stderr

- Fix continue_session=True generating a wrong random session_id
- Add _as_optional_bool helper for strict type validation on bool fields
- Default debug stderr to sys.stderr when no custom callback is provided

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk-python): address remaining wenshao review feedback

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(cli): harden settings dialog restart prompt test

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk-python): review fixes — UUID compat, stderr fallback, sync cleanup

- Remove UUID version restriction to support v6/v7/v8 (RFC 9562)
- Always write to sys.stderr when stderr callback raises (was silent when debug=False)
- Prevent duplicate _STOP sentinel in SyncQuery.close() via _stop_sent flag
- Add ruff format --check to CI workflow
- Fix smoke_real.py version guard: fail early before imports instead of NameError
- Apply ruff format to existing files

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk-python): remaining review fixes — exit_code attr, guard strictness, sync timeout

- Add exit_code attribute to ProcessExitError for programmatic access
- Strengthen is_control_response/is_control_cancel guards to require
  payload fields, preventing misrouting of malformed messages
- Expose control_request_timeout property on Query so SyncQuery uses
  the configured timeout instead of a hardcoded 30s default
- Use dataclasses.replace() instead of direct mutation on frozen-style
  QueryOptions in query() factory
- Add ResourceWarning in SyncQuery.__del__ when not properly closed

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk-python): add exit_code default and guard __del__ against partial GC

- Give ProcessExitError.exit_code a default value (-1) so user code can
  construct the exception with just a message string
- Wrap SyncQuery.__del__ in try/except AttributeError to prevent crashes
  when the object is partially garbage-collected

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk-python): review fixes — resource leak, type safety, CI matrix, docs

- Fix SyncQuery.__del__ to call close() on GC instead of only warning
- Replace hasattr duck-type check with isinstance(prompt, AsyncIterable)
- Type-validate permission_mode/auth_type in QueryOptions.from_mapping
- Use TypeGuard return types on all is_sdk_*/is_control_* predicates
- Add 5s margin to sync wrapper timeouts to prevent error type masking
- Expand CI matrix to test Python 3.10, 3.11, 3.12
- Change ProcessExitError.exit_code default from -1 to None
- Add stderr to docs QueryOptions listing
- Update README sync example to use context manager pattern

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk-python): preserve iterator exhaustion state and suppress detached task warning

- Add _exhausted flag to Query.__anext__ and SyncQuery.__next__ so
  repeated iteration after end-of-stream raises Stop(Async)Iteration
  instead of blocking forever.
- Remove re-raise in _initialize() to prevent asyncio
  "Task exception was never retrieved" warning on detached tasks;
  the error is already surfaced via _finish_with_error().

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk-python): reject mcp_servers at validation time and add iterator/init tests

- Reject mcp_servers in validate_query_options() with a clear error
  instead of advertising MCP support to the CLI and then failing at
  runtime when mcp_message arrives.
- Remove dead mcp_servers branch from _initialize().
- Add tests for async/sync iterator exhaustion, detached init task
  warning suppression, and mcp_servers validation.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk-python): fix ruff lint errors in new tests

- Use ControlRequestTimeoutError instead of bare Exception (B017)
- Fix import sorting for stdlib vs third-party (I001)
- Break long line to stay within 88-char limit (E501)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* style(sdk-python): apply ruff format to new tests

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: jinye.djy <jinye.djy@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-25 07:02:58 +08:00