mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
fix(gemini): wire --resume flag through to Gemini backend (#378)
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user