mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-14 13:53:02 -07:00
feat(core): Fully migrate packages/core to AgentLoopContext. (#22115)
This commit is contained in:
@@ -36,12 +36,15 @@ describe('ConsecaSafetyChecker', () => {
|
||||
checker = ConsecaSafetyChecker.getInstance();
|
||||
|
||||
mockConfig = {
|
||||
get config() {
|
||||
return this;
|
||||
},
|
||||
enableConseca: true,
|
||||
getToolRegistry: vi.fn().mockReturnValue({
|
||||
getFunctionDeclarations: vi.fn().mockReturnValue([]),
|
||||
}),
|
||||
} as unknown as Config;
|
||||
checker.setConfig(mockConfig);
|
||||
checker.setContext(mockConfig);
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Default mock implementations
|
||||
@@ -72,9 +75,12 @@ describe('ConsecaSafetyChecker', () => {
|
||||
|
||||
it('should return ALLOW if enableConseca is false', async () => {
|
||||
const disabledConfig = {
|
||||
get config() {
|
||||
return this;
|
||||
},
|
||||
enableConseca: false,
|
||||
} as unknown as Config;
|
||||
checker.setConfig(disabledConfig);
|
||||
checker.setContext(disabledConfig);
|
||||
|
||||
const input: SafetyCheckInput = {
|
||||
protocolVersion: '1.0.0',
|
||||
|
||||
@@ -23,12 +23,13 @@ import type { Config } from '../../config/config.js';
|
||||
import { generatePolicy } from './policy-generator.js';
|
||||
import { enforcePolicy } from './policy-enforcer.js';
|
||||
import type { SecurityPolicy } from './types.js';
|
||||
import type { AgentLoopContext } from '../../config/agent-loop-context.js';
|
||||
|
||||
export class ConsecaSafetyChecker implements InProcessChecker {
|
||||
private static instance: ConsecaSafetyChecker | undefined;
|
||||
private currentPolicy: SecurityPolicy | null = null;
|
||||
private activeUserPrompt: string | null = null;
|
||||
private config: Config | null = null;
|
||||
private context: AgentLoopContext | null = null;
|
||||
|
||||
/**
|
||||
* Private constructor to enforce singleton pattern.
|
||||
@@ -50,8 +51,8 @@ export class ConsecaSafetyChecker implements InProcessChecker {
|
||||
ConsecaSafetyChecker.instance = undefined;
|
||||
}
|
||||
|
||||
setConfig(config: Config): void {
|
||||
this.config = config;
|
||||
setContext(context: AgentLoopContext): void {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
async check(input: SafetyCheckInput): Promise<SafetyCheckResult> {
|
||||
@@ -59,7 +60,7 @@ export class ConsecaSafetyChecker implements InProcessChecker {
|
||||
`[Conseca] check called. History is: ${JSON.stringify(input.context.history)}`,
|
||||
);
|
||||
|
||||
if (!this.config) {
|
||||
if (!this.context) {
|
||||
debugLogger.debug('[Conseca] check failed: Config not initialized');
|
||||
return {
|
||||
decision: SafetyCheckDecision.ALLOW,
|
||||
@@ -67,7 +68,7 @@ export class ConsecaSafetyChecker implements InProcessChecker {
|
||||
};
|
||||
}
|
||||
|
||||
if (!this.config.enableConseca) {
|
||||
if (!this.context.config.enableConseca) {
|
||||
debugLogger.debug('[Conseca] check skipped: Conseca is not enabled.');
|
||||
return {
|
||||
decision: SafetyCheckDecision.ALLOW,
|
||||
@@ -78,14 +79,14 @@ export class ConsecaSafetyChecker implements InProcessChecker {
|
||||
const userPrompt = this.extractUserPrompt(input);
|
||||
let trustedContent = '';
|
||||
|
||||
const toolRegistry = this.config.getToolRegistry();
|
||||
const toolRegistry = this.context.toolRegistry;
|
||||
if (toolRegistry) {
|
||||
const tools = toolRegistry.getFunctionDeclarations();
|
||||
trustedContent = JSON.stringify(tools, null, 2);
|
||||
}
|
||||
|
||||
if (userPrompt) {
|
||||
await this.getPolicy(userPrompt, trustedContent, this.config);
|
||||
await this.getPolicy(userPrompt, trustedContent, this.context.config);
|
||||
} else {
|
||||
debugLogger.debug(
|
||||
`[Conseca] Skipping policy generation because userPrompt is null`,
|
||||
@@ -104,12 +105,12 @@ export class ConsecaSafetyChecker implements InProcessChecker {
|
||||
result = await enforcePolicy(
|
||||
this.currentPolicy,
|
||||
input.toolCall,
|
||||
this.config,
|
||||
this.context.config,
|
||||
);
|
||||
}
|
||||
|
||||
logConsecaVerdict(
|
||||
this.config,
|
||||
this.context.config,
|
||||
new ConsecaVerdictEvent(
|
||||
userPrompt || '',
|
||||
JSON.stringify(this.currentPolicy || {}),
|
||||
|
||||
@@ -8,6 +8,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { ContextBuilder } from './context-builder.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import type { Content, FunctionCall } from '@google/genai';
|
||||
import type { GeminiClient } from '../core/client.js';
|
||||
|
||||
describe('ContextBuilder', () => {
|
||||
let contextBuilder: ContextBuilder;
|
||||
@@ -20,15 +21,20 @@ describe('ContextBuilder', () => {
|
||||
vi.spyOn(process, 'cwd').mockReturnValue(mockCwd);
|
||||
mockHistory = [];
|
||||
|
||||
const mockGeminiClient = {
|
||||
getHistory: vi.fn().mockImplementation(() => mockHistory),
|
||||
};
|
||||
mockConfig = {
|
||||
get config() {
|
||||
return this as unknown as Config;
|
||||
},
|
||||
geminiClient: mockGeminiClient as unknown as GeminiClient,
|
||||
getWorkspaceContext: vi.fn().mockReturnValue({
|
||||
getDirectories: vi.fn().mockReturnValue(mockWorkspaces),
|
||||
}),
|
||||
getQuestion: vi.fn().mockReturnValue('mock question'),
|
||||
getGeminiClient: vi.fn().mockReturnValue({
|
||||
getHistory: vi.fn().mockImplementation(() => mockHistory),
|
||||
}),
|
||||
};
|
||||
getGeminiClient: vi.fn().mockReturnValue(mockGeminiClient),
|
||||
} as Partial<Config>;
|
||||
contextBuilder = new ContextBuilder(mockConfig as unknown as Config);
|
||||
});
|
||||
|
||||
|
||||
@@ -5,21 +5,21 @@
|
||||
*/
|
||||
|
||||
import type { SafetyCheckInput, ConversationTurn } from './protocol.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import type { Content, FunctionCall } from '@google/genai';
|
||||
import type { AgentLoopContext } from '../config/agent-loop-context.js';
|
||||
|
||||
/**
|
||||
* Builds context objects for safety checkers, ensuring sensitive data is filtered.
|
||||
*/
|
||||
export class ContextBuilder {
|
||||
constructor(private readonly config: Config) {}
|
||||
constructor(private readonly context: AgentLoopContext) {}
|
||||
|
||||
/**
|
||||
* Builds the full context object with all available data.
|
||||
*/
|
||||
buildFullContext(): SafetyCheckInput['context'] {
|
||||
const clientHistory = this.config.getGeminiClient()?.getHistory() || [];
|
||||
const clientHistory = this.context.geminiClient?.getHistory() || [];
|
||||
const history = this.convertHistoryToTurns(clientHistory);
|
||||
|
||||
debugLogger.debug(
|
||||
@@ -29,7 +29,7 @@ export class ContextBuilder {
|
||||
// ContextBuilder's responsibility is to provide the *current* context.
|
||||
// If the conversation hasn't started (history is empty), we check if there's a pending question.
|
||||
// However, if the history is NOT empty, we trust it reflects the true state.
|
||||
const currentQuestion = this.config.getQuestion();
|
||||
const currentQuestion = this.context.config.getQuestion();
|
||||
if (currentQuestion && history.length === 0) {
|
||||
history.push({
|
||||
user: {
|
||||
@@ -43,7 +43,7 @@ export class ContextBuilder {
|
||||
environment: {
|
||||
cwd: process.cwd(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
workspaces: this.config
|
||||
workspaces: this.context.config
|
||||
.getWorkspaceContext()
|
||||
.getDirectories() as string[],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user