mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-26 17:51:04 -07:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d564eb7ffa | |||
| 430a52fc27 | |||
| 72ec782fe0 | |||
| 9b40e96f80 | |||
| 8a00e41ba8 | |||
| 35905c29ab | |||
| 839c6da07c | |||
| 6c2f005428 | |||
| 05baea6627 | |||
| ab2f9bd9a7 | |||
| 9dfe9eeb89 | |||
| cd34c9666e | |||
| bb459defe9 | |||
| 1088e1febf | |||
| 6795567d28 | |||
| 7c7150f487 | |||
| 24a4a0da1e | |||
| f7b08330f7 | |||
| c3b5bcb84c | |||
| 6d8cee7620 | |||
| f34b146a05 | |||
| e02072abf8 | |||
| 52f2479007 | |||
| 3b0906f319 | |||
| 8e9961a791 | |||
| 6a80311a37 | |||
| 6fb7bcf868 | |||
| 56656dfbc9 | |||
| 93322430a0 | |||
| 25c5d44678 | |||
| 2dfe237738 | |||
| f77e4716fa | |||
| 3e0b8aa958 | |||
| b268e93a1d | |||
| 218adcd6c3 |
@@ -1605,6 +1605,12 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.adk.agentSessionInteractiveEnabled`** (boolean):
|
||||
- **Description:** Enable the agent session implementation for the interactive
|
||||
CLI.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.enableAgents`** (boolean):
|
||||
- **Description:** Enable local and remote subagents.
|
||||
- **Default:** `true`
|
||||
|
||||
@@ -1970,6 +1970,16 @@ const SETTINGS_SCHEMA = {
|
||||
description: 'Enable non-interactive agent sessions.',
|
||||
showInDialog: false,
|
||||
},
|
||||
agentSessionInteractiveEnabled: {
|
||||
type: 'boolean',
|
||||
label: 'Interactive Agent Session Enabled',
|
||||
category: 'Experimental',
|
||||
requiresRestart: true,
|
||||
default: false,
|
||||
description:
|
||||
'Enable the agent session implementation for the interactive CLI.',
|
||||
showInDialog: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
enableAgents: {
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
LegacyAgentSession,
|
||||
ToolErrorType,
|
||||
geminiPartsToContentParts,
|
||||
debugLogger,
|
||||
} from '@google/gemini-cli-core';
|
||||
|
||||
import type { Part } from '@google/genai';
|
||||
@@ -599,6 +600,7 @@ export async function runNonInteractive({
|
||||
// Explicitly ignore these non-interactive events
|
||||
break;
|
||||
default:
|
||||
debugLogger.error('Unknown agent event type:', event);
|
||||
event satisfies never;
|
||||
break;
|
||||
}
|
||||
|
||||
+1
-7
@@ -78,7 +78,7 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders header when scrolled
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders mixed tool calls including update_topic 1`] = `
|
||||
"
|
||||
Testing Topic: This is the description
|
||||
Testing Topic: This is the summary
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ read_file Read a file │
|
||||
@@ -142,12 +142,6 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders two tool groups where
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders update_topic tool call using TopicMessage > update_topic_tool 1`] = `
|
||||
"
|
||||
Testing Topic: This is the description
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders with limited terminal height 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool-with-result Tool with output │
|
||||
|
||||
@@ -432,6 +432,7 @@ function isStructuredError(error: unknown): error is StructuredError {
|
||||
return (
|
||||
typeof error === 'object' &&
|
||||
error !== null &&
|
||||
'status' in error &&
|
||||
'message' in error &&
|
||||
typeof error.message === 'string'
|
||||
);
|
||||
|
||||
@@ -17,6 +17,9 @@ import type {
|
||||
ToolCallRequestInfo,
|
||||
} from '../scheduler/types.js';
|
||||
import { CoreToolCallStatus } from '../scheduler/types.js';
|
||||
import type { GeminiClient } from '../core/client.js';
|
||||
import type { Scheduler } from '../scheduler/scheduler.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mock helpers
|
||||
@@ -24,7 +27,7 @@ import { CoreToolCallStatus } from '../scheduler/types.js';
|
||||
|
||||
function createMockDeps(
|
||||
overrides?: Partial<LegacyAgentSessionDeps>,
|
||||
): LegacyAgentSessionDeps {
|
||||
): Required<LegacyAgentSessionDeps> {
|
||||
const mockClient = {
|
||||
sendMessageStream: vi.fn(),
|
||||
getChat: vi.fn().mockReturnValue({
|
||||
@@ -40,18 +43,22 @@ function createMockDeps(
|
||||
const mockConfig = {
|
||||
getMaxSessionTurns: vi.fn().mockReturnValue(-1),
|
||||
getModel: vi.fn().mockReturnValue('gemini-2.5-pro'),
|
||||
getGeminiClient: vi.fn().mockReturnValue(mockClient),
|
||||
getMessageBus: vi.fn().mockImplementation(() => ({
|
||||
subscribe: vi.fn(),
|
||||
unsubscribe: vi.fn(),
|
||||
})),
|
||||
};
|
||||
|
||||
return {
|
||||
client: mockClient as unknown as LegacyAgentSessionDeps['client'],
|
||||
|
||||
scheduler: mockScheduler as unknown as LegacyAgentSessionDeps['scheduler'],
|
||||
|
||||
config: mockConfig as unknown as LegacyAgentSessionDeps['config'],
|
||||
client: mockClient as unknown as GeminiClient,
|
||||
scheduler: mockScheduler as unknown as Scheduler,
|
||||
config: mockConfig as unknown as Config,
|
||||
promptId: 'test-prompt',
|
||||
streamId: 'test-stream',
|
||||
getPreferredEditor: vi.fn().mockReturnValue(undefined),
|
||||
...overrides,
|
||||
};
|
||||
} as Required<LegacyAgentSessionDeps>;
|
||||
}
|
||||
|
||||
async function* makeStream(
|
||||
@@ -129,7 +136,7 @@ async function collectEvents(
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('LegacyAgentSession', () => {
|
||||
let deps: LegacyAgentSessionDeps;
|
||||
let deps: Required<LegacyAgentSessionDeps>;
|
||||
|
||||
beforeEach(() => {
|
||||
deps = createMockDeps();
|
||||
|
||||
@@ -14,10 +14,11 @@ 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 type { Scheduler } from '../scheduler/scheduler.js';
|
||||
import { 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 type { EditorType } from '../utils/editor.js';
|
||||
import {
|
||||
buildToolResponseData,
|
||||
contentPartsToGeminiParts,
|
||||
@@ -45,14 +46,15 @@ function isAbortLikeError(err: unknown): boolean {
|
||||
}
|
||||
|
||||
export interface LegacyAgentSessionDeps {
|
||||
client: GeminiClient;
|
||||
scheduler: Scheduler;
|
||||
config: Config;
|
||||
promptId: string;
|
||||
client?: GeminiClient;
|
||||
scheduler?: Scheduler;
|
||||
promptId?: string;
|
||||
streamId?: string;
|
||||
getPreferredEditor?: () => EditorType | undefined;
|
||||
}
|
||||
|
||||
class LegacyAgentProtocol implements AgentProtocol {
|
||||
export class LegacyAgentProtocol implements AgentProtocol {
|
||||
private _events: AgentEvent[] = [];
|
||||
private _subscribers = new Set<(event: AgentEvent) => void>();
|
||||
private _translationState: TranslationState;
|
||||
@@ -69,10 +71,16 @@ 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._promptId = deps.promptId;
|
||||
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),
|
||||
});
|
||||
}
|
||||
|
||||
get events(): readonly AgentEvent[] {
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import type { Kind } from '../tools/tools.js';
|
||||
|
||||
export type WithMeta = { _meta?: Record<string, unknown> };
|
||||
|
||||
export type Unsubscribe = () => void;
|
||||
@@ -180,6 +182,16 @@ export interface ToolRequest {
|
||||
name: string;
|
||||
/** The arguments for the tool. */
|
||||
args: Record<string, unknown>;
|
||||
/** UI specific metadata */
|
||||
_meta?: {
|
||||
legacyState?: {
|
||||
displayName?: string;
|
||||
isOutputMarkdown?: boolean;
|
||||
description?: string;
|
||||
kind?: Kind;
|
||||
};
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,6 +204,18 @@ export interface ToolUpdate {
|
||||
displayContent?: ContentPart[];
|
||||
content?: ContentPart[];
|
||||
data?: Record<string, unknown>;
|
||||
/** UI specific metadata */
|
||||
_meta?: {
|
||||
legacyState?: {
|
||||
status?: string;
|
||||
progressMessage?: string;
|
||||
progress?: number;
|
||||
progressTotal?: number;
|
||||
pid?: number;
|
||||
description?: string;
|
||||
};
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ToolResponse {
|
||||
@@ -205,6 +229,13 @@ export interface ToolResponse {
|
||||
data?: Record<string, unknown>;
|
||||
/** When true, the tool call encountered an error that will be sent to the model. */
|
||||
isError?: boolean;
|
||||
/** UI specific metadata */
|
||||
_meta?: {
|
||||
legacyState?: {
|
||||
outputFile?: string;
|
||||
};
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
export type ElicitationRequest = {
|
||||
|
||||
@@ -225,6 +225,7 @@ export interface GemmaModelRouterSettings {
|
||||
|
||||
export interface ADKSettings {
|
||||
agentSessionNoninteractiveEnabled?: boolean;
|
||||
agentSessionInteractiveEnabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ExtensionSetting {
|
||||
@@ -892,6 +893,7 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
|
||||
private readonly gemmaModelRouter: GemmaModelRouterSettings;
|
||||
private readonly agentSessionNoninteractiveEnabled: boolean;
|
||||
private readonly agentSessionInteractiveEnabled: boolean;
|
||||
|
||||
private readonly continueOnFailedApiCall: boolean;
|
||||
private readonly retryFetchErrors: boolean;
|
||||
@@ -1314,6 +1316,8 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
|
||||
this.agentSessionNoninteractiveEnabled =
|
||||
params.adk?.agentSessionNoninteractiveEnabled ?? false;
|
||||
this.agentSessionInteractiveEnabled =
|
||||
params.adk?.agentSessionInteractiveEnabled ?? false;
|
||||
this.retryFetchErrors = params.retryFetchErrors ?? true;
|
||||
this.maxAttempts = Math.min(
|
||||
params.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,
|
||||
@@ -3377,6 +3381,10 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
return this.agentSessionNoninteractiveEnabled;
|
||||
}
|
||||
|
||||
getAgentSessionInteractiveEnabled(): boolean {
|
||||
return this.agentSessionInteractiveEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get override settings for a specific agent.
|
||||
* Reads from agents.overrides.<agentName>.
|
||||
|
||||
@@ -2775,6 +2775,13 @@
|
||||
"markdownDescription": "Enable non-interactive agent sessions.\n\n- Category: `Experimental`\n- Requires restart: `yes`\n- Default: `false`",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"agentSessionInteractiveEnabled": {
|
||||
"title": "Interactive Agent Session Enabled",
|
||||
"description": "Enable the agent session implementation for the interactive CLI.",
|
||||
"markdownDescription": "Enable the agent session implementation for the interactive CLI.\n\n- Category: `Experimental`\n- Requires restart: `yes`\n- Default: `false`",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
||||
Reference in New Issue
Block a user