Skip to content

Commit 3c20383

Browse files
authored
fix: use proper ACP setSessionMode, restore multi-provider gateway env (#596)
### TL;DR Refactored agent connection handling and simplified session management in the Claude agent implementation.
1 parent 8a4324c commit 3c20383

4 files changed

Lines changed: 24 additions & 52 deletions

File tree

apps/twig/src/main/services/agent/service.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -641,10 +641,7 @@ export class AgentService extends TypedEventEmitter<AgentServiceEvents> {
641641
}
642642

643643
try {
644-
await session.clientSideConnection.extMethod("session/setMode", {
645-
sessionId,
646-
modeId,
647-
});
644+
await session.clientSideConnection.setSessionMode({ sessionId, modeId });
648645
log.info("Session mode updated", { sessionId, modeId });
649646
} catch (err) {
650647
log.error("Failed to set session mode", { sessionId, modeId, err });

packages/agent/src/adapters/base-acp-agent.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ export interface BaseSession {
2626

2727
export abstract class BaseAcpAgent implements Agent {
2828
abstract readonly adapterName: string;
29-
protected session: BaseSession | null = null;
30-
protected sessionId: string | null = null;
29+
protected session!: BaseSession;
30+
protected sessionId!: string;
3131
client: AgentSideConnection;
3232
protected logger: Logger;
3333
protected fileContentCache: { [key: string]: string } = {};
@@ -43,7 +43,7 @@ export abstract class BaseAcpAgent implements Agent {
4343
protected abstract interruptSession(): Promise<void>;
4444

4545
async cancel(params: CancelNotification): Promise<void> {
46-
if (this.sessionId !== params.sessionId || !this.session) {
46+
if (this.sessionId !== params.sessionId) {
4747
throw new Error("Session not found");
4848
}
4949
this.session.cancelled = true;
@@ -55,9 +55,6 @@ export abstract class BaseAcpAgent implements Agent {
5555
}
5656

5757
async closeSession(): Promise<void> {
58-
if (!this.session || !this.sessionId) {
59-
return;
60-
}
6158
try {
6259
await this.cancel({ sessionId: this.sessionId });
6360
this.session.abortController.abort();
@@ -68,19 +65,17 @@ export abstract class BaseAcpAgent implements Agent {
6865
error: err,
6966
});
7067
}
71-
this.session = null;
72-
this.sessionId = null;
7368
}
7469

7570
hasSession(sessionId: string): boolean {
76-
return this.sessionId === sessionId && this.session !== null;
71+
return this.sessionId === sessionId;
7772
}
7873

7974
appendNotification(
8075
sessionId: string,
8176
notification: SessionNotification,
8277
): void {
83-
if (this.sessionId === sessionId && this.session) {
78+
if (this.sessionId === sessionId) {
8479
this.session.notificationHistory.push(notification);
8580
}
8681
}

packages/agent/src/adapters/claude/claude-agent.ts

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ async function getAvailableSlashCommands(
146146

147147
export class ClaudeAcpAgent extends BaseAcpAgent {
148148
readonly adapterName = "claude";
149-
declare session: Session | null;
149+
declare session: Session;
150150
toolUseCache: ToolUseCache;
151151
backgroundTerminals: { [key: string]: BackgroundTerminal } = {};
152152
clientCapabilities?: ClientCapabilities;
@@ -239,13 +239,6 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
239239
}, 0);
240240
}
241241

242-
private getSession(): Session {
243-
if (!this.session) {
244-
throw new Error("Session not found");
245-
}
246-
return this.session;
247-
}
248-
249242
private registerPersistence(
250243
sessionId: string,
251244
meta: Record<string, unknown> | undefined,
@@ -420,11 +413,10 @@ Before pushing a "workspace-*" branch to origin, rename it to something descript
420413
}
421414

422415
async prompt(params: PromptRequest): Promise<PromptResponse> {
423-
const session = this.getSession();
424-
session.cancelled = false;
425-
session.interruptReason = undefined;
416+
this.session.cancelled = false;
417+
this.session.interruptReason = undefined;
426418

427-
const { query: q, input } = session;
419+
const { query: q, input } = this.session;
428420

429421
for (const chunk of params.prompt) {
430422
const userNotification = {
@@ -441,7 +433,7 @@ Before pushing a "workspace-*" branch to origin, rename it to something descript
441433
input.push(promptToClaude({ ...params, prompt: params.prompt }));
442434

443435
const context = {
444-
session,
436+
session: this.session,
445437
sessionId: params.sessionId,
446438
client: this.client,
447439
toolUseCache: this.toolUseCache,
@@ -452,11 +444,11 @@ Before pushing a "workspace-*" branch to origin, rename it to something descript
452444
while (true) {
453445
const { value: message, done } = await q.next();
454446
if (done || !message) {
455-
if (session.cancelled) {
447+
if (this.session.cancelled) {
456448
return {
457449
stopReason: "cancelled",
458-
_meta: session.interruptReason
459-
? { interruptReason: session.interruptReason }
450+
_meta: this.session.interruptReason
451+
? { interruptReason: this.session.interruptReason }
460452
: undefined,
461453
};
462454
}
@@ -506,30 +498,24 @@ Before pushing a "workspace-*" branch to origin, rename it to something descript
506498
}
507499

508500
protected async interruptSession(): Promise<void> {
509-
if (!this.session) {
510-
return;
511-
}
512501
await this.session.query.interrupt();
513502
}
514503

515504
async setSessionModel(params: SetSessionModelRequest) {
516-
const session = this.getSession();
517-
await session.query.setModel(params.modelId);
505+
await this.session.query.setModel(params.modelId);
518506
}
519507

520508
async setSessionMode(
521509
params: SetSessionModeRequest,
522510
): Promise<SetSessionModeResponse> {
523-
const session = this.getSession();
524-
525511
switch (params.modeId) {
526512
case "default":
527513
case "acceptEdits":
528514
case "bypassPermissions":
529515
case "plan":
530-
session.permissionMode = params.modeId;
516+
this.session.permissionMode = params.modeId;
531517
try {
532-
await session.query.setPermissionMode(params.modeId);
518+
await this.session.query.setPermissionMode(params.modeId);
533519
} catch (error) {
534520
const errorMessage =
535521
error instanceof Error && error.message
@@ -549,17 +535,16 @@ Before pushing a "workspace-*" branch to origin, rename it to something descript
549535

550536
canUseTool(sessionId: string): CanUseTool {
551537
return async (toolName, toolInput, { suggestions, toolUseID }) => {
552-
if (this.sessionId !== sessionId || !this.session) {
538+
if (this.sessionId !== sessionId) {
553539
return {
554540
behavior: "deny",
555541
message: "Session not found",
556542
interrupt: true,
557543
};
558544
}
559-
const session = this.session;
560545

561546
const context = {
562-
session,
547+
session: this.session,
563548
toolName,
564549
toolInput: toolInput as Record<string, unknown>,
565550
toolUseID,
@@ -592,15 +577,6 @@ Before pushing a "workspace-*" branch to origin, rename it to something descript
592577
return {};
593578
}
594579

595-
if (method === "session/setMode") {
596-
const { sessionId, modeId } = params as {
597-
sessionId: string;
598-
modeId: string;
599-
};
600-
await this.setSessionMode({ sessionId, modeId });
601-
return {};
602-
}
603-
604580
throw RequestError.methodNotFound(method);
605581
}
606582

@@ -610,7 +586,7 @@ Before pushing a "workspace-*" branch to origin, rename it to something descript
610586
this.logger.info("[RESUME] Resuming session", { params });
611587
const { sessionId } = params;
612588

613-
if (this.sessionId === sessionId && this.session) {
589+
if (this.sessionId === sessionId) {
614590
return {};
615591
}
616592

packages/agent/src/agent.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export class Agent {
4242
const apiKey = this.posthogAPI.getApiKey();
4343
process.env.ANTHROPIC_BASE_URL = gatewayUrl;
4444
process.env.ANTHROPIC_AUTH_TOKEN = apiKey;
45+
process.env.OPENAI_BASE_URL = gatewayUrl;
46+
process.env.OPENAI_API_KEY = apiKey;
47+
process.env.GEMINI_BASE_URL = gatewayUrl;
48+
process.env.GEMINI_API_KEY = apiKey;
4549
} catch (error) {
4650
this.logger.error("Failed to configure LLM gateway", error);
4751
throw error;

0 commit comments

Comments
 (0)