mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
Merge 12c38dbdf2 into 53fb175855
This commit is contained in:
commit
bfc04a2ecd
2 changed files with 73 additions and 1 deletions
|
|
@ -782,7 +782,16 @@ async function consumeDaemonRun({
|
|||
}
|
||||
}
|
||||
|
||||
if (endStatus === 'canceled') return;
|
||||
if (endStatus === 'canceled') {
|
||||
// OpenCode and other agents can emit useful output before the daemon
|
||||
// SIGTERM's the child (shutdown, user cancel, long-run timeout). The
|
||||
// run status is still `canceled`, but abandoning `acc` here drops the
|
||||
// assistant text and skips the onDone file-diff path in ProjectView.
|
||||
if (acc.trim()) {
|
||||
handlers.onDone(acc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Trust the server's authoritative success declaration. When the server
|
||||
// explicitly sets `status: 'succeeded'` (either in the SSE end payload
|
||||
|
|
|
|||
|
|
@ -709,6 +709,69 @@ describe('streamViaDaemon', () => {
|
|||
expect(handlers.onDone).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('preserves streamed output when a run ends as canceled', async () => {
|
||||
const handlers = createDaemonHandlers();
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn()
|
||||
.mockResolvedValueOnce(jsonResponse({ runId: 'run-1' }))
|
||||
.mockResolvedValueOnce(
|
||||
sseResponse(
|
||||
[
|
||||
'event: stdout',
|
||||
'data: {"chunk":"partial output"}',
|
||||
'',
|
||||
'event: end',
|
||||
'data: {"code":null,"signal":"SIGTERM","status":"canceled"}',
|
||||
'',
|
||||
'',
|
||||
].join('\n'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await streamViaDaemon({
|
||||
agentId: 'mock',
|
||||
history: [{ id: '1', role: 'user', content: 'hello' }],
|
||||
systemPrompt: '',
|
||||
signal: new AbortController().signal,
|
||||
handlers,
|
||||
});
|
||||
|
||||
expect(handlers.onDone).toHaveBeenCalledWith('partial output');
|
||||
expect(handlers.onError).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not call onDone when a canceled run produced no output', async () => {
|
||||
const handlers = createDaemonHandlers();
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn()
|
||||
.mockResolvedValueOnce(jsonResponse({ runId: 'run-1' }))
|
||||
.mockResolvedValueOnce(
|
||||
sseResponse(
|
||||
[
|
||||
'event: end',
|
||||
'data: {"code":null,"signal":"SIGTERM","status":"canceled"}',
|
||||
'',
|
||||
'',
|
||||
].join('\n'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await streamViaDaemon({
|
||||
agentId: 'mock',
|
||||
history: [{ id: '1', role: 'user', content: 'hello' }],
|
||||
systemPrompt: '',
|
||||
signal: new AbortController().signal,
|
||||
handlers,
|
||||
});
|
||||
|
||||
expect(handlers.onDone).not.toHaveBeenCalled();
|
||||
expect(handlers.onError).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('keeps the daemon run alive when the browser-side stream aborts', async () => {
|
||||
const handlers = createDaemonHandlers();
|
||||
const controller = new AbortController();
|
||||
|
|
|
|||
Loading…
Reference in a new issue