mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-08-05 06:31:44 -07:00
366036a197
Refactors the existing background skill extractor into a layered memory subsystem that GeminiClient can drive uniformly across interactive and non-interactive sessions. - Adds an internal `MemoryProvider` interface (not exported, not surfaced via extensions) as a typing seam between the orchestrator and its concrete implementation - Refactors the existing skill-extraction logic into `DefaultMemoryProvider`, the sole implementation of the seam - Introduces `MemoryService` as a thin orchestrator that owns a `DefaultMemoryProvider` and wraps every lifecycle call in try/catch so a buggy provider can't crash a turn - Moves MemoryService ownership into `GeminiClient` (private field exposed via optional methods) so non-interactive entry points share the same lifecycle as the interactive UI - Keeps builtin memory extraction asynchronous on startup to avoid blocking the first turn - Adds unit tests for MemoryService, DefaultMemoryProvider, and the GeminiClient integration The whole subsystem remains gated behind the existing `isMemoryManagerEnabled()` experimental flag.
86 lines
2.5 KiB
TypeScript
86 lines
2.5 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2026 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import type { Config } from '../config/config.js';
|
|
import { DefaultMemoryProvider } from './defaultMemoryProvider.js';
|
|
import type { MemoryProvider } from './memoryProvider.js';
|
|
import { debugLogger } from '../utils/debugLogger.js';
|
|
|
|
/**
|
|
* Orchestrates the memory subsystem for a single GeminiClient. The service
|
|
* owns a `DefaultMemoryProvider` and exposes a stable lifecycle surface
|
|
* (`onSessionStart`, `getSystemInstructions`, `getTurnContext`,
|
|
* `onTurnComplete`, `onSessionEnd`) so that GeminiClient can stay agnostic
|
|
* of the underlying implementation. Each lifecycle call is wrapped in a
|
|
* try/catch so a buggy provider can never crash a turn.
|
|
*
|
|
* The methods return `Promise`s for callsite consistency even though the
|
|
* current provider is synchronous; this keeps the boundary stable should
|
|
* the provider ever need to do asynchronous work.
|
|
*/
|
|
export class MemoryService {
|
|
private readonly provider: MemoryProvider = new DefaultMemoryProvider();
|
|
|
|
constructor(private readonly config: Config) {}
|
|
|
|
async onSessionStart(sessionId: string): Promise<void> {
|
|
try {
|
|
this.provider.onSessionStart(this.config, sessionId);
|
|
} catch (error) {
|
|
debugLogger.warn(
|
|
`[MemoryService] Provider "${this.provider.id}" threw during onSessionStart:`,
|
|
error,
|
|
);
|
|
}
|
|
}
|
|
|
|
async getSystemInstructions(): Promise<string> {
|
|
try {
|
|
return this.provider.getSystemInstructions();
|
|
} catch (error) {
|
|
debugLogger.warn(
|
|
`[MemoryService] Provider "${this.provider.id}" threw during getSystemInstructions:`,
|
|
error,
|
|
);
|
|
return '';
|
|
}
|
|
}
|
|
|
|
async getTurnContext(query: string): Promise<string> {
|
|
try {
|
|
return this.provider.getTurnContext(query);
|
|
} catch (error) {
|
|
debugLogger.warn(
|
|
`[MemoryService] Provider "${this.provider.id}" threw during getTurnContext:`,
|
|
error,
|
|
);
|
|
return '';
|
|
}
|
|
}
|
|
|
|
onTurnComplete(userMessage: string, assistantMessage: string): void {
|
|
try {
|
|
this.provider.onTurnComplete(userMessage, assistantMessage);
|
|
} catch (error) {
|
|
debugLogger.warn(
|
|
`[MemoryService] Provider "${this.provider.id}" threw during onTurnComplete:`,
|
|
error,
|
|
);
|
|
}
|
|
}
|
|
|
|
async onSessionEnd(): Promise<void> {
|
|
try {
|
|
this.provider.onSessionEnd();
|
|
} catch (error) {
|
|
debugLogger.warn(
|
|
`[MemoryService] Provider "${this.provider.id}" threw during onSessionEnd:`,
|
|
error,
|
|
);
|
|
}
|
|
}
|
|
}
|