Simplify GeminiClient (#101)
Doing some more clean-up: * Remove confusing continue/break * Handle empty result * Rename the file just client.js
This commit is contained in:
parent
dd81be1b9b
commit
cacf0cc0ef
|
@ -21,7 +21,7 @@ import { getFolderStructure } from '../utils/getFolderStructure.js';
|
||||||
import { Turn, ServerTool, ServerGeminiStreamEvent } from './turn.js';
|
import { Turn, ServerTool, ServerGeminiStreamEvent } from './turn.js';
|
||||||
|
|
||||||
export class GeminiClient {
|
export class GeminiClient {
|
||||||
private ai: GoogleGenAI;
|
private client: GoogleGenAI;
|
||||||
private model: string;
|
private model: string;
|
||||||
private generateContentConfig: GenerateContentConfig = {
|
private generateContentConfig: GenerateContentConfig = {
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
|
@ -30,7 +30,7 @@ export class GeminiClient {
|
||||||
private readonly MAX_TURNS = 100;
|
private readonly MAX_TURNS = 100;
|
||||||
|
|
||||||
constructor(apiKey: string, model: string) {
|
constructor(apiKey: string, model: string) {
|
||||||
this.ai = new GoogleGenAI({ apiKey: apiKey });
|
this.client = new GoogleGenAI({ apiKey: apiKey });
|
||||||
this.model = model;
|
this.model = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,14 +56,9 @@ export class GeminiClient {
|
||||||
|
|
||||||
async startChat(toolDeclarations: FunctionDeclaration[]): Promise<Chat> {
|
async startChat(toolDeclarations: FunctionDeclaration[]): Promise<Chat> {
|
||||||
const envPart = await this.getEnvironment();
|
const envPart = await this.getEnvironment();
|
||||||
// const tools: Tool[] = toolDeclarations.map((declaration) => ({
|
|
||||||
// functionDeclarations: [declaration],
|
|
||||||
// }));
|
|
||||||
// merge all functions into a single tool, as seems to be required for gemini 2.5 series
|
|
||||||
// can test by asking "what tools do you have?", which lists single function unless merged
|
|
||||||
const tools: Tool[] = [{ functionDeclarations: toolDeclarations }];
|
const tools: Tool[] = [{ functionDeclarations: toolDeclarations }];
|
||||||
try {
|
try {
|
||||||
const chat = this.ai.chats.create({
|
return this.client.chats.create({
|
||||||
model: this.model,
|
model: this.model,
|
||||||
config: {
|
config: {
|
||||||
systemInstruction: CoreSystemPrompt,
|
systemInstruction: CoreSystemPrompt,
|
||||||
|
@ -81,7 +76,6 @@ export class GeminiClient {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
return chat;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error initializing Gemini chat session:', error);
|
console.error('Error initializing Gemini chat session:', error);
|
||||||
const message = error instanceof Error ? error.message : 'Unknown error.';
|
const message = error instanceof Error ? error.message : 'Unknown error.';
|
||||||
|
@ -111,14 +105,11 @@ export class GeminiClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
// What do we do when we have both function responses and confirmations?
|
// What do we do when we have both function responses and confirmations?
|
||||||
|
|
||||||
const fnResponses = turn.getFunctionResponses();
|
const fnResponses = turn.getFunctionResponses();
|
||||||
if (fnResponses.length > 0) {
|
if (fnResponses.length == 0) {
|
||||||
request = fnResponses;
|
break; // user's turn to respond
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
request = fnResponses;
|
||||||
}
|
}
|
||||||
if (turns >= this.MAX_TURNS) {
|
if (turns >= this.MAX_TURNS) {
|
||||||
console.warn(
|
console.warn(
|
||||||
|
@ -140,7 +131,7 @@ export class GeminiClient {
|
||||||
schema: SchemaUnion,
|
schema: SchemaUnion,
|
||||||
): Promise<Record<string, unknown>> {
|
): Promise<Record<string, unknown>> {
|
||||||
try {
|
try {
|
||||||
const result = await this.ai.models.generateContent({
|
const result = await this.client.models.generateContent({
|
||||||
model: this.model,
|
model: this.model,
|
||||||
config: {
|
config: {
|
||||||
...this.generateContentConfig,
|
...this.generateContentConfig,
|
||||||
|
@ -150,15 +141,13 @@ export class GeminiClient {
|
||||||
},
|
},
|
||||||
contents,
|
contents,
|
||||||
});
|
});
|
||||||
const responseText = result.text;
|
if (!result || !result.text) {
|
||||||
if (!responseText) {
|
|
||||||
throw new Error('API returned an empty response.');
|
throw new Error('API returned an empty response.');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const parsedJson = JSON.parse(responseText);
|
return JSON.parse(result.text);
|
||||||
return parsedJson;
|
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
console.error('Failed to parse JSON response:', responseText);
|
console.error('Failed to parse JSON response:', result.text);
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to parse API response as JSON: ${parseError instanceof Error ? parseError.message : String(parseError)}`,
|
`Failed to parse API response as JSON: ${parseError instanceof Error ? parseError.message : String(parseError)}`,
|
||||||
);
|
);
|
|
@ -8,7 +8,7 @@
|
||||||
export * from './config/config.js';
|
export * from './config/config.js';
|
||||||
|
|
||||||
// Export Core Logic
|
// Export Core Logic
|
||||||
export * from './core/gemini-client.js';
|
export * from './core/client.js';
|
||||||
export * from './core/prompts.js';
|
export * from './core/prompts.js';
|
||||||
export * from './core/turn.js';
|
export * from './core/turn.js';
|
||||||
// Potentially export types from turn.ts if needed externally
|
// Potentially export types from turn.ts if needed externally
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import { Content, SchemaUnion, Type } from '@google/genai';
|
import { Content, SchemaUnion, Type } from '@google/genai';
|
||||||
import { getErrorMessage, isNodeError } from '../utils/errors.js';
|
import { getErrorMessage, isNodeError } from '../utils/errors.js';
|
||||||
import { GeminiClient } from '../core/gemini-client.js';
|
import { GeminiClient } from '../core/client.js';
|
||||||
import { Config } from '../config/config.js';
|
import { Config } from '../config/config.js';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import { exec as _exec } from 'child_process';
|
import { exec as _exec } from 'child_process';
|
||||||
|
|
Loading…
Reference in New Issue