| ... | ... | @@ -228,28 +228,25 @@ function appendTurnItem( |
| 228 | 228 | resolveTurnSnapshot(context, turnId).items.push(item); |
| 229 | 229 | } |
| 230 | 230 | |
| 231 | | function ensureSessionContext( |
| 231 | const ensureSessionContext = Effect.fn("ensureSessionContext")(function* ( |
| 232 | 232 | sessions: ReadonlyMap<ThreadId, OpenCodeSessionContext>, |
| 233 | 233 | threadId: ThreadId, |
| 234 | | ): OpenCodeSessionContext { |
| 234 | ) { |
| 235 | 235 | const session = sessions.get(threadId); |
| 236 | 236 | if (!session) { |
| 237 | | throw new ProviderAdapterSessionNotFoundError({ |
| 237 | return yield* new ProviderAdapterSessionNotFoundError({ |
| 238 | 238 | provider: PROVIDER, |
| 239 | 239 | threadId, |
| 240 | 240 | }); |
| 241 | 241 | } |
| 242 | | // `ensureSessionContext` is a sync gate used from both sync helpers and |
| 243 | | // Effect bodies. `Ref.getUnsafe` is an atomic read of the backing cell — |
| 244 | | // no fiber suspension required, which keeps this callable everywhere. |
| 245 | | if (Ref.getUnsafe(session.stopped)) { |
| 246 | | throw new ProviderAdapterSessionClosedError({ |
| 242 | if (yield* Ref.get(session.stopped)) { |
| 243 | return yield* new ProviderAdapterSessionClosedError({ |
| 247 | 244 | provider: PROVIDER, |
| 248 | 245 | threadId, |
| 249 | 246 | }); |
| 250 | 247 | } |
| 251 | 248 | return session; |
| 252 | | } |
| 249 | }); |
| 253 | 250 | |
| 254 | 251 | function normalizeQuestionRequest(request: QuestionRequest): ReadonlyArray<UserInputQuestion> { |
| 255 | 252 | return request.questions.map((question, index) => ({ |
| ... | ... | @@ -1167,7 +1164,7 @@ export function makeOpenCodeAdapter( |
| 1167 | 1164 | ); |
| 1168 | 1165 | |
| 1169 | 1166 | const sendTurn: OpenCodeAdapterShape["sendTurn"] = Effect.fn("sendTurn")(function* (input) { |
| 1170 | | const context = ensureSessionContext(sessions, input.threadId); |
| 1167 | const context = yield* ensureSessionContext(sessions, input.threadId); |
| 1171 | 1168 | // A sendTurn while a turn is active is a steer: OpenCode queues the |
| 1172 | 1169 | // prompt into the busy session and the work continues as one turn, so |
| 1173 | 1170 | // the active turn id is reused instead of opening a new turn. |
| ... | ... | @@ -1291,7 +1288,7 @@ export function makeOpenCodeAdapter( |
| 1291 | 1288 | |
| 1292 | 1289 | const interruptTurn: OpenCodeAdapterShape["interruptTurn"] = Effect.fn("interruptTurn")( |
| 1293 | 1290 | function* (threadId, turnId) { |
| 1294 | | const context = ensureSessionContext(sessions, threadId); |
| 1291 | const context = yield* ensureSessionContext(sessions, threadId); |
| 1295 | 1292 | yield* runOpenCodeSdk("session.abort", () => |
| 1296 | 1293 | context.client.session.abort({ sessionID: context.openCodeSessionId }), |
| 1297 | 1294 | ).pipe(Effect.mapError(toRequestError)); |
| ... | ... | @@ -1313,7 +1310,7 @@ export function makeOpenCodeAdapter( |
| 1313 | 1310 | const respondToRequest: OpenCodeAdapterShape["respondToRequest"] = Effect.fn( |
| 1314 | 1311 | "respondToRequest", |
| 1315 | 1312 | )(function* (threadId, requestId, decision) { |
| 1316 | | const context = ensureSessionContext(sessions, threadId); |
| 1313 | const context = yield* ensureSessionContext(sessions, threadId); |
| 1317 | 1314 | if (!context.pendingPermissions.has(requestId)) { |
| 1318 | 1315 | return yield* new ProviderAdapterRequestError({ |
| 1319 | 1316 | provider: PROVIDER, |
| ... | ... | @@ -1333,7 +1330,7 @@ export function makeOpenCodeAdapter( |
| 1333 | 1330 | const respondToUserInput: OpenCodeAdapterShape["respondToUserInput"] = Effect.fn( |
| 1334 | 1331 | "respondToUserInput", |
| 1335 | 1332 | )(function* (threadId, requestId, answers) { |
| 1336 | | const context = ensureSessionContext(sessions, threadId); |
| 1333 | const context = yield* ensureSessionContext(sessions, threadId); |
| 1337 | 1334 | const request = context.pendingQuestions.get(requestId); |
| 1338 | 1335 | if (!request) { |
| 1339 | 1336 | return yield* new ProviderAdapterRequestError({ |
| ... | ... | @@ -1355,7 +1352,7 @@ export function makeOpenCodeAdapter( |
| 1355 | 1352 | function* (threadId) { |
| 1356 | 1353 | const context = sessions.get(threadId); |
| 1357 | 1354 | if (!context) { |
| 1358 | | throw new ProviderAdapterSessionNotFoundError({ |
| 1355 | return yield* new ProviderAdapterSessionNotFoundError({ |
| 1359 | 1356 | provider: PROVIDER, |
| 1360 | 1357 | threadId, |
| 1361 | 1358 | }); |
| ... | ... | @@ -1385,7 +1382,7 @@ export function makeOpenCodeAdapter( |
| 1385 | 1382 | |
| 1386 | 1383 | const readThread: OpenCodeAdapterShape["readThread"] = Effect.fn("readThread")( |
| 1387 | 1384 | function* (threadId) { |
| 1388 | | const context = ensureSessionContext(sessions, threadId); |
| 1385 | const context = yield* ensureSessionContext(sessions, threadId); |
| 1389 | 1386 | const messages = yield* runOpenCodeSdk("session.messages", () => |
| 1390 | 1387 | context.client.session.messages({ |
| 1391 | 1388 | sessionID: context.openCodeSessionId, |
| ... | ... | @@ -1411,7 +1408,7 @@ export function makeOpenCodeAdapter( |
| 1411 | 1408 | |
| 1412 | 1409 | const rollbackThread: OpenCodeAdapterShape["rollbackThread"] = Effect.fn("rollbackThread")( |
| 1413 | 1410 | function* (threadId, numTurns) { |
| 1414 | | const context = ensureSessionContext(sessions, threadId); |
| 1411 | const context = yield* ensureSessionContext(sessions, threadId); |
| 1415 | 1412 | const messages = yield* runOpenCodeSdk("session.messages", () => |
| 1416 | 1413 | context.client.session.messages({ |
| 1417 | 1414 | sessionID: context.openCodeSessionId, |