Skip to content
Closed
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
3 changes: 3 additions & 0 deletions packages/sdk-python/src/qwen_code_sdk/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,4 +240,7 @@ def build_cli_arguments(options: QueryOptions) -> list[str]:
elif options.session_id:
args.extend(["--session-id", options.session_id])

if options.extra_args:
args.extend(options.extra_args)

return args
3 changes: 3 additions & 0 deletions packages/sdk-python/src/qwen_code_sdk/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class QueryOptionsDict(TypedDict, total=False):
timeout: TimeoutOptionsDict
mcp_servers: dict[str, dict[str, Any]]
stderr: Callable[[str], None]
extra_args: list[str]


@dataclass
Expand All @@ -139,6 +140,7 @@ class QueryOptions:
timeout: TimeoutOptions = TimeoutOptions()
mcp_servers: dict[str, dict[str, Any]] | None = None
stderr: Callable[[str], None] | None = None
extra_args: list[str] | None = None

@classmethod
def from_mapping(cls, value: Mapping[str, Any] | None) -> QueryOptions:
Expand Down Expand Up @@ -183,6 +185,7 @@ def from_mapping(cls, value: Mapping[str, Any] | None) -> QueryOptions:
Callable[[str], None] | None,
_as_optional_callable(data, "stderr"),
),
extra_args=_as_optional_str_list(data, "extra_args"),
)


Expand Down
13 changes: 13 additions & 0 deletions packages/sdk-python/src/qwen_code_sdk/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ def validate_query_options(options: QueryOptions) -> None:
):
raise ValidationError("path_to_qwen_executable cannot be empty")

if options.extra_args:
_CONFLICTING_FLAGS = {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] _CONFLICTING_FLAGS is defined inside the if options.extra_args: block, but the file's convention is module-level constants (see _VALID_PERMISSION_MODES, _VALID_AUTH_TYPES at lines 13-14). Move it to module scope for consistency and discoverability:

Suggested change
_CONFLICTING_FLAGS = {
_CONFLICTING_FLAGS = frozenset({"--input-format", "--output-format", "--channel"})

Also, the blocklist only covers 3 of ~15 SDK-managed flags. Since extra_args is appended last, a user can silently override --model, --approval-mode, --resume, --session-id, etc. via last-wins CLI semantics. Consider either expanding the blocklist to cover all SDK-managed flags, or updating the docstring/JSDoc to warn that only the three protocol-breaking flags are hard-blocked.

— qwen3.7-max via Qwen Code /review

"--input-format",
"--output-format",
"--channel",
}
for arg in options.extra_args:
if arg in _CONFLICTING_FLAGS:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] The check if arg in _CONFLICTING_FLAGS uses exact string matching, so --input-format=json or --channel=custom (with =) bypasses validation entirely. The SDK itself uses --channel=SDK (equals syntax), proving the CLI accepts this form.

Suggested change
if arg in _CONFLICTING_FLAGS:
for arg in options.extra_args:
flag_name = arg.split("=", 1)[0]
if flag_name in _CONFLICTING_FLAGS:

— qwen3.7-max via Qwen Code /review

raise ValidationError(
f"extra_args cannot include '{arg}' — "
"it is managed by the SDK"
)

if options.mcp_servers:
raise ValidationError(
"mcp_servers is not supported in Python SDK v1. "
Expand Down
1 change: 1 addition & 0 deletions packages/sdk-typescript/src/query/createQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export function query({
includePartialMessages: options.includePartialMessages,
resume: options.resume,
sessionId,
extraArgs: options.extraArgs,
});

const queryOptions: QueryOptions = {
Expand Down
4 changes: 4 additions & 0 deletions packages/sdk-typescript/src/transport/ProcessTransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,10 @@ export class ProcessTransport implements Transport {
args.push('--session-id', this.options.sessionId);
}

if (this.options.extraArgs && this.options.extraArgs.length > 0) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] The TypeScript SDK has no conflicting-flag validation for extraArgs. The JSDoc on TransportOptions.extraArgs states "Cannot include --input-format, --output-format, or --channel (managed by the SDK)" but this is documentation-only — the Zod schema accepts z.array(z.string()).optional() with no refinement, and buildCliArguments blindly spreads the array. A user passing extraArgs: ['--input-format', 'text'] silently breaks the stream-json protocol.

Add runtime validation matching the Python SDK:

const CONFLICTING_FLAGS = new Set(['--input-format', '--output-format', '--channel']);
for (const arg of this.options.extraArgs ?? []) {
  const name = arg.split('=', 1)[0];
  if (CONFLICTING_FLAGS.has(name)) {
    throw new Error(`extraArgs cannot include '${name}' — it is managed by the SDK`);
  }
}

— qwen3.7-max via Qwen Code /review

args.push(...this.options.extraArgs);
}

return args;
}

Expand Down
1 change: 1 addition & 0 deletions packages/sdk-typescript/src/types/queryOptionsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,5 +182,6 @@ export const QueryOptionsSchema = z
resume: z.string().optional(),
sessionId: z.string().optional(),
timeout: TimeoutConfigSchema.optional(),
extraArgs: z.array(z.string()).optional(),
})
.strict();
15 changes: 15 additions & 0 deletions packages/sdk-typescript/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ export type TransportOptions = {
* When resume is provided, this should match the resume ID.
*/
sessionId?: string;
/**
* Additional CLI arguments to pass to the qwen process.
* Escape hatch for flags not explicitly supported by the SDK.
* Cannot include --input-format, --output-format, or --channel
* (managed by the SDK).
*/
extraArgs?: string[];
};

export interface QuerySystemPromptPreset {
Expand Down Expand Up @@ -503,4 +510,12 @@ export interface QueryOptions {
*/
streamClose?: number;
};

/**
* Additional CLI arguments to pass to the qwen process.
* Escape hatch for flags not explicitly supported by the SDK.
* Cannot include --input-format, --output-format, or --channel
* (managed by the SDK).
*/
extraArgs?: string[];
}
Loading