diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index b3d51813..6fa72c57 100755 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -11,6 +11,7 @@ import type { import { extensionsCommand } from '../commands/extensions.js'; import { ApprovalMode, + AuthType, Config, DEFAULT_QWEN_EMBEDDING_MODEL, DEFAULT_MEMORY_FILE_FILTERING_OPTIONS, @@ -128,6 +129,10 @@ export interface CliArgs { inputFormat?: string | undefined; outputFormat: string | undefined; includePartialMessages?: boolean; + maxSessionTurns: number | undefined; + coreTools: string[] | undefined; + excludeTools: string[] | undefined; + authType: string | undefined; } function normalizeOutputFormat( @@ -395,6 +400,31 @@ export async function parseArguments(settings: Settings): Promise { 'Include partial assistant messages when using stream-json output.', default: false, }) + .option('max-session-turns', { + type: 'number', + description: 'Maximum number of session turns', + }) + .option('core-tools', { + type: 'array', + string: true, + description: 'Core tool paths', + coerce: (tools: string[]) => + // Handle comma-separated values + tools.flatMap((tool) => tool.split(',').map((t) => t.trim())), + }) + .option('exclude-tools', { + type: 'array', + string: true, + description: 'Tools to exclude', + coerce: (tools: string[]) => + // Handle comma-separated values + tools.flatMap((tool) => tool.split(',').map((t) => t.trim())), + }) + .option('auth-type', { + type: 'string', + choices: [AuthType.USE_OPENAI, AuthType.QWEN_OAUTH], + description: 'Authentication type', + }) .deprecateOption( 'show-memory-usage', 'Use the "ui.showMemoryUsage" setting in settings.json instead. This flag will be removed in a future version.', @@ -738,6 +768,7 @@ export async function loadCliConfig( settings, activeExtensions, extraExcludes.length > 0 ? extraExcludes : undefined, + argv.excludeTools, ); const blockedMcpServers: Array<{ name: string; extensionName: string }> = []; @@ -793,7 +824,7 @@ export async function loadCliConfig( debugMode, question, fullContext: argv.allFiles || false, - coreTools: settings.tools?.core || undefined, + coreTools: argv.coreTools || settings.tools?.core || undefined, allowedTools: argv.allowedTools || settings.tools?.allowed || undefined, excludeTools, toolDiscoveryCommand: settings.tools?.discoveryCommand, @@ -826,13 +857,16 @@ export async function loadCliConfig( model: resolvedModel, extensionContextFilePaths, sessionTokenLimit: settings.model?.sessionTokenLimit ?? -1, - maxSessionTurns: settings.model?.maxSessionTurns ?? -1, + maxSessionTurns: + argv.maxSessionTurns ?? settings.model?.maxSessionTurns ?? -1, experimentalZedIntegration: argv.experimentalAcp || false, listExtensions: argv.listExtensions || false, extensions: allExtensions, blockedMcpServers, noBrowser: !!process.env['NO_BROWSER'], - authType: settings.security?.auth?.selectedType, + authType: + (argv.authType as AuthType | undefined) || + settings.security?.auth?.selectedType, inputFormat, outputFormat, includePartialMessages, @@ -941,8 +975,10 @@ function mergeExcludeTools( settings: Settings, extensions: Extension[], extraExcludes?: string[] | undefined, + cliExcludeTools?: string[] | undefined, ): string[] { const allExcludeTools = new Set([ + ...(cliExcludeTools || []), ...(settings.tools?.exclude || []), ...(extraExcludes || []), ]); diff --git a/packages/sdk/typescript/src/query/createQuery.ts b/packages/sdk/typescript/src/query/createQuery.ts index 99613e7d..f9117d51 100644 --- a/packages/sdk/typescript/src/query/createQuery.ts +++ b/packages/sdk/typescript/src/query/createQuery.ts @@ -73,6 +73,10 @@ export function query({ abortController, debug: options.debug, stderr: options.stderr, + maxSessionTurns: options.maxSessionTurns, + coreTools: options.coreTools, + excludeTools: options.excludeTools, + authType: options.authType, }); // Build query options with abortController diff --git a/packages/sdk/typescript/src/transport/ProcessTransport.ts b/packages/sdk/typescript/src/transport/ProcessTransport.ts index bd3ba7d0..4dc7cc54 100644 --- a/packages/sdk/typescript/src/transport/ProcessTransport.ts +++ b/packages/sdk/typescript/src/transport/ProcessTransport.ts @@ -166,6 +166,22 @@ export class ProcessTransport implements Transport { } } + if (this.options.maxSessionTurns !== undefined) { + args.push('--max-session-turns', String(this.options.maxSessionTurns)); + } + + if (this.options.coreTools && this.options.coreTools.length > 0) { + args.push('--core-tools', this.options.coreTools.join(',')); + } + + if (this.options.excludeTools && this.options.excludeTools.length > 0) { + args.push('--exclude-tools', this.options.excludeTools.join(',')); + } + + if (this.options.authType) { + args.push('--auth-type', this.options.authType); + } + return args; } diff --git a/packages/sdk/typescript/src/types/config.ts b/packages/sdk/typescript/src/types/config.ts index 91a4780c..da1bfde1 100644 --- a/packages/sdk/typescript/src/types/config.ts +++ b/packages/sdk/typescript/src/types/config.ts @@ -77,7 +77,7 @@ export type CreateQueryOptions = { /** Permission mode ('default' | 'plan' | 'auto-edit' | 'yolo') */ permissionMode?: PermissionMode; /** Callback invoked before each tool execution */ - canUseTool?: PermissionCallback; + canUseTool?: CanUseTool; // Hook system /** Hook configuration for tool execution lifecycle */ @@ -107,6 +107,14 @@ export type CreateQueryOptions = { debug?: boolean; /** Callback for stderr output */ stderr?: (message: string) => void; + /** Maximum number of session turns */ + maxSessionTurns?: number; + /** Core tool paths */ + coreTools?: string[]; + /** Tools to exclude */ + excludeTools?: string[]; + /** Authentication type */ + authType?: string; }; /** @@ -131,4 +139,49 @@ export type TransportOptions = { debug?: boolean; /** Callback for stderr output */ stderr?: (message: string) => void; + /** Maximum number of session turns */ + maxSessionTurns?: number; + /** Core tool paths */ + coreTools?: string[]; + /** Tools to exclude */ + excludeTools?: string[]; + /** Authentication type */ + authType?: string; }; + +/** + * Tool input type + * TODO: align this type with actual tool inputs + */ +type ToolInput = Record; + +/** + * Permission callback function + * Called before each tool execution to determine if it should be allowed + * + * @param toolName - Name of the tool being executed + * @param input - Input parameters for the tool + * @param options - Options including abort signal + * @returns Promise with permission result + */ +type CanUseTool = ( + toolName: string, + input: ToolInput, + options: { + signal: AbortSignal; + }, +) => Promise; + +/** + * Result of permission check + */ +type PermissionResult = + | { + behavior: 'allow'; + updatedInput: ToolInput; + } + | { + behavior: 'deny'; + message: string; + interrupt?: boolean; + }; diff --git a/packages/sdk/typescript/src/types/queryOptionsSchema.ts b/packages/sdk/typescript/src/types/queryOptionsSchema.ts index de816186..c3444c19 100644 --- a/packages/sdk/typescript/src/types/queryOptionsSchema.ts +++ b/packages/sdk/typescript/src/types/queryOptionsSchema.ts @@ -48,6 +48,10 @@ export const QueryOptionsSchema = z (message: string) => void >((val) => typeof val === 'function', { message: 'stderr must be a function' }) .optional(), + maxSessionTurns: z.number().optional(), + coreTools: z.array(z.string()).optional(), + excludeTools: z.array(z.string()).optional(), + authType: z.enum(['openai', 'qwen-oauth']).optional(), }) .strict();