@perstack/react 0.0.47 → 0.0.49

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
@@ -52,41 +52,6 @@ function ExpertRunner() {
52
52
  }
53
53
  ```
54
54
 
55
- ### useEventStream
56
-
57
- A hook for consuming PerstackEvent streams with automatic connection management. This hook is API-agnostic and accepts a factory function that creates the event source.
58
-
59
- ```tsx
60
- import { useEventStream } from "@perstack/react"
61
-
62
- function JobActivityView({ jobId, isRunning }: { jobId: string; isRunning: boolean }) {
63
- const { activities, streaming, isConnected, isComplete, error } = useEventStream({
64
- enabled: isRunning,
65
- createEventSource: async ({ signal }) => {
66
- const response = await fetch(`/api/jobs/${jobId}/stream`, { signal })
67
- // Return an async generator of PerstackEvent
68
- return parseSSEStream(response.body)
69
- },
70
- })
71
-
72
- return (
73
- <div>
74
- {isConnected && <span>Live</span>}
75
- {activities.map((activity) => (
76
- <ActivityCard key={activity.id} activity={activity} />
77
- ))}
78
- {Object.entries(streaming.runs).map(([runId, run]) => (
79
- <div key={runId}>
80
- {run.isReasoningActive && <div>Thinking: {run.reasoning}</div>}
81
- {run.isRunResultActive && <div>Generating: {run.runResult}</div>}
82
- </div>
83
- ))}
84
- {error && <div>Error: {error.message}</div>}
85
- </div>
86
- )
87
- }
88
- ```
89
-
90
55
  ### Utility Functions
91
56
 
92
57
  For advanced use cases, you can use the utility functions directly:
@@ -126,27 +91,6 @@ Returns an object with:
126
91
 
127
92
  **Note:** Activities are append-only and never cleared. This is required for compatibility with Ink's `<Static>` component.
128
93
 
129
- ### useEventStream(options)
130
-
131
- Options:
132
-
133
- - `enabled`: Whether the stream should be active
134
- - `createEventSource`: Factory function that returns an async generator of `PerstackEvent`
135
-
136
- Returns an object with:
137
-
138
- - `activities`: Array of `ActivityOrGroup` from processed events
139
- - `streaming`: Current `StreamingState` for real-time display
140
- - `isConnected`: Whether currently connected to the event source
141
- - `isComplete`: Whether the run has completed
142
- - `error`: Last error encountered, if any
143
-
144
- The hook automatically:
145
- - Connects when `enabled` is `true` and `createEventSource` is provided
146
- - Disconnects and aborts when `enabled` becomes `false` or on unmount
147
- - Processes events through `useRun` internally
148
- - Clears error state on reconnection
149
-
150
94
  ## Types
151
95
 
152
96
  ### StreamingState
@@ -19,55 +19,32 @@ type StreamingState = {
19
19
  runs: Record<string, PerRunStreamingState>;
20
20
  };
21
21
 
22
- /**
23
- * Options for creating an event stream connection.
24
- */
25
- type EventStreamOptions = {
26
- /** AbortSignal to cancel the stream */
27
- signal: AbortSignal;
28
- };
29
- /**
30
- * Factory function that creates an async generator of PerstackEvents.
31
- * This abstraction allows the hook to work with any event source.
32
- */
33
- type EventSourceFactory = (options: EventStreamOptions) => Promise<AsyncGenerator<PerstackEvent, void, unknown>>;
34
- type EventStreamState = {
35
- /** Accumulated activities from processed events */
22
+ type StreamConnector = (jobId: string, signal: AbortSignal) => Promise<AsyncIterable<PerstackEvent>>;
23
+
24
+ type JobStreamState = {
36
25
  activities: ActivityOrGroup[];
37
- /** Current streaming state for real-time display */
38
26
  streaming: StreamingState;
39
- /** Whether currently connected to the event source */
27
+ latestActivity: ActivityOrGroup | null;
40
28
  isConnected: boolean;
41
- /** Whether the run has completed */
42
- isComplete: boolean;
43
- /** Last error encountered, if any */
44
29
  error: Error | null;
45
30
  };
46
- type UseEventStreamOptions = {
47
- /** Whether the stream should be active */
48
- enabled: boolean;
49
- /** Factory to create the event source when enabled */
50
- createEventSource: EventSourceFactory | null;
31
+ declare function useJobStream(options: {
32
+ jobId: string | null;
33
+ connect: StreamConnector;
34
+ enabled?: boolean;
35
+ }): JobStreamState;
36
+
37
+ type JobStreamSummary = {
38
+ latestActivity: ActivityOrGroup | null;
39
+ isConnected: boolean;
51
40
  };
52
- /**
53
- * Hook for consuming PerstackEvent streams with automatic connection management.
54
- *
55
- * This hook is API-agnostic - it accepts a factory function that creates
56
- * the event source, allowing it to work with any backend.
57
- *
58
- * @example
59
- * ```tsx
60
- * const { activities, streaming, isConnected, error } = useEventStream({
61
- * enabled: isRunning,
62
- * createEventSource: async ({ signal }) => {
63
- * const result = await apiClient.jobs.stream(jobId, { signal })
64
- * if (!result.ok) throw new Error(result.error.message)
65
- * return result.data.events
66
- * },
67
- * })
68
- * ```
69
- */
70
- declare function useEventStream(options: UseEventStreamOptions): EventStreamState;
41
+ declare function useJobStreams(options: {
42
+ jobs: Array<{
43
+ id: string;
44
+ enabled: boolean;
45
+ }>;
46
+ connect: StreamConnector;
47
+ }): Map<string, JobStreamSummary>;
71
48
 
72
49
  /**
73
50
  * Converts a tool call and result to an Activity.
@@ -185,4 +162,4 @@ type RunGroup = {
185
162
  */
186
163
  declare function groupActivitiesByRun(activities: ActivityOrGroup[]): RunGroup[];
187
164
 
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 };
165
+ export { type ActivityProcessState, type JobStreamState, type JobStreamSummary, type PerRunStreamingState, type RunGroup, type RunResult, type StreamConnector, type StreamingState, type ActivityProcessState as UtilActivityProcessState, createInitialActivityProcessState, groupActivitiesByRun, processRunEventToActivity, toolToActivity, useJobStream, useJobStreams, useRun };
package/dist/src/index.js CHANGED
@@ -1,7 +1,17 @@
1
- import { useState, useRef, useCallback, useEffect } from 'react';
1
+ import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
2
2
  import { BASE_SKILL_PREFIX, createBaseToolActivity, createGeneralToolActivity } from '@perstack/core';
3
3
 
4
- // src/hooks/use-event-stream.ts
4
+ // src/hooks/use-job-stream.ts
5
+
6
+ // src/utils/stream.ts
7
+ var isAbortError = (err) => err instanceof DOMException && err.name === "AbortError";
8
+ 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
+ }
14
+ }
5
15
  var TOOL_RESULT_EVENT_TYPES = /* @__PURE__ */ new Set(["resolveToolResults", "attemptCompletion"]);
6
16
  function toolToActivity(toolCall, toolResult, reasoning, meta) {
7
17
  const { skillName, toolName } = toolCall;
@@ -345,9 +355,6 @@ function processStreamingEvent(event, prevState) {
345
355
  };
346
356
  }
347
357
  case "streamReasoning": {
348
- if (event.type !== "streamReasoning") {
349
- return { newState: prevState, handled: false };
350
- }
351
358
  return {
352
359
  newState: {
353
360
  ...prevState,
@@ -398,9 +405,6 @@ function processStreamingEvent(event, prevState) {
398
405
  };
399
406
  }
400
407
  case "streamRunResult": {
401
- if (event.type !== "streamRunResult") {
402
- return { newState: prevState, handled: false };
403
- }
404
408
  return {
405
409
  newState: {
406
410
  ...prevState,
@@ -515,53 +519,125 @@ function useRun() {
515
519
  };
516
520
  }
517
521
 
518
- // src/hooks/use-event-stream.ts
519
- function useEventStream(options) {
520
- const { enabled, createEventSource } = options;
521
- const runState = useRun();
522
+ // src/hooks/use-job-stream.ts
523
+ function useJobStream(options) {
524
+ const { jobId, connect, enabled = true } = options;
525
+ const shouldConnect = Boolean(jobId && enabled);
526
+ const { activities, streaming, addEvent } = useRun();
522
527
  const [isConnected, setIsConnected] = useState(false);
523
528
  const [error, setError] = useState(null);
524
- const abortControllerRef = useRef(null);
525
- const addEventRef = useRef(runState.addEvent);
526
- addEventRef.current = runState.addEvent;
529
+ const addEventRef = useRef(addEvent);
530
+ addEventRef.current = addEvent;
531
+ const connectRef = useRef(connect);
532
+ connectRef.current = connect;
527
533
  useEffect(() => {
528
- if (!enabled || !createEventSource) {
534
+ if (!shouldConnect || !jobId) {
535
+ setIsConnected(false);
529
536
  return;
530
537
  }
531
- const abortController = new AbortController();
532
- abortControllerRef.current = abortController;
533
- const { signal } = abortController;
534
- const connect = async () => {
535
- setIsConnected(true);
538
+ const controller = new AbortController();
539
+ async function run() {
536
540
  setError(null);
541
+ setIsConnected(true);
537
542
  try {
538
- const events = await createEventSource({ signal });
539
- for await (const event of events) {
540
- if (signal.aborted) break;
543
+ await consumeStream(connectRef.current, jobId, controller.signal, (event) => {
541
544
  addEventRef.current(event);
542
- }
545
+ });
543
546
  } catch (err) {
544
- if (err instanceof DOMException && err.name === "AbortError") {
545
- return;
546
- }
547
- setError(err instanceof Error ? err : new Error("Stream connection failed"));
547
+ if (isAbortError(err)) return;
548
+ setError(err instanceof Error ? err : new Error(String(err)));
548
549
  } finally {
549
550
  setIsConnected(false);
550
551
  }
552
+ }
553
+ run();
554
+ return () => {
555
+ controller.abort();
551
556
  };
552
- connect();
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 };
563
+ }
564
+ 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(() => {
553
632
  return () => {
554
- abortController.abort();
555
- abortControllerRef.current = null;
633
+ for (const controller of controllersRef.current.values()) {
634
+ controller.abort();
635
+ }
636
+ controllersRef.current.clear();
637
+ activityStateRef.current.clear();
556
638
  };
557
- }, [enabled, createEventSource]);
558
- return {
559
- activities: runState.activities,
560
- streaming: runState.streaming,
561
- isConnected,
562
- isComplete: runState.isComplete,
563
- error
564
- };
639
+ }, []);
640
+ return states;
565
641
  }
566
642
 
567
643
  // src/utils/group-by-run.ts
@@ -596,6 +672,6 @@ function groupActivitiesByRun(activities) {
596
672
  return order.map((runId) => groupMap.get(runId));
597
673
  }
598
674
 
599
- export { createInitialActivityProcessState, groupActivitiesByRun, processRunEventToActivity, toolToActivity, useEventStream, useRun };
675
+ export { createInitialActivityProcessState, groupActivitiesByRun, processRunEventToActivity, toolToActivity, useJobStream, useJobStreams, useRun };
600
676
  //# sourceMappingURL=index.js.map
601
677
  //# 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/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"]}
1
+ {"version":3,"sources":["../../src/utils/stream.ts","../../src/utils/event-to-activity.ts","../../src/hooks/use-run.ts","../../src/hooks/use-job-stream.ts","../../src/hooks/use-job-streams.ts","../../src/utils/group-by-run.ts"],"names":["runState","useState","useRef","useCallback","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import type { PerstackEvent } from \"@perstack/core\"\n\nexport type StreamConnector = (\n jobId: string,\n signal: AbortSignal,\n) => Promise<AsyncIterable<PerstackEvent>>\n\nexport const isAbortError = (err: unknown): boolean =>\n err instanceof DOMException && err.name === \"AbortError\"\n\n/**\n * Consumes an SSE stream with abort-safe iteration and error normalization.\n *\n * Handles the connection lifecycle shared by all streaming hooks:\n * 1. Calls `connect` to obtain an async iterable\n * 2. Iterates events, stopping on signal abort\n * 3. Filters out AbortError (normal cleanup), surfaces all others\n */\nexport async function consumeStream(\n connect: StreamConnector,\n jobId: string,\n signal: AbortSignal,\n onEvent: (event: PerstackEvent) => void,\n): Promise<void> {\n const events = await connect(jobId, signal)\n for await (const event of events) {\n if (signal.aborted) break\n onEvent(event)\n }\n}\n","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 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 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 } from \"@perstack/core\"\nimport { useEffect, useMemo, useRef, useState } from \"react\"\nimport type { StreamingState } from \"../types/index.js\"\nimport { consumeStream, isAbortError, type StreamConnector } from \"../utils/stream.js\"\nimport { useRun } from \"./use-run.js\"\n\nexport type { StreamConnector }\n\nexport type JobStreamState = {\n activities: ActivityOrGroup[]\n streaming: StreamingState\n latestActivity: ActivityOrGroup | null\n isConnected: boolean\n error: Error | null\n}\n\nexport function useJobStream(options: {\n jobId: string | null\n connect: StreamConnector\n enabled?: boolean\n}): JobStreamState {\n const { jobId, connect, enabled = true } = options\n const shouldConnect = Boolean(jobId && enabled)\n const { activities, streaming, addEvent } = useRun()\n const [isConnected, setIsConnected] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n const addEventRef = useRef(addEvent)\n addEventRef.current = addEvent\n const connectRef = useRef(connect)\n connectRef.current = connect\n\n useEffect(() => {\n if (!shouldConnect || !jobId) {\n setIsConnected(false)\n return\n }\n\n const controller = new AbortController()\n\n async function run() {\n setError(null)\n setIsConnected(true)\n try {\n await consumeStream(connectRef.current, jobId!, controller.signal, (event) => {\n addEventRef.current(event)\n })\n } catch (err) {\n if (isAbortError(err)) return\n setError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setIsConnected(false)\n }\n }\n\n run()\n return () => {\n controller.abort()\n }\n }, [shouldConnect, jobId])\n\n const latestActivity = useMemo(\n () => (activities.length > 0 ? activities[activities.length - 1] : null),\n [activities],\n )\n\n return { activities, streaming, latestActivity, isConnected, error }\n}\n","import type { ActivityOrGroup } from \"@perstack/core\"\nimport { useCallback, useEffect, useRef, useState } from \"react\"\nimport {\n type ActivityProcessState,\n createInitialActivityProcessState,\n processRunEventToActivity,\n} from \"../utils/event-to-activity.js\"\nimport { consumeStream, isAbortError, type StreamConnector } from \"../utils/stream.js\"\n\nexport type JobStreamSummary = {\n latestActivity: ActivityOrGroup | null\n isConnected: boolean\n}\n\nexport function useJobStreams(options: {\n jobs: Array<{ id: string; enabled: boolean }>\n connect: StreamConnector\n}): Map<string, JobStreamSummary> {\n const { jobs, connect } = options\n const [states, setStates] = useState<Map<string, JobStreamSummary>>(new Map())\n const controllersRef = useRef<Map<string, AbortController>>(new Map())\n const activityStateRef = useRef<Map<string, ActivityProcessState>>(new Map())\n const connectRef = useRef(connect)\n connectRef.current = connect\n\n const connectToJob = useCallback(async (jobId: string, signal: AbortSignal) => {\n setStates((prev) => {\n const next = new Map(prev)\n next.set(jobId, { latestActivity: null, isConnected: true })\n return next\n })\n\n let state = activityStateRef.current.get(jobId)\n if (!state) {\n state = createInitialActivityProcessState()\n activityStateRef.current.set(jobId, state)\n }\n\n try {\n await consumeStream(connectRef.current, jobId, signal, (event) => {\n let latestActivity: ActivityOrGroup | null = null\n processRunEventToActivity(state!, event, (activity) => {\n latestActivity = activity\n })\n if (latestActivity) {\n setStates((prev) => {\n const next = new Map(prev)\n next.set(jobId, { latestActivity, isConnected: true })\n return next\n })\n }\n })\n } catch (err) {\n if (isAbortError(err)) return\n console.error(`Stream connection failed for job ${jobId}:`, err)\n } finally {\n setStates((prev) => {\n const current = prev.get(jobId)\n if (!current) return prev\n const next = new Map(prev)\n next.set(jobId, { ...current, isConnected: false })\n return next\n })\n }\n }, [])\n\n useEffect(() => {\n const enabledIds = new Set(jobs.filter((j) => j.enabled).map((j) => j.id))\n\n // Disconnect removed/disabled jobs\n for (const [jobId, controller] of controllersRef.current) {\n if (!enabledIds.has(jobId)) {\n controller.abort()\n controllersRef.current.delete(jobId)\n activityStateRef.current.delete(jobId)\n setStates((prev) => {\n const next = new Map(prev)\n next.delete(jobId)\n return next\n })\n }\n }\n\n // Connect new jobs\n for (const jobId of enabledIds) {\n if (!controllersRef.current.has(jobId)) {\n const controller = new AbortController()\n controllersRef.current.set(jobId, controller)\n connectToJob(jobId, controller.signal)\n }\n }\n }, [jobs, connectToJob])\n\n // Cleanup on unmount only\n useEffect(() => {\n return () => {\n for (const controller of controllersRef.current.values()) {\n controller.abort()\n }\n controllersRef.current.clear()\n activityStateRef.current.clear()\n }\n }, [])\n\n return states\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.47",
3
+ "version": "0.0.49",
4
4
  "description": "React hooks and utilities for Perstack integration",
5
5
  "author": "Wintermute Technologies, Inc.",
6
6
  "license": "Apache-2.0",
@@ -18,8 +18,7 @@
18
18
  "dist"
19
19
  ],
20
20
  "dependencies": {
21
- "react": "^19.2.3",
22
- "@perstack/core": "0.0.43"
21
+ "@perstack/core": "0.0.45"
23
22
  },
24
23
  "peerDependencies": {
25
24
  "react": ">=18.0.0"