@perstack/react 0.0.45 → 0.0.46

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/README.md CHANGED
@@ -12,18 +12,18 @@ pnpm add @perstack/react
12
12
 
13
13
  ## Usage
14
14
 
15
- ### useLogStore
15
+ ### useRun
16
16
 
17
- The main hook for managing Perstack events. It separates events into:
18
- - **LogEntry[]** - Accumulated log from RunEvent (state machine transitions)
19
- - **RuntimeState** - Current state from RuntimeEvent (runtime environment)
17
+ The main hook for managing Perstack run state. It processes events into:
18
+
19
+ - **activities** - Accumulated activities from RunEvent (append-only)
20
+ - **streaming** - Current streaming state for real-time display
20
21
 
21
22
  ```tsx
22
- import { useLogStore } from "@perstack/react"
23
+ import { useRun } from "@perstack/react"
23
24
 
24
- function MyComponent() {
25
- const { logs, runtimeState, isComplete, eventCount, addEvent, appendHistoricalEvents } =
26
- useLogStore()
25
+ function ExpertRunner() {
26
+ const { activities, streaming, isComplete, addEvent, appendHistoricalEvents } = useRun()
27
27
 
28
28
  // Add events from your event source
29
29
  useEffect(() => {
@@ -36,19 +36,17 @@ function MyComponent() {
36
36
 
37
37
  return (
38
38
  <div>
39
- {logs.map((entry) => (
40
- <LogRow key={entry.id} action={entry.action} />
41
- ))}
42
- {Object.entries(runtimeState.streaming.runs).map(([runId, run]) => (
43
- <div key={runId}>
44
- {run.isReasoningActive && (
45
- <div>[{run.expertKey}] Reasoning: {run.reasoning}</div>
46
- )}
47
- {run.isRunResultActive && (
48
- <div>[{run.expertKey}] Generating: {run.runResult}</div>
49
- )}
50
- </div>
39
+ {/* Show streaming content (grouped by run for parallel execution) */}
40
+ {Object.entries(streaming.runs).map(([runId, run]) => (
41
+ run.isReasoningActive && (
42
+ <div key={runId}>[{run.expertKey}] Reasoning: {run.reasoning}</div>
43
+ )
51
44
  ))}
45
+
46
+ {/* Show accumulated activities */}
47
+ <ActivityLog activities={activities} />
48
+
49
+ {isComplete && <div>Run complete!</div>}
52
50
  </div>
53
51
  )
54
52
  }
@@ -89,58 +87,44 @@ function JobActivityView({ jobId, isRunning }: { jobId: string; isRunning: boole
89
87
  }
90
88
  ```
91
89
 
92
- ### useRuntimeState
93
-
94
- A lower-level hook for managing RuntimeState separately.
95
-
96
- ```tsx
97
- import { useRuntimeState } from "@perstack/react"
98
-
99
- function MyComponent() {
100
- const { runtimeState, handleRuntimeEvent, clearStreaming, resetRuntimeState } = useRuntimeState()
101
-
102
- // Returns true if the event was handled (RuntimeEvent)
103
- // Returns false if the event should be processed elsewhere (RunEvent)
104
- const wasHandled = handleRuntimeEvent(event)
105
- }
106
- ```
107
-
108
90
  ### Utility Functions
109
91
 
110
92
  For advanced use cases, you can use the utility functions directly:
111
93
 
112
94
  ```tsx
113
95
  import {
114
- createInitialLogProcessState,
115
- processRunEventToLog,
116
- toolToCheckpointAction,
96
+ createInitialActivityProcessState,
97
+ processRunEventToActivity,
98
+ toolToActivity,
99
+ groupActivitiesByRun,
117
100
  } from "@perstack/react"
118
101
 
119
102
  // Create processing state
120
- const state = createInitialLogProcessState()
103
+ const state = createInitialActivityProcessState()
121
104
 
122
- // Process RunEvent into LogEntry
123
- const logs = []
124
- processRunEventToLog(state, event, (entry) => logs.push(entry))
105
+ // Process RunEvent into Activity
106
+ const activities = []
107
+ processRunEventToActivity(state, event, (activity) => activities.push(activity))
125
108
 
126
- // Convert a single tool call + result to CheckpointAction
127
- const action = toolToCheckpointAction(toolCall, toolResult, reasoning)
109
+ // Group activities by run ID
110
+ const grouped = groupActivitiesByRun(activities)
128
111
  ```
129
112
 
130
113
  ## API
131
114
 
132
- ### useLogStore()
115
+ ### useRun()
133
116
 
134
117
  Returns an object with:
135
118
 
136
- - `logs`: Array of `LogEntry` representing completed actions (append-only)
137
- - `runtimeState`: Current `RuntimeState` including streaming state
119
+ - `activities`: Array of `ActivityOrGroup` representing completed actions (append-only)
120
+ - `streaming`: Current `StreamingState` for real-time display
138
121
  - `isComplete`: Whether the run is complete
139
122
  - `eventCount`: Total number of processed events
140
123
  - `addEvent(event)`: Add a new event to process
141
- - `appendHistoricalEvents(events)`: Append historical events to logs
124
+ - `appendHistoricalEvents(events)`: Bulk load historical events
125
+ - `clearStreaming()`: Clear streaming state
142
126
 
143
- **Note:** Logs are append-only and never cleared. This is required for compatibility with Ink's `<Static>` component.
127
+ **Note:** Activities are append-only and never cleared. This is required for compatibility with Ink's `<Static>` component.
144
128
 
145
129
  ### useEventStream(options)
146
130
 
@@ -163,47 +147,8 @@ The hook automatically:
163
147
  - Processes events through `useRun` internally
164
148
  - Clears error state on reconnection
165
149
 
166
- ### useRuntimeState()
167
-
168
- Returns an object with:
169
-
170
- - `runtimeState`: Current `RuntimeState`
171
- - `handleRuntimeEvent(event)`: Process a RuntimeEvent, returns `true` if handled
172
- - `clearStreaming()`: Reset streaming state
173
- - `resetRuntimeState()`: Reset entire runtime state
174
-
175
150
  ## Types
176
151
 
177
- ### LogEntry
178
-
179
- Wraps `CheckpointAction` with an ID for React key purposes:
180
-
181
- ```typescript
182
- type LogEntry = {
183
- id: string
184
- action: CheckpointAction
185
- }
186
- ```
187
-
188
- ### RuntimeState
189
-
190
- Captures current runtime environment state:
191
-
192
- ```typescript
193
- type RuntimeState = {
194
- query?: string
195
- expertName?: string
196
- model?: string
197
- runtime?: string
198
- runtimeVersion?: string
199
- skills: Map<string, SkillState>
200
- dockerBuild?: DockerBuildState
201
- dockerContainers: Map<string, DockerContainerState>
202
- proxyAccess?: ProxyAccessState
203
- streaming: StreamingState
204
- }
205
- ```
206
-
207
152
  ### StreamingState
208
153
 
209
154
  Real-time streaming state, organized by run ID to support parallel execution:
@@ -1,40 +1,5 @@
1
1
  import { PerstackEvent, ActivityOrGroup, ToolCall, ToolResult, Activity } from '@perstack/core';
2
2
 
3
- /**
4
- * RuntimeState represents the current state of the runtime environment.
5
- * This is derived from RuntimeEvent and only the latest state matters.
6
- *
7
- * Unlike LogEntry (which accumulates), RuntimeState is replaced on each update.
8
- */
9
- /** Skill connection state */
10
- type SkillState = {
11
- name: string;
12
- status: "starting" | "connected" | "disconnected";
13
- serverInfo?: {
14
- name: string;
15
- version: string;
16
- };
17
- };
18
- /** Docker build progress state */
19
- type DockerBuildState = {
20
- stage: "pulling" | "building" | "complete" | "error";
21
- service: string;
22
- message: string;
23
- progress?: number;
24
- };
25
- /** Docker container status state */
26
- type DockerContainerState = {
27
- status: "starting" | "running" | "healthy" | "unhealthy" | "stopped" | "error";
28
- service: string;
29
- message?: string;
30
- };
31
- /** Proxy access state (most recent) */
32
- type ProxyAccessState = {
33
- action: "allowed" | "blocked";
34
- domain: string;
35
- port: number;
36
- reason?: string;
37
- };
38
3
  /** Per-run streaming state for real-time display */
39
4
  type PerRunStreamingState = {
40
5
  /** Expert key for this run */
@@ -53,31 +18,6 @@ type StreamingState = {
53
18
  /** Per-run streaming state, keyed by runId */
54
19
  runs: Record<string, PerRunStreamingState>;
55
20
  };
56
- /**
57
- * RuntimeState captures the current state of the runtime environment.
58
- * All fields represent the latest state from RuntimeEvent.
59
- */
60
- type RuntimeState = {
61
- /** Current query being processed */
62
- query?: string;
63
- /** Current expert name */
64
- expertName?: string;
65
- /** Model being used */
66
- model?: string;
67
- /** Runtime type (e.g., "docker", "local") */
68
- runtime?: string;
69
- /** Runtime version */
70
- runtimeVersion?: string;
71
- skills: Map<string, SkillState>;
72
- /** Docker build progress (latest) */
73
- dockerBuild?: DockerBuildState;
74
- /** Docker container states (keyed by service name) */
75
- dockerContainers: Map<string, DockerContainerState>;
76
- proxyAccess?: ProxyAccessState;
77
- streaming: StreamingState;
78
- };
79
- /** Creates an empty initial runtime state */
80
- declare function createInitialRuntimeState(): RuntimeState;
81
21
 
82
22
  /**
83
23
  * Options for creating an event stream connection.
@@ -222,18 +162,6 @@ type RunResult = {
222
162
  */
223
163
  declare function useRun(): RunResult;
224
164
 
225
- type RuntimeResult = {
226
- runtimeState: RuntimeState;
227
- handleRuntimeEvent: (event: PerstackEvent) => boolean;
228
- resetRuntimeState: () => void;
229
- };
230
- /**
231
- * Hook for managing RuntimeState from RuntimeEvent stream.
232
- * Only handles infrastructure-level events (skills, docker, proxy).
233
- * Streaming events are now handled by useRun.
234
- */
235
- declare function useRuntime(): RuntimeResult;
236
-
237
165
  /**
238
166
  * Represents a group of activities belonging to the same run
239
167
  */
@@ -257,4 +185,4 @@ type RunGroup = {
257
185
  */
258
186
  declare function groupActivitiesByRun(activities: ActivityOrGroup[]): RunGroup[];
259
187
 
260
- export { type ActivityProcessState, type DockerBuildState, type DockerContainerState, type EventSourceFactory, type EventStreamOptions, type EventStreamState, type PerRunStreamingState, type ProxyAccessState, type RunGroup, type RunResult, type RuntimeResult, type RuntimeState, type SkillState, type StreamingState, type UseEventStreamOptions, type ActivityProcessState as UtilActivityProcessState, createInitialActivityProcessState, createInitialRuntimeState, groupActivitiesByRun, processRunEventToActivity, toolToActivity, useEventStream, useRun, useRuntime };
188
+ export { type ActivityProcessState, type EventSourceFactory, type EventStreamOptions, type EventStreamState, type PerRunStreamingState, type RunGroup, type RunResult, type StreamingState, type UseEventStreamOptions, type ActivityProcessState as UtilActivityProcessState, createInitialActivityProcessState, groupActivitiesByRun, processRunEventToActivity, toolToActivity, useEventStream, useRun };
package/dist/src/index.js CHANGED
@@ -564,132 +564,6 @@ function useEventStream(options) {
564
564
  };
565
565
  }
566
566
 
567
- // src/types/runtime-state.ts
568
- function createInitialRuntimeState() {
569
- return {
570
- skills: /* @__PURE__ */ new Map(),
571
- dockerContainers: /* @__PURE__ */ new Map(),
572
- streaming: { runs: {} }
573
- };
574
- }
575
-
576
- // src/hooks/use-runtime.ts
577
- var RUNTIME_EVENT_TYPES = /* @__PURE__ */ new Set([
578
- "initializeRuntime",
579
- "skillStarting",
580
- "skillConnected",
581
- "skillDisconnected",
582
- "skillStderr",
583
- "dockerBuildProgress",
584
- "dockerContainerStatus",
585
- "proxyAccess"
586
- ]);
587
- var isRuntimeEvent = (event) => "type" in event && RUNTIME_EVENT_TYPES.has(event.type);
588
- function useRuntime() {
589
- const [runtimeState, setRuntimeState] = useState(createInitialRuntimeState);
590
- const handleRuntimeEvent = useCallback((event) => {
591
- if (!isRuntimeEvent(event)) {
592
- return false;
593
- }
594
- switch (event.type) {
595
- case "initializeRuntime": {
596
- if (event.type !== "initializeRuntime") return false;
597
- setRuntimeState((prev) => ({
598
- ...prev,
599
- query: event.query,
600
- expertName: event.expertName,
601
- model: event.model,
602
- runtime: event.runtime,
603
- runtimeVersion: event.runtimeVersion
604
- }));
605
- return true;
606
- }
607
- case "skillStarting": {
608
- if (event.type !== "skillStarting") return false;
609
- setRuntimeState((prev) => {
610
- const skills = new Map(prev.skills);
611
- skills.set(event.skillName, { name: event.skillName, status: "starting" });
612
- return { ...prev, skills };
613
- });
614
- return true;
615
- }
616
- case "skillConnected": {
617
- if (event.type !== "skillConnected") return false;
618
- setRuntimeState((prev) => {
619
- const skills = new Map(prev.skills);
620
- skills.set(event.skillName, {
621
- name: event.skillName,
622
- status: "connected",
623
- serverInfo: event.serverInfo
624
- });
625
- return { ...prev, skills };
626
- });
627
- return true;
628
- }
629
- case "skillDisconnected": {
630
- if (event.type !== "skillDisconnected") return false;
631
- setRuntimeState((prev) => {
632
- const skills = new Map(prev.skills);
633
- skills.set(event.skillName, { name: event.skillName, status: "disconnected" });
634
- return { ...prev, skills };
635
- });
636
- return true;
637
- }
638
- case "skillStderr":
639
- return true;
640
- case "dockerBuildProgress": {
641
- if (event.type !== "dockerBuildProgress") return false;
642
- setRuntimeState((prev) => ({
643
- ...prev,
644
- dockerBuild: {
645
- stage: event.stage,
646
- service: event.service,
647
- message: event.message,
648
- progress: event.progress
649
- }
650
- }));
651
- return true;
652
- }
653
- case "dockerContainerStatus": {
654
- if (event.type !== "dockerContainerStatus") return false;
655
- setRuntimeState((prev) => {
656
- const dockerContainers = new Map(prev.dockerContainers);
657
- dockerContainers.set(event.service, {
658
- status: event.status,
659
- service: event.service,
660
- message: event.message
661
- });
662
- return { ...prev, dockerContainers };
663
- });
664
- return true;
665
- }
666
- case "proxyAccess": {
667
- if (event.type !== "proxyAccess") return false;
668
- setRuntimeState((prev) => ({
669
- ...prev,
670
- proxyAccess: {
671
- action: event.action,
672
- domain: event.domain,
673
- port: event.port,
674
- reason: event.reason
675
- }
676
- }));
677
- return true;
678
- }
679
- default:
680
- return false;
681
- }
682
- }, []);
683
- const resetRuntimeState = useCallback(() => {
684
- setRuntimeState(createInitialRuntimeState());
685
- }, []);
686
- return {
687
- runtimeState,
688
- handleRuntimeEvent,
689
- resetRuntimeState
690
- };
691
- }
692
-
693
567
  // src/utils/group-by-run.ts
694
568
  function getActivityProps(activityOrGroup) {
695
569
  if (activityOrGroup.type === "parallelGroup") {
@@ -722,6 +596,6 @@ function groupActivitiesByRun(activities) {
722
596
  return order.map((runId) => groupMap.get(runId));
723
597
  }
724
598
 
725
- export { createInitialActivityProcessState, createInitialRuntimeState, groupActivitiesByRun, processRunEventToActivity, toolToActivity, useEventStream, useRun, useRuntime };
599
+ export { createInitialActivityProcessState, groupActivitiesByRun, processRunEventToActivity, toolToActivity, useEventStream, useRun };
726
600
  //# sourceMappingURL=index.js.map
727
601
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/event-to-activity.ts","../../src/hooks/use-run.ts","../../src/hooks/use-event-stream.ts","../../src/types/runtime-state.ts","../../src/hooks/use-runtime.ts","../../src/utils/group-by-run.ts"],"names":["runState","useState","useRef","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n Activity,\n ActivityOrGroup,\n ParallelActivitiesGroup,\n PerstackEvent,\n RunEvent,\n ToolCall,\n ToolResult,\n} from \"@perstack/core\"\nimport {\n BASE_SKILL_PREFIX,\n createBaseToolActivity,\n createGeneralToolActivity,\n} from \"@perstack/core\"\n\nconst TOOL_RESULT_EVENT_TYPES = new Set([\"resolveToolResults\", \"attemptCompletion\"])\n\n/**\n * Converts a tool call and result to an Activity.\n * Delegates to core's createBaseToolActivity/createGeneralToolActivity to avoid duplication.\n */\nexport function toolToActivity(\n toolCall: ToolCall,\n toolResult: ToolResult,\n reasoning: string | undefined,\n meta: {\n id: string\n expertKey: string\n runId: string\n previousActivityId?: string\n delegatedBy?: { expertKey: string; runId: string }\n },\n): Activity {\n const { skillName, toolName } = toolCall\n\n const baseActivity = skillName.startsWith(BASE_SKILL_PREFIX)\n ? createBaseToolActivity(toolName, toolCall, toolResult, reasoning)\n : createGeneralToolActivity(skillName, toolName, toolCall, toolResult, reasoning)\n\n // Override the base fields with the correct metadata\n return {\n ...baseActivity,\n id: meta.id,\n expertKey: meta.expertKey,\n runId: meta.runId,\n previousActivityId: meta.previousActivityId,\n delegatedBy: meta.delegatedBy,\n } as Activity\n}\n\ntype ToolState = {\n id: string\n toolCall: ToolCall\n logged: boolean\n}\n\n/**\n * Per-run state to support parallel execution.\n * Each run maintains its own independent state.\n */\ntype RunState = {\n expertKey: string\n queryLogged: boolean\n completionLogged: boolean\n isComplete: boolean\n completedReasoning?: string\n lastActivityId?: string\n delegatedBy?: {\n expertKey: string\n runId: string\n }\n /** Track if this run has pending delegate tool calls (for delegation complete detection) */\n pendingDelegateCount: number\n}\n\n/**\n * State for processing RunEvent stream into Activity[].\n * This state tracks tool calls and their results to create complete Activity items.\n *\n * Supports the daisy chain architecture:\n * - Within-Run ordering via lastActivityId (per-run state)\n * - Cross-Run ordering via delegatedBy (per-run state)\n *\n * Note: `tools` is NOT cleared on new run to support delegation results\n * that arrive after parent expert resumes with a new runId.\n */\nexport type ActivityProcessState = {\n /** Tool calls indexed by toolCallId - persisted across runs for delegation handling */\n tools: Map<string, ToolState>\n /** Per-run state to support parallel execution */\n runStates: Map<string, RunState>\n}\n\nexport function createInitialActivityProcessState(): ActivityProcessState {\n return {\n tools: new Map(),\n runStates: new Map(),\n }\n}\n\nfunction getOrCreateRunState(\n state: ActivityProcessState,\n runId: string,\n expertKey: string,\n): RunState {\n let runState = state.runStates.get(runId)\n if (!runState) {\n runState = {\n expertKey,\n queryLogged: false,\n completionLogged: false,\n isComplete: false,\n pendingDelegateCount: 0,\n }\n state.runStates.set(runId, runState)\n }\n return runState\n}\n\nconst isRunEvent = (event: PerstackEvent): event is RunEvent =>\n \"type\" in event && \"expertKey\" in event\n\nconst isCompleteStreamingReasoningEvent = (event: PerstackEvent): boolean =>\n \"type\" in event && event.type === \"completeStreamingReasoning\"\n\ntype DelegatedByInfo = {\n expert: { key: string }\n toolCallId: string\n toolName: string\n checkpointId: string\n runId: string\n}\n\nconst isToolCallsEvent = (event: RunEvent): event is RunEvent & { toolCalls: ToolCall[] } =>\n event.type === \"callTools\" && \"toolCalls\" in event\n\ntype DelegationTarget = {\n expert: { key: string; name: string; version: string }\n toolCallId: string\n toolName: string\n query: string\n}\n\nconst isStopRunByDelegateEvent = (\n event: RunEvent,\n): event is RunEvent & {\n checkpoint: { delegateTo?: DelegationTarget[] }\n} => event.type === \"stopRunByDelegate\" && \"checkpoint\" in event\n\nconst isStopRunByInteractiveToolEvent = (\n event: RunEvent,\n): event is RunEvent & {\n checkpoint: { pendingToolCalls?: ToolCall[] }\n} => event.type === \"stopRunByInteractiveTool\" && \"checkpoint\" in event\n\nconst isToolResultsEvent = (event: RunEvent): event is RunEvent & { toolResults: ToolResult[] } =>\n event.type === \"resolveToolResults\" && \"toolResults\" in event\n\nconst isToolResultEvent = (event: RunEvent): event is RunEvent & { toolResult: ToolResult } =>\n TOOL_RESULT_EVENT_TYPES.has(event.type) && \"toolResult\" in event\n\n/**\n * Wraps multiple activities in a ParallelActivitiesGroup with shared reasoning.\n * If only one activity, returns it directly.\n */\nfunction wrapInGroupIfParallel(\n activities: Activity[],\n reasoning: string | undefined,\n meta: { expertKey: string; runId: string; delegatedBy?: { expertKey: string; runId: string } },\n): ActivityOrGroup[] {\n if (activities.length <= 1) {\n return activities\n }\n\n // Remove reasoning from individual activities since it's on the group\n const activitiesWithoutReasoning = activities.map((a) => {\n const { reasoning: _, ...rest } = a\n return rest as Activity\n })\n\n const group: ParallelActivitiesGroup = {\n type: \"parallelGroup\",\n id: `parallel-${activities[0].id}`,\n expertKey: meta.expertKey,\n runId: meta.runId,\n reasoning,\n activities: activitiesWithoutReasoning,\n }\n\n return [group]\n}\n\n/**\n * Processes a RunEvent and produces Activity or ParallelActivitiesGroup items.\n * Only processes RunEvent (state machine transitions), not RuntimeEvent.\n *\n * @param state - Mutable processing state\n * @param event - The event to process\n * @param addActivity - Callback to add a new Activity or ParallelActivitiesGroup\n */\nexport function processRunEventToActivity(\n state: ActivityProcessState,\n event: PerstackEvent,\n addActivity: (activity: ActivityOrGroup) => void,\n): void {\n if (isCompleteStreamingReasoningEvent(event)) {\n const reasoningEvent = event as { text: string; runId: string; expertKey: string }\n const { runId, text, expertKey } = reasoningEvent\n const runState = state.runStates.get(runId)\n if (runState) {\n runState.completedReasoning = text\n } else {\n state.runStates.set(runId, {\n expertKey,\n queryLogged: false,\n completionLogged: false,\n isComplete: false,\n pendingDelegateCount: 0,\n completedReasoning: text,\n })\n }\n return\n }\n\n if (!isRunEvent(event)) {\n return\n }\n\n const runState = getOrCreateRunState(state, event.runId, event.expertKey)\n\n // Handle startRun - extract query from inputMessages and delegatedBy\n if (event.type === \"startRun\") {\n const startRunEvent = event as {\n inputMessages: Array<{ type: string; contents?: Array<{ type: string; text?: string }> }>\n initialCheckpoint?: {\n status?: string\n delegatedBy?: {\n expert: { key: string }\n toolCallId: string\n toolName: string\n checkpointId: string\n runId: string\n }\n }\n }\n const userMessage = startRunEvent.inputMessages.find((m) => m.type === \"userMessage\")\n const queryText = userMessage?.contents?.find((c) => c.type === \"textPart\")?.text\n\n // Extract delegatedBy from initialCheckpoint (only on first startRun for this runId)\n if (!runState.delegatedBy) {\n const delegatedByInfo = startRunEvent.initialCheckpoint?.delegatedBy\n if (delegatedByInfo) {\n runState.delegatedBy = {\n expertKey: delegatedByInfo.expert.key,\n runId: delegatedByInfo.runId,\n }\n }\n }\n\n // Check if this is a delegation return (parent expert resuming after delegation)\n // In this case, don't log the query again as it was already logged in the original run\n const isDelegationReturn =\n startRunEvent.initialCheckpoint?.status === \"stoppedByDelegate\" ||\n startRunEvent.initialCheckpoint?.status === \"stoppedByInteractiveTool\"\n\n if (queryText && !runState.queryLogged && !isDelegationReturn) {\n const activityId = `query-${event.runId}`\n addActivity({\n type: \"query\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n text: queryText,\n })\n runState.lastActivityId = activityId\n runState.queryLogged = true\n }\n return\n }\n\n // Handle resumeFromStop - extract delegatedBy from checkpoint for delegation return\n if (event.type === \"resumeFromStop\") {\n // Extract delegatedBy from checkpoint (only on first resumeFromStop for this runId)\n if (!runState.delegatedBy) {\n const resumeEvent = event as { checkpoint?: { delegatedBy?: DelegatedByInfo } }\n const delegatedByInfo = resumeEvent.checkpoint?.delegatedBy\n if (delegatedByInfo) {\n runState.delegatedBy = {\n expertKey: delegatedByInfo.expert.key,\n runId: delegatedByInfo.runId,\n }\n }\n }\n return\n }\n\n // Handle retry\n if (event.type === \"retry\") {\n const retryEvent = event as { reason: string }\n const activityId = `retry-${event.id}`\n addActivity({\n type: \"retry\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n reasoning: runState.completedReasoning,\n error: retryEvent.reason,\n message: \"\",\n })\n runState.lastActivityId = activityId\n runState.completedReasoning = undefined\n return\n }\n\n // Handle completion\n if (event.type === \"completeRun\") {\n if (!runState.completionLogged) {\n const text = (event as { text?: string }).text ?? \"\"\n const activityId = `completion-${event.runId}`\n addActivity({\n type: \"complete\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n reasoning: runState.completedReasoning,\n text,\n })\n runState.lastActivityId = activityId\n runState.completionLogged = true\n runState.isComplete = true\n runState.completedReasoning = undefined\n }\n return\n }\n\n // Handle error\n if (event.type === \"stopRunByError\") {\n const errorEvent = event as {\n error: { name: string; message: string; statusCode?: number; isRetryable?: boolean }\n }\n const activityId = `error-${event.id}`\n addActivity({\n type: \"error\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n errorName: errorEvent.error.name,\n error: errorEvent.error.message,\n isRetryable: errorEvent.error.isRetryable,\n })\n runState.lastActivityId = activityId\n runState.isComplete = true\n runState.completedReasoning = undefined\n return\n }\n\n // Track tool calls from callTools event\n if (isToolCallsEvent(event)) {\n for (const toolCall of event.toolCalls) {\n if (!state.tools.has(toolCall.id)) {\n state.tools.set(toolCall.id, { id: toolCall.id, toolCall, logged: false })\n }\n }\n }\n\n // Handle stopRunByDelegate - log delegation activities\n if (isStopRunByDelegateEvent(event)) {\n const reasoning = runState.completedReasoning\n const delegations = event.checkpoint.delegateTo ?? []\n runState.pendingDelegateCount += delegations.length\n\n const delegateActivities: Activity[] = []\n for (const delegation of delegations) {\n const existingTool = state.tools.get(delegation.toolCallId)\n if (!existingTool || !existingTool.logged) {\n // Mark as logged if exists\n if (existingTool) {\n existingTool.logged = true\n }\n const activityId = `delegate-${delegation.toolCallId}`\n delegateActivities.push({\n type: \"delegate\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n delegateExpertKey: delegation.expert.key,\n query: delegation.query,\n reasoning,\n })\n runState.lastActivityId = activityId\n }\n }\n\n // Wrap in group if multiple delegations\n const wrapped = wrapInGroupIfParallel(delegateActivities, reasoning, {\n expertKey: event.expertKey,\n runId: event.runId,\n delegatedBy: runState.delegatedBy,\n })\n for (const item of wrapped) {\n addActivity(item)\n }\n\n // Clear reasoning after delegation activities are logged\n runState.completedReasoning = undefined\n return\n }\n\n // Handle stopRunByInteractiveTool - log interactive tool activities\n if (isStopRunByInteractiveToolEvent(event)) {\n const reasoning = runState.completedReasoning\n const pendingToolCalls = event.checkpoint.pendingToolCalls ?? []\n\n const interactiveActivities: Activity[] = []\n for (const toolCall of pendingToolCalls) {\n const existingTool = state.tools.get(toolCall.id)\n if (!existingTool || !existingTool.logged) {\n // Mark as logged if exists\n if (existingTool) {\n existingTool.logged = true\n }\n const activityId = `interactive-${toolCall.id}`\n interactiveActivities.push({\n type: \"interactiveTool\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n skillName: toolCall.skillName,\n toolName: toolCall.toolName,\n args: toolCall.args as Record<string, unknown>,\n reasoning,\n })\n runState.lastActivityId = activityId\n }\n }\n\n // Wrap in group if multiple interactive tools\n const wrapped = wrapInGroupIfParallel(interactiveActivities, reasoning, {\n expertKey: event.expertKey,\n runId: event.runId,\n delegatedBy: runState.delegatedBy,\n })\n for (const item of wrapped) {\n addActivity(item)\n }\n\n // Clear reasoning after interactive tool activities are logged\n runState.completedReasoning = undefined\n return\n }\n\n // Process tool results\n if (isToolResultsEvent(event)) {\n const reasoning = runState.completedReasoning\n const toolActivities: Activity[] = []\n\n for (const toolResult of event.toolResults) {\n const tool = state.tools.get(toolResult.id)\n if (tool && !tool.logged) {\n const activityId = `action-${tool.id}`\n const activity = toolToActivity(tool.toolCall, toolResult, reasoning, {\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n })\n toolActivities.push(activity)\n runState.lastActivityId = activityId\n tool.logged = true\n }\n }\n\n if (toolActivities.length > 0) {\n // Wrap in group if multiple tool results\n const wrapped = wrapInGroupIfParallel(toolActivities, reasoning, {\n expertKey: event.expertKey,\n runId: event.runId,\n delegatedBy: runState.delegatedBy,\n })\n for (const item of wrapped) {\n addActivity(item)\n }\n runState.completedReasoning = undefined\n }\n } else if (isToolResultEvent(event)) {\n const { toolResult } = event\n const tool = state.tools.get(toolResult.id)\n if (tool && !tool.logged) {\n const activityId = `action-${tool.id}`\n const activity = toolToActivity(tool.toolCall, toolResult, runState.completedReasoning, {\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n })\n addActivity(activity)\n runState.lastActivityId = activityId\n tool.logged = true\n runState.completedReasoning = undefined\n }\n }\n}\n","import type { ActivityOrGroup, PerstackEvent, StreamingEvent } from \"@perstack/core\"\nimport { useCallback, useRef, useState } from \"react\"\nimport type { StreamingState } from \"../types/index.js\"\nimport {\n type ActivityProcessState,\n createInitialActivityProcessState,\n processRunEventToActivity,\n} from \"../utils/event-to-activity.js\"\n\nexport type { ActivityProcessState }\n\nconst STREAMING_EVENT_TYPES = new Set([\n \"startStreamingReasoning\",\n \"streamReasoning\",\n \"completeStreamingReasoning\",\n \"startStreamingRunResult\",\n \"streamRunResult\",\n \"completeStreamingRunResult\",\n])\n\nexport const isStreamingEvent = (event: PerstackEvent): event is StreamingEvent =>\n \"type\" in event && \"expertKey\" in event && STREAMING_EVENT_TYPES.has(event.type)\n\nexport type ProcessStreamingEventResult = {\n newState: StreamingState\n handled: boolean\n}\n\nexport function processStreamingEvent(\n event: StreamingEvent,\n prevState: StreamingState,\n): ProcessStreamingEventResult {\n const { runId, expertKey } = event\n\n switch (event.type) {\n case \"startStreamingReasoning\": {\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n expertKey,\n reasoning: \"\",\n isReasoningActive: true,\n },\n },\n },\n handled: true,\n }\n }\n\n case \"streamReasoning\": {\n if (event.type !== \"streamReasoning\") {\n return { newState: prevState, handled: false }\n }\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n ...prevState.runs[runId],\n expertKey,\n reasoning: (prevState.runs[runId]?.reasoning ?? \"\") + event.delta,\n },\n },\n },\n handled: true,\n }\n }\n\n case \"completeStreamingReasoning\": {\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n ...prevState.runs[runId],\n expertKey,\n isReasoningActive: false,\n },\n },\n },\n handled: false,\n }\n }\n\n case \"startStreamingRunResult\": {\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n expertKey,\n reasoning: undefined,\n isReasoningActive: false,\n runResult: \"\",\n isRunResultActive: true,\n },\n },\n },\n handled: true,\n }\n }\n\n case \"streamRunResult\": {\n if (event.type !== \"streamRunResult\") {\n return { newState: prevState, handled: false }\n }\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n ...prevState.runs[runId],\n expertKey,\n runResult: (prevState.runs[runId]?.runResult ?? \"\") + event.delta,\n },\n },\n },\n handled: true,\n }\n }\n\n case \"completeStreamingRunResult\": {\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n ...prevState.runs[runId],\n expertKey,\n isRunResultActive: false,\n },\n },\n },\n handled: true,\n }\n }\n\n default:\n return { newState: prevState, handled: false }\n }\n}\n\nexport type RunResult = {\n /** Accumulated activities from RunEvent (may include ParallelActivitiesGroup) */\n activities: ActivityOrGroup[]\n /** Current streaming state */\n streaming: StreamingState\n /** Whether the run is complete */\n isComplete: boolean\n /** Number of events processed */\n eventCount: number\n /** Add a new event to be processed */\n addEvent: (event: PerstackEvent) => void\n /** Append historical events (processes and appends to activities) */\n appendHistoricalEvents: (events: PerstackEvent[]) => void\n /** Clear streaming state */\n clearStreaming: () => void\n}\n\n/**\n * Hook for managing Run state from RunEvent stream.\n *\n * Architecture:\n * - ExpertStateEvent → ActivityOrGroup[] (accumulated, append-only)\n * - StreamingEvent → StreamingState (latest only, for display)\n *\n * IMPORTANT: activities are append-only and never cleared.\n * This is required for compatibility with Ink's <Static> component.\n */\nexport function useRun(): RunResult {\n const [activities, setActivities] = useState<ActivityOrGroup[]>([])\n const [streaming, setStreaming] = useState<StreamingState>({ runs: {} })\n const [eventCount, setEventCount] = useState(0)\n const [isComplete, setIsComplete] = useState(false)\n\n const stateRef = useRef<ActivityProcessState>(createInitialActivityProcessState())\n\n const clearStreaming = useCallback(() => {\n setStreaming({ runs: {} })\n }, [])\n\n const handleStreamingEvent = useCallback((event: StreamingEvent): boolean => {\n let handled = false\n setStreaming((prev) => {\n const result = processStreamingEvent(event, prev)\n handled = result.handled\n return result.newState\n })\n return handled\n }, [])\n\n const processEvent = useCallback((event: PerstackEvent) => {\n const newActivities: ActivityOrGroup[] = []\n const addActivity = (activity: ActivityOrGroup) => newActivities.push(activity)\n\n processRunEventToActivity(stateRef.current, event, addActivity)\n\n if (newActivities.length > 0) {\n setActivities((prev) => [...prev, ...newActivities])\n }\n\n const rootRunComplete = Array.from(stateRef.current.runStates.values()).some(\n (rs) => rs.isComplete && !rs.delegatedBy,\n )\n setIsComplete(rootRunComplete)\n }, [])\n\n const clearRunStreaming = useCallback((runId: string) => {\n setStreaming((prev) => {\n const { [runId]: _, ...rest } = prev.runs\n return { runs: rest }\n })\n }, [])\n\n const addEvent = useCallback(\n (event: PerstackEvent) => {\n if (isStreamingEvent(event)) {\n const handled = handleStreamingEvent(event)\n if (handled) {\n setEventCount((prev) => prev + 1)\n return\n }\n }\n\n if (\n \"type\" in event &&\n \"runId\" in event &&\n (event.type === \"completeRun\" || event.type === \"stopRunByError\")\n ) {\n clearRunStreaming(event.runId as string)\n }\n\n processEvent(event)\n setEventCount((prev) => prev + 1)\n },\n [handleStreamingEvent, clearRunStreaming, processEvent],\n )\n\n const appendHistoricalEvents = useCallback((historicalEvents: PerstackEvent[]) => {\n const newActivities: ActivityOrGroup[] = []\n const addActivity = (activity: ActivityOrGroup) => newActivities.push(activity)\n\n for (const event of historicalEvents) {\n processRunEventToActivity(stateRef.current, event, addActivity)\n }\n\n if (newActivities.length > 0) {\n setActivities((prev) => [...prev, ...newActivities])\n }\n\n setEventCount((prev) => prev + historicalEvents.length)\n const rootRunComplete = Array.from(stateRef.current.runStates.values()).some(\n (rs) => rs.isComplete && !rs.delegatedBy,\n )\n setIsComplete(rootRunComplete)\n }, [])\n\n return {\n activities,\n streaming,\n isComplete,\n eventCount,\n addEvent,\n appendHistoricalEvents,\n clearStreaming,\n }\n}\n","import type { ActivityOrGroup, PerstackEvent } from \"@perstack/core\"\nimport { useEffect, useRef, useState } from \"react\"\nimport type { StreamingState } from \"../types/index.js\"\nimport { useRun } from \"./use-run.js\"\n\n/**\n * Options for creating an event stream connection.\n */\nexport type EventStreamOptions = {\n /** AbortSignal to cancel the stream */\n signal: AbortSignal\n}\n\n/**\n * Factory function that creates an async generator of PerstackEvents.\n * This abstraction allows the hook to work with any event source.\n */\nexport type EventSourceFactory = (\n options: EventStreamOptions,\n) => Promise<AsyncGenerator<PerstackEvent, void, unknown>>\n\nexport type EventStreamState = {\n /** Accumulated activities from processed events */\n activities: ActivityOrGroup[]\n /** Current streaming state for real-time display */\n streaming: StreamingState\n /** Whether currently connected to the event source */\n isConnected: boolean\n /** Whether the run has completed */\n isComplete: boolean\n /** Last error encountered, if any */\n error: Error | null\n}\n\nexport type UseEventStreamOptions = {\n /** Whether the stream should be active */\n enabled: boolean\n /** Factory to create the event source when enabled */\n createEventSource: EventSourceFactory | null\n}\n\n/**\n * Hook for consuming PerstackEvent streams with automatic connection management.\n *\n * This hook is API-agnostic - it accepts a factory function that creates\n * the event source, allowing it to work with any backend.\n *\n * @example\n * ```tsx\n * const { activities, streaming, isConnected, error } = useEventStream({\n * enabled: isRunning,\n * createEventSource: async ({ signal }) => {\n * const result = await apiClient.jobs.stream(jobId, { signal })\n * if (!result.ok) throw new Error(result.error.message)\n * return result.data.events\n * },\n * })\n * ```\n */\nexport function useEventStream(options: UseEventStreamOptions): EventStreamState {\n const { enabled, createEventSource } = options\n\n const runState = useRun()\n const [isConnected, setIsConnected] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const abortControllerRef = useRef<AbortController | null>(null)\n // Store addEvent in a ref to avoid dependency changes triggering reconnection\n const addEventRef = useRef(runState.addEvent)\n addEventRef.current = runState.addEvent\n\n useEffect(() => {\n if (!enabled || !createEventSource) {\n return\n }\n\n const abortController = new AbortController()\n abortControllerRef.current = abortController\n const { signal } = abortController\n\n const connect = async () => {\n setIsConnected(true)\n setError(null)\n\n try {\n const events = await createEventSource({ signal })\n\n for await (const event of events) {\n if (signal.aborted) break\n addEventRef.current(event)\n }\n } catch (err) {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n return // Intentional cancellation\n }\n setError(err instanceof Error ? err : new Error(\"Stream connection failed\"))\n } finally {\n setIsConnected(false)\n }\n }\n\n connect()\n\n return () => {\n abortController.abort()\n abortControllerRef.current = null\n }\n }, [enabled, createEventSource])\n\n return {\n activities: runState.activities,\n streaming: runState.streaming,\n isConnected,\n isComplete: runState.isComplete,\n error,\n }\n}\n","/**\n * RuntimeState represents the current state of the runtime environment.\n * This is derived from RuntimeEvent and only the latest state matters.\n *\n * Unlike LogEntry (which accumulates), RuntimeState is replaced on each update.\n */\n\n/** Skill connection state */\nexport type SkillState = {\n name: string\n status: \"starting\" | \"connected\" | \"disconnected\"\n serverInfo?: {\n name: string\n version: string\n }\n}\n\n/** Docker build progress state */\nexport type DockerBuildState = {\n stage: \"pulling\" | \"building\" | \"complete\" | \"error\"\n service: string\n message: string\n progress?: number\n}\n\n/** Docker container status state */\nexport type DockerContainerState = {\n status: \"starting\" | \"running\" | \"healthy\" | \"unhealthy\" | \"stopped\" | \"error\"\n service: string\n message?: string\n}\n\n/** Proxy access state (most recent) */\nexport type ProxyAccessState = {\n action: \"allowed\" | \"blocked\"\n domain: string\n port: number\n reason?: string\n}\n\n/** Per-run streaming state for real-time display */\nexport type PerRunStreamingState = {\n /** Expert key for this run */\n expertKey: string\n /** Accumulated reasoning text during extended thinking */\n reasoning?: string\n /** Accumulated run result text during generation */\n runResult?: string\n /** Whether reasoning is currently streaming */\n isReasoningActive?: boolean\n /** Whether run result is currently streaming */\n isRunResultActive?: boolean\n}\n\n/** Streaming state organized by run ID to support parallel execution */\nexport type StreamingState = {\n /** Per-run streaming state, keyed by runId */\n runs: Record<string, PerRunStreamingState>\n}\n\n/**\n * RuntimeState captures the current state of the runtime environment.\n * All fields represent the latest state from RuntimeEvent.\n */\nexport type RuntimeState = {\n // From initializeRuntime\n /** Current query being processed */\n query?: string\n /** Current expert name */\n expertName?: string\n /** Model being used */\n model?: string\n /** Runtime type (e.g., \"docker\", \"local\") */\n runtime?: string\n /** Runtime version */\n runtimeVersion?: string\n\n // Skill states (keyed by skill name)\n skills: Map<string, SkillState>\n\n // Docker states\n /** Docker build progress (latest) */\n dockerBuild?: DockerBuildState\n /** Docker container states (keyed by service name) */\n dockerContainers: Map<string, DockerContainerState>\n\n // Proxy access (latest)\n proxyAccess?: ProxyAccessState\n\n // Streaming state\n streaming: StreamingState\n}\n\n/** Creates an empty initial runtime state */\nexport function createInitialRuntimeState(): RuntimeState {\n return {\n skills: new Map(),\n dockerContainers: new Map(),\n streaming: { runs: {} },\n }\n}\n","import type { PerstackEvent, RuntimeEvent } from \"@perstack/core\"\nimport { useCallback, useState } from \"react\"\nimport type { RuntimeState } from \"../types/index.js\"\nimport { createInitialRuntimeState } from \"../types/index.js\"\n\nconst RUNTIME_EVENT_TYPES = new Set([\n \"initializeRuntime\",\n \"skillStarting\",\n \"skillConnected\",\n \"skillDisconnected\",\n \"skillStderr\",\n \"dockerBuildProgress\",\n \"dockerContainerStatus\",\n \"proxyAccess\",\n])\n\nconst isRuntimeEvent = (event: PerstackEvent): event is RuntimeEvent =>\n \"type\" in event && RUNTIME_EVENT_TYPES.has(event.type)\n\nexport type RuntimeResult = {\n runtimeState: RuntimeState\n handleRuntimeEvent: (event: PerstackEvent) => boolean\n resetRuntimeState: () => void\n}\n\n/**\n * Hook for managing RuntimeState from RuntimeEvent stream.\n * Only handles infrastructure-level events (skills, docker, proxy).\n * Streaming events are now handled by useRun.\n */\nexport function useRuntime(): RuntimeResult {\n const [runtimeState, setRuntimeState] = useState<RuntimeState>(createInitialRuntimeState)\n\n const handleRuntimeEvent = useCallback((event: PerstackEvent): boolean => {\n if (!isRuntimeEvent(event)) {\n return false\n }\n\n switch (event.type) {\n case \"initializeRuntime\": {\n if (event.type !== \"initializeRuntime\") return false\n setRuntimeState((prev) => ({\n ...prev,\n query: event.query,\n expertName: event.expertName,\n model: event.model,\n runtime: event.runtime,\n runtimeVersion: event.runtimeVersion,\n }))\n return true\n }\n\n case \"skillStarting\": {\n if (event.type !== \"skillStarting\") return false\n setRuntimeState((prev) => {\n const skills = new Map(prev.skills)\n skills.set(event.skillName, { name: event.skillName, status: \"starting\" })\n return { ...prev, skills }\n })\n return true\n }\n\n case \"skillConnected\": {\n if (event.type !== \"skillConnected\") return false\n setRuntimeState((prev) => {\n const skills = new Map(prev.skills)\n skills.set(event.skillName, {\n name: event.skillName,\n status: \"connected\",\n serverInfo: event.serverInfo,\n })\n return { ...prev, skills }\n })\n return true\n }\n\n case \"skillDisconnected\": {\n if (event.type !== \"skillDisconnected\") return false\n setRuntimeState((prev) => {\n const skills = new Map(prev.skills)\n skills.set(event.skillName, { name: event.skillName, status: \"disconnected\" })\n return { ...prev, skills }\n })\n return true\n }\n\n case \"skillStderr\":\n // skillStderr events are informational only (for logging)\n // No state update needed, but we still return true to indicate it's handled\n return true\n\n case \"dockerBuildProgress\": {\n if (event.type !== \"dockerBuildProgress\") return false\n setRuntimeState((prev) => ({\n ...prev,\n dockerBuild: {\n stage: event.stage,\n service: event.service,\n message: event.message,\n progress: event.progress,\n },\n }))\n return true\n }\n\n case \"dockerContainerStatus\": {\n if (event.type !== \"dockerContainerStatus\") return false\n setRuntimeState((prev) => {\n const dockerContainers = new Map(prev.dockerContainers)\n dockerContainers.set(event.service, {\n status: event.status,\n service: event.service,\n message: event.message,\n })\n return { ...prev, dockerContainers }\n })\n return true\n }\n\n case \"proxyAccess\": {\n if (event.type !== \"proxyAccess\") return false\n setRuntimeState((prev) => ({\n ...prev,\n proxyAccess: {\n action: event.action,\n domain: event.domain,\n port: event.port,\n reason: event.reason,\n },\n }))\n return true\n }\n\n default:\n return false\n }\n }, [])\n\n const resetRuntimeState = useCallback(() => {\n setRuntimeState(createInitialRuntimeState())\n }, [])\n\n return {\n runtimeState,\n handleRuntimeEvent,\n resetRuntimeState,\n }\n}\n","import type { ActivityOrGroup } from \"@perstack/core\"\n\n/**\n * Represents a group of activities belonging to the same run\n */\nexport type RunGroup = {\n runId: string\n expertKey: string\n activities: ActivityOrGroup[]\n delegatedBy?: {\n expertKey: string\n runId: string\n }\n}\n\n/**\n * Extract base properties from ActivityOrGroup for grouping.\n */\nfunction getActivityProps(activityOrGroup: ActivityOrGroup): {\n runId: string\n expertKey: string\n delegatedBy?: { expertKey: string; runId: string }\n} {\n if (activityOrGroup.type === \"parallelGroup\") {\n const firstActivity = activityOrGroup.activities[0]\n return {\n runId: activityOrGroup.runId,\n expertKey: activityOrGroup.expertKey,\n delegatedBy: firstActivity?.delegatedBy,\n }\n }\n return activityOrGroup\n}\n\n/**\n * Groups activities by their runId while preserving order.\n *\n * This function groups activities so that each run can be displayed in its own\n * visual section (e.g., separate <Static> components in Ink).\n *\n * @param activities - Array of activities or groups to group\n * @returns Array of RunGroup objects, ordered by first appearance\n */\nexport function groupActivitiesByRun(activities: ActivityOrGroup[]): RunGroup[] {\n const groupMap = new Map<string, RunGroup>()\n const order: string[] = []\n\n for (const activityOrGroup of activities) {\n const { runId, expertKey, delegatedBy } = getActivityProps(activityOrGroup)\n\n if (!groupMap.has(runId)) {\n groupMap.set(runId, {\n runId,\n expertKey,\n activities: [],\n delegatedBy,\n })\n order.push(runId)\n }\n\n const group = groupMap.get(runId)!\n group.activities.push(activityOrGroup)\n }\n\n return order.map((runId) => groupMap.get(runId)!)\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/event-to-activity.ts","../../src/hooks/use-run.ts","../../src/hooks/use-event-stream.ts","../../src/utils/group-by-run.ts"],"names":["runState","useState","useRef"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n Activity,\n ActivityOrGroup,\n ParallelActivitiesGroup,\n PerstackEvent,\n RunEvent,\n ToolCall,\n ToolResult,\n} from \"@perstack/core\"\nimport {\n BASE_SKILL_PREFIX,\n createBaseToolActivity,\n createGeneralToolActivity,\n} from \"@perstack/core\"\n\nconst TOOL_RESULT_EVENT_TYPES = new Set([\"resolveToolResults\", \"attemptCompletion\"])\n\n/**\n * Converts a tool call and result to an Activity.\n * Delegates to core's createBaseToolActivity/createGeneralToolActivity to avoid duplication.\n */\nexport function toolToActivity(\n toolCall: ToolCall,\n toolResult: ToolResult,\n reasoning: string | undefined,\n meta: {\n id: string\n expertKey: string\n runId: string\n previousActivityId?: string\n delegatedBy?: { expertKey: string; runId: string }\n },\n): Activity {\n const { skillName, toolName } = toolCall\n\n const baseActivity = skillName.startsWith(BASE_SKILL_PREFIX)\n ? createBaseToolActivity(toolName, toolCall, toolResult, reasoning)\n : createGeneralToolActivity(skillName, toolName, toolCall, toolResult, reasoning)\n\n // Override the base fields with the correct metadata\n return {\n ...baseActivity,\n id: meta.id,\n expertKey: meta.expertKey,\n runId: meta.runId,\n previousActivityId: meta.previousActivityId,\n delegatedBy: meta.delegatedBy,\n } as Activity\n}\n\ntype ToolState = {\n id: string\n toolCall: ToolCall\n logged: boolean\n}\n\n/**\n * Per-run state to support parallel execution.\n * Each run maintains its own independent state.\n */\ntype RunState = {\n expertKey: string\n queryLogged: boolean\n completionLogged: boolean\n isComplete: boolean\n completedReasoning?: string\n lastActivityId?: string\n delegatedBy?: {\n expertKey: string\n runId: string\n }\n /** Track if this run has pending delegate tool calls (for delegation complete detection) */\n pendingDelegateCount: number\n}\n\n/**\n * State for processing RunEvent stream into Activity[].\n * This state tracks tool calls and their results to create complete Activity items.\n *\n * Supports the daisy chain architecture:\n * - Within-Run ordering via lastActivityId (per-run state)\n * - Cross-Run ordering via delegatedBy (per-run state)\n *\n * Note: `tools` is NOT cleared on new run to support delegation results\n * that arrive after parent expert resumes with a new runId.\n */\nexport type ActivityProcessState = {\n /** Tool calls indexed by toolCallId - persisted across runs for delegation handling */\n tools: Map<string, ToolState>\n /** Per-run state to support parallel execution */\n runStates: Map<string, RunState>\n}\n\nexport function createInitialActivityProcessState(): ActivityProcessState {\n return {\n tools: new Map(),\n runStates: new Map(),\n }\n}\n\nfunction getOrCreateRunState(\n state: ActivityProcessState,\n runId: string,\n expertKey: string,\n): RunState {\n let runState = state.runStates.get(runId)\n if (!runState) {\n runState = {\n expertKey,\n queryLogged: false,\n completionLogged: false,\n isComplete: false,\n pendingDelegateCount: 0,\n }\n state.runStates.set(runId, runState)\n }\n return runState\n}\n\nconst isRunEvent = (event: PerstackEvent): event is RunEvent =>\n \"type\" in event && \"expertKey\" in event\n\nconst isCompleteStreamingReasoningEvent = (event: PerstackEvent): boolean =>\n \"type\" in event && event.type === \"completeStreamingReasoning\"\n\ntype DelegatedByInfo = {\n expert: { key: string }\n toolCallId: string\n toolName: string\n checkpointId: string\n runId: string\n}\n\nconst isToolCallsEvent = (event: RunEvent): event is RunEvent & { toolCalls: ToolCall[] } =>\n event.type === \"callTools\" && \"toolCalls\" in event\n\ntype DelegationTarget = {\n expert: { key: string; name: string; version: string }\n toolCallId: string\n toolName: string\n query: string\n}\n\nconst isStopRunByDelegateEvent = (\n event: RunEvent,\n): event is RunEvent & {\n checkpoint: { delegateTo?: DelegationTarget[] }\n} => event.type === \"stopRunByDelegate\" && \"checkpoint\" in event\n\nconst isStopRunByInteractiveToolEvent = (\n event: RunEvent,\n): event is RunEvent & {\n checkpoint: { pendingToolCalls?: ToolCall[] }\n} => event.type === \"stopRunByInteractiveTool\" && \"checkpoint\" in event\n\nconst isToolResultsEvent = (event: RunEvent): event is RunEvent & { toolResults: ToolResult[] } =>\n event.type === \"resolveToolResults\" && \"toolResults\" in event\n\nconst isToolResultEvent = (event: RunEvent): event is RunEvent & { toolResult: ToolResult } =>\n TOOL_RESULT_EVENT_TYPES.has(event.type) && \"toolResult\" in event\n\n/**\n * Wraps multiple activities in a ParallelActivitiesGroup with shared reasoning.\n * If only one activity, returns it directly.\n */\nfunction wrapInGroupIfParallel(\n activities: Activity[],\n reasoning: string | undefined,\n meta: { expertKey: string; runId: string; delegatedBy?: { expertKey: string; runId: string } },\n): ActivityOrGroup[] {\n if (activities.length <= 1) {\n return activities\n }\n\n // Remove reasoning from individual activities since it's on the group\n const activitiesWithoutReasoning = activities.map((a) => {\n const { reasoning: _, ...rest } = a\n return rest as Activity\n })\n\n const group: ParallelActivitiesGroup = {\n type: \"parallelGroup\",\n id: `parallel-${activities[0].id}`,\n expertKey: meta.expertKey,\n runId: meta.runId,\n reasoning,\n activities: activitiesWithoutReasoning,\n }\n\n return [group]\n}\n\n/**\n * Processes a RunEvent and produces Activity or ParallelActivitiesGroup items.\n * Only processes RunEvent (state machine transitions), not RuntimeEvent.\n *\n * @param state - Mutable processing state\n * @param event - The event to process\n * @param addActivity - Callback to add a new Activity or ParallelActivitiesGroup\n */\nexport function processRunEventToActivity(\n state: ActivityProcessState,\n event: PerstackEvent,\n addActivity: (activity: ActivityOrGroup) => void,\n): void {\n if (isCompleteStreamingReasoningEvent(event)) {\n const reasoningEvent = event as { text: string; runId: string; expertKey: string }\n const { runId, text, expertKey } = reasoningEvent\n const runState = state.runStates.get(runId)\n if (runState) {\n runState.completedReasoning = text\n } else {\n state.runStates.set(runId, {\n expertKey,\n queryLogged: false,\n completionLogged: false,\n isComplete: false,\n pendingDelegateCount: 0,\n completedReasoning: text,\n })\n }\n return\n }\n\n if (!isRunEvent(event)) {\n return\n }\n\n const runState = getOrCreateRunState(state, event.runId, event.expertKey)\n\n // Handle startRun - extract query from inputMessages and delegatedBy\n if (event.type === \"startRun\") {\n const startRunEvent = event as {\n inputMessages: Array<{ type: string; contents?: Array<{ type: string; text?: string }> }>\n initialCheckpoint?: {\n status?: string\n delegatedBy?: {\n expert: { key: string }\n toolCallId: string\n toolName: string\n checkpointId: string\n runId: string\n }\n }\n }\n const userMessage = startRunEvent.inputMessages.find((m) => m.type === \"userMessage\")\n const queryText = userMessage?.contents?.find((c) => c.type === \"textPart\")?.text\n\n // Extract delegatedBy from initialCheckpoint (only on first startRun for this runId)\n if (!runState.delegatedBy) {\n const delegatedByInfo = startRunEvent.initialCheckpoint?.delegatedBy\n if (delegatedByInfo) {\n runState.delegatedBy = {\n expertKey: delegatedByInfo.expert.key,\n runId: delegatedByInfo.runId,\n }\n }\n }\n\n // Check if this is a delegation return (parent expert resuming after delegation)\n // In this case, don't log the query again as it was already logged in the original run\n const isDelegationReturn =\n startRunEvent.initialCheckpoint?.status === \"stoppedByDelegate\" ||\n startRunEvent.initialCheckpoint?.status === \"stoppedByInteractiveTool\"\n\n if (queryText && !runState.queryLogged && !isDelegationReturn) {\n const activityId = `query-${event.runId}`\n addActivity({\n type: \"query\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n text: queryText,\n })\n runState.lastActivityId = activityId\n runState.queryLogged = true\n }\n return\n }\n\n // Handle resumeFromStop - extract delegatedBy from checkpoint for delegation return\n if (event.type === \"resumeFromStop\") {\n // Extract delegatedBy from checkpoint (only on first resumeFromStop for this runId)\n if (!runState.delegatedBy) {\n const resumeEvent = event as { checkpoint?: { delegatedBy?: DelegatedByInfo } }\n const delegatedByInfo = resumeEvent.checkpoint?.delegatedBy\n if (delegatedByInfo) {\n runState.delegatedBy = {\n expertKey: delegatedByInfo.expert.key,\n runId: delegatedByInfo.runId,\n }\n }\n }\n return\n }\n\n // Handle retry\n if (event.type === \"retry\") {\n const retryEvent = event as { reason: string }\n const activityId = `retry-${event.id}`\n addActivity({\n type: \"retry\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n reasoning: runState.completedReasoning,\n error: retryEvent.reason,\n message: \"\",\n })\n runState.lastActivityId = activityId\n runState.completedReasoning = undefined\n return\n }\n\n // Handle completion\n if (event.type === \"completeRun\") {\n if (!runState.completionLogged) {\n const text = (event as { text?: string }).text ?? \"\"\n const activityId = `completion-${event.runId}`\n addActivity({\n type: \"complete\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n reasoning: runState.completedReasoning,\n text,\n })\n runState.lastActivityId = activityId\n runState.completionLogged = true\n runState.isComplete = true\n runState.completedReasoning = undefined\n }\n return\n }\n\n // Handle error\n if (event.type === \"stopRunByError\") {\n const errorEvent = event as {\n error: { name: string; message: string; statusCode?: number; isRetryable?: boolean }\n }\n const activityId = `error-${event.id}`\n addActivity({\n type: \"error\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n errorName: errorEvent.error.name,\n error: errorEvent.error.message,\n isRetryable: errorEvent.error.isRetryable,\n })\n runState.lastActivityId = activityId\n runState.isComplete = true\n runState.completedReasoning = undefined\n return\n }\n\n // Track tool calls from callTools event\n if (isToolCallsEvent(event)) {\n for (const toolCall of event.toolCalls) {\n if (!state.tools.has(toolCall.id)) {\n state.tools.set(toolCall.id, { id: toolCall.id, toolCall, logged: false })\n }\n }\n }\n\n // Handle stopRunByDelegate - log delegation activities\n if (isStopRunByDelegateEvent(event)) {\n const reasoning = runState.completedReasoning\n const delegations = event.checkpoint.delegateTo ?? []\n runState.pendingDelegateCount += delegations.length\n\n const delegateActivities: Activity[] = []\n for (const delegation of delegations) {\n const existingTool = state.tools.get(delegation.toolCallId)\n if (!existingTool || !existingTool.logged) {\n // Mark as logged if exists\n if (existingTool) {\n existingTool.logged = true\n }\n const activityId = `delegate-${delegation.toolCallId}`\n delegateActivities.push({\n type: \"delegate\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n delegateExpertKey: delegation.expert.key,\n query: delegation.query,\n reasoning,\n })\n runState.lastActivityId = activityId\n }\n }\n\n // Wrap in group if multiple delegations\n const wrapped = wrapInGroupIfParallel(delegateActivities, reasoning, {\n expertKey: event.expertKey,\n runId: event.runId,\n delegatedBy: runState.delegatedBy,\n })\n for (const item of wrapped) {\n addActivity(item)\n }\n\n // Clear reasoning after delegation activities are logged\n runState.completedReasoning = undefined\n return\n }\n\n // Handle stopRunByInteractiveTool - log interactive tool activities\n if (isStopRunByInteractiveToolEvent(event)) {\n const reasoning = runState.completedReasoning\n const pendingToolCalls = event.checkpoint.pendingToolCalls ?? []\n\n const interactiveActivities: Activity[] = []\n for (const toolCall of pendingToolCalls) {\n const existingTool = state.tools.get(toolCall.id)\n if (!existingTool || !existingTool.logged) {\n // Mark as logged if exists\n if (existingTool) {\n existingTool.logged = true\n }\n const activityId = `interactive-${toolCall.id}`\n interactiveActivities.push({\n type: \"interactiveTool\",\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n skillName: toolCall.skillName,\n toolName: toolCall.toolName,\n args: toolCall.args as Record<string, unknown>,\n reasoning,\n })\n runState.lastActivityId = activityId\n }\n }\n\n // Wrap in group if multiple interactive tools\n const wrapped = wrapInGroupIfParallel(interactiveActivities, reasoning, {\n expertKey: event.expertKey,\n runId: event.runId,\n delegatedBy: runState.delegatedBy,\n })\n for (const item of wrapped) {\n addActivity(item)\n }\n\n // Clear reasoning after interactive tool activities are logged\n runState.completedReasoning = undefined\n return\n }\n\n // Process tool results\n if (isToolResultsEvent(event)) {\n const reasoning = runState.completedReasoning\n const toolActivities: Activity[] = []\n\n for (const toolResult of event.toolResults) {\n const tool = state.tools.get(toolResult.id)\n if (tool && !tool.logged) {\n const activityId = `action-${tool.id}`\n const activity = toolToActivity(tool.toolCall, toolResult, reasoning, {\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n })\n toolActivities.push(activity)\n runState.lastActivityId = activityId\n tool.logged = true\n }\n }\n\n if (toolActivities.length > 0) {\n // Wrap in group if multiple tool results\n const wrapped = wrapInGroupIfParallel(toolActivities, reasoning, {\n expertKey: event.expertKey,\n runId: event.runId,\n delegatedBy: runState.delegatedBy,\n })\n for (const item of wrapped) {\n addActivity(item)\n }\n runState.completedReasoning = undefined\n }\n } else if (isToolResultEvent(event)) {\n const { toolResult } = event\n const tool = state.tools.get(toolResult.id)\n if (tool && !tool.logged) {\n const activityId = `action-${tool.id}`\n const activity = toolToActivity(tool.toolCall, toolResult, runState.completedReasoning, {\n id: activityId,\n expertKey: event.expertKey,\n runId: event.runId,\n previousActivityId: runState.lastActivityId,\n delegatedBy: runState.delegatedBy,\n })\n addActivity(activity)\n runState.lastActivityId = activityId\n tool.logged = true\n runState.completedReasoning = undefined\n }\n }\n}\n","import type { ActivityOrGroup, PerstackEvent, StreamingEvent } from \"@perstack/core\"\nimport { useCallback, useRef, useState } from \"react\"\nimport type { StreamingState } from \"../types/index.js\"\nimport {\n type ActivityProcessState,\n createInitialActivityProcessState,\n processRunEventToActivity,\n} from \"../utils/event-to-activity.js\"\n\nexport type { ActivityProcessState }\n\nconst STREAMING_EVENT_TYPES = new Set([\n \"startStreamingReasoning\",\n \"streamReasoning\",\n \"completeStreamingReasoning\",\n \"startStreamingRunResult\",\n \"streamRunResult\",\n \"completeStreamingRunResult\",\n])\n\nexport const isStreamingEvent = (event: PerstackEvent): event is StreamingEvent =>\n \"type\" in event && \"expertKey\" in event && STREAMING_EVENT_TYPES.has(event.type)\n\nexport type ProcessStreamingEventResult = {\n newState: StreamingState\n handled: boolean\n}\n\nexport function processStreamingEvent(\n event: StreamingEvent,\n prevState: StreamingState,\n): ProcessStreamingEventResult {\n const { runId, expertKey } = event\n\n switch (event.type) {\n case \"startStreamingReasoning\": {\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n expertKey,\n reasoning: \"\",\n isReasoningActive: true,\n },\n },\n },\n handled: true,\n }\n }\n\n case \"streamReasoning\": {\n if (event.type !== \"streamReasoning\") {\n return { newState: prevState, handled: false }\n }\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n ...prevState.runs[runId],\n expertKey,\n reasoning: (prevState.runs[runId]?.reasoning ?? \"\") + event.delta,\n },\n },\n },\n handled: true,\n }\n }\n\n case \"completeStreamingReasoning\": {\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n ...prevState.runs[runId],\n expertKey,\n isReasoningActive: false,\n },\n },\n },\n handled: false,\n }\n }\n\n case \"startStreamingRunResult\": {\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n expertKey,\n reasoning: undefined,\n isReasoningActive: false,\n runResult: \"\",\n isRunResultActive: true,\n },\n },\n },\n handled: true,\n }\n }\n\n case \"streamRunResult\": {\n if (event.type !== \"streamRunResult\") {\n return { newState: prevState, handled: false }\n }\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n ...prevState.runs[runId],\n expertKey,\n runResult: (prevState.runs[runId]?.runResult ?? \"\") + event.delta,\n },\n },\n },\n handled: true,\n }\n }\n\n case \"completeStreamingRunResult\": {\n return {\n newState: {\n ...prevState,\n runs: {\n ...prevState.runs,\n [runId]: {\n ...prevState.runs[runId],\n expertKey,\n isRunResultActive: false,\n },\n },\n },\n handled: true,\n }\n }\n\n default:\n return { newState: prevState, handled: false }\n }\n}\n\nexport type RunResult = {\n /** Accumulated activities from RunEvent (may include ParallelActivitiesGroup) */\n activities: ActivityOrGroup[]\n /** Current streaming state */\n streaming: StreamingState\n /** Whether the run is complete */\n isComplete: boolean\n /** Number of events processed */\n eventCount: number\n /** Add a new event to be processed */\n addEvent: (event: PerstackEvent) => void\n /** Append historical events (processes and appends to activities) */\n appendHistoricalEvents: (events: PerstackEvent[]) => void\n /** Clear streaming state */\n clearStreaming: () => void\n}\n\n/**\n * Hook for managing Run state from RunEvent stream.\n *\n * Architecture:\n * - ExpertStateEvent → ActivityOrGroup[] (accumulated, append-only)\n * - StreamingEvent → StreamingState (latest only, for display)\n *\n * IMPORTANT: activities are append-only and never cleared.\n * This is required for compatibility with Ink's <Static> component.\n */\nexport function useRun(): RunResult {\n const [activities, setActivities] = useState<ActivityOrGroup[]>([])\n const [streaming, setStreaming] = useState<StreamingState>({ runs: {} })\n const [eventCount, setEventCount] = useState(0)\n const [isComplete, setIsComplete] = useState(false)\n\n const stateRef = useRef<ActivityProcessState>(createInitialActivityProcessState())\n\n const clearStreaming = useCallback(() => {\n setStreaming({ runs: {} })\n }, [])\n\n const handleStreamingEvent = useCallback((event: StreamingEvent): boolean => {\n let handled = false\n setStreaming((prev) => {\n const result = processStreamingEvent(event, prev)\n handled = result.handled\n return result.newState\n })\n return handled\n }, [])\n\n const processEvent = useCallback((event: PerstackEvent) => {\n const newActivities: ActivityOrGroup[] = []\n const addActivity = (activity: ActivityOrGroup) => newActivities.push(activity)\n\n processRunEventToActivity(stateRef.current, event, addActivity)\n\n if (newActivities.length > 0) {\n setActivities((prev) => [...prev, ...newActivities])\n }\n\n const rootRunComplete = Array.from(stateRef.current.runStates.values()).some(\n (rs) => rs.isComplete && !rs.delegatedBy,\n )\n setIsComplete(rootRunComplete)\n }, [])\n\n const clearRunStreaming = useCallback((runId: string) => {\n setStreaming((prev) => {\n const { [runId]: _, ...rest } = prev.runs\n return { runs: rest }\n })\n }, [])\n\n const addEvent = useCallback(\n (event: PerstackEvent) => {\n if (isStreamingEvent(event)) {\n const handled = handleStreamingEvent(event)\n if (handled) {\n setEventCount((prev) => prev + 1)\n return\n }\n }\n\n if (\n \"type\" in event &&\n \"runId\" in event &&\n (event.type === \"completeRun\" || event.type === \"stopRunByError\")\n ) {\n clearRunStreaming(event.runId as string)\n }\n\n processEvent(event)\n setEventCount((prev) => prev + 1)\n },\n [handleStreamingEvent, clearRunStreaming, processEvent],\n )\n\n const appendHistoricalEvents = useCallback((historicalEvents: PerstackEvent[]) => {\n const newActivities: ActivityOrGroup[] = []\n const addActivity = (activity: ActivityOrGroup) => newActivities.push(activity)\n\n for (const event of historicalEvents) {\n processRunEventToActivity(stateRef.current, event, addActivity)\n }\n\n if (newActivities.length > 0) {\n setActivities((prev) => [...prev, ...newActivities])\n }\n\n setEventCount((prev) => prev + historicalEvents.length)\n const rootRunComplete = Array.from(stateRef.current.runStates.values()).some(\n (rs) => rs.isComplete && !rs.delegatedBy,\n )\n setIsComplete(rootRunComplete)\n }, [])\n\n return {\n activities,\n streaming,\n isComplete,\n eventCount,\n addEvent,\n appendHistoricalEvents,\n clearStreaming,\n }\n}\n","import type { ActivityOrGroup, PerstackEvent } from \"@perstack/core\"\nimport { useEffect, useRef, useState } from \"react\"\nimport type { StreamingState } from \"../types/index.js\"\nimport { useRun } from \"./use-run.js\"\n\n/**\n * Options for creating an event stream connection.\n */\nexport type EventStreamOptions = {\n /** AbortSignal to cancel the stream */\n signal: AbortSignal\n}\n\n/**\n * Factory function that creates an async generator of PerstackEvents.\n * This abstraction allows the hook to work with any event source.\n */\nexport type EventSourceFactory = (\n options: EventStreamOptions,\n) => Promise<AsyncGenerator<PerstackEvent, void, unknown>>\n\nexport type EventStreamState = {\n /** Accumulated activities from processed events */\n activities: ActivityOrGroup[]\n /** Current streaming state for real-time display */\n streaming: StreamingState\n /** Whether currently connected to the event source */\n isConnected: boolean\n /** Whether the run has completed */\n isComplete: boolean\n /** Last error encountered, if any */\n error: Error | null\n}\n\nexport type UseEventStreamOptions = {\n /** Whether the stream should be active */\n enabled: boolean\n /** Factory to create the event source when enabled */\n createEventSource: EventSourceFactory | null\n}\n\n/**\n * Hook for consuming PerstackEvent streams with automatic connection management.\n *\n * This hook is API-agnostic - it accepts a factory function that creates\n * the event source, allowing it to work with any backend.\n *\n * @example\n * ```tsx\n * const { activities, streaming, isConnected, error } = useEventStream({\n * enabled: isRunning,\n * createEventSource: async ({ signal }) => {\n * const result = await apiClient.jobs.stream(jobId, { signal })\n * if (!result.ok) throw new Error(result.error.message)\n * return result.data.events\n * },\n * })\n * ```\n */\nexport function useEventStream(options: UseEventStreamOptions): EventStreamState {\n const { enabled, createEventSource } = options\n\n const runState = useRun()\n const [isConnected, setIsConnected] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const abortControllerRef = useRef<AbortController | null>(null)\n // Store addEvent in a ref to avoid dependency changes triggering reconnection\n const addEventRef = useRef(runState.addEvent)\n addEventRef.current = runState.addEvent\n\n useEffect(() => {\n if (!enabled || !createEventSource) {\n return\n }\n\n const abortController = new AbortController()\n abortControllerRef.current = abortController\n const { signal } = abortController\n\n const connect = async () => {\n setIsConnected(true)\n setError(null)\n\n try {\n const events = await createEventSource({ signal })\n\n for await (const event of events) {\n if (signal.aborted) break\n addEventRef.current(event)\n }\n } catch (err) {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n return // Intentional cancellation\n }\n setError(err instanceof Error ? err : new Error(\"Stream connection failed\"))\n } finally {\n setIsConnected(false)\n }\n }\n\n connect()\n\n return () => {\n abortController.abort()\n abortControllerRef.current = null\n }\n }, [enabled, createEventSource])\n\n return {\n activities: runState.activities,\n streaming: runState.streaming,\n isConnected,\n isComplete: runState.isComplete,\n error,\n }\n}\n","import type { ActivityOrGroup } from \"@perstack/core\"\n\n/**\n * Represents a group of activities belonging to the same run\n */\nexport type RunGroup = {\n runId: string\n expertKey: string\n activities: ActivityOrGroup[]\n delegatedBy?: {\n expertKey: string\n runId: string\n }\n}\n\n/**\n * Extract base properties from ActivityOrGroup for grouping.\n */\nfunction getActivityProps(activityOrGroup: ActivityOrGroup): {\n runId: string\n expertKey: string\n delegatedBy?: { expertKey: string; runId: string }\n} {\n if (activityOrGroup.type === \"parallelGroup\") {\n const firstActivity = activityOrGroup.activities[0]\n return {\n runId: activityOrGroup.runId,\n expertKey: activityOrGroup.expertKey,\n delegatedBy: firstActivity?.delegatedBy,\n }\n }\n return activityOrGroup\n}\n\n/**\n * Groups activities by their runId while preserving order.\n *\n * This function groups activities so that each run can be displayed in its own\n * visual section (e.g., separate <Static> components in Ink).\n *\n * @param activities - Array of activities or groups to group\n * @returns Array of RunGroup objects, ordered by first appearance\n */\nexport function groupActivitiesByRun(activities: ActivityOrGroup[]): RunGroup[] {\n const groupMap = new Map<string, RunGroup>()\n const order: string[] = []\n\n for (const activityOrGroup of activities) {\n const { runId, expertKey, delegatedBy } = getActivityProps(activityOrGroup)\n\n if (!groupMap.has(runId)) {\n groupMap.set(runId, {\n runId,\n expertKey,\n activities: [],\n delegatedBy,\n })\n order.push(runId)\n }\n\n const group = groupMap.get(runId)!\n group.activities.push(activityOrGroup)\n }\n\n return order.map((runId) => groupMap.get(runId)!)\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perstack/react",
3
- "version": "0.0.45",
3
+ "version": "0.0.46",
4
4
  "description": "React hooks and utilities for Perstack integration",
5
5
  "author": "Wintermute Technologies, Inc.",
6
6
  "license": "Apache-2.0",