summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json58
-rw-r--r--packages/cli/src/config/config.ts1
-rw-r--r--packages/cli/src/config/settings.ts1
-rw-r--r--packages/cli/src/services/CommandService.test.ts1
-rw-r--r--packages/cli/src/services/CommandService.ts2
-rw-r--r--packages/cli/src/ui/App.test.tsx3
-rw-r--r--packages/cli/src/ui/commands/backgroundCommand.ts262
-rw-r--r--packages/core/src/background/backgroundAgent.ts126
-rw-r--r--packages/core/src/background/backgroundManager.ts40
-rw-r--r--packages/core/src/background/types.ts107
-rw-r--r--packages/core/src/config/config.ts16
-rw-r--r--packages/core/src/index.ts3
-rw-r--r--packages/core/src/tools/mcp-tool.ts4
-rw-r--r--packages/examples/background_agent/README.md16
-rw-r--r--packages/examples/background_agent/demo-background-agent.ts217
-rw-r--r--packages/examples/package.json17
16 files changed, 3 insertions, 871 deletions
diff --git a/package-lock.json b/package-lock.json
index 947eb6ab..d5d0e294 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -916,10 +916,6 @@
"resolved": "packages/core",
"link": true
},
- "node_modules/@google/gemini-cli-examples": {
- "resolved": "packages/examples",
- "link": true
- },
"node_modules/@google/genai": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.9.0.tgz",
@@ -5661,19 +5657,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/get-tsconfig": {
- "version": "4.10.1",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
- "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "resolve-pkg-maps": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
- }
- },
"node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@@ -9207,16 +9190,6 @@
"node": ">=4"
}
},
- "node_modules/resolve-pkg-maps": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
- "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
- }
- },
"node_modules/restore-cursor": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
@@ -10517,26 +10490,6 @@
"dev": true,
"license": "0BSD"
},
- "node_modules/tsx": {
- "version": "4.20.3",
- "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.3.tgz",
- "integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "esbuild": "~0.25.0",
- "get-tsconfig": "^4.7.5"
- },
- "bin": {
- "tsx": "dist/cli.mjs"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.3"
- }
- },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -11907,17 +11860,6 @@
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
- "packages/examples": {
- "name": "@google/gemini-cli-examples",
- "version": "0.1.0",
- "dependencies": {
- "@modelcontextprotocol/sdk": "1.15.1",
- "zod": "^3.23.8"
- },
- "devDependencies": {
- "tsx": "^4.16.2"
- }
- },
"packages/vscode-ide-companion": {
"name": "gemini-cli-vscode-ide-companion",
"version": "0.0.1",
diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts
index 84ca6815..2d33daa3 100644
--- a/packages/cli/src/config/config.ts
+++ b/packages/cli/src/config/config.ts
@@ -382,7 +382,6 @@ export async function loadCliConfig(
toolCallCommand: settings.toolCallCommand,
mcpServerCommand: settings.mcpServerCommand,
mcpServers,
- backgroundAgents: settings.backgroundAgents,
userMemory: memoryContent,
geminiMdFileCount: fileCount,
approvalMode: argv.yolo || false ? ApprovalMode.YOLO : ApprovalMode.DEFAULT,
diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts
index 2da2e592..604e89dc 100644
--- a/packages/cli/src/config/settings.ts
+++ b/packages/cli/src/config/settings.ts
@@ -64,7 +64,6 @@ export interface Settings {
toolCallCommand?: string;
mcpServerCommand?: string;
mcpServers?: Record<string, MCPServerConfig>;
- backgroundAgents?: Record<string, MCPServerConfig>;
allowMCPServers?: string[];
excludeMCPServers?: string[];
showMemoryUsage?: boolean;
diff --git a/packages/cli/src/services/CommandService.test.ts b/packages/cli/src/services/CommandService.test.ts
index 5945e3f6..d03bf988 100644
--- a/packages/cli/src/services/CommandService.test.ts
+++ b/packages/cli/src/services/CommandService.test.ts
@@ -96,7 +96,6 @@ describe('CommandService', () => {
mockConfig = {
getIdeMode: vi.fn(),
getCheckpointingEnabled: vi.fn(),
- getBackgroundAgentManager: vi.fn(),
} as unknown as Mocked<Config>;
vi.mocked(ideCommand).mockReturnValue(null);
vi.mocked(restoreCommand).mockReturnValue(null);
diff --git a/packages/cli/src/services/CommandService.ts b/packages/cli/src/services/CommandService.ts
index 9db4e9e6..def8cfcc 100644
--- a/packages/cli/src/services/CommandService.ts
+++ b/packages/cli/src/services/CommandService.ts
@@ -7,7 +7,6 @@
import { Config } from '@google/gemini-cli-core';
import { SlashCommand } from '../ui/commands/types.js';
import { memoryCommand } from '../ui/commands/memoryCommand.js';
-import { backgroundCommand } from '../ui/commands/backgroundCommand.js';
import { helpCommand } from '../ui/commands/helpCommand.js';
import { clearCommand } from '../ui/commands/clearCommand.js';
import { corgiCommand } from '../ui/commands/corgiCommand.js';
@@ -34,7 +33,6 @@ const loadBuiltInCommands = async (
const allCommands = [
aboutCommand,
authCommand,
- backgroundCommand(config),
bugCommand,
chatCommand,
clearCommand,
diff --git a/packages/cli/src/ui/App.test.tsx b/packages/cli/src/ui/App.test.tsx
index 24d30f74..e03c80ae 100644
--- a/packages/cli/src/ui/App.test.tsx
+++ b/packages/cli/src/ui/App.test.tsx
@@ -9,7 +9,6 @@ import { render } from 'ink-testing-library';
import { AppWrapper as App } from './App.js';
import {
Config as ServerConfig,
- BackgroundAgentManager,
MCPServerConfig,
ApprovalMode,
ToolRegistry,
@@ -52,7 +51,6 @@ interface MockServerConfig {
getSandbox: Mock<() => SandboxConfig | undefined>;
getTargetDir: Mock<() => string>;
getToolRegistry: Mock<() => ToolRegistry>; // Use imported ToolRegistry type
- getBackgroundAgentManager: Mock<() => BackgroundAgentManager>;
getDebugMode: Mock<() => boolean>;
getQuestion: Mock<() => string | undefined>;
getFullContext: Mock<() => boolean>;
@@ -119,7 +117,6 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
getSandbox: vi.fn(() => opts.sandbox),
getTargetDir: vi.fn(() => opts.targetDir || '/test/dir'),
getToolRegistry: vi.fn(() => ({}) as ToolRegistry), // Simple mock
- getBackgroundAgentManager: vi.fn(() => new BackgroundAgentManager([])),
getDebugMode: vi.fn(() => opts.debugMode || false),
getQuestion: vi.fn(() => opts.question),
getFullContext: vi.fn(() => opts.fullContext ?? false),
diff --git a/packages/cli/src/ui/commands/backgroundCommand.ts b/packages/cli/src/ui/commands/backgroundCommand.ts
deleted file mode 100644
index cbeb18df..00000000
--- a/packages/cli/src/ui/commands/backgroundCommand.ts
+++ /dev/null
@@ -1,262 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { SlashCommand, CommandContext } from './types.js';
-import {
- Config,
- BackgroundAgentMessage,
- partListUnionToString,
-} from '@google/gemini-cli-core';
-
-const MAX_STATUS_MESSAGE_LENGTH = 100;
-
-function toMessageString(message?: BackgroundAgentMessage): string {
- return partListUnionToString(message?.parts ?? []).trim();
-}
-
-function toOneliner(input: string, maxlength: number) {
- let output = input.replace(/\r?\n|\r/g, ' ');
- if (output.length > maxlength) {
- output = output.substring(0, maxlength) + '...';
- }
- return output;
-}
-
-function getActiveAgent(context: CommandContext) {
- const agent =
- context.services.config?.getBackgroundAgentManager()?.activeAgent;
- if (!agent) {
- throw Error('There is no active background agent.');
- }
- return agent;
-}
-
-function addClientHistory(context: CommandContext, text: string) {
- context.services.config!.getGeminiClient().addHistory({
- role: 'user',
- parts: [{ text }],
- });
-
- context.services.config!.getGeminiClient().addHistory({
- role: 'model',
- parts: [{ text: 'Got it.' }],
- });
-}
-
-const startSubcommand: SlashCommand = {
- name: 'start',
- description:
- 'Start a new task with the provided prompt. Usage: /bg start <prompt>',
- action: async (context, args) => {
- if (!args || args.trim() === '') {
- return {
- type: 'message',
- messageType: 'error',
- content: 'The `start` command requires a prompt.',
- };
- }
-
- const agent = getActiveAgent(context);
- const task = await agent.startTask(args);
-
- addClientHistory(
- context,
- `I started a background task with id '${task.id}' and prompt:\n${args}`,
- );
-
- return {
- type: 'message',
- messageType: 'info',
- content: `Started background task with id '${task.id}' and prompt:\n${args}`,
- };
- },
-};
-
-const stopSubcommand: SlashCommand = {
- name: 'stop',
- description: 'Stops a running task. Usage: /bg stop <task_id>',
- action: async (context, args) => {
- if (!args || args.trim() === '') {
- return {
- type: 'message',
- messageType: 'error',
- content: 'The `stop` command requires a task id.',
- };
- }
- const agent = getActiveAgent(context);
- await agent.cancelTask(args);
- addClientHistory(context, `I canceled the background task with id ${args}`);
- return {
- type: 'message',
- messageType: 'info',
- content: `Stopped background task with id ${args}.`,
- };
- },
-};
-
-const listSubcommand: SlashCommand = {
- name: 'list',
- description: 'List all tasks',
- action: async (context, args) => {
- if (args && args.trim() !== '') {
- return {
- type: 'message',
- messageType: 'error',
- content: 'The `list` command takes no arguments.',
- };
- }
-
- const agent = getActiveAgent(context);
- const tasks = await agent.listTasks();
- let content: string;
- if (tasks.length === 0) {
- content = 'No background tasks found.';
- } else {
- const taskList = tasks
- .map((task) => {
- const shortStatus = toOneliner(
- toMessageString(task.status.message),
- MAX_STATUS_MESSAGE_LENGTH,
- );
- return ` - ${task.id}: (${task.status.state}) ${shortStatus}`;
- })
- .join('\n');
- content = `Background tasks:\n${taskList}`;
- }
- return {
- type: 'message',
- messageType: 'info',
- content,
- };
- },
-};
-
-const getSubcommand: SlashCommand = {
- name: 'get',
- description: 'View a task. Usage: /bg get <task_id>',
- action: async (context, args) => {
- if (!args || args.trim() === '') {
- return {
- type: 'message',
- messageType: 'error',
- content: 'The `get` command requires a task id.',
- };
- }
- const agent = getActiveAgent(context);
- const task = await agent.getTask(args);
- const content = `Task Details for ${task.id}:
-Status: (${task.status.state}) ${toMessageString(task.status.message)}}`;
-
- return {
- type: 'message',
- messageType: 'info',
- content,
- };
- },
-};
-
-const logsSubcommand: SlashCommand = {
- name: 'logs',
- description: "View a task's recent logs. Usage: /bg log <task_id>",
- action: async (context, args) => {
- if (!args || args.trim() === '') {
- return {
- type: 'message',
- messageType: 'error',
- content: 'The `log` command requires a task id.',
- };
- }
- const agent = getActiveAgent(context);
- const task = await agent.getTask(args, 5);
- const contents = [
- `Task logs for ${task.id}. status: (${task.status.state})`,
- ];
- (task.history ?? []).forEach((message) => {
- contents.push(toMessageString(message));
- });
- return {
- type: 'message',
- messageType: 'info',
- content: contents.join('\n\n'),
- };
- },
-};
-
-const messageSubcommand: SlashCommand = {
- name: 'message',
- description:
- 'Send a message to a task. Usage: /bg message <task_id> <message>',
- action: async (context, args) => {
- if (!args || args.trim() === '' || !args.trim().includes(' ')) {
- return {
- type: 'message',
- messageType: 'error',
- content: 'The `message` command requires a task id and a message.',
- };
- }
-
- const firstSpaceIndex = args.indexOf(' ');
- const id = args.substring(0, firstSpaceIndex);
- const message = args.substring(firstSpaceIndex + 1);
-
- const agent = getActiveAgent(context);
- await agent.messageTask(id, message);
- addClientHistory(
- context,
- `I sent a message to the background task with id '${id}':\n${message}`,
- );
-
- return {
- type: 'message',
- messageType: 'info',
- content: `Sent a message to the background task with id '${id}':\n${message}`,
- };
- },
-};
-
-const deleteSubcommand: SlashCommand = {
- name: 'delete',
- description: 'Deletes a task. Usage: /bg delete <task_id>',
- action: async (context, args) => {
- if (!args) {
- return {
- type: 'message',
- messageType: 'error',
- content: 'The `delete` command requires a task id.',
- };
- }
- const agent = getActiveAgent(context);
- await agent.deleteTask(args);
- addClientHistory(context, `I deleted the background task with id ${args}`);
- return {
- type: 'message',
- messageType: 'info',
- content: `Task ${args} deleted.`,
- };
- },
-};
-
-export const backgroundCommand = (
- config: Config | null,
-): SlashCommand | null => {
- if (!config?.getBackgroundAgentManager()?.activeAgent) {
- return null;
- }
- return {
- name: 'background',
- altName: 'bg',
- description: "Commands for managing the background agent's tasks",
- subCommands: [
- startSubcommand,
- stopSubcommand,
- listSubcommand,
- getSubcommand,
- logsSubcommand,
- messageSubcommand,
- deleteSubcommand,
- ],
- };
-};
diff --git a/packages/core/src/background/backgroundAgent.ts b/packages/core/src/background/backgroundAgent.ts
deleted file mode 100644
index 008010cd..00000000
--- a/packages/core/src/background/backgroundAgent.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { MCPServerConfig } from '../config/config.js';
-import { connectToMcpServer, discoverTools } from '../tools/mcp-client.js';
-import { DiscoveredMCPTool } from '../tools/mcp-tool.js';
-import {
- BackgroundAgentTasksResponseSchema,
- BackgroundAgentTaskResponseSchema,
- BackgroundAgentTask,
-} from './types.js';
-
-export async function loadBackgroundAgent(
- name: string,
- config: MCPServerConfig,
- debugMode: boolean,
-): Promise<BackgroundAgent> {
- const server = await connectToMcpServer(name, config, debugMode);
- try {
- const tools = await discoverTools(name, config, server);
- return new BackgroundAgent(name, tools);
- } catch (error) {
- await server.close();
- throw error;
- }
-}
-
-export class BackgroundAgent {
- readonly startTaskTool: DiscoveredMCPTool;
- readonly getTaskTool: DiscoveredMCPTool;
- readonly listTasksTool: DiscoveredMCPTool;
- readonly messageTaskTool: DiscoveredMCPTool;
- readonly deleteTaskTool: DiscoveredMCPTool;
- readonly cancelTaskTool: DiscoveredMCPTool;
-
- constructor(
- readonly serverName: string,
- tools: DiscoveredMCPTool[],
- ) {
- const getToolOrFail = (name: string): DiscoveredMCPTool => {
- for (const tool of tools) {
- if (tool.serverToolName === name) {
- return tool;
- }
- }
- throw new Error(`missing expected tool: ${name}`);
- };
-
- this.startTaskTool = getToolOrFail('startTask');
- this.getTaskTool = getToolOrFail('getTask');
- this.listTasksTool = getToolOrFail('listTasks');
- this.messageTaskTool = getToolOrFail('messageTask');
- this.deleteTaskTool = getToolOrFail('deleteTask');
- this.cancelTaskTool = getToolOrFail('cancelTask');
- }
-
- async startTask(prompt: string): Promise<BackgroundAgentTask> {
- const resp = await this.callTool(this.startTaskTool, {
- prompt: {
- role: 'user',
- parts: [{ text: prompt }],
- },
- });
- const taskResp = await BackgroundAgentTaskResponseSchema.parseAsync(resp);
- return taskResp.structuredContent;
- }
-
- async getTask(
- id: string,
- historyLength?: number,
- ): Promise<BackgroundAgentTask> {
- const resp = await this.callTool(this.getTaskTool, {
- id,
- historyLength,
- });
- const taskResp = await BackgroundAgentTaskResponseSchema.parseAsync(resp);
- return taskResp.structuredContent;
- }
-
- async listTasks(): Promise<BackgroundAgentTask[]> {
- const resp = await this.callTool(this.listTasksTool, {});
- const tasksResp = await BackgroundAgentTasksResponseSchema.parseAsync(resp);
- return tasksResp.structuredContent;
- }
-
- async messageTask(id: string, message: string) {
- await this.callTool(this.messageTaskTool, {
- id,
- message: {
- role: 'user',
- parts: [{ text: message }],
- },
- });
- }
-
- async deleteTask(id: string) {
- await this.callTool(this.deleteTaskTool, { id });
- }
-
- async cancelTask(id: string) {
- await this.callTool(this.cancelTaskTool, { id });
- }
-
- private async callTool(
- tool: DiscoveredMCPTool,
- params: Record<string, unknown>,
- ): Promise<Record<string, unknown>> {
- const { llmContent: parts } = await tool.execute(params);
- if (
- !Array.isArray(parts) ||
- parts.length !== 1 ||
- typeof parts[0] !== 'object' ||
- parts[0]?.functionResponse?.response === undefined
- ) {
- throw new Error('Expected exactly one part with a functionResponse');
- }
- const resp = parts[0].functionResponse.response;
- if ('isError' in resp && resp.isError) {
- throw new Error(`Error calling ${tool.displayName}: ${resp}`);
- }
- return resp;
- }
-}
diff --git a/packages/core/src/background/backgroundManager.ts b/packages/core/src/background/backgroundManager.ts
deleted file mode 100644
index a3ec526c..00000000
--- a/packages/core/src/background/backgroundManager.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { MCPServerConfig } from '../config/config.js';
-import { BackgroundAgent, loadBackgroundAgent } from './backgroundAgent.js';
-
-export async function loadBackgroundAgentManager(
- backgroundAgentConfigs: Record<string, MCPServerConfig> | undefined,
- debugMode: boolean,
-): Promise<BackgroundAgentManager> {
- const agents = await Promise.all(
- Object.entries(backgroundAgentConfigs ?? {}).map(([name, config]) =>
- loadBackgroundAgent(name, config, debugMode).catch((error) => {
- console.error(`Error loading background agent '${name}': ${error}`);
- return null;
- }),
- ),
- ).then((agents) => agents.filter((agent) => agent !== null));
- return new BackgroundAgentManager(agents);
-}
-
-export class BackgroundAgentManager {
- // The active agent. May be empty if none are confgured.
- activeAgent?: BackgroundAgent;
-
- constructor(readonly backgroundAgents: BackgroundAgent[]) {
- if (backgroundAgents.length !== 0) {
- this.activeAgent = backgroundAgents[0];
- }
- }
-
- setActiveAgentByName(name: string) {
- this.activeAgent = this.backgroundAgents.find(
- (agent) => agent.serverName === name,
- );
- }
-}
diff --git a/packages/core/src/background/types.ts b/packages/core/src/background/types.ts
deleted file mode 100644
index 60927af6..00000000
--- a/packages/core/src/background/types.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { z } from 'zod';
-import { Outcome, Language, FunctionResponseScheduling } from '@google/genai';
-
-// Should conform to Part in @google/genai
-export const PartSchema = z.object({
- videoMetadata: z
- .object({
- fps: z.number().optional(),
- endOffset: z.string().optional(),
- startOffset: z.string().optional(),
- })
- .optional(),
- thought: z.boolean().optional(),
- inlineData: z
- .object({
- displayName: z.string().optional(),
- data: z.string(),
- mimeType: z.string(),
- })
- .optional(),
- fileData: z
- .object({
- displayName: z.string().optional(),
- fileUri: z.string(),
- mimeType: z.string(),
- })
- .optional(),
- thoughtSignature: z.string().optional(),
- codeExecutionResult: z
- .object({
- outcome: z.nativeEnum(Outcome).optional(),
- output: z.string().optional(),
- })
- .optional(),
- executableCode: z
- .object({
- code: z.string().optional(),
- language: z.nativeEnum(Language).optional(),
- })
- .optional(),
- functionCall: z
- .object({
- id: z.string().optional(),
- args: z.record(z.unknown()).optional(),
- name: z.string(),
- })
- .optional(),
- functionResponse: z
- .object({
- willContinue: z.boolean().optional(),
- scheduling: z.nativeEnum(FunctionResponseScheduling).optional(),
- id: z.string().optional(),
- name: z.string(),
- response: z.record(z.unknown()).optional(),
- })
- .optional(),
- text: z.string().optional(),
-});
-
-export const BackgroundAgentMessageSchema = z.object({
- role: z.enum(['user', 'agent']).describe('The role of the sender.'),
- parts: z.array(PartSchema).describe('The parts of the message.'),
-});
-
-export const BackgroundAgentTaskStatusSchema = z.object({
- state: z.enum([
- 'submitted',
- 'working',
- 'input-required',
- 'completed',
- 'failed',
- ]),
- message: BackgroundAgentMessageSchema.describe(
- 'Message describing the state of the task.',
- ).optional(),
-});
-
-export const BackgroundAgentTaskSchema = z.object({
- id: z.string().describe('The id of the task. Must match `[a-zA-Z0-9.-_]+`'),
- status: BackgroundAgentTaskStatusSchema.describe(
- 'The current status of the task.',
- ),
- history: z
- .array(BackgroundAgentMessageSchema)
- .describe('Recent history of messages associated with this task')
- .optional(),
-});
-
-export type BackgroundAgentMessage = z.infer<
- typeof BackgroundAgentMessageSchema
->;
-
-export type BackgroundAgentTask = z.infer<typeof BackgroundAgentTaskSchema>;
-
-export const BackgroundAgentTaskResponseSchema = z.object({
- structuredContent: BackgroundAgentTaskSchema,
-});
-
-export const BackgroundAgentTasksResponseSchema = z.object({
- structuredContent: z.array(BackgroundAgentTaskSchema),
-});
diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts
index 5d02f269..f81b3e32 100644
--- a/packages/core/src/config/config.ts
+++ b/packages/core/src/config/config.ts
@@ -45,10 +45,6 @@ import {
DEFAULT_GEMINI_FLASH_MODEL,
} from './models.js';
import { ClearcutLogger } from '../telemetry/clearcut-logger/clearcut-logger.js';
-import {
- BackgroundAgentManager,
- loadBackgroundAgentManager,
-} from '../background/backgroundManager.js';
export enum ApprovalMode {
DEFAULT = 'default',
@@ -131,7 +127,6 @@ export interface ConfigParameters {
toolCallCommand?: string;
mcpServerCommand?: string;
mcpServers?: Record<string, MCPServerConfig>;
- backgroundAgents?: Record<string, MCPServerConfig>;
userMemory?: string;
geminiMdFileCount?: number;
approvalMode?: ApprovalMode;
@@ -163,7 +158,6 @@ export interface ConfigParameters {
export class Config {
private toolRegistry!: ToolRegistry;
- private backgroundAgentManager?: BackgroundAgentManager;
private readonly sessionId: string;
private contentGeneratorConfig!: ContentGeneratorConfig;
private readonly embeddingModel: string;
@@ -178,7 +172,6 @@ export class Config {
private readonly toolCallCommand: string | undefined;
private readonly mcpServerCommand: string | undefined;
private readonly mcpServers: Record<string, MCPServerConfig> | undefined;
- private readonly backgroundAgents?: Record<string, MCPServerConfig>;
private userMemory: string;
private geminiMdFileCount: number;
private approvalMode: ApprovalMode;
@@ -231,7 +224,6 @@ export class Config {
this.toolCallCommand = params.toolCallCommand;
this.mcpServerCommand = params.mcpServerCommand;
this.mcpServers = params.mcpServers;
- this.backgroundAgents = params.backgroundAgents;
this.userMemory = params.userMemory ?? '';
this.geminiMdFileCount = params.geminiMdFileCount ?? 0;
this.approvalMode = params.approvalMode ?? ApprovalMode.DEFAULT;
@@ -289,10 +281,6 @@ export class Config {
if (this.getCheckpointingEnabled()) {
await this.getGitService();
}
- this.backgroundAgentManager = await loadBackgroundAgentManager(
- this.backgroundAgents,
- this.debugMode,
- );
this.toolRegistry = await this.createToolRegistry();
}
@@ -418,10 +406,6 @@ export class Config {
return this.mcpServers;
}
- getBackgroundAgentManager(): BackgroundAgentManager | undefined {
- return this.backgroundAgentManager;
- }
-
getUserMemory(): string {
return this.userMemory;
}
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index a3d77ddc..24d8bdb2 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -24,9 +24,6 @@ export * from './code_assist/oauth2.js';
export * from './code_assist/server.js';
export * from './code_assist/types.js';
-export * from './background/types.js';
-export * from './background/backgroundManager.js';
-
// Export utilities
export * from './utils/paths.js';
export * from './utils/schemaValidator.js';
diff --git a/packages/core/src/tools/mcp-tool.ts b/packages/core/src/tools/mcp-tool.ts
index 2cb124ed..9916d7f9 100644
--- a/packages/core/src/tools/mcp-tool.ts
+++ b/packages/core/src/tools/mcp-tool.ts
@@ -113,7 +113,9 @@ export class DiscoveredMCPTool extends BaseTool<ToolParams, ToolResult> {
args: params,
},
];
- const responseParts = await this.mcpTool.callTool(functionCalls);
+
+ const responseParts: Part[] = await this.mcpTool.callTool(functionCalls);
+
return {
llmContent: responseParts,
returnDisplay: getStringifiedResultForDisplay(responseParts),
diff --git a/packages/examples/background_agent/README.md b/packages/examples/background_agent/README.md
deleted file mode 100644
index 0e5fd6dc..00000000
--- a/packages/examples/background_agent/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Demo Background Agent
-
-A pretend background agent that does not actually process tasks in the background. Configure in your settings.json with:
-
-```javascript
- "backgroundAgents": {
- "demo-background-agent": {
- "command": "npm",
- "args": [
- "run",
- "start:demo-background-agent",
- "--workspace=@google/gemini-cli-examples"
- ]
- }
- },
-```
diff --git a/packages/examples/background_agent/demo-background-agent.ts b/packages/examples/background_agent/demo-background-agent.ts
deleted file mode 100644
index 9ac568f4..00000000
--- a/packages/examples/background_agent/demo-background-agent.ts
+++ /dev/null
@@ -1,217 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
-import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
-import { z } from 'zod';
-
-const BackgroundAgentMessageSchema = z.object({
- role: z.enum(['user', 'agent']),
- parts: z.array(z.any()),
-});
-
-const BackgroundAgentTaskStatusSchema = z.object({
- state: z.enum([
- 'submitted',
- 'working',
- 'input-required',
- 'completed',
- 'canceled',
- 'failed',
- ]),
- message: BackgroundAgentMessageSchema.optional(),
-});
-
-const BackgroundAgentTaskSchema = z.object({
- id: z.string(),
- status: BackgroundAgentTaskStatusSchema,
- history: z.array(BackgroundAgentMessageSchema).optional(),
-});
-type BackgroundAgentTask = z.infer<typeof BackgroundAgentTaskSchema>;
-
-const server = new McpServer({
- name: 'demo-background-agent',
- version: '1.0.0',
-});
-
-const idToTask = new Map<string, BackgroundAgentTask>();
-
-server.registerTool(
- 'startTask',
- {
- title: 'Start a new task',
- description: 'Launches a new task asynchronously.',
- inputSchema: { prompt: BackgroundAgentMessageSchema },
- outputSchema: BackgroundAgentTaskSchema.shape,
- },
- ({ prompt }) => {
- const task: BackgroundAgentTask = {
- id: crypto.randomUUID(),
- status: {
- state: 'submitted',
- message: prompt,
- },
- history: [],
- };
-
- idToTask.set(task.id, task);
-
- return {
- content: [],
- structuredContent: task,
- };
- },
-);
-
-server.registerTool(
- 'getTask',
- {
- title: 'Get a task',
- inputSchema: { id: z.string() },
- outputSchema: BackgroundAgentTaskSchema.shape,
- },
- ({ id }) => {
- const task = idToTask.get(id);
- if (!task) {
- return {
- isError: true,
- content: [
- {
- type: 'text',
- text: 'No such task',
- },
- ],
- };
- }
-
- return {
- content: [],
- structuredContent: task,
- };
- },
-);
-
-server.registerTool(
- 'listTasks',
- {
- title: 'Lists tasks',
- outputSchema: {
- tasks: z.array(BackgroundAgentTaskSchema),
- },
- },
- () => {
- const out = {
- tasks: Array.from(idToTask.values()),
- };
- return {
- content: [],
- structuredContent: out,
- };
- },
-);
-
-server.registerTool(
- 'messageTask',
- {
- title: 'Send a message to a task',
- inputSchema: {
- id: z.string(),
- message: BackgroundAgentMessageSchema,
- },
- },
- ({ id, message }) => {
- const task = idToTask.get(id);
- if (!task) {
- return {
- isError: true,
- content: [
- {
- type: 'text',
- text: 'No such task',
- },
- ],
- };
- }
-
- task.history?.push(message);
- task.status.message = message;
-
- const statuses = BackgroundAgentTaskStatusSchema.shape.state.options;
- const randomStatus = statuses[Math.floor(Math.random() * statuses.length)];
- task.status.state = randomStatus;
-
- return {
- content: [],
- };
- },
-);
-
-server.registerTool(
- 'deleteTask',
- {
- title: 'Delete a task',
- inputSchema: { id: z.string() },
- },
- ({ id }) => {
- const task = idToTask.get(id);
- if (!task) {
- return {
- isError: true,
- content: [
- {
- type: 'text',
- text: 'No such task',
- },
- ],
- };
- }
- idToTask.delete(id);
-
- return {
- content: [
- {
- type: 'text',
- text: 'Task deleted',
- },
- ],
- };
- },
-);
-
-server.registerTool(
- 'cancelTask',
- {
- title: 'Cancels a task',
- inputSchema: { id: z.string() },
- },
- ({ id }) => {
- const task = idToTask.get(id);
- if (!task) {
- return {
- isError: true,
- content: [
- {
- type: 'text',
- text: 'No such task',
- },
- ],
- };
- }
- task.status.state = 'canceled';
-
- return {
- content: [
- {
- type: 'text',
- text: 'Task cancelled',
- },
- ],
- };
- },
-);
-
-const transport = new StdioServerTransport();
-await server.connect(transport);
diff --git a/packages/examples/package.json b/packages/examples/package.json
deleted file mode 100644
index 133d1b75..00000000
--- a/packages/examples/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "@google/gemini-cli-examples",
- "version": "0.1.0",
- "private": true,
- "type": "module",
- "scripts": {
- "start:demo-background-agent": "tsx background_agent/demo-background-agent.ts",
- "build": "echo 'nothing to build'"
- },
- "dependencies": {
- "@modelcontextprotocol/sdk": "1.15.1",
- "zod": "^3.23.8"
- },
- "devDependencies": {
- "tsx": "^4.16.2"
- }
-}