continuous session

This commit is contained in:
Your Name
2026-03-06 20:28:23 +00:00
parent 7ec477d40d
commit ca184a386e
35 changed files with 947 additions and 53 deletions

View File

@@ -777,6 +777,7 @@ export async function loadCliConfig(
skillsSupport: settings.skills?.enabled ?? true,
disabledSkills: settings.skills?.disabled,
experimentalJitContext: settings.experimental?.jitContext,
continuousSession: settings.experimental?.continuousSession,
modelSteering: settings.experimental?.modelSteering,
toolOutputMasking: settings.experimental?.toolOutputMasking,
noBrowser: !!process.env['NO_BROWSER'],

View File

@@ -1846,6 +1846,15 @@ const SETTINGS_SCHEMA = {
'Enable model steering (user hints) to guide the model during tool execution.',
showInDialog: true,
},
continuousSession: {
type: 'boolean',
label: 'Continuous Session',
category: 'Experimental',
requiresRestart: false,
default: false,
description: 'Enables tool and prompts for a continuous session effect.',
showInDialog: true,
},
directWebFetch: {
type: 'boolean',
label: 'Direct Web Fetch',

View File

@@ -0,0 +1,51 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, afterEach } from 'vitest';
import { AppRig } from '../test-utils/AppRig.js';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { PolicyDecision } from '@google/gemini-cli-core';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
describe('Continuous Session Integration', () => {
let rig: AppRig | undefined;
afterEach(async () => {
await rig?.unmount();
});
it('should handle checkpoint_state and manual compress tools correctly', async () => {
const fakeResponsesPath = path.join(
__dirname,
'../test-utils/fixtures/continuous_session.responses',
);
rig = new AppRig({
fakeResponsesPath,
});
await rig.initialize();
rig.render();
await rig.waitForIdle();
// Set policies to AUTO so it proceeds without asking user
rig.setToolPolicy('checkpoint_state', PolicyDecision.ALLOW);
rig.setToolPolicy('compress', PolicyDecision.ALLOW);
// Start the quest
await rig.type('Start the mission');
await rig.pressEnter();
// 1. Wait for CheckpointState tool call
await rig.waitForOutput('CheckpointState');
// 2. Wait for Compress tool call
await rig.waitForOutput('Compress');
// 3. Wait for final model response after compression
await rig.waitForOutput('Compression successful.');
});
});

View File

@@ -680,9 +680,10 @@ export class AppRig {
await this.waitUntil(
() => {
const frame = this.lastFrame;
return typeof pattern === 'string'
const matched = typeof pattern === 'string'
? frame.includes(pattern)
: pattern.test(frame);
return matched;
},
{
timeout,

View File

@@ -0,0 +1,5 @@
{"method":"generateContentStream","response":[{"candidates":[{"content":{"role":"model","parts":[{"text":"I will now checkpoint our progress."},{"functionCall":{"name":"checkpoint_state","args":{"summary":"GOAL: Implementation of session continuity.\nPROGRESS: Tools implemented.\nCONSTRAINT: Use high-fidelity summary."}}}]},"finishReason":"STOP"}]}]}
{"method":"generateContentStream","response":[{"candidates":[{"content":{"role":"model","parts":[{"text":"Checkpoint created. Now I will trigger compression to clear the context."},{"functionCall":{"name":"compress","args":{"force":true}}}]},"finishReason":"STOP"}]}]}
{"method":"generateContent","response":{"candidates":[{"content":{"role":"model","parts":[{"text":"<state_snapshot>\n<overall_goal>Implement session continuity</overall_goal>\n<active_constraints>Use high-fidelity summary</active_constraints>\n<key_knowledge>Tools implemented: checkpoint_state, compress</key_knowledge>\n<task_state>1. [DONE] Implement tools\n2. [IN PROGRESS] Verify continuity\n</task_state>\n</state_snapshot>"}]}}],"finishReason":"STOP"}}
{"method":"generateContent","response":{"candidates":[{"content":{"role":"model","parts":[{"text":"The <state_snapshot> is accurate and preserves all critical details."}]},"finishReason":"STOP"}]}}
{"method":"generateContentStream","response":[{"candidates":[{"content":{"role":"model","parts":[{"text":"Compression successful. I have clear context and I remember our mission."}]},"finishReason":"STOP"}]}]}

View File

@@ -1278,10 +1278,22 @@ export const useGeminiStream = (
case ServerGeminiEventType.ChatCompressed:
handleChatCompressionEvent(event.value, userMessageTimestamp);
break;
case ServerGeminiEventType.ToolCallConfirmation:
case ServerGeminiEventType.ToolCallResponse:
// do nothing
case ServerGeminiEventType.ToolCallResponse: {
const response = event.value;
if (response.resultDisplay) {
addItem(
{
type: MessageType.INFO,
text: typeof response.resultDisplay === 'string'
? response.resultDisplay
: 'Tool execution completed.',
},
userMessageTimestamp,
);
}
break;
}
case ServerGeminiEventType.ToolCallConfirmation:
case ServerGeminiEventType.MaxSessionTurns:
handleMaxSessionTurnsEvent();
break;