fix(gemini): wire --resume flag through to Gemini backend (#378)

This commit is contained in:
Junmo Kim
2026-03-31 10:46:21 +08:00
committed by GitHub
parent 1f67d36c06
commit 3a073dc4a9
5 changed files with 68 additions and 9 deletions
+7
View File
@@ -15,6 +15,7 @@ export const geminiCommand: CommandDefinition = {
startingMode?: 'local' | 'remote'
permissionMode?: GeminiPermissionMode
model?: string
resumeSessionId?: string
} = {}
for (let i = 0; i < commandArgs.length; i++) {
@@ -30,6 +31,12 @@ export const geminiCommand: CommandDefinition = {
}
} else if (arg === '--yolo') {
options.permissionMode = 'yolo'
} else if (arg === '--resume') {
const sessionId = commandArgs[++i]
if (!sessionId) {
throw new Error('Missing --resume value')
}
options.resumeSessionId = sessionId
} else if (arg === '--model') {
const model = commandArgs[++i]
if (!model) {
+31 -8
View File
@@ -54,7 +54,6 @@ class GeminiRemoteLauncher extends RemoteLauncherBase {
const backend = createGeminiBackend({
model: runtimeConfig.model,
token: runtimeConfig.token,
resumeSessionId: session.sessionId,
hookSettingsPath: this.hookSettingsPath,
cwd: session.path,
permissionMode: session.getPermissionMode() as string | undefined
@@ -69,10 +68,33 @@ class GeminiRemoteLauncher extends RemoteLauncherBase {
await backend.initialize();
const acpSessionId = await backend.newSession({
cwd: session.path,
mcpServers: toAcpMcpServers(mcpServers)
});
const resumeSessionId = session.sessionId;
const acpMcpServers = toAcpMcpServers(mcpServers);
let acpSessionId: string;
if (resumeSessionId) {
try {
acpSessionId = await backend.loadSession({
sessionId: resumeSessionId,
cwd: session.path,
mcpServers: acpMcpServers
});
} catch (error) {
logger.warn('[gemini-remote] resume failed, starting new session', error);
session.sendSessionEvent({
type: 'message',
message: 'Gemini resume failed; starting a new session.'
});
acpSessionId = await backend.newSession({
cwd: session.path,
mcpServers: acpMcpServers
});
}
} else {
acpSessionId = await backend.newSession({
cwd: session.path,
mcpServers: acpMcpServers
});
}
session.onSessionFound(acpSessionId);
this.permissionHandler = new GeminiPermissionHandler(
@@ -115,12 +137,13 @@ class GeminiRemoteLauncher extends RemoteLauncherBase {
this.handleAgentMessage(message);
});
} catch (error) {
logger.warn('[gemini-remote] prompt failed', error);
const errorMessage = error instanceof Error ? error.message : String(error);
logger.warn('[gemini-remote] prompt failed', { message: errorMessage });
session.sendSessionEvent({
type: 'message',
message: 'Gemini prompt failed. Check logs for details.'
message: `Gemini prompt failed: ${errorMessage}`
});
messageBuffer.addMessage('Gemini prompt failed', 'status');
messageBuffer.addMessage(`Gemini prompt failed: ${errorMessage}`, 'status');
} finally {
session.onThinkingChange(false);
await this.permissionHandler?.cancelAll('Prompt finished');
+6 -1
View File
@@ -19,6 +19,7 @@ interface GeminiLoopOptions {
model?: string;
hookSettingsPath?: string;
allowedTools?: string[];
resumeSessionId?: string;
onSessionReady?: (session: GeminiSession) => void;
}
@@ -31,7 +32,7 @@ export async function geminiLoop(opts: GeminiLoopOptions): Promise<void> {
api: opts.api,
client: opts.session,
path: opts.path,
sessionId: null,
sessionId: opts.resumeSessionId ?? null,
logPath,
messageQueue: opts.messageQueue,
onModeChange: opts.onModeChange,
@@ -41,6 +42,10 @@ export async function geminiLoop(opts: GeminiLoopOptions): Promise<void> {
permissionMode: opts.permissionMode ?? 'default'
});
if (opts.resumeSessionId) {
session.onSessionFound(opts.resumeSessionId);
}
await runLocalRemoteSession({
session,
startingMode: opts.startingMode,
+22
View File
@@ -106,4 +106,26 @@ describe('runGemini', () => {
expect(harness.bootstrapArgs[0]?.model).toBeUndefined();
expect(harness.geminiLoopArgs[0]?.model).toBe('gemini-2.5-pro');
});
it('passes resumeSessionId through to geminiLoop', async () => {
resolveGeminiRuntimeConfigMock.mockReturnValue({
model: 'gemini-2.5-pro',
modelSource: 'default'
});
await runGemini({ resumeSessionId: 'a6157ffa-f692-4b73-82d5-63d42177f4f9' });
expect(harness.geminiLoopArgs[0]?.resumeSessionId).toBe('a6157ffa-f692-4b73-82d5-63d42177f4f9');
});
it('does not set resumeSessionId when not provided', async () => {
resolveGeminiRuntimeConfigMock.mockReturnValue({
model: 'gemini-2.5-pro',
modelSource: 'default'
});
await runGemini({});
expect(harness.geminiLoopArgs[0]?.resumeSessionId).toBeUndefined();
});
});
+2
View File
@@ -21,6 +21,7 @@ export async function runGemini(opts: {
startingMode?: 'local' | 'remote';
permissionMode?: PermissionMode;
model?: string;
resumeSessionId?: string;
} = {}): Promise<void> {
const workingDirectory = getInvokedCwd();
const startedBy = opts.startedBy ?? 'terminal';
@@ -149,6 +150,7 @@ export async function runGemini(opts: {
permissionMode: currentPermissionMode,
model: resolvedModel,
hookSettingsPath,
resumeSessionId: opts.resumeSessionId,
onModeChange: createModeChangeHandler(session),
onSessionReady: (instance) => {
sessionWrapperRef.current = instance;