Skip to content

Commit f0f77cd

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(terminal): preserve legacy stream attribution
1 parent 25347a9 commit f0f77cd

4 files changed

Lines changed: 105 additions & 2 deletions

File tree

apps/sim/lib/workflows/streaming/streaming.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,69 @@ describe('createStreamingResponse agent-events-v1', () => {
10431043
expect(events.some((event) => event.event === 'final')).toBe(true)
10441044
})
10451045

1046+
it('suppresses final selected output when streamed content is keyed by invocation', async () => {
1047+
const stream = await createStreamingResponse({
1048+
requestId: 'request-invocation-selected-output',
1049+
streamConfig: {
1050+
selectedOutputs: ['agent-1_content'],
1051+
},
1052+
executeFn: async ({ onStream, onBlockComplete }) => {
1053+
await onStream({
1054+
stream: new ReadableStream<Uint8Array>({
1055+
start(controller) {
1056+
controller.enqueue(new TextEncoder().encode('current answer'))
1057+
controller.close()
1058+
},
1059+
}),
1060+
streamFormat: 'text',
1061+
blockExecutionId: 'invoke-current',
1062+
execution: {
1063+
blockId: 'agent-1',
1064+
success: true,
1065+
output: { content: 'current answer' },
1066+
logs: [],
1067+
metadata: {},
1068+
},
1069+
} as any)
1070+
await onBlockComplete('agent-1', { content: 'current answer' }, 'invoke-current')
1071+
1072+
return {
1073+
success: true,
1074+
output: { content: 'current answer' },
1075+
logs: [
1076+
{
1077+
blockId: 'agent-1',
1078+
blockExecutionId: 'invoke-stale',
1079+
output: { content: 'stale answer' },
1080+
startedAt: new Date().toISOString(),
1081+
endedAt: new Date().toISOString(),
1082+
durationMs: 1,
1083+
success: true,
1084+
},
1085+
{
1086+
blockId: 'agent-1',
1087+
blockExecutionId: 'invoke-current',
1088+
output: { content: '' },
1089+
startedAt: new Date().toISOString(),
1090+
endedAt: new Date().toISOString(),
1091+
durationMs: 1,
1092+
success: true,
1093+
},
1094+
],
1095+
} as any
1096+
},
1097+
})
1098+
1099+
const events = await collectSSEEvents(stream)
1100+
expect(events.filter((event) => event.chunk !== undefined)).toEqual([
1101+
{ blockId: 'agent-1', chunk: 'current answer' },
1102+
])
1103+
expect(events.find((event) => event.event === 'final')).toEqual({
1104+
event: 'final',
1105+
data: { success: true, output: {} },
1106+
})
1107+
})
1108+
10461109
it('stays fully text-only when both policies are off', async () => {
10471110
const stream = await createStreamingResponse({
10481111
requestId: 'request-1',

apps/sim/lib/workflows/streaming/streaming.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,15 @@ async function buildMinimalResult(
387387
let selectedOutputBytes = assertSelectedOutputBytes(minimalResult.output)
388388
for (const descriptor of getSelectedOutputDescriptors(selectedOutputs)) {
389389
const { blockId, path } = descriptor
390+
const blockLogs = result.logs.filter((log: BlockLog) => log.blockId === blockId)
390391

391-
if (streamedContent.has(blockId)) {
392+
if (
393+
streamedContent.has(blockId) ||
394+
blockLogs.some(
395+
(log: BlockLog) =>
396+
log.blockExecutionId !== undefined && streamedContent.has(log.blockExecutionId)
397+
)
398+
) {
392399
continue
393400
}
394401

@@ -410,7 +417,7 @@ async function buildMinimalResult(
410417
continue
411418
}
412419

413-
const blockLog = result.logs.find((log: BlockLog) => log.blockId === blockId)
420+
const blockLog = blockLogs[0]
414421
if (!blockLog?.output) {
415422
continue
416423
}

apps/sim/stores/terminal/console/store.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,38 @@ describe('terminal console store', () => {
285285
expect.objectContaining({ blockId: 'function-1', candidateCount: 2 })
286286
)
287287
})
288+
289+
it('enriches an exactly matched legacy child workflow entry with its instance id', () => {
290+
useTerminalConsoleStore.getState().addConsole({
291+
workflowId: 'wf-1',
292+
blockId: 'workflow-1',
293+
blockName: 'Workflow',
294+
blockType: 'workflow',
295+
executionId: 'exec-1',
296+
executionOrder: 3,
297+
iterationCurrent: 1,
298+
iterationType: 'loop',
299+
iterationContainerId: 'loop-1',
300+
isRunning: true,
301+
})
302+
303+
useTerminalConsoleStore.getState().updateConsole(
304+
'workflow-1',
305+
{
306+
childWorkflowInstanceId: 'child-inst-1',
307+
executionOrder: 3,
308+
iterationCurrent: 1,
309+
iterationType: 'loop',
310+
iterationContainerId: 'loop-1',
311+
},
312+
'exec-1'
313+
)
314+
315+
expect(useTerminalConsoleStore.getState().getWorkflowEntries('wf-1')[0]).toMatchObject({
316+
childWorkflowInstanceId: 'child-inst-1',
317+
isRunning: true,
318+
})
319+
})
288320
})
289321

290322
describe('cancelRunningEntries', () => {

apps/sim/stores/terminal/console/store.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ const matchesEntryForUpdate = (
167167

168168
if (
169169
update.childWorkflowInstanceId !== undefined &&
170+
entry.childWorkflowInstanceId !== undefined &&
170171
entry.childWorkflowInstanceId !== update.childWorkflowInstanceId
171172
) {
172173
return false

0 commit comments

Comments
 (0)