fix: close OpenCode event streams before ending requests
Completed parallel conversations could leave buffered event connections open. Chat and native context compaction now cancel their own subscriptions before ending SDK iteration, without cancelling another conversation or its Server. Strengthen cleanup-order regressions and verify real OpenCode parallel runs, cancellation and compaction. The remote Agent uses ACP stdio and transcript polling rather than this SDK event stream and needs no corresponding change. Validation: 99 focused tests passed; the final candidate passed 4089 tests with 66 skipped, typecheck and lint. No external model calls were made.
This commit is contained in:
@@ -15,7 +15,7 @@ const binaryPath = join(
|
||||
)
|
||||
|
||||
it.skipIf(!existsSync(binaryPath))(
|
||||
'closes real event streams after parallel runs without cancelling a peer',
|
||||
'closes real event streams after parallel runs and compaction without cancelling a peer',
|
||||
async () => {
|
||||
const workspace = await mkdtemp(join(tmpdir(), 'goodbuddy-opencode-lifecycle-'))
|
||||
let cancelledController: AbortController | undefined
|
||||
@@ -94,14 +94,18 @@ it.skipIf(!existsSync(binaryPath))(
|
||||
}
|
||||
})
|
||||
})
|
||||
const run = async (controller = new AbortController(), cancel = false): Promise<string> => {
|
||||
const run = async (
|
||||
controller = new AbortController(),
|
||||
cancel = false,
|
||||
conversationId = crypto.randomUUID()
|
||||
): Promise<string> => {
|
||||
const requestId = crypto.randomUUID()
|
||||
const token = gateway.grant(requestId, [crypto.randomUUID()], controller.signal)!
|
||||
const deadline = setTimeout(() => controller.abort(), 30_000)
|
||||
let text = ''
|
||||
try {
|
||||
for await (const event of runtime.run({
|
||||
requestId, conversationId: crypto.randomUUID(), workMode: 'ask',
|
||||
requestId, conversationId, workMode: 'ask',
|
||||
prompt: cancel ? 'CANCEL_LIFECYCLE' : 'Reply LIFECYCLE_OK without tools.',
|
||||
knowledgeCapabilityToken: token
|
||||
}, controller.signal)) {
|
||||
@@ -126,6 +130,18 @@ it.skipIf(!existsSync(binaryPath))(
|
||||
expect(run()).resolves.toBe('LIFECYCLE_OK')
|
||||
])
|
||||
await expect.poll(() => openEventBodies).toBe(0)
|
||||
const conversationId = crypto.randomUUID()
|
||||
await expect(run(new AbortController(), false, conversationId)).resolves.toBe('LIFECYCLE_OK')
|
||||
await expect(runtime.compactConversation({
|
||||
requestId: crypto.randomUUID(),
|
||||
conversationId,
|
||||
runtimeSelection: { provider: 'opencode' },
|
||||
history: [],
|
||||
historyMessageIds: []
|
||||
}, new AbortController().signal)).resolves.toMatchObject({
|
||||
result: { compacted: true }
|
||||
})
|
||||
await expect.poll(() => openEventBodies).toBe(0)
|
||||
} finally {
|
||||
await runtime.dispose()
|
||||
await gateway.dispose()
|
||||
|
||||
Reference in New Issue
Block a user