mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-20 11:00:40 -07:00
feat(sdk): initial package bootstrap for SDK (#18861)
This commit is contained in:
130
packages/sdk/src/agent.ts
Normal file
130
packages/sdk/src/agent.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
Config,
|
||||
type ConfigParameters,
|
||||
PREVIEW_GEMINI_MODEL_AUTO,
|
||||
GeminiEventType,
|
||||
type ToolCallRequestInfo,
|
||||
type ServerGeminiStreamEvent,
|
||||
type GeminiClient,
|
||||
scheduleAgentTools,
|
||||
getAuthTypeFromEnv,
|
||||
AuthType,
|
||||
} from '@google/gemini-cli-core';
|
||||
|
||||
import { type Tool, SdkTool, type z } from './tool.js';
|
||||
|
||||
export interface GeminiCliAgentOptions {
|
||||
instructions: string;
|
||||
tools?: Array<Tool<z.ZodType>>;
|
||||
model?: string;
|
||||
cwd?: string;
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
export class GeminiCliAgent {
|
||||
private readonly config: Config;
|
||||
private readonly tools: Array<Tool<z.ZodType>>;
|
||||
|
||||
constructor(options: GeminiCliAgentOptions) {
|
||||
const cwd = options.cwd || process.cwd();
|
||||
this.tools = options.tools || [];
|
||||
|
||||
const configParams: ConfigParameters = {
|
||||
sessionId: `sdk-${Date.now()}`,
|
||||
targetDir: cwd,
|
||||
cwd,
|
||||
debugMode: options.debug ?? false,
|
||||
model: options.model || PREVIEW_GEMINI_MODEL_AUTO,
|
||||
userMemory: options.instructions,
|
||||
// Minimal config
|
||||
enableHooks: false,
|
||||
mcpEnabled: false,
|
||||
extensionsEnabled: false,
|
||||
};
|
||||
|
||||
this.config = new Config(configParams);
|
||||
}
|
||||
|
||||
async *sendStream(
|
||||
prompt: string,
|
||||
signal?: AbortSignal,
|
||||
): AsyncGenerator<ServerGeminiStreamEvent> {
|
||||
// Lazy initialization of auth and client
|
||||
if (!this.config.getContentGenerator()) {
|
||||
const authType = getAuthTypeFromEnv() || AuthType.COMPUTE_ADC;
|
||||
|
||||
await this.config.refreshAuth(authType);
|
||||
await this.config.initialize();
|
||||
|
||||
// Register tools now that registry exists
|
||||
const registry = this.config.getToolRegistry();
|
||||
const messageBus = this.config.getMessageBus();
|
||||
|
||||
for (const toolDef of this.tools) {
|
||||
const sdkTool = new SdkTool(toolDef, messageBus);
|
||||
registry.registerTool(sdkTool);
|
||||
}
|
||||
}
|
||||
|
||||
const client = this.config.getGeminiClient();
|
||||
|
||||
let request: Parameters<GeminiClient['sendMessageStream']>[0] = [
|
||||
{ text: prompt },
|
||||
];
|
||||
const abortSignal = signal ?? new AbortController().signal;
|
||||
const sessionId = this.config.getSessionId();
|
||||
|
||||
while (true) {
|
||||
// sendMessageStream returns AsyncGenerator<ServerGeminiStreamEvent, Turn>
|
||||
const stream = client.sendMessageStream(request, abortSignal, sessionId);
|
||||
|
||||
const toolCallsToSchedule: ToolCallRequestInfo[] = [];
|
||||
|
||||
for await (const event of stream) {
|
||||
yield event;
|
||||
if (event.type === GeminiEventType.ToolCallRequest) {
|
||||
const toolCall = event.value;
|
||||
let args = toolCall.args;
|
||||
if (typeof args === 'string') {
|
||||
args = JSON.parse(args);
|
||||
}
|
||||
toolCallsToSchedule.push({
|
||||
...toolCall,
|
||||
args,
|
||||
isClientInitiated: false,
|
||||
prompt_id: sessionId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (toolCallsToSchedule.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const completedCalls = await scheduleAgentTools(
|
||||
this.config,
|
||||
toolCallsToSchedule,
|
||||
{
|
||||
schedulerId: sessionId,
|
||||
toolRegistry: this.config.getToolRegistry(),
|
||||
signal: abortSignal,
|
||||
},
|
||||
);
|
||||
|
||||
const functionResponses = completedCalls.flatMap(
|
||||
(call) => call.response.responseParts,
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
request = functionResponses as unknown as Parameters<
|
||||
GeminiClient['sendMessageStream']
|
||||
>[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
8
packages/sdk/src/index.ts
Normal file
8
packages/sdk/src/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
export * from './agent.js';
|
||||
export * from './tool.js';
|
||||
113
packages/sdk/src/tool.ts
Normal file
113
packages/sdk/src/tool.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { z } from 'zod';
|
||||
import { zodToJsonSchema } from 'zod-to-json-schema';
|
||||
import {
|
||||
BaseDeclarativeTool,
|
||||
BaseToolInvocation,
|
||||
type ToolResult,
|
||||
type ToolInvocation,
|
||||
Kind,
|
||||
type MessageBus,
|
||||
} from '@google/gemini-cli-core';
|
||||
|
||||
export { z };
|
||||
|
||||
export interface ToolDefinition<T extends z.ZodType> {
|
||||
name: string;
|
||||
description: string;
|
||||
inputSchema: T;
|
||||
}
|
||||
|
||||
export interface Tool<T extends z.ZodType> extends ToolDefinition<T> {
|
||||
action: (params: z.infer<T>) => Promise<unknown>;
|
||||
}
|
||||
|
||||
class SdkToolInvocation<T extends z.ZodType> extends BaseToolInvocation<
|
||||
z.infer<T>,
|
||||
ToolResult
|
||||
> {
|
||||
constructor(
|
||||
params: z.infer<T>,
|
||||
messageBus: MessageBus,
|
||||
private readonly action: (params: z.infer<T>) => Promise<unknown>,
|
||||
toolName: string,
|
||||
) {
|
||||
super(params, messageBus, toolName);
|
||||
}
|
||||
|
||||
getDescription(): string {
|
||||
return `Executing ${this._toolName}...`;
|
||||
}
|
||||
|
||||
async execute(
|
||||
_signal: AbortSignal,
|
||||
_updateOutput?: (output: string) => void,
|
||||
): Promise<ToolResult> {
|
||||
try {
|
||||
const result = await this.action(this.params);
|
||||
const output =
|
||||
typeof result === 'string' ? result : JSON.stringify(result, null, 2);
|
||||
return {
|
||||
llmContent: output,
|
||||
returnDisplay: output,
|
||||
};
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
return {
|
||||
llmContent: `Error: ${errorMessage}`,
|
||||
returnDisplay: `Error: ${errorMessage}`,
|
||||
error: {
|
||||
message: errorMessage,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SdkTool<T extends z.ZodType> extends BaseDeclarativeTool<
|
||||
z.infer<T>,
|
||||
ToolResult
|
||||
> {
|
||||
constructor(
|
||||
private readonly definition: Tool<T>,
|
||||
messageBus: MessageBus,
|
||||
) {
|
||||
super(
|
||||
definition.name,
|
||||
definition.name,
|
||||
definition.description,
|
||||
Kind.Other,
|
||||
zodToJsonSchema(definition.inputSchema),
|
||||
messageBus,
|
||||
);
|
||||
}
|
||||
|
||||
protected createInvocation(
|
||||
params: z.infer<T>,
|
||||
messageBus: MessageBus,
|
||||
toolName?: string,
|
||||
): ToolInvocation<z.infer<T>, ToolResult> {
|
||||
return new SdkToolInvocation(
|
||||
params,
|
||||
messageBus,
|
||||
this.definition.action,
|
||||
toolName || this.name,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function tool<T extends z.ZodType>(
|
||||
definition: ToolDefinition<T>,
|
||||
action: (params: z.infer<T>) => Promise<unknown>,
|
||||
): Tool<T> {
|
||||
return {
|
||||
...definition,
|
||||
action,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user