From 0a06f4daf175c9b87d233447e9f25ab6222e1163 Mon Sep 17 00:00:00 2001 From: David Balderston Date: Mon, 29 Jun 2026 14:30:01 -0700 Subject: [PATCH] Share OpenCode local server for chat sessions --- .../provider/Layers/OpenCodeAdapter.test.ts | 33 +++++++++++++++++-- .../src/provider/Layers/OpenCodeAdapter.ts | 2 +- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts b/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts index 004809a8f08..2114cf7e7ec 100644 --- a/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts +++ b/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts @@ -309,21 +309,48 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { }), ); - it.effect("requests an exclusive local server lease for chat sessions", () => + it.effect("requests a shared local server lease for chat sessions", () => Effect.gen(function* () { const adapter = yield* OpenCodeAdapter; yield* adapter.startSession({ provider: ProviderDriverKind.make("opencode"), - threadId: asThreadId("thread-opencode-local-exclusive"), + threadId: asThreadId("thread-opencode-local-shared"), runtimeMode: "full-access", }); - assert.deepEqual(runtimeMock.state.connectReuseLocalServer, [false]); + assert.deepEqual(runtimeMock.state.connectReuseLocalServer, [true]); assert.deepEqual(runtimeMock.state.sessionCreateUrls, ["http://127.0.0.1:4301"]); }).pipe(Effect.provide(OpenCodeAdapterLocalServerTestLayer)), ); + it.effect("can keep multiple local OpenCode-backed chat sessions open", () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + + const first = yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId: asThreadId("thread-opencode-local-first"), + runtimeMode: "full-access", + }); + const second = yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId: asThreadId("thread-opencode-local-second"), + runtimeMode: "full-access", + }); + + assert.equal(first.threadId, "thread-opencode-local-first"); + assert.equal(second.threadId, "thread-opencode-local-second"); + assert.deepEqual(runtimeMock.state.connectReuseLocalServer, [true, true]); + assert.deepEqual(runtimeMock.state.sessionCreateUrls, [ + "http://127.0.0.1:4301", + "http://127.0.0.1:4301", + ]); + const sessions = yield* adapter.listSessions(); + assert.equal(sessions.length, 2); + }).pipe(Effect.provide(OpenCodeAdapterLocalServerTestLayer)), + ); + it.effect("does not abort a resumed OpenCode session when concurrent starts race", () => Effect.gen(function* () { const adapter = yield* OpenCodeAdapter; diff --git a/apps/server/src/provider/Layers/OpenCodeAdapter.ts b/apps/server/src/provider/Layers/OpenCodeAdapter.ts index 0ebe639616c..88a1a1a8473 100644 --- a/apps/server/src/provider/Layers/OpenCodeAdapter.ts +++ b/apps/server/src/provider/Layers/OpenCodeAdapter.ts @@ -1101,7 +1101,7 @@ export function makeOpenCodeAdapter( binaryPath, serverUrl, ...(options?.environment ? { environment: options.environment } : {}), - reuseLocalServer: false, + reuseLocalServer: true, }); const client = openCodeRuntime.createOpenCodeSdkClient({ baseUrl: server.url,