@perstack/react 0.0.53 → 0.0.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/index.js CHANGED
@@ -1,677 +1,679 @@
1
- import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
2
- import { BASE_SKILL_PREFIX, createBaseToolActivity, createGeneralToolActivity } from '@perstack/core';
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
+ import { BASE_SKILL_PREFIX, createBaseToolActivity, createGeneralToolActivity } from "@perstack/core";
3
3
 
4
- // src/hooks/use-job-stream.ts
5
-
6
- // src/utils/stream.ts
7
- var isAbortError = (err) => err instanceof DOMException && err.name === "AbortError";
4
+ //#region src/utils/stream.ts
5
+ const isAbortError = (err) => err instanceof DOMException && err.name === "AbortError";
6
+ /**
7
+ * Consumes an SSE stream with abort-safe iteration and error normalization.
8
+ *
9
+ * Handles the connection lifecycle shared by all streaming hooks:
10
+ * 1. Calls `connect` to obtain an async iterable
11
+ * 2. Iterates events, stopping on signal abort
12
+ * 3. Filters out AbortError (normal cleanup), surfaces all others
13
+ */
8
14
  async function consumeStream(connect, jobId, signal, onEvent) {
9
- const events = await connect(jobId, signal);
10
- for await (const event of events) {
11
- if (signal.aborted) break;
12
- onEvent(event);
13
- }
15
+ const events = await connect(jobId, signal);
16
+ for await (const event of events) {
17
+ if (signal.aborted) break;
18
+ onEvent(event);
19
+ }
14
20
  }
15
- var TOOL_RESULT_EVENT_TYPES = /* @__PURE__ */ new Set(["resolveToolResults", "attemptCompletion"]);
21
+
22
+ //#endregion
23
+ //#region src/utils/event-to-activity.ts
24
+ const TOOL_RESULT_EVENT_TYPES = new Set(["resolveToolResults", "attemptCompletion"]);
25
+ /**
26
+ * Converts a tool call and result to an Activity.
27
+ * Delegates to core's createBaseToolActivity/createGeneralToolActivity to avoid duplication.
28
+ */
16
29
  function toolToActivity(toolCall, toolResult, reasoning, meta) {
17
- const { skillName, toolName } = toolCall;
18
- const baseActivity = skillName.startsWith(BASE_SKILL_PREFIX) ? createBaseToolActivity(toolName, toolCall, toolResult, reasoning) : createGeneralToolActivity(skillName, toolName, toolCall, toolResult, reasoning);
19
- return {
20
- ...baseActivity,
21
- id: meta.id,
22
- expertKey: meta.expertKey,
23
- runId: meta.runId,
24
- previousActivityId: meta.previousActivityId,
25
- delegatedBy: meta.delegatedBy
26
- };
30
+ const { skillName, toolName } = toolCall;
31
+ return {
32
+ ...skillName.startsWith(BASE_SKILL_PREFIX) ? createBaseToolActivity(toolName, toolCall, toolResult, reasoning) : createGeneralToolActivity(skillName, toolName, toolCall, toolResult, reasoning),
33
+ id: meta.id,
34
+ expertKey: meta.expertKey,
35
+ runId: meta.runId,
36
+ previousActivityId: meta.previousActivityId,
37
+ delegatedBy: meta.delegatedBy
38
+ };
27
39
  }
28
40
  function createInitialActivityProcessState() {
29
- return {
30
- tools: /* @__PURE__ */ new Map(),
31
- runStates: /* @__PURE__ */ new Map()
32
- };
41
+ return {
42
+ tools: /* @__PURE__ */ new Map(),
43
+ runStates: /* @__PURE__ */ new Map()
44
+ };
33
45
  }
34
46
  function getOrCreateRunState(state, runId, expertKey) {
35
- let runState = state.runStates.get(runId);
36
- if (!runState) {
37
- runState = {
38
- expertKey,
39
- queryLogged: false,
40
- completionLogged: false,
41
- isComplete: false,
42
- pendingDelegateCount: 0
43
- };
44
- state.runStates.set(runId, runState);
45
- }
46
- return runState;
47
+ let runState = state.runStates.get(runId);
48
+ if (!runState) {
49
+ runState = {
50
+ expertKey,
51
+ queryLogged: false,
52
+ completionLogged: false,
53
+ isComplete: false,
54
+ pendingDelegateCount: 0
55
+ };
56
+ state.runStates.set(runId, runState);
57
+ }
58
+ return runState;
47
59
  }
48
- var isRunEvent = (event) => "type" in event && "expertKey" in event;
49
- var isCompleteStreamingReasoningEvent = (event) => "type" in event && event.type === "completeStreamingReasoning";
50
- var isToolCallsEvent = (event) => event.type === "callTools" && "toolCalls" in event;
51
- var isStopRunByDelegateEvent = (event) => event.type === "stopRunByDelegate" && "checkpoint" in event;
52
- var isStopRunByInteractiveToolEvent = (event) => event.type === "stopRunByInteractiveTool" && "checkpoint" in event;
53
- var isToolResultsEvent = (event) => event.type === "resolveToolResults" && "toolResults" in event;
54
- var isToolResultEvent = (event) => TOOL_RESULT_EVENT_TYPES.has(event.type) && "toolResult" in event;
60
+ const isRunEvent = (event) => "type" in event && "expertKey" in event;
61
+ const isCompleteStreamingReasoningEvent = (event) => "type" in event && event.type === "completeStreamingReasoning";
62
+ const isToolCallsEvent = (event) => event.type === "callTools" && "toolCalls" in event;
63
+ const isStopRunByDelegateEvent = (event) => event.type === "stopRunByDelegate" && "checkpoint" in event;
64
+ const isStopRunByInteractiveToolEvent = (event) => event.type === "stopRunByInteractiveTool" && "checkpoint" in event;
65
+ const isToolResultsEvent = (event) => event.type === "resolveToolResults" && "toolResults" in event;
66
+ const isToolResultEvent = (event) => TOOL_RESULT_EVENT_TYPES.has(event.type) && "toolResult" in event;
67
+ /**
68
+ * Wraps multiple activities in a ParallelActivitiesGroup with shared reasoning.
69
+ * If only one activity, returns it directly.
70
+ */
55
71
  function wrapInGroupIfParallel(activities, reasoning, meta) {
56
- if (activities.length <= 1) {
57
- return activities;
58
- }
59
- const activitiesWithoutReasoning = activities.map((a) => {
60
- const { reasoning: _, ...rest } = a;
61
- return rest;
62
- });
63
- const group = {
64
- type: "parallelGroup",
65
- id: `parallel-${activities[0].id}`,
66
- expertKey: meta.expertKey,
67
- runId: meta.runId,
68
- reasoning,
69
- activities: activitiesWithoutReasoning
70
- };
71
- return [group];
72
+ if (activities.length <= 1) return activities;
73
+ const activitiesWithoutReasoning = activities.map((a) => {
74
+ const { reasoning: _, ...rest } = a;
75
+ return rest;
76
+ });
77
+ return [{
78
+ type: "parallelGroup",
79
+ id: `parallel-${activities[0].id}`,
80
+ expertKey: meta.expertKey,
81
+ runId: meta.runId,
82
+ reasoning,
83
+ activities: activitiesWithoutReasoning
84
+ }];
72
85
  }
86
+ /**
87
+ * Processes a RunEvent and produces Activity or ParallelActivitiesGroup items.
88
+ * Only processes RunEvent (state machine transitions), not RuntimeEvent.
89
+ *
90
+ * @param state - Mutable processing state
91
+ * @param event - The event to process
92
+ * @param addActivity - Callback to add a new Activity or ParallelActivitiesGroup
93
+ */
73
94
  function processRunEventToActivity(state, event, addActivity) {
74
- if (isCompleteStreamingReasoningEvent(event)) {
75
- const reasoningEvent = event;
76
- const { runId, text, expertKey } = reasoningEvent;
77
- const runState2 = state.runStates.get(runId);
78
- if (runState2) {
79
- runState2.completedReasoning = text;
80
- } else {
81
- state.runStates.set(runId, {
82
- expertKey,
83
- queryLogged: false,
84
- completionLogged: false,
85
- isComplete: false,
86
- pendingDelegateCount: 0,
87
- completedReasoning: text
88
- });
89
- }
90
- return;
91
- }
92
- if (!isRunEvent(event)) {
93
- return;
94
- }
95
- const runState = getOrCreateRunState(state, event.runId, event.expertKey);
96
- if (event.type === "startRun") {
97
- const startRunEvent = event;
98
- const userMessage = startRunEvent.inputMessages.find((m) => m.type === "userMessage");
99
- const queryText = userMessage?.contents?.find((c) => c.type === "textPart")?.text;
100
- if (!runState.delegatedBy) {
101
- const delegatedByInfo = startRunEvent.initialCheckpoint?.delegatedBy;
102
- if (delegatedByInfo) {
103
- runState.delegatedBy = {
104
- expertKey: delegatedByInfo.expert.key,
105
- runId: delegatedByInfo.runId
106
- };
107
- }
108
- }
109
- const isDelegationReturn = startRunEvent.initialCheckpoint?.status === "stoppedByDelegate" || startRunEvent.initialCheckpoint?.status === "stoppedByInteractiveTool";
110
- if (queryText && !runState.queryLogged && !isDelegationReturn) {
111
- const activityId = `query-${event.runId}`;
112
- addActivity({
113
- type: "query",
114
- id: activityId,
115
- expertKey: event.expertKey,
116
- runId: event.runId,
117
- previousActivityId: runState.lastActivityId,
118
- delegatedBy: runState.delegatedBy,
119
- text: queryText
120
- });
121
- runState.lastActivityId = activityId;
122
- runState.queryLogged = true;
123
- }
124
- return;
125
- }
126
- if (event.type === "resumeFromStop") {
127
- if (!runState.delegatedBy) {
128
- const resumeEvent = event;
129
- const delegatedByInfo = resumeEvent.checkpoint?.delegatedBy;
130
- if (delegatedByInfo) {
131
- runState.delegatedBy = {
132
- expertKey: delegatedByInfo.expert.key,
133
- runId: delegatedByInfo.runId
134
- };
135
- }
136
- }
137
- return;
138
- }
139
- if (event.type === "retry") {
140
- const retryEvent = event;
141
- const activityId = `retry-${event.id}`;
142
- addActivity({
143
- type: "retry",
144
- id: activityId,
145
- expertKey: event.expertKey,
146
- runId: event.runId,
147
- previousActivityId: runState.lastActivityId,
148
- delegatedBy: runState.delegatedBy,
149
- reasoning: runState.completedReasoning,
150
- error: retryEvent.reason,
151
- message: ""
152
- });
153
- runState.lastActivityId = activityId;
154
- runState.completedReasoning = void 0;
155
- return;
156
- }
157
- if (event.type === "completeRun") {
158
- if (!runState.completionLogged) {
159
- const text = event.text ?? "";
160
- const activityId = `completion-${event.runId}`;
161
- addActivity({
162
- type: "complete",
163
- id: activityId,
164
- expertKey: event.expertKey,
165
- runId: event.runId,
166
- previousActivityId: runState.lastActivityId,
167
- delegatedBy: runState.delegatedBy,
168
- reasoning: runState.completedReasoning,
169
- text
170
- });
171
- runState.lastActivityId = activityId;
172
- runState.completionLogged = true;
173
- runState.isComplete = true;
174
- runState.completedReasoning = void 0;
175
- }
176
- return;
177
- }
178
- if (event.type === "stopRunByError") {
179
- const errorEvent = event;
180
- const activityId = `error-${event.id}`;
181
- addActivity({
182
- type: "error",
183
- id: activityId,
184
- expertKey: event.expertKey,
185
- runId: event.runId,
186
- previousActivityId: runState.lastActivityId,
187
- delegatedBy: runState.delegatedBy,
188
- errorName: errorEvent.error.name,
189
- error: errorEvent.error.message,
190
- isRetryable: errorEvent.error.isRetryable
191
- });
192
- runState.lastActivityId = activityId;
193
- runState.isComplete = true;
194
- runState.completedReasoning = void 0;
195
- return;
196
- }
197
- if (isToolCallsEvent(event)) {
198
- for (const toolCall of event.toolCalls) {
199
- if (!state.tools.has(toolCall.id)) {
200
- state.tools.set(toolCall.id, { id: toolCall.id, toolCall, logged: false });
201
- }
202
- }
203
- }
204
- if (isStopRunByDelegateEvent(event)) {
205
- const reasoning = runState.completedReasoning;
206
- const delegations = event.checkpoint.delegateTo ?? [];
207
- runState.pendingDelegateCount += delegations.length;
208
- const delegateActivities = [];
209
- for (const delegation of delegations) {
210
- const existingTool = state.tools.get(delegation.toolCallId);
211
- if (!existingTool || !existingTool.logged) {
212
- if (existingTool) {
213
- existingTool.logged = true;
214
- }
215
- const activityId = `delegate-${delegation.toolCallId}`;
216
- delegateActivities.push({
217
- type: "delegate",
218
- id: activityId,
219
- expertKey: event.expertKey,
220
- runId: event.runId,
221
- previousActivityId: runState.lastActivityId,
222
- delegatedBy: runState.delegatedBy,
223
- delegateExpertKey: delegation.expert.key,
224
- query: delegation.query,
225
- reasoning
226
- });
227
- runState.lastActivityId = activityId;
228
- }
229
- }
230
- const wrapped = wrapInGroupIfParallel(delegateActivities, reasoning, {
231
- expertKey: event.expertKey,
232
- runId: event.runId,
233
- delegatedBy: runState.delegatedBy
234
- });
235
- for (const item of wrapped) {
236
- addActivity(item);
237
- }
238
- runState.completedReasoning = void 0;
239
- return;
240
- }
241
- if (isStopRunByInteractiveToolEvent(event)) {
242
- const reasoning = runState.completedReasoning;
243
- const pendingToolCalls = event.checkpoint.pendingToolCalls ?? [];
244
- const interactiveActivities = [];
245
- for (const toolCall of pendingToolCalls) {
246
- const existingTool = state.tools.get(toolCall.id);
247
- if (!existingTool || !existingTool.logged) {
248
- if (existingTool) {
249
- existingTool.logged = true;
250
- }
251
- const activityId = `interactive-${toolCall.id}`;
252
- interactiveActivities.push({
253
- type: "interactiveTool",
254
- id: activityId,
255
- expertKey: event.expertKey,
256
- runId: event.runId,
257
- previousActivityId: runState.lastActivityId,
258
- delegatedBy: runState.delegatedBy,
259
- skillName: toolCall.skillName,
260
- toolName: toolCall.toolName,
261
- args: toolCall.args,
262
- reasoning
263
- });
264
- runState.lastActivityId = activityId;
265
- }
266
- }
267
- const wrapped = wrapInGroupIfParallel(interactiveActivities, reasoning, {
268
- expertKey: event.expertKey,
269
- runId: event.runId,
270
- delegatedBy: runState.delegatedBy
271
- });
272
- for (const item of wrapped) {
273
- addActivity(item);
274
- }
275
- runState.completedReasoning = void 0;
276
- return;
277
- }
278
- if (isToolResultsEvent(event)) {
279
- const reasoning = runState.completedReasoning;
280
- const toolActivities = [];
281
- for (const toolResult of event.toolResults) {
282
- const tool = state.tools.get(toolResult.id);
283
- if (tool && !tool.logged) {
284
- const activityId = `action-${tool.id}`;
285
- const activity = toolToActivity(tool.toolCall, toolResult, reasoning, {
286
- id: activityId,
287
- expertKey: event.expertKey,
288
- runId: event.runId,
289
- previousActivityId: runState.lastActivityId,
290
- delegatedBy: runState.delegatedBy
291
- });
292
- toolActivities.push(activity);
293
- runState.lastActivityId = activityId;
294
- tool.logged = true;
295
- }
296
- }
297
- if (toolActivities.length > 0) {
298
- const wrapped = wrapInGroupIfParallel(toolActivities, reasoning, {
299
- expertKey: event.expertKey,
300
- runId: event.runId,
301
- delegatedBy: runState.delegatedBy
302
- });
303
- for (const item of wrapped) {
304
- addActivity(item);
305
- }
306
- runState.completedReasoning = void 0;
307
- }
308
- } else if (isToolResultEvent(event)) {
309
- const { toolResult } = event;
310
- const tool = state.tools.get(toolResult.id);
311
- if (tool && !tool.logged) {
312
- const activityId = `action-${tool.id}`;
313
- const activity = toolToActivity(tool.toolCall, toolResult, runState.completedReasoning, {
314
- id: activityId,
315
- expertKey: event.expertKey,
316
- runId: event.runId,
317
- previousActivityId: runState.lastActivityId,
318
- delegatedBy: runState.delegatedBy
319
- });
320
- addActivity(activity);
321
- runState.lastActivityId = activityId;
322
- tool.logged = true;
323
- runState.completedReasoning = void 0;
324
- }
325
- }
95
+ if (isCompleteStreamingReasoningEvent(event)) {
96
+ const { runId, text, expertKey } = event;
97
+ const runState = state.runStates.get(runId);
98
+ if (runState) runState.completedReasoning = text;
99
+ else state.runStates.set(runId, {
100
+ expertKey,
101
+ queryLogged: false,
102
+ completionLogged: false,
103
+ isComplete: false,
104
+ pendingDelegateCount: 0,
105
+ completedReasoning: text
106
+ });
107
+ return;
108
+ }
109
+ if (!isRunEvent(event)) return;
110
+ const runState = getOrCreateRunState(state, event.runId, event.expertKey);
111
+ if (event.type === "startRun") {
112
+ const startRunEvent = event;
113
+ const queryText = startRunEvent.inputMessages.find((m) => m.type === "userMessage")?.contents?.find((c) => c.type === "textPart")?.text;
114
+ if (!runState.delegatedBy) {
115
+ const delegatedByInfo = startRunEvent.initialCheckpoint?.delegatedBy;
116
+ if (delegatedByInfo) runState.delegatedBy = {
117
+ expertKey: delegatedByInfo.expert.key,
118
+ runId: delegatedByInfo.runId
119
+ };
120
+ }
121
+ const isDelegationReturn = startRunEvent.initialCheckpoint?.status === "stoppedByDelegate" || startRunEvent.initialCheckpoint?.status === "stoppedByInteractiveTool";
122
+ if (queryText && !runState.queryLogged && !isDelegationReturn) {
123
+ const activityId = `query-${event.runId}`;
124
+ addActivity({
125
+ type: "query",
126
+ id: activityId,
127
+ expertKey: event.expertKey,
128
+ runId: event.runId,
129
+ previousActivityId: runState.lastActivityId,
130
+ delegatedBy: runState.delegatedBy,
131
+ text: queryText
132
+ });
133
+ runState.lastActivityId = activityId;
134
+ runState.queryLogged = true;
135
+ }
136
+ return;
137
+ }
138
+ if (event.type === "resumeFromStop") {
139
+ if (!runState.delegatedBy) {
140
+ const delegatedByInfo = event.checkpoint?.delegatedBy;
141
+ if (delegatedByInfo) runState.delegatedBy = {
142
+ expertKey: delegatedByInfo.expert.key,
143
+ runId: delegatedByInfo.runId
144
+ };
145
+ }
146
+ return;
147
+ }
148
+ if (event.type === "retry") {
149
+ const retryEvent = event;
150
+ const activityId = `retry-${event.id}`;
151
+ addActivity({
152
+ type: "retry",
153
+ id: activityId,
154
+ expertKey: event.expertKey,
155
+ runId: event.runId,
156
+ previousActivityId: runState.lastActivityId,
157
+ delegatedBy: runState.delegatedBy,
158
+ reasoning: runState.completedReasoning,
159
+ error: retryEvent.reason,
160
+ message: ""
161
+ });
162
+ runState.lastActivityId = activityId;
163
+ runState.completedReasoning = void 0;
164
+ return;
165
+ }
166
+ if (event.type === "completeRun") {
167
+ if (!runState.completionLogged) {
168
+ const text = event.text ?? "";
169
+ const activityId = `completion-${event.runId}`;
170
+ addActivity({
171
+ type: "complete",
172
+ id: activityId,
173
+ expertKey: event.expertKey,
174
+ runId: event.runId,
175
+ previousActivityId: runState.lastActivityId,
176
+ delegatedBy: runState.delegatedBy,
177
+ reasoning: runState.completedReasoning,
178
+ text
179
+ });
180
+ runState.lastActivityId = activityId;
181
+ runState.completionLogged = true;
182
+ runState.isComplete = true;
183
+ runState.completedReasoning = void 0;
184
+ }
185
+ return;
186
+ }
187
+ if (event.type === "stopRunByError") {
188
+ const errorEvent = event;
189
+ const activityId = `error-${event.id}`;
190
+ addActivity({
191
+ type: "error",
192
+ id: activityId,
193
+ expertKey: event.expertKey,
194
+ runId: event.runId,
195
+ previousActivityId: runState.lastActivityId,
196
+ delegatedBy: runState.delegatedBy,
197
+ errorName: errorEvent.error.name,
198
+ error: errorEvent.error.message,
199
+ isRetryable: errorEvent.error.isRetryable
200
+ });
201
+ runState.lastActivityId = activityId;
202
+ runState.isComplete = true;
203
+ runState.completedReasoning = void 0;
204
+ return;
205
+ }
206
+ if (isToolCallsEvent(event)) {
207
+ for (const toolCall of event.toolCalls) if (!state.tools.has(toolCall.id)) state.tools.set(toolCall.id, {
208
+ id: toolCall.id,
209
+ toolCall,
210
+ logged: false
211
+ });
212
+ }
213
+ if (isStopRunByDelegateEvent(event)) {
214
+ const reasoning = runState.completedReasoning;
215
+ const delegations = event.checkpoint.delegateTo ?? [];
216
+ runState.pendingDelegateCount += delegations.length;
217
+ const delegateActivities = [];
218
+ for (const delegation of delegations) {
219
+ const existingTool = state.tools.get(delegation.toolCallId);
220
+ if (!existingTool || !existingTool.logged) {
221
+ if (existingTool) existingTool.logged = true;
222
+ const activityId = `delegate-${delegation.toolCallId}`;
223
+ delegateActivities.push({
224
+ type: "delegate",
225
+ id: activityId,
226
+ expertKey: event.expertKey,
227
+ runId: event.runId,
228
+ previousActivityId: runState.lastActivityId,
229
+ delegatedBy: runState.delegatedBy,
230
+ delegateExpertKey: delegation.expert.key,
231
+ query: delegation.query,
232
+ reasoning
233
+ });
234
+ runState.lastActivityId = activityId;
235
+ }
236
+ }
237
+ const wrapped = wrapInGroupIfParallel(delegateActivities, reasoning, {
238
+ expertKey: event.expertKey,
239
+ runId: event.runId,
240
+ delegatedBy: runState.delegatedBy
241
+ });
242
+ for (const item of wrapped) addActivity(item);
243
+ runState.completedReasoning = void 0;
244
+ return;
245
+ }
246
+ if (isStopRunByInteractiveToolEvent(event)) {
247
+ const reasoning = runState.completedReasoning;
248
+ const pendingToolCalls = event.checkpoint.pendingToolCalls ?? [];
249
+ const interactiveActivities = [];
250
+ for (const toolCall of pendingToolCalls) {
251
+ const existingTool = state.tools.get(toolCall.id);
252
+ if (!existingTool || !existingTool.logged) {
253
+ if (existingTool) existingTool.logged = true;
254
+ const activityId = `interactive-${toolCall.id}`;
255
+ interactiveActivities.push({
256
+ type: "interactiveTool",
257
+ id: activityId,
258
+ expertKey: event.expertKey,
259
+ runId: event.runId,
260
+ previousActivityId: runState.lastActivityId,
261
+ delegatedBy: runState.delegatedBy,
262
+ skillName: toolCall.skillName,
263
+ toolName: toolCall.toolName,
264
+ args: toolCall.args,
265
+ reasoning
266
+ });
267
+ runState.lastActivityId = activityId;
268
+ }
269
+ }
270
+ const wrapped = wrapInGroupIfParallel(interactiveActivities, reasoning, {
271
+ expertKey: event.expertKey,
272
+ runId: event.runId,
273
+ delegatedBy: runState.delegatedBy
274
+ });
275
+ for (const item of wrapped) addActivity(item);
276
+ runState.completedReasoning = void 0;
277
+ return;
278
+ }
279
+ if (isToolResultsEvent(event)) {
280
+ const reasoning = runState.completedReasoning;
281
+ const toolActivities = [];
282
+ for (const toolResult of event.toolResults) {
283
+ const tool = state.tools.get(toolResult.id);
284
+ if (tool && !tool.logged) {
285
+ const activityId = `action-${tool.id}`;
286
+ const activity = toolToActivity(tool.toolCall, toolResult, reasoning, {
287
+ id: activityId,
288
+ expertKey: event.expertKey,
289
+ runId: event.runId,
290
+ previousActivityId: runState.lastActivityId,
291
+ delegatedBy: runState.delegatedBy
292
+ });
293
+ toolActivities.push(activity);
294
+ runState.lastActivityId = activityId;
295
+ tool.logged = true;
296
+ }
297
+ }
298
+ if (toolActivities.length > 0) {
299
+ const wrapped = wrapInGroupIfParallel(toolActivities, reasoning, {
300
+ expertKey: event.expertKey,
301
+ runId: event.runId,
302
+ delegatedBy: runState.delegatedBy
303
+ });
304
+ for (const item of wrapped) addActivity(item);
305
+ runState.completedReasoning = void 0;
306
+ }
307
+ } else if (isToolResultEvent(event)) {
308
+ const { toolResult } = event;
309
+ const tool = state.tools.get(toolResult.id);
310
+ if (tool && !tool.logged) {
311
+ const activityId = `action-${tool.id}`;
312
+ addActivity(toolToActivity(tool.toolCall, toolResult, runState.completedReasoning, {
313
+ id: activityId,
314
+ expertKey: event.expertKey,
315
+ runId: event.runId,
316
+ previousActivityId: runState.lastActivityId,
317
+ delegatedBy: runState.delegatedBy
318
+ }));
319
+ runState.lastActivityId = activityId;
320
+ tool.logged = true;
321
+ runState.completedReasoning = void 0;
322
+ }
323
+ }
326
324
  }
327
325
 
328
- // src/hooks/use-run.ts
329
- var STREAMING_EVENT_TYPES = /* @__PURE__ */ new Set([
330
- "startStreamingReasoning",
331
- "streamReasoning",
332
- "completeStreamingReasoning",
333
- "startStreamingRunResult",
334
- "streamRunResult",
335
- "completeStreamingRunResult"
326
+ //#endregion
327
+ //#region src/hooks/use-run.ts
328
+ const STREAMING_EVENT_TYPES = new Set([
329
+ "startStreamingReasoning",
330
+ "streamReasoning",
331
+ "completeStreamingReasoning",
332
+ "startStreamingRunResult",
333
+ "streamRunResult",
334
+ "completeStreamingRunResult"
336
335
  ]);
337
- var isStreamingEvent = (event) => "type" in event && "expertKey" in event && STREAMING_EVENT_TYPES.has(event.type);
336
+ const isStreamingEvent = (event) => "type" in event && "expertKey" in event && STREAMING_EVENT_TYPES.has(event.type);
338
337
  function processStreamingEvent(event, prevState) {
339
- const { runId, expertKey } = event;
340
- switch (event.type) {
341
- case "startStreamingReasoning": {
342
- return {
343
- newState: {
344
- ...prevState,
345
- runs: {
346
- ...prevState.runs,
347
- [runId]: {
348
- expertKey,
349
- reasoning: "",
350
- isReasoningActive: true
351
- }
352
- }
353
- },
354
- handled: true
355
- };
356
- }
357
- case "streamReasoning": {
358
- return {
359
- newState: {
360
- ...prevState,
361
- runs: {
362
- ...prevState.runs,
363
- [runId]: {
364
- ...prevState.runs[runId],
365
- expertKey,
366
- reasoning: (prevState.runs[runId]?.reasoning ?? "") + event.delta
367
- }
368
- }
369
- },
370
- handled: true
371
- };
372
- }
373
- case "completeStreamingReasoning": {
374
- return {
375
- newState: {
376
- ...prevState,
377
- runs: {
378
- ...prevState.runs,
379
- [runId]: {
380
- ...prevState.runs[runId],
381
- expertKey,
382
- isReasoningActive: false
383
- }
384
- }
385
- },
386
- handled: false
387
- };
388
- }
389
- case "startStreamingRunResult": {
390
- return {
391
- newState: {
392
- ...prevState,
393
- runs: {
394
- ...prevState.runs,
395
- [runId]: {
396
- expertKey,
397
- reasoning: void 0,
398
- isReasoningActive: false,
399
- runResult: "",
400
- isRunResultActive: true
401
- }
402
- }
403
- },
404
- handled: true
405
- };
406
- }
407
- case "streamRunResult": {
408
- return {
409
- newState: {
410
- ...prevState,
411
- runs: {
412
- ...prevState.runs,
413
- [runId]: {
414
- ...prevState.runs[runId],
415
- expertKey,
416
- runResult: (prevState.runs[runId]?.runResult ?? "") + event.delta
417
- }
418
- }
419
- },
420
- handled: true
421
- };
422
- }
423
- case "completeStreamingRunResult": {
424
- return {
425
- newState: {
426
- ...prevState,
427
- runs: {
428
- ...prevState.runs,
429
- [runId]: {
430
- ...prevState.runs[runId],
431
- expertKey,
432
- isRunResultActive: false
433
- }
434
- }
435
- },
436
- handled: true
437
- };
438
- }
439
- default:
440
- return { newState: prevState, handled: false };
441
- }
338
+ const { runId, expertKey } = event;
339
+ switch (event.type) {
340
+ case "startStreamingReasoning": return {
341
+ newState: {
342
+ ...prevState,
343
+ runs: {
344
+ ...prevState.runs,
345
+ [runId]: {
346
+ expertKey,
347
+ reasoning: "",
348
+ isReasoningActive: true
349
+ }
350
+ }
351
+ },
352
+ handled: true
353
+ };
354
+ case "streamReasoning": return {
355
+ newState: {
356
+ ...prevState,
357
+ runs: {
358
+ ...prevState.runs,
359
+ [runId]: {
360
+ ...prevState.runs[runId],
361
+ expertKey,
362
+ reasoning: (prevState.runs[runId]?.reasoning ?? "") + event.delta
363
+ }
364
+ }
365
+ },
366
+ handled: true
367
+ };
368
+ case "completeStreamingReasoning": return {
369
+ newState: {
370
+ ...prevState,
371
+ runs: {
372
+ ...prevState.runs,
373
+ [runId]: {
374
+ ...prevState.runs[runId],
375
+ expertKey,
376
+ isReasoningActive: false
377
+ }
378
+ }
379
+ },
380
+ handled: false
381
+ };
382
+ case "startStreamingRunResult": return {
383
+ newState: {
384
+ ...prevState,
385
+ runs: {
386
+ ...prevState.runs,
387
+ [runId]: {
388
+ expertKey,
389
+ reasoning: void 0,
390
+ isReasoningActive: false,
391
+ runResult: "",
392
+ isRunResultActive: true
393
+ }
394
+ }
395
+ },
396
+ handled: true
397
+ };
398
+ case "streamRunResult": return {
399
+ newState: {
400
+ ...prevState,
401
+ runs: {
402
+ ...prevState.runs,
403
+ [runId]: {
404
+ ...prevState.runs[runId],
405
+ expertKey,
406
+ runResult: (prevState.runs[runId]?.runResult ?? "") + event.delta
407
+ }
408
+ }
409
+ },
410
+ handled: true
411
+ };
412
+ case "completeStreamingRunResult": return {
413
+ newState: {
414
+ ...prevState,
415
+ runs: {
416
+ ...prevState.runs,
417
+ [runId]: {
418
+ ...prevState.runs[runId],
419
+ expertKey,
420
+ isRunResultActive: false
421
+ }
422
+ }
423
+ },
424
+ handled: true
425
+ };
426
+ default: return {
427
+ newState: prevState,
428
+ handled: false
429
+ };
430
+ }
442
431
  }
432
+ /**
433
+ * Hook for managing Run state from RunEvent stream.
434
+ *
435
+ * Architecture:
436
+ * - ExpertStateEvent → ActivityOrGroup[] (accumulated, append-only)
437
+ * - StreamingEvent → StreamingState (latest only, for display)
438
+ *
439
+ * IMPORTANT: activities are append-only and never cleared.
440
+ * This is required for compatibility with Ink's <Static> component.
441
+ */
443
442
  function useRun() {
444
- const [activities, setActivities] = useState([]);
445
- const [streaming, setStreaming] = useState({ runs: {} });
446
- const [eventCount, setEventCount] = useState(0);
447
- const [isComplete, setIsComplete] = useState(false);
448
- const stateRef = useRef(createInitialActivityProcessState());
449
- const clearStreaming = useCallback(() => {
450
- setStreaming({ runs: {} });
451
- }, []);
452
- const handleStreamingEvent = useCallback((event) => {
453
- let handled = false;
454
- setStreaming((prev) => {
455
- const result = processStreamingEvent(event, prev);
456
- handled = result.handled;
457
- return result.newState;
458
- });
459
- return handled;
460
- }, []);
461
- const processEvent = useCallback((event) => {
462
- const newActivities = [];
463
- const addActivity = (activity) => newActivities.push(activity);
464
- processRunEventToActivity(stateRef.current, event, addActivity);
465
- if (newActivities.length > 0) {
466
- setActivities((prev) => [...prev, ...newActivities]);
467
- }
468
- const rootRunComplete = Array.from(stateRef.current.runStates.values()).some(
469
- (rs) => rs.isComplete && !rs.delegatedBy
470
- );
471
- setIsComplete(rootRunComplete);
472
- }, []);
473
- const clearRunStreaming = useCallback((runId) => {
474
- setStreaming((prev) => {
475
- const { [runId]: _, ...rest } = prev.runs;
476
- return { runs: rest };
477
- });
478
- }, []);
479
- const addEvent = useCallback(
480
- (event) => {
481
- if (isStreamingEvent(event)) {
482
- const handled = handleStreamingEvent(event);
483
- if (handled) {
484
- setEventCount((prev) => prev + 1);
485
- return;
486
- }
487
- }
488
- if ("type" in event && "runId" in event && (event.type === "completeRun" || event.type === "stopRunByError")) {
489
- clearRunStreaming(event.runId);
490
- }
491
- processEvent(event);
492
- setEventCount((prev) => prev + 1);
493
- },
494
- [handleStreamingEvent, clearRunStreaming, processEvent]
495
- );
496
- const appendHistoricalEvents = useCallback((historicalEvents) => {
497
- const newActivities = [];
498
- const addActivity = (activity) => newActivities.push(activity);
499
- for (const event of historicalEvents) {
500
- processRunEventToActivity(stateRef.current, event, addActivity);
501
- }
502
- if (newActivities.length > 0) {
503
- setActivities((prev) => [...prev, ...newActivities]);
504
- }
505
- setEventCount((prev) => prev + historicalEvents.length);
506
- const rootRunComplete = Array.from(stateRef.current.runStates.values()).some(
507
- (rs) => rs.isComplete && !rs.delegatedBy
508
- );
509
- setIsComplete(rootRunComplete);
510
- }, []);
511
- return {
512
- activities,
513
- streaming,
514
- isComplete,
515
- eventCount,
516
- addEvent,
517
- appendHistoricalEvents,
518
- clearStreaming
519
- };
443
+ const [activities, setActivities] = useState([]);
444
+ const [streaming, setStreaming] = useState({ runs: {} });
445
+ const [eventCount, setEventCount] = useState(0);
446
+ const [isComplete, setIsComplete] = useState(false);
447
+ const stateRef = useRef(createInitialActivityProcessState());
448
+ const clearStreaming = useCallback(() => {
449
+ setStreaming({ runs: {} });
450
+ }, []);
451
+ const handleStreamingEvent = useCallback((event) => {
452
+ let handled = false;
453
+ setStreaming((prev) => {
454
+ const result = processStreamingEvent(event, prev);
455
+ handled = result.handled;
456
+ return result.newState;
457
+ });
458
+ return handled;
459
+ }, []);
460
+ const processEvent = useCallback((event) => {
461
+ const newActivities = [];
462
+ const addActivity = (activity) => newActivities.push(activity);
463
+ processRunEventToActivity(stateRef.current, event, addActivity);
464
+ if (newActivities.length > 0) setActivities((prev) => [...prev, ...newActivities]);
465
+ setIsComplete(Array.from(stateRef.current.runStates.values()).some((rs) => rs.isComplete && !rs.delegatedBy));
466
+ }, []);
467
+ const clearRunStreaming = useCallback((runId) => {
468
+ setStreaming((prev) => {
469
+ const { [runId]: _, ...rest } = prev.runs;
470
+ return { runs: rest };
471
+ });
472
+ }, []);
473
+ return {
474
+ activities,
475
+ streaming,
476
+ isComplete,
477
+ eventCount,
478
+ addEvent: useCallback((event) => {
479
+ if (isStreamingEvent(event)) {
480
+ if (handleStreamingEvent(event)) {
481
+ setEventCount((prev) => prev + 1);
482
+ return;
483
+ }
484
+ }
485
+ if ("type" in event && "runId" in event && (event.type === "completeRun" || event.type === "stopRunByError")) clearRunStreaming(event.runId);
486
+ processEvent(event);
487
+ setEventCount((prev) => prev + 1);
488
+ }, [
489
+ handleStreamingEvent,
490
+ clearRunStreaming,
491
+ processEvent
492
+ ]),
493
+ appendHistoricalEvents: useCallback((historicalEvents) => {
494
+ const newActivities = [];
495
+ const addActivity = (activity) => newActivities.push(activity);
496
+ for (const event of historicalEvents) processRunEventToActivity(stateRef.current, event, addActivity);
497
+ if (newActivities.length > 0) setActivities((prev) => [...prev, ...newActivities]);
498
+ setEventCount((prev) => prev + historicalEvents.length);
499
+ setIsComplete(Array.from(stateRef.current.runStates.values()).some((rs) => rs.isComplete && !rs.delegatedBy));
500
+ }, []),
501
+ clearStreaming
502
+ };
520
503
  }
521
504
 
522
- // src/hooks/use-job-stream.ts
505
+ //#endregion
506
+ //#region src/hooks/use-job-stream.ts
523
507
  function useJobStream(options) {
524
- const { jobId, connect, enabled = true } = options;
525
- const shouldConnect = Boolean(jobId && enabled);
526
- const { activities, streaming, addEvent } = useRun();
527
- const [isConnected, setIsConnected] = useState(false);
528
- const [error, setError] = useState(null);
529
- const addEventRef = useRef(addEvent);
530
- addEventRef.current = addEvent;
531
- const connectRef = useRef(connect);
532
- connectRef.current = connect;
533
- useEffect(() => {
534
- if (!shouldConnect || !jobId) {
535
- setIsConnected(false);
536
- return;
537
- }
538
- const controller = new AbortController();
539
- async function run() {
540
- setError(null);
541
- setIsConnected(true);
542
- try {
543
- await consumeStream(connectRef.current, jobId, controller.signal, (event) => {
544
- addEventRef.current(event);
545
- });
546
- } catch (err) {
547
- if (isAbortError(err)) return;
548
- setError(err instanceof Error ? err : new Error(String(err)));
549
- } finally {
550
- setIsConnected(false);
551
- }
552
- }
553
- run();
554
- return () => {
555
- controller.abort();
556
- };
557
- }, [shouldConnect, jobId]);
558
- const latestActivity = useMemo(
559
- () => activities.length > 0 ? activities[activities.length - 1] : null,
560
- [activities]
561
- );
562
- return { activities, streaming, latestActivity, isConnected, error };
508
+ const { jobId, connect, enabled = true } = options;
509
+ const shouldConnect = Boolean(jobId && enabled);
510
+ const { activities, streaming, addEvent } = useRun();
511
+ const [isConnected, setIsConnected] = useState(false);
512
+ const [error, setError] = useState(null);
513
+ const addEventRef = useRef(addEvent);
514
+ addEventRef.current = addEvent;
515
+ const connectRef = useRef(connect);
516
+ connectRef.current = connect;
517
+ useEffect(() => {
518
+ if (!shouldConnect || !jobId) {
519
+ setIsConnected(false);
520
+ return;
521
+ }
522
+ const controller = new AbortController();
523
+ async function run() {
524
+ setError(null);
525
+ setIsConnected(true);
526
+ try {
527
+ await consumeStream(connectRef.current, jobId, controller.signal, (event) => {
528
+ addEventRef.current(event);
529
+ });
530
+ } catch (err) {
531
+ if (isAbortError(err)) return;
532
+ setError(err instanceof Error ? err : new Error(String(err)));
533
+ } finally {
534
+ setIsConnected(false);
535
+ }
536
+ }
537
+ run();
538
+ return () => {
539
+ controller.abort();
540
+ };
541
+ }, [shouldConnect, jobId]);
542
+ return {
543
+ activities,
544
+ streaming,
545
+ latestActivity: useMemo(() => activities.length > 0 ? activities[activities.length - 1] : null, [activities]),
546
+ isConnected,
547
+ error
548
+ };
563
549
  }
550
+
551
+ //#endregion
552
+ //#region src/hooks/use-job-streams.ts
564
553
  function useJobStreams(options) {
565
- const { jobs, connect } = options;
566
- const [states, setStates] = useState(/* @__PURE__ */ new Map());
567
- const controllersRef = useRef(/* @__PURE__ */ new Map());
568
- const activityStateRef = useRef(/* @__PURE__ */ new Map());
569
- const connectRef = useRef(connect);
570
- connectRef.current = connect;
571
- const connectToJob = useCallback(async (jobId, signal) => {
572
- setStates((prev) => {
573
- const next = new Map(prev);
574
- next.set(jobId, { latestActivity: null, isConnected: true });
575
- return next;
576
- });
577
- let state = activityStateRef.current.get(jobId);
578
- if (!state) {
579
- state = createInitialActivityProcessState();
580
- activityStateRef.current.set(jobId, state);
581
- }
582
- try {
583
- await consumeStream(connectRef.current, jobId, signal, (event) => {
584
- let latestActivity = null;
585
- processRunEventToActivity(state, event, (activity) => {
586
- latestActivity = activity;
587
- });
588
- if (latestActivity) {
589
- setStates((prev) => {
590
- const next = new Map(prev);
591
- next.set(jobId, { latestActivity, isConnected: true });
592
- return next;
593
- });
594
- }
595
- });
596
- } catch (err) {
597
- if (isAbortError(err)) return;
598
- console.error(`Stream connection failed for job ${jobId}:`, err);
599
- } finally {
600
- setStates((prev) => {
601
- const current = prev.get(jobId);
602
- if (!current) return prev;
603
- const next = new Map(prev);
604
- next.set(jobId, { ...current, isConnected: false });
605
- return next;
606
- });
607
- }
608
- }, []);
609
- useEffect(() => {
610
- const enabledIds = new Set(jobs.filter((j) => j.enabled).map((j) => j.id));
611
- for (const [jobId, controller] of controllersRef.current) {
612
- if (!enabledIds.has(jobId)) {
613
- controller.abort();
614
- controllersRef.current.delete(jobId);
615
- activityStateRef.current.delete(jobId);
616
- setStates((prev) => {
617
- const next = new Map(prev);
618
- next.delete(jobId);
619
- return next;
620
- });
621
- }
622
- }
623
- for (const jobId of enabledIds) {
624
- if (!controllersRef.current.has(jobId)) {
625
- const controller = new AbortController();
626
- controllersRef.current.set(jobId, controller);
627
- connectToJob(jobId, controller.signal);
628
- }
629
- }
630
- }, [jobs, connectToJob]);
631
- useEffect(() => {
632
- return () => {
633
- for (const controller of controllersRef.current.values()) {
634
- controller.abort();
635
- }
636
- controllersRef.current.clear();
637
- activityStateRef.current.clear();
638
- };
639
- }, []);
640
- return states;
554
+ const { jobs, connect } = options;
555
+ const [states, setStates] = useState(/* @__PURE__ */ new Map());
556
+ const controllersRef = useRef(/* @__PURE__ */ new Map());
557
+ const activityStateRef = useRef(/* @__PURE__ */ new Map());
558
+ const connectRef = useRef(connect);
559
+ connectRef.current = connect;
560
+ const connectToJob = useCallback(async (jobId, signal) => {
561
+ setStates((prev) => {
562
+ const next = new Map(prev);
563
+ next.set(jobId, {
564
+ latestActivity: null,
565
+ isConnected: true
566
+ });
567
+ return next;
568
+ });
569
+ let state = activityStateRef.current.get(jobId);
570
+ if (!state) {
571
+ state = createInitialActivityProcessState();
572
+ activityStateRef.current.set(jobId, state);
573
+ }
574
+ try {
575
+ await consumeStream(connectRef.current, jobId, signal, (event) => {
576
+ let latestActivity = null;
577
+ processRunEventToActivity(state, event, (activity) => {
578
+ latestActivity = activity;
579
+ });
580
+ if (latestActivity) setStates((prev) => {
581
+ const next = new Map(prev);
582
+ next.set(jobId, {
583
+ latestActivity,
584
+ isConnected: true
585
+ });
586
+ return next;
587
+ });
588
+ });
589
+ } catch (err) {
590
+ if (isAbortError(err)) return;
591
+ console.error(`Stream connection failed for job ${jobId}:`, err);
592
+ } finally {
593
+ setStates((prev) => {
594
+ const current = prev.get(jobId);
595
+ if (!current) return prev;
596
+ const next = new Map(prev);
597
+ next.set(jobId, {
598
+ ...current,
599
+ isConnected: false
600
+ });
601
+ return next;
602
+ });
603
+ }
604
+ }, []);
605
+ useEffect(() => {
606
+ const enabledIds = new Set(jobs.filter((j) => j.enabled).map((j) => j.id));
607
+ for (const [jobId, controller] of controllersRef.current) if (!enabledIds.has(jobId)) {
608
+ controller.abort();
609
+ controllersRef.current.delete(jobId);
610
+ activityStateRef.current.delete(jobId);
611
+ setStates((prev) => {
612
+ const next = new Map(prev);
613
+ next.delete(jobId);
614
+ return next;
615
+ });
616
+ }
617
+ for (const jobId of enabledIds) if (!controllersRef.current.has(jobId)) {
618
+ const controller = new AbortController();
619
+ controllersRef.current.set(jobId, controller);
620
+ connectToJob(jobId, controller.signal);
621
+ }
622
+ }, [jobs, connectToJob]);
623
+ useEffect(() => {
624
+ return () => {
625
+ for (const controller of controllersRef.current.values()) controller.abort();
626
+ controllersRef.current.clear();
627
+ activityStateRef.current.clear();
628
+ };
629
+ }, []);
630
+ return states;
641
631
  }
642
632
 
643
- // src/utils/group-by-run.ts
633
+ //#endregion
634
+ //#region src/utils/group-by-run.ts
635
+ /**
636
+ * Extract base properties from ActivityOrGroup for grouping.
637
+ */
644
638
  function getActivityProps(activityOrGroup) {
645
- if (activityOrGroup.type === "parallelGroup") {
646
- const firstActivity = activityOrGroup.activities[0];
647
- return {
648
- runId: activityOrGroup.runId,
649
- expertKey: activityOrGroup.expertKey,
650
- delegatedBy: firstActivity?.delegatedBy
651
- };
652
- }
653
- return activityOrGroup;
639
+ if (activityOrGroup.type === "parallelGroup") {
640
+ const firstActivity = activityOrGroup.activities[0];
641
+ return {
642
+ runId: activityOrGroup.runId,
643
+ expertKey: activityOrGroup.expertKey,
644
+ delegatedBy: firstActivity?.delegatedBy
645
+ };
646
+ }
647
+ return activityOrGroup;
654
648
  }
649
+ /**
650
+ * Groups activities by their runId while preserving order.
651
+ *
652
+ * This function groups activities so that each run can be displayed in its own
653
+ * visual section (e.g., separate <Static> components in Ink).
654
+ *
655
+ * @param activities - Array of activities or groups to group
656
+ * @returns Array of RunGroup objects, ordered by first appearance
657
+ */
655
658
  function groupActivitiesByRun(activities) {
656
- const groupMap = /* @__PURE__ */ new Map();
657
- const order = [];
658
- for (const activityOrGroup of activities) {
659
- const { runId, expertKey, delegatedBy } = getActivityProps(activityOrGroup);
660
- if (!groupMap.has(runId)) {
661
- groupMap.set(runId, {
662
- runId,
663
- expertKey,
664
- activities: [],
665
- delegatedBy
666
- });
667
- order.push(runId);
668
- }
669
- const group = groupMap.get(runId);
670
- group.activities.push(activityOrGroup);
671
- }
672
- return order.map((runId) => groupMap.get(runId));
659
+ const groupMap = /* @__PURE__ */ new Map();
660
+ const order = [];
661
+ for (const activityOrGroup of activities) {
662
+ const { runId, expertKey, delegatedBy } = getActivityProps(activityOrGroup);
663
+ if (!groupMap.has(runId)) {
664
+ groupMap.set(runId, {
665
+ runId,
666
+ expertKey,
667
+ activities: [],
668
+ delegatedBy
669
+ });
670
+ order.push(runId);
671
+ }
672
+ groupMap.get(runId).activities.push(activityOrGroup);
673
+ }
674
+ return order.map((runId) => groupMap.get(runId));
673
675
  }
674
676
 
677
+ //#endregion
675
678
  export { createInitialActivityProcessState, groupActivitiesByRun, processRunEventToActivity, toolToActivity, useJobStream, useJobStreams, useRun };
676
- //# sourceMappingURL=index.js.map
677
679
  //# sourceMappingURL=index.js.map