diff --git a/packages/cli/src/acp-integration/acpAgent.ts b/packages/cli/src/acp-integration/acpAgent.ts index a7ae2cf4c..8c8fa3a37 100644 --- a/packages/cli/src/acp-integration/acpAgent.ts +++ b/packages/cli/src/acp-integration/acpAgent.ts @@ -153,10 +153,14 @@ class GeminiAgent { const session = await this.createAndStoreSession(config); const availableModels = this.buildAvailableModels(config); + const modesData = this.buildModesData(config); + const configOptions = this.buildConfigOptions(config); return { sessionId: session.getId(), models: availableModels, + modes: modesData, + configOptions, }; } @@ -449,6 +453,70 @@ class GeminiAgent { }; } + private buildModesData(config: Config): acp.ModesData { + const currentApprovalMode = config.getApprovalMode(); + + const availableModes = APPROVAL_MODES.map((mode) => ({ + id: mode as ApprovalModeValue, + name: APPROVAL_MODE_INFO[mode].name, + description: APPROVAL_MODE_INFO[mode].description, + })); + + return { + currentModeId: currentApprovalMode as ApprovalModeValue, + availableModes, + }; + } + + private buildConfigOptions(config: Config): acp.ConfigOption[] { + const currentApprovalMode = config.getApprovalMode(); + const currentModelId = this.formatCurrentModelId( + config.getModel() || this.config.getModel() || '', + config.getAuthType(), + ); + + const modeOptions = APPROVAL_MODES.map((mode) => ({ + value: mode, + name: APPROVAL_MODE_INFO[mode].name, + description: APPROVAL_MODE_INFO[mode].description, + })); + + const allConfiguredModels = config.getAllConfiguredModels(); + const modelOptions = allConfiguredModels.map((model) => { + const effectiveModelId = + model.isRuntimeModel && model.runtimeSnapshotId + ? model.runtimeSnapshotId + : model.id; + + return { + value: formatAcpModelId(effectiveModelId, model.authType), + name: model.label, + description: model.description ?? '', + }; + }); + + return [ + { + id: 'mode', + name: 'Mode', + description: 'Session permission mode', + category: 'mode', + type: 'select', + currentValue: currentApprovalMode, + options: modeOptions, + }, + { + id: 'model', + name: 'Model', + description: 'AI model to use', + category: 'model', + type: 'select', + currentValue: currentModelId, + options: modelOptions, + }, + ]; + } + private formatCurrentModelId( baseModelId: string, authType?: AuthType, diff --git a/packages/cli/src/acp-integration/schema.ts b/packages/cli/src/acp-integration/schema.ts index 952ad0bd5..258dd28ce 100644 --- a/packages/cli/src/acp-integration/schema.ts +++ b/packages/cli/src/acp-integration/schema.ts @@ -59,7 +59,7 @@ export type CancelNotification = z.infer; export type AuthenticateRequest = z.infer; -export type NewSessionResponse = z.infer; +// Note: NewSessionResponse type is defined later after newSessionResponseSchema export type LoadSessionResponse = z.infer; @@ -285,10 +285,7 @@ export const sessionModelStateSchema = z.object({ currentModelId: modelIdSchema, }); -export const newSessionResponseSchema = z.object({ - sessionId: z.string(), - models: sessionModelStateSchema, -}); +// Note: newSessionResponseSchema is defined later in the file after modesDataSchema export const loadSessionResponseSchema = z.null(); @@ -451,6 +448,34 @@ export const modesDataSchema = z.object({ availableModes: z.array(modeInfoSchema), }); +export const configOptionSchema = z.object({ + id: z.string(), + name: z.string(), + description: z.string(), + category: z.string(), + type: z.string(), + currentValue: z.string(), + options: z.array( + z.object({ + value: z.string(), + name: z.string(), + description: z.string(), + }), + ), +}); + +export type ConfigOption = z.infer; + +// newSessionResponseSchema includes modes and configOptions for ACP/Zed integration +export const newSessionResponseSchema = z.object({ + sessionId: z.string(), + models: sessionModelStateSchema, + modes: modesDataSchema, + configOptions: z.array(configOptionSchema), +}); + +export type NewSessionResponse = z.infer; + export const agentInfoSchema = z.object({ name: z.string(), title: z.string(),