diff --git a/packages/cli/src/utils/errors.ts b/packages/cli/src/utils/errors.ts index 5e48abed99..774d9e994c 100644 --- a/packages/cli/src/utils/errors.ts +++ b/packages/cli/src/utils/errors.ts @@ -20,7 +20,6 @@ import { coreEvents, getErrorType, getErrorMessage, - getErrorType, } from '@google/gemini-cli-core'; import { runSyncCleanup } from './cleanup.js'; diff --git a/packages/core/src/agent/legacy-agent-session.test.ts b/packages/core/src/agent/legacy-agent-session.test.ts index 926e11d99c..e158a0b159 100644 --- a/packages/core/src/agent/legacy-agent-session.test.ts +++ b/packages/core/src/agent/legacy-agent-session.test.ts @@ -143,7 +143,7 @@ describe('LegacyAgentSession', () => { describe('send', () => { it('returns streamId', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -163,7 +163,7 @@ describe('LegacyAgentSession', () => { }); it('records the sent user message in the trajectory before send resolves', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -240,7 +240,7 @@ describe('LegacyAgentSession', () => { }); it('returns streamId before emitting agent_start', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -280,7 +280,7 @@ describe('LegacyAgentSession', () => { it('throws if send is called while a stream is active', async () => { let resolveHang: (() => void) | undefined; - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -308,7 +308,7 @@ describe('LegacyAgentSession', () => { }); it('creates a new streamId after the previous stream completes', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock @@ -370,7 +370,7 @@ describe('LegacyAgentSession', () => { describe('stream - basic flow', () => { it('emits agent_start, content messages, and agent_end', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -409,7 +409,7 @@ describe('LegacyAgentSession', () => { describe('stream - tool calls', () => { it('handles a tool call round-trip', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; // First turn: model requests a tool @@ -436,7 +436,7 @@ describe('LegacyAgentSession', () => { ]), ); - const scheduleMock = deps.scheduler!.schedule as ReturnType; + const scheduleMock = deps.scheduler.schedule as ReturnType; scheduleMock.mockResolvedValueOnce([ makeCompletedToolCall('call-1', 'read_file', 'file contents'), ]); @@ -469,7 +469,7 @@ describe('LegacyAgentSession', () => { }); it('handles tool errors and sends error message in content', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValueOnce( @@ -506,7 +506,7 @@ describe('LegacyAgentSession', () => { }, } as CompletedToolCall; - const scheduleMock = deps.scheduler!.schedule as ReturnType; + const scheduleMock = deps.scheduler.schedule as ReturnType; scheduleMock.mockResolvedValueOnce([errorToolCall]); const session = new LegacyAgentSession(deps); @@ -527,7 +527,7 @@ describe('LegacyAgentSession', () => { }); it('stops on STOP_EXECUTION tool error', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValueOnce( @@ -555,7 +555,7 @@ describe('LegacyAgentSession', () => { }, } as CompletedToolCall; - const scheduleMock = deps.scheduler!.schedule as ReturnType; + const scheduleMock = deps.scheduler.schedule as ReturnType; scheduleMock.mockResolvedValueOnce([stopToolCall]); const session = new LegacyAgentSession(deps); @@ -571,7 +571,7 @@ describe('LegacyAgentSession', () => { }); it('treats fatal tool errors as tool_response followed by agent_end failed', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValueOnce( @@ -599,7 +599,7 @@ describe('LegacyAgentSession', () => { }, } as CompletedToolCall; - const scheduleMock = deps.scheduler!.schedule as ReturnType; + const scheduleMock = deps.scheduler.schedule as ReturnType; scheduleMock.mockResolvedValueOnce([fatalToolCall]); const session = new LegacyAgentSession(deps); @@ -628,7 +628,7 @@ describe('LegacyAgentSession', () => { describe('stream - terminal events', () => { it('handles AgentExecutionStopped', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -652,7 +652,7 @@ describe('LegacyAgentSession', () => { }); it('handles AgentExecutionBlocked as non-terminal and continues the stream', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -699,7 +699,7 @@ describe('LegacyAgentSession', () => { }); it('handles Error events', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -723,7 +723,7 @@ describe('LegacyAgentSession', () => { }); it('handles LoopDetected as non-terminal warning event', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; // LoopDetected followed by more content — stream continues @@ -777,7 +777,7 @@ describe('LegacyAgentSession', () => { >; configMock.mockReturnValue(0); - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -803,7 +803,7 @@ describe('LegacyAgentSession', () => { }); it('treats GeminiClient MaxSessionTurns as a terminal max_turns stream end', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -832,7 +832,7 @@ describe('LegacyAgentSession', () => { describe('abort', () => { it('treats abort before the first model event as aborted without fatal error', async () => { let releaseAbort: (() => void) | undefined; - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -871,7 +871,7 @@ describe('LegacyAgentSession', () => { }); it('aborts the stream', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; // Stream that yields content then checks abort signal via a deferred @@ -914,7 +914,7 @@ describe('LegacyAgentSession', () => { it('treats abort during pending scheduler work as aborted without fatal error', async () => { let resolveSchedule: ((value: CompletedToolCall[]) => void) | undefined; - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -930,7 +930,7 @@ describe('LegacyAgentSession', () => { ]), ); - const scheduleMock = deps.scheduler!.schedule as ReturnType; + const scheduleMock = deps.scheduler.schedule as ReturnType; scheduleMock.mockReturnValue( new Promise((resolve) => { resolveSchedule = resolve; @@ -966,7 +966,7 @@ describe('LegacyAgentSession', () => { describe('events property', () => { it('accumulates all events', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -990,7 +990,7 @@ describe('LegacyAgentSession', () => { describe('subscription and stream scoping', () => { it('subscribe receives live events for the next stream', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -1021,7 +1021,7 @@ describe('LegacyAgentSession', () => { }); it('subscribe is live-only and does not replay old history when idle', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock @@ -1073,7 +1073,7 @@ describe('LegacyAgentSession', () => { }); it('streams only the requested streamId', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock @@ -1131,7 +1131,7 @@ describe('LegacyAgentSession', () => { }); it('resumes from eventId within the same stream only', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock @@ -1192,7 +1192,7 @@ describe('LegacyAgentSession', () => { describe('agent_end ordering', () => { it('agent_end is always the final event yielded', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -1214,7 +1214,7 @@ describe('LegacyAgentSession', () => { }); it('agent_end is final even after error events', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValue( @@ -1236,7 +1236,7 @@ describe('LegacyAgentSession', () => { describe('intermediate Finished events', () => { it('does NOT emit agent_end when tool calls are pending', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; // First turn: tool request + Finished (should NOT produce agent_end) @@ -1269,7 +1269,7 @@ describe('LegacyAgentSession', () => { ]), ); - const scheduleMock = deps.scheduler!.schedule as ReturnType; + const scheduleMock = deps.scheduler.schedule as ReturnType; scheduleMock.mockResolvedValueOnce([ makeCompletedToolCall('call-1', 'read_file', 'data'), ]); @@ -1285,7 +1285,7 @@ describe('LegacyAgentSession', () => { }); it('emits usage for intermediate Finished events', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockReturnValueOnce( @@ -1316,7 +1316,7 @@ describe('LegacyAgentSession', () => { ]), ); - const scheduleMock = deps.scheduler!.schedule as ReturnType; + const scheduleMock = deps.scheduler.schedule as ReturnType; scheduleMock.mockResolvedValueOnce([ makeCompletedToolCall('call-1', 'read_file', 'contents'), ]); @@ -1337,7 +1337,7 @@ describe('LegacyAgentSession', () => { describe('error handling in runLoop', () => { it('catches thrown errors and emits error + agent_end', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; sendMock.mockImplementation(() => { @@ -1363,7 +1363,7 @@ describe('LegacyAgentSession', () => { describe('_emitErrorAndAgentEnd metadata', () => { it('preserves exitCode and code in _meta for FatalError', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; // Simulate a FatalError being thrown @@ -1386,7 +1386,7 @@ describe('LegacyAgentSession', () => { }); it('preserves exitCode for non-FatalError errors that carry one', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; const exitCodeError = new Error('custom exit'); @@ -1406,7 +1406,7 @@ describe('LegacyAgentSession', () => { }); it('preserves code in _meta for errors with code property', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; const codedError = new Error('ENOENT'); @@ -1426,7 +1426,7 @@ describe('LegacyAgentSession', () => { }); it('preserves status in _meta for errors with status property', async () => { - const sendMock = deps.client!.sendMessageStream as ReturnType< + const sendMock = deps.client.sendMessageStream as ReturnType< typeof vi.fn >; const statusError = new Error('rate limited'); diff --git a/packages/core/src/agent/legacy-agent-session.ts b/packages/core/src/agent/legacy-agent-session.ts index e6a1c59631..fa1d652eb2 100644 --- a/packages/core/src/agent/legacy-agent-session.ts +++ b/packages/core/src/agent/legacy-agent-session.ts @@ -14,12 +14,10 @@ import type { Part } from '@google/genai'; import type { GeminiClient } from '../core/client.js'; import type { Config } from '../config/config.js'; import type { ToolCallRequestInfo } from '../scheduler/types.js'; -import { Scheduler } from '../scheduler/scheduler.js'; +import type { Scheduler } from '../scheduler/scheduler.js'; import { recordToolCallInteractions } from '../code_assist/telemetry.js'; import { ToolErrorType, isFatalToolError } from '../tools/tool-error.js'; import { debugLogger } from '../utils/debugLogger.js'; -import { MessageBusType } from '../confirmation-bus/types.js'; -import type { ToolCallsUpdateMessage } from '../confirmation-bus/types.js'; import { buildToolResponseData, contentPartsToGeminiParts, @@ -46,18 +44,15 @@ function isAbortLikeError(err: unknown): boolean { return err instanceof Error && err.name === 'AbortError'; } -import type { EditorType } from '../utils/editor.js'; - export interface LegacyAgentSessionDeps { + client: GeminiClient; + scheduler: Scheduler; config: Config; - client?: GeminiClient; - scheduler?: Scheduler; - promptId?: string; + promptId: string; streamId?: string; - getPreferredEditor?: () => EditorType | undefined; } -export class LegacyAgentProtocol implements AgentProtocol { +class LegacyAgentProtocol implements AgentProtocol { private _events: AgentEvent[] = []; private _subscribers = new Set<(event: AgentEvent) => void>(); private _translationState: TranslationState; @@ -74,16 +69,10 @@ export class LegacyAgentProtocol implements AgentProtocol { constructor(deps: LegacyAgentSessionDeps) { this._translationState = createTranslationState(deps.streamId); this._nextStreamIdOverride = deps.streamId; + this._client = deps.client; + this._scheduler = deps.scheduler; this._config = deps.config; - this._client = deps.client ?? deps.config.getGeminiClient(); - this._promptId = deps.promptId ?? deps.config.promptId ?? ''; - this._scheduler = - deps.scheduler ?? - new Scheduler({ - context: deps.config, - schedulerId: 'legacy-agent-scheduler', - getPreferredEditor: deps.getPreferredEditor ?? (() => undefined), - }); + this._promptId = deps.promptId; } get events(): readonly AgentEvent[] { @@ -174,223 +163,142 @@ export class LegacyAgentProtocol implements AgentProtocol { let turnCount = 0; const maxTurns = this._config.getMaxSessionTurns(); - const handleToolCallsUpdate = (event: ToolCallsUpdateMessage) => { - const toolUpdates: AgentEvent[] = []; - for (const tc of event.toolCalls) { - if (tc.status === 'awaiting_approval') { - this._emit([ - this._makeToolResponseEvent({ - requestId: tc.request.callId, - name: tc.request.name, - content: [ - { type: 'text', text: 'Tool approvals not yet implemented.' }, - ], - isError: true, - displayContent: [{ type: 'text', text: 'Approval required' }], - }), - this._makeErrorEvent({ - status: 'UNIMPLEMENTED', - message: - 'TODO: Tool approvals not yet implemented, please switch to YOLO mode to test.', - fatal: true, - }), - ]); - void this.abort(); - return; - } - - if (tc.status === 'executing') { - toolUpdates.push( - this._makeToolUpdateEvent({ - requestId: tc.request.callId, - displayContent: toolResultDisplayToContentParts(tc.liveOutput), - data: { - progressMessage: tc.progressMessage, - progress: tc.progress, - progressTotal: tc.progressTotal, - pid: tc.pid, - }, - _meta: { - description: tc.invocation.getDescription(), - }, - }), - ); - } + while (true) { + turnCount++; + if (maxTurns >= 0 && turnCount > maxTurns) { + this._finishStream('max_turns', { + code: 'MAX_TURNS_EXCEEDED', + maxTurns, + turnCount: turnCount - 1, + }); + return; } - this._emit(toolUpdates); - }; - this._config - .getMessageBus() - .subscribe(MessageBusType.TOOL_CALLS_UPDATE, handleToolCallsUpdate); + const toolCallRequests: ToolCallRequestInfo[] = []; + const responseStream = this._client.sendMessageStream( + currentParts, + this._abortController.signal, + this._promptId, + undefined, + false, + currentDisplayContent, + ); + currentDisplayContent = undefined; - try { - while (true) { - turnCount++; - if (maxTurns >= 0 && turnCount > maxTurns) { - this._finishStream('max_turns', { - code: 'MAX_TURNS_EXCEEDED', - maxTurns, - turnCount: turnCount - 1, - }); + for await (const event of responseStream) { + if (this._abortController.signal.aborted) { + this._finishStream('aborted'); return; } - const toolCallRequests: ToolCallRequestInfo[] = []; - const responseStream = this._client.sendMessageStream( - currentParts, - this._abortController.signal, - this._promptId, - undefined, - false, - currentDisplayContent, - ); - currentDisplayContent = undefined; + if (event.type === GeminiEventType.ToolCallRequest) { + toolCallRequests.push(event.value); + } - for await (const event of responseStream) { - if (this._abortController.signal.aborted) { - this._finishStream('aborted'); + this._emit(translateEvent(event, this._translationState)); + + switch (event.type) { + case GeminiEventType.Error: + case GeminiEventType.InvalidStream: + case GeminiEventType.ContextWindowWillOverflow: + this._finishStream('failed'); return; - } - - if (event.type === GeminiEventType.ToolCallRequest) { - toolCallRequests.push(event.value); - } - - const translatedEvents = translateEvent( - event, - this._translationState, - ); - - for (const ev of translatedEvents) { - if (ev.type === 'tool_request') { - const tool = this._config.getToolRegistry().getTool(ev.name); - const invocation = tool?.build(ev.args); - ev._meta = { - legacyState: { - displayName: tool?.displayName ?? ev.name, - description: - invocation?.getDescription() ?? tool?.description ?? '', - isOutputMarkdown: tool?.isOutputMarkdown ?? false, - kind: tool?.kind, - }, - }; + case GeminiEventType.Finished: + if (toolCallRequests.length === 0) { + this._finishStream(mapFinishReason(event.value.reason)); + return; } - } - - this._emit(translatedEvents); - - switch (event.type) { - case GeminiEventType.Error: - case GeminiEventType.InvalidStream: - case GeminiEventType.ContextWindowWillOverflow: - this._finishStream('failed'); - return; - case GeminiEventType.Finished: - if (toolCallRequests.length === 0) { - this._finishStream(mapFinishReason(event.value.reason)); - return; - } - break; - case GeminiEventType.AgentExecutionStopped: - case GeminiEventType.UserCancelled: - case GeminiEventType.MaxSessionTurns: - this._clearActiveStream(); - return; - default: - break; - } + break; + case GeminiEventType.AgentExecutionStopped: + case GeminiEventType.UserCancelled: + case GeminiEventType.MaxSessionTurns: + this._clearActiveStream(); + return; + default: + break; } - - if (this._abortController.signal.aborted) { - this._finishStream('aborted'); - return; - } - - if (toolCallRequests.length === 0) { - this._finishStream('completed'); - return; - } - - const completedToolCalls = await this._scheduler.schedule( - toolCallRequests, - this._abortController.signal, - ); - - if (this._abortController.signal.aborted) { - this._finishStream('aborted'); - return; - } - - const toolResponseParts: Part[] = []; - for (const tc of completedToolCalls) { - const response = tc.response; - const request = tc.request; - const content: ContentPart[] = response.error - ? [{ type: 'text', text: response.error.message }] - : geminiPartsToContentParts(response.responseParts); - const displayContent = toolResultDisplayToContentParts( - response.resultDisplay, - ); - const data = buildToolResponseData(response); - - this._emit([ - this._makeToolResponseEvent({ - requestId: request.callId, - name: request.name, - content, - isError: response.error !== undefined, - ...(displayContent ? { displayContent } : {}), - ...(data ? { data } : {}), - _meta: { - resultDisplay: response.resultDisplay, - outputFile: response.outputFile, - }, - }), - ]); - - if (response.responseParts) { - toolResponseParts.push(...response.responseParts); - } - } - - try { - const currentModel = - this._client.getCurrentSequenceModel() ?? this._config.getModel(); - this._client - .getChat() - .recordCompletedToolCalls(currentModel, completedToolCalls); - await recordToolCallInteractions(this._config, completedToolCalls); - } catch (error) { - debugLogger.error( - `Error recording completed tool call information: ${error}`, - ); - } - - const stopTool = completedToolCalls.find( - (tc) => - tc.response.errorType === ToolErrorType.STOP_EXECUTION && - tc.response.error !== undefined, - ); - if (stopTool) { - this._finishStream('completed'); - return; - } - - const fatalTool = completedToolCalls.find((tc) => - isFatalToolError(tc.response.errorType), - ); - if (fatalTool) { - this._finishStream('failed'); - return; - } - - currentParts = toolResponseParts; } - } finally { - this._config - .getMessageBus() - .unsubscribe(MessageBusType.TOOL_CALLS_UPDATE, handleToolCallsUpdate); + + if (this._abortController.signal.aborted) { + this._finishStream('aborted'); + return; + } + + if (toolCallRequests.length === 0) { + this._finishStream('completed'); + return; + } + + const completedToolCalls = await this._scheduler.schedule( + toolCallRequests, + this._abortController.signal, + ); + + if (this._abortController.signal.aborted) { + this._finishStream('aborted'); + return; + } + + const toolResponseParts: Part[] = []; + for (const tc of completedToolCalls) { + const response = tc.response; + const request = tc.request; + const content: ContentPart[] = response.error + ? [{ type: 'text', text: response.error.message }] + : geminiPartsToContentParts(response.responseParts); + const displayContent = toolResultDisplayToContentParts( + response.resultDisplay, + ); + const data = buildToolResponseData(response); + + this._emit([ + this._makeToolResponseEvent({ + requestId: request.callId, + name: request.name, + content, + isError: response.error !== undefined, + ...(displayContent ? { displayContent } : {}), + ...(data ? { data } : {}), + }), + ]); + + if (response.responseParts) { + toolResponseParts.push(...response.responseParts); + } + } + + try { + const currentModel = + this._client.getCurrentSequenceModel() ?? this._config.getModel(); + this._client + .getChat() + .recordCompletedToolCalls(currentModel, completedToolCalls); + await recordToolCallInteractions(this._config, completedToolCalls); + } catch (error) { + debugLogger.error( + `Error recording completed tool call information: ${error}`, + ); + } + + const stopTool = completedToolCalls.find( + (tc) => + tc.response.errorType === ToolErrorType.STOP_EXECUTION && + tc.response.error !== undefined, + ); + if (stopTool) { + this._finishStream('completed'); + return; + } + + const fatalTool = completedToolCalls.find((tc) => + isFatalToolError(tc.response.errorType), + ); + if (fatalTool) { + this._finishStream('failed'); + return; + } + + currentParts = toolResponseParts; } } @@ -526,20 +434,6 @@ export class LegacyAgentProtocol implements AgentProtocol { return event; } - private _makeToolUpdateEvent( - payload: Omit< - AgentEvent<'tool_update'>, - 'id' | 'timestamp' | 'streamId' | 'type' - >, - ): AgentEvent<'tool_update'> { - const event = { - ...this._nextEventFields(), - type: 'tool_update', - ...payload, - } satisfies AgentEvent<'tool_update'>; - return event; - } - private _makeAgentStartEvent(): AgentEvent<'agent_start'> { const event = { ...this._nextEventFields(), diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index ceb3e5004f..8fede6146b 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -681,18 +681,11 @@ export interface ConfigParameters { adminSkillsEnabled?: boolean; experimentalJitContext?: boolean; experimentalMemoryManager?: boolean; -<<<<<<< HEAD -<<<<<<< HEAD useAgentProtocol?: boolean; -======= experimentalAgentHistoryTruncation?: boolean; experimentalAgentHistoryTruncationThreshold?: number; experimentalAgentHistoryRetainedMessages?: number; experimentalAgentHistorySummarization?: boolean; ->>>>>>> 320c8aba4 (feat(core): Land `AgentHistoryProvider`. (#23978)) -======= - useAgentProtocol?: boolean; ->>>>>>> 792d1c88d (feat: add experimental useAgentProtocol flag) topicUpdateNarration?: boolean; toolOutputMasking?: Partial; disableLLMCorrection?: boolean; @@ -1135,10 +1128,7 @@ export class Config implements McpContext, AgentLoopContext { this.experimentalJitContext = params.experimentalJitContext ?? true; this.experimentalMemoryManager = params.experimentalMemoryManager ?? false; -<<<<<<< HEAD -<<<<<<< HEAD this.useAgentProtocol = params.useAgentProtocol ?? false; -======= this.experimentalAgentHistoryTruncation = params.experimentalAgentHistoryTruncation ?? false; this.experimentalAgentHistoryTruncationThreshold = @@ -1147,10 +1137,7 @@ export class Config implements McpContext, AgentLoopContext { params.experimentalAgentHistoryRetainedMessages ?? 15; this.experimentalAgentHistorySummarization = params.experimentalAgentHistorySummarization ?? false; ->>>>>>> 320c8aba4 (feat(core): Land `AgentHistoryProvider`. (#23978)) -======= this.useAgentProtocol = params.useAgentProtocol ?? false; ->>>>>>> 792d1c88d (feat: add experimental useAgentProtocol flag) this.topicUpdateNarration = params.topicUpdateNarration ?? false; this.modelSteering = params.modelSteering ?? false; this.injectionService = new InjectionService(() => @@ -2332,7 +2319,6 @@ export class Config implements McpContext, AgentLoopContext { } getExperimentalUseAgentProtocol(): boolean { -<<<<<<< HEAD return ( this.useAgentProtocol || process.env['GEMINI_CLI_USE_AGENT_PROTOCOL'] === 'true' @@ -2353,9 +2339,6 @@ export class Config implements McpContext, AgentLoopContext { isExperimentalAgentHistorySummarizationEnabled(): boolean { return this.experimentalAgentHistorySummarization; -======= - return this.useAgentProtocol; ->>>>>>> 792d1c88d (feat: add experimental useAgentProtocol flag) } isTopicUpdateNarrationEnabled(): boolean { @@ -3645,9 +3628,3 @@ export class Config implements McpContext, AgentLoopContext { } // Export model constants for use in CLI export { DEFAULT_GEMINI_FLASH_MODEL }; -er.stop(); - } - } -} -// Export model constants for use in CLI -export { DEFAULT_GEMINI_FLASH_MODEL };