@perstack/react 0.0.57 → 0.0.58

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.
Files changed (47) hide show
  1. package/README.md +1 -3
  2. package/dist/src/hooks/index.d.ts +4 -0
  3. package/dist/src/hooks/index.d.ts.map +1 -0
  4. package/dist/src/hooks/index.js +4 -0
  5. package/dist/src/hooks/index.js.map +1 -0
  6. package/dist/src/hooks/use-job-stream.d.ts +17 -0
  7. package/dist/src/hooks/use-job-stream.d.ts.map +1 -0
  8. package/dist/src/hooks/use-job-stream.js +45 -0
  9. package/dist/src/hooks/use-job-stream.js.map +1 -0
  10. package/dist/src/hooks/use-job-streams.d.ts +14 -0
  11. package/dist/src/hooks/use-job-streams.d.ts.map +1 -0
  12. package/dist/src/hooks/use-job-streams.js +89 -0
  13. package/dist/src/hooks/use-job-streams.js.map +1 -0
  14. package/dist/src/hooks/use-run.d.ts +38 -0
  15. package/dist/src/hooks/use-run.d.ts.map +1 -0
  16. package/dist/src/hooks/use-run.js +200 -0
  17. package/dist/src/hooks/use-run.js.map +1 -0
  18. package/dist/src/index.d.ts +3 -156
  19. package/dist/src/index.d.ts.map +1 -0
  20. package/dist/src/index.js +4 -660
  21. package/dist/src/index.js.map +1 -1
  22. package/dist/src/types/index.d.ts +2 -0
  23. package/dist/src/types/index.d.ts.map +1 -0
  24. package/dist/src/types/index.js +2 -0
  25. package/dist/src/types/index.js.map +1 -0
  26. package/dist/src/types/runtime-state.d.ts +19 -0
  27. package/dist/src/types/runtime-state.d.ts.map +1 -0
  28. package/dist/src/types/runtime-state.js +2 -0
  29. package/dist/src/types/runtime-state.js.map +1 -0
  30. package/dist/src/utils/event-to-activity.d.ts +67 -0
  31. package/dist/src/utils/event-to-activity.d.ts.map +1 -0
  32. package/dist/src/utils/event-to-activity.js +337 -0
  33. package/dist/src/utils/event-to-activity.js.map +1 -0
  34. package/dist/src/utils/group-by-run.d.ts +24 -0
  35. package/dist/src/utils/group-by-run.d.ts.map +1 -0
  36. package/dist/src/utils/group-by-run.js +43 -0
  37. package/dist/src/utils/group-by-run.js.map +1 -0
  38. package/dist/src/utils/index.d.ts +4 -0
  39. package/dist/src/utils/index.d.ts.map +1 -0
  40. package/dist/src/utils/index.js +4 -0
  41. package/dist/src/utils/index.js.map +1 -0
  42. package/dist/src/utils/stream.d.ts +13 -0
  43. package/dist/src/utils/stream.d.ts.map +1 -0
  44. package/dist/src/utils/stream.js +18 -0
  45. package/dist/src/utils/stream.js.map +1 -0
  46. package/package.json +20 -18
  47. package/LICENSE +0 -202
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"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"],"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\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\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 }\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"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,OAAO,EAML,YAAY,EACZ,aAAa,EACb,MAAM,GACP,MAAM,kBAAkB,CAAA;AAKzB,QAAQ;AACR,OAAO,EAEL,iCAAiC,EACjC,oBAAoB,EACpB,yBAAyB,EAEzB,cAAc,GACf,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export type { PerRunStreamingState, StreamingState } from "./runtime-state.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,19 @@
1
+ /** Per-run streaming state for real-time display */
2
+ export type PerRunStreamingState = {
3
+ /** Expert key for this run */
4
+ expertKey: string;
5
+ /** Accumulated reasoning text during extended thinking */
6
+ reasoning?: string;
7
+ /** Accumulated run result text during generation */
8
+ runResult?: string;
9
+ /** Whether reasoning is currently streaming */
10
+ isReasoningActive?: boolean;
11
+ /** Whether run result is currently streaming */
12
+ isRunResultActive?: boolean;
13
+ };
14
+ /** Streaming state organized by run ID to support parallel execution */
15
+ export type StreamingState = {
16
+ /** Per-run streaming state, keyed by runId */
17
+ runs: Record<string, PerRunStreamingState>;
18
+ };
19
+ //# sourceMappingURL=runtime-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-state.d.ts","sourceRoot":"","sources":["../../../src/types/runtime-state.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,MAAM,MAAM,oBAAoB,GAAG;IACjC,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B,CAAA;AAED,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG;IAC3B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;CAC3C,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=runtime-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-state.js","sourceRoot":"","sources":["../../../src/types/runtime-state.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ import type { Activity, ActivityOrGroup, PerstackEvent, ToolCall, ToolResult } from "@perstack/core";
2
+ /**
3
+ * Converts a tool call and result to an Activity.
4
+ * Delegates to core's createBaseToolActivity/createGeneralToolActivity to avoid duplication.
5
+ */
6
+ export declare function toolToActivity(toolCall: ToolCall, toolResult: ToolResult, reasoning: string | undefined, meta: {
7
+ id: string;
8
+ expertKey: string;
9
+ runId: string;
10
+ previousActivityId?: string;
11
+ delegatedBy?: {
12
+ expertKey: string;
13
+ runId: string;
14
+ };
15
+ }): Activity;
16
+ type ToolState = {
17
+ id: string;
18
+ toolCall: ToolCall;
19
+ logged: boolean;
20
+ };
21
+ /**
22
+ * Per-run state to support parallel execution.
23
+ * Each run maintains its own independent state.
24
+ */
25
+ type RunState = {
26
+ expertKey: string;
27
+ queryLogged: boolean;
28
+ completionLogged: boolean;
29
+ isComplete: boolean;
30
+ completedReasoning?: string;
31
+ lastActivityId?: string;
32
+ delegatedBy?: {
33
+ expertKey: string;
34
+ runId: string;
35
+ };
36
+ /** Track if this run has pending delegate tool calls (for delegation complete detection) */
37
+ pendingDelegateCount: number;
38
+ };
39
+ /**
40
+ * State for processing RunEvent stream into Activity[].
41
+ * This state tracks tool calls and their results to create complete Activity items.
42
+ *
43
+ * Supports the daisy chain architecture:
44
+ * - Within-Run ordering via lastActivityId (per-run state)
45
+ * - Cross-Run ordering via delegatedBy (per-run state)
46
+ *
47
+ * Note: `tools` is NOT cleared on new run to support delegation results
48
+ * that arrive after parent expert resumes with a new runId.
49
+ */
50
+ export type ActivityProcessState = {
51
+ /** Tool calls indexed by toolCallId - persisted across runs for delegation handling */
52
+ tools: Map<string, ToolState>;
53
+ /** Per-run state to support parallel execution */
54
+ runStates: Map<string, RunState>;
55
+ };
56
+ export declare function createInitialActivityProcessState(): ActivityProcessState;
57
+ /**
58
+ * Processes a RunEvent and produces Activity or ParallelActivitiesGroup items.
59
+ * Only processes RunEvent (state machine transitions), not RuntimeEvent.
60
+ *
61
+ * @param state - Mutable processing state
62
+ * @param event - The event to process
63
+ * @param addActivity - Callback to add a new Activity or ParallelActivitiesGroup
64
+ */
65
+ export declare function processRunEventToActivity(state: ActivityProcessState, event: PerstackEvent, addActivity: (activity: ActivityOrGroup) => void): void;
66
+ export {};
67
+ //# sourceMappingURL=event-to-activity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-to-activity.d.ts","sourceRoot":"","sources":["../../../src/utils/event-to-activity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EAEf,aAAa,EAEb,QAAQ,EACR,UAAU,EACX,MAAM,gBAAgB,CAAA;AAOvB;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,IAAI,EAAE;IACJ,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,WAAW,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CACnD,GACA,QAAQ,CAgBV;AAED,KAAK,SAAS,GAAG;IACf,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,QAAQ,CAAA;IAClB,MAAM,EAAE,OAAO,CAAA;CAChB,CAAA;AAED;;;GAGG;AACH,KAAK,QAAQ,GAAG;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,OAAO,CAAA;IACpB,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE,OAAO,CAAA;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE;QACZ,SAAS,EAAE,MAAM,CAAA;QACjB,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;IACD,4FAA4F;IAC5F,oBAAoB,EAAE,MAAM,CAAA;CAC7B,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,uFAAuF;IACvF,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC7B,kDAAkD;IAClD,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CACjC,CAAA;AAED,wBAAgB,iCAAiC,IAAI,oBAAoB,CAKxE;AA2FD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,aAAa,EACpB,WAAW,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,IAAI,GAC/C,IAAI,CAsSN"}
@@ -0,0 +1,337 @@
1
+ import { BASE_SKILL_PREFIX, createBaseToolActivity, createGeneralToolActivity, } from "@perstack/core";
2
+ /**
3
+ * Converts a tool call and result to an Activity.
4
+ * Delegates to core's createBaseToolActivity/createGeneralToolActivity to avoid duplication.
5
+ */
6
+ export function toolToActivity(toolCall, toolResult, reasoning, meta) {
7
+ const { skillName, toolName } = toolCall;
8
+ const baseActivity = skillName.startsWith(BASE_SKILL_PREFIX)
9
+ ? createBaseToolActivity(toolName, toolCall, toolResult, reasoning)
10
+ : createGeneralToolActivity(skillName, toolName, toolCall, toolResult, reasoning);
11
+ // Override the base fields with the correct metadata
12
+ return {
13
+ ...baseActivity,
14
+ id: meta.id,
15
+ expertKey: meta.expertKey,
16
+ runId: meta.runId,
17
+ previousActivityId: meta.previousActivityId,
18
+ delegatedBy: meta.delegatedBy,
19
+ };
20
+ }
21
+ export function createInitialActivityProcessState() {
22
+ return {
23
+ tools: new Map(),
24
+ runStates: new Map(),
25
+ };
26
+ }
27
+ function getOrCreateRunState(state, runId, expertKey) {
28
+ let runState = state.runStates.get(runId);
29
+ if (!runState) {
30
+ runState = {
31
+ expertKey,
32
+ queryLogged: false,
33
+ completionLogged: false,
34
+ isComplete: false,
35
+ pendingDelegateCount: 0,
36
+ };
37
+ state.runStates.set(runId, runState);
38
+ }
39
+ return runState;
40
+ }
41
+ const isRunEvent = (event) => "type" in event && "expertKey" in event;
42
+ const isCompleteStreamingReasoningEvent = (event) => "type" in event && event.type === "completeStreamingReasoning";
43
+ const isToolCallsEvent = (event) => event.type === "callTools" && "toolCalls" in event;
44
+ const isStopRunByDelegateEvent = (event) => event.type === "stopRunByDelegate" && "checkpoint" in event;
45
+ const isStopRunByInteractiveToolEvent = (event) => event.type === "stopRunByInteractiveTool" && "checkpoint" in event;
46
+ const isToolResultsEvent = (event) => event.type === "resolveToolResults" && "toolResults" in event;
47
+ /**
48
+ * Wraps multiple activities in a ParallelActivitiesGroup with shared reasoning.
49
+ * If only one activity, returns it directly.
50
+ */
51
+ function wrapInGroupIfParallel(activities, reasoning, meta) {
52
+ if (activities.length <= 1) {
53
+ return activities;
54
+ }
55
+ // Remove reasoning from individual activities since it's on the group
56
+ const activitiesWithoutReasoning = activities.map((a) => {
57
+ const { reasoning: _, ...rest } = a;
58
+ return rest;
59
+ });
60
+ const group = {
61
+ type: "parallelGroup",
62
+ id: `parallel-${activities[0].id}`,
63
+ expertKey: meta.expertKey,
64
+ runId: meta.runId,
65
+ reasoning,
66
+ activities: activitiesWithoutReasoning,
67
+ };
68
+ return [group];
69
+ }
70
+ /**
71
+ * Processes a RunEvent and produces Activity or ParallelActivitiesGroup items.
72
+ * Only processes RunEvent (state machine transitions), not RuntimeEvent.
73
+ *
74
+ * @param state - Mutable processing state
75
+ * @param event - The event to process
76
+ * @param addActivity - Callback to add a new Activity or ParallelActivitiesGroup
77
+ */
78
+ export function processRunEventToActivity(state, event, addActivity) {
79
+ if (isCompleteStreamingReasoningEvent(event)) {
80
+ const reasoningEvent = event;
81
+ const { runId, text, expertKey } = reasoningEvent;
82
+ const runState = state.runStates.get(runId);
83
+ if (runState) {
84
+ runState.completedReasoning = text;
85
+ }
86
+ else {
87
+ state.runStates.set(runId, {
88
+ expertKey,
89
+ queryLogged: false,
90
+ completionLogged: false,
91
+ isComplete: false,
92
+ pendingDelegateCount: 0,
93
+ completedReasoning: text,
94
+ });
95
+ }
96
+ return;
97
+ }
98
+ if (!isRunEvent(event)) {
99
+ return;
100
+ }
101
+ const runState = getOrCreateRunState(state, event.runId, event.expertKey);
102
+ // Handle startRun - extract query from inputMessages and delegatedBy
103
+ if (event.type === "startRun") {
104
+ const startRunEvent = event;
105
+ const userMessage = startRunEvent.inputMessages.find((m) => m.type === "userMessage");
106
+ const queryText = userMessage?.contents?.find((c) => c.type === "textPart")?.text;
107
+ // Extract delegatedBy from initialCheckpoint (only on first startRun for this runId)
108
+ if (!runState.delegatedBy) {
109
+ const delegatedByInfo = startRunEvent.initialCheckpoint?.delegatedBy;
110
+ if (delegatedByInfo) {
111
+ runState.delegatedBy = {
112
+ expertKey: delegatedByInfo.expert.key,
113
+ runId: delegatedByInfo.runId,
114
+ };
115
+ }
116
+ }
117
+ // Check if this is a delegation return (parent expert resuming after delegation)
118
+ // In this case, don't log the query again as it was already logged in the original run
119
+ const isDelegationReturn = startRunEvent.initialCheckpoint?.status === "stoppedByDelegate" ||
120
+ startRunEvent.initialCheckpoint?.status === "stoppedByInteractiveTool";
121
+ if (queryText && !runState.queryLogged && !isDelegationReturn) {
122
+ const activityId = `query-${event.runId}`;
123
+ addActivity({
124
+ type: "query",
125
+ id: activityId,
126
+ expertKey: event.expertKey,
127
+ runId: event.runId,
128
+ previousActivityId: runState.lastActivityId,
129
+ delegatedBy: runState.delegatedBy,
130
+ text: queryText,
131
+ });
132
+ runState.lastActivityId = activityId;
133
+ runState.queryLogged = true;
134
+ }
135
+ return;
136
+ }
137
+ // Handle resumeFromStop - extract delegatedBy from checkpoint for delegation return
138
+ if (event.type === "resumeFromStop") {
139
+ // Extract delegatedBy from checkpoint (only on first resumeFromStop for this runId)
140
+ if (!runState.delegatedBy) {
141
+ const resumeEvent = event;
142
+ const delegatedByInfo = resumeEvent.checkpoint?.delegatedBy;
143
+ if (delegatedByInfo) {
144
+ runState.delegatedBy = {
145
+ expertKey: delegatedByInfo.expert.key,
146
+ runId: delegatedByInfo.runId,
147
+ };
148
+ }
149
+ }
150
+ return;
151
+ }
152
+ // Handle retry
153
+ if (event.type === "retry") {
154
+ const retryEvent = event;
155
+ const activityId = `retry-${event.id}`;
156
+ addActivity({
157
+ type: "retry",
158
+ id: activityId,
159
+ expertKey: event.expertKey,
160
+ runId: event.runId,
161
+ previousActivityId: runState.lastActivityId,
162
+ delegatedBy: runState.delegatedBy,
163
+ reasoning: runState.completedReasoning,
164
+ error: retryEvent.reason,
165
+ message: "",
166
+ });
167
+ runState.lastActivityId = activityId;
168
+ runState.completedReasoning = undefined;
169
+ return;
170
+ }
171
+ // Handle completion
172
+ if (event.type === "completeRun") {
173
+ if (!runState.completionLogged) {
174
+ const text = event.text ?? "";
175
+ const activityId = `completion-${event.runId}`;
176
+ addActivity({
177
+ type: "complete",
178
+ id: activityId,
179
+ expertKey: event.expertKey,
180
+ runId: event.runId,
181
+ previousActivityId: runState.lastActivityId,
182
+ delegatedBy: runState.delegatedBy,
183
+ reasoning: runState.completedReasoning,
184
+ text,
185
+ });
186
+ runState.lastActivityId = activityId;
187
+ runState.completionLogged = true;
188
+ runState.isComplete = true;
189
+ runState.completedReasoning = undefined;
190
+ }
191
+ return;
192
+ }
193
+ // Handle error
194
+ if (event.type === "stopRunByError") {
195
+ const errorEvent = event;
196
+ const activityId = `error-${event.id}`;
197
+ addActivity({
198
+ type: "error",
199
+ id: activityId,
200
+ expertKey: event.expertKey,
201
+ runId: event.runId,
202
+ previousActivityId: runState.lastActivityId,
203
+ delegatedBy: runState.delegatedBy,
204
+ errorName: errorEvent.error.name,
205
+ error: errorEvent.error.message,
206
+ isRetryable: errorEvent.error.isRetryable,
207
+ });
208
+ runState.lastActivityId = activityId;
209
+ runState.isComplete = true;
210
+ runState.completedReasoning = undefined;
211
+ return;
212
+ }
213
+ // Track tool calls from callTools event
214
+ if (isToolCallsEvent(event)) {
215
+ for (const toolCall of event.toolCalls) {
216
+ if (!state.tools.has(toolCall.id)) {
217
+ state.tools.set(toolCall.id, { id: toolCall.id, toolCall, logged: false });
218
+ }
219
+ }
220
+ }
221
+ // Handle stopRunByDelegate - log delegation activities
222
+ if (isStopRunByDelegateEvent(event)) {
223
+ const reasoning = runState.completedReasoning;
224
+ const delegations = event.checkpoint.delegateTo ?? [];
225
+ runState.pendingDelegateCount += delegations.length;
226
+ const delegateActivities = [];
227
+ for (const delegation of delegations) {
228
+ const existingTool = state.tools.get(delegation.toolCallId);
229
+ if (!existingTool || !existingTool.logged) {
230
+ // Mark as logged if exists
231
+ if (existingTool) {
232
+ existingTool.logged = true;
233
+ }
234
+ const activityId = `delegate-${delegation.toolCallId}`;
235
+ delegateActivities.push({
236
+ type: "delegate",
237
+ id: activityId,
238
+ expertKey: event.expertKey,
239
+ runId: event.runId,
240
+ previousActivityId: runState.lastActivityId,
241
+ delegatedBy: runState.delegatedBy,
242
+ delegateExpertKey: delegation.expert.key,
243
+ query: delegation.query,
244
+ reasoning,
245
+ });
246
+ runState.lastActivityId = activityId;
247
+ }
248
+ }
249
+ // Wrap in group if multiple delegations
250
+ const wrapped = wrapInGroupIfParallel(delegateActivities, reasoning, {
251
+ expertKey: event.expertKey,
252
+ runId: event.runId,
253
+ delegatedBy: runState.delegatedBy,
254
+ });
255
+ for (const item of wrapped) {
256
+ addActivity(item);
257
+ }
258
+ // Clear reasoning after delegation activities are logged
259
+ runState.completedReasoning = undefined;
260
+ return;
261
+ }
262
+ // Handle stopRunByInteractiveTool - log interactive tool activities
263
+ if (isStopRunByInteractiveToolEvent(event)) {
264
+ const reasoning = runState.completedReasoning;
265
+ const pendingToolCalls = event.checkpoint.pendingToolCalls ?? [];
266
+ const interactiveActivities = [];
267
+ for (const toolCall of pendingToolCalls) {
268
+ const existingTool = state.tools.get(toolCall.id);
269
+ if (!existingTool || !existingTool.logged) {
270
+ // Mark as logged if exists
271
+ if (existingTool) {
272
+ existingTool.logged = true;
273
+ }
274
+ const activityId = `interactive-${toolCall.id}`;
275
+ interactiveActivities.push({
276
+ type: "interactiveTool",
277
+ id: activityId,
278
+ expertKey: event.expertKey,
279
+ runId: event.runId,
280
+ previousActivityId: runState.lastActivityId,
281
+ delegatedBy: runState.delegatedBy,
282
+ skillName: toolCall.skillName,
283
+ toolName: toolCall.toolName,
284
+ args: toolCall.args,
285
+ reasoning,
286
+ });
287
+ runState.lastActivityId = activityId;
288
+ }
289
+ }
290
+ // Wrap in group if multiple interactive tools
291
+ const wrapped = wrapInGroupIfParallel(interactiveActivities, reasoning, {
292
+ expertKey: event.expertKey,
293
+ runId: event.runId,
294
+ delegatedBy: runState.delegatedBy,
295
+ });
296
+ for (const item of wrapped) {
297
+ addActivity(item);
298
+ }
299
+ // Clear reasoning after interactive tool activities are logged
300
+ runState.completedReasoning = undefined;
301
+ return;
302
+ }
303
+ // Process tool results
304
+ if (isToolResultsEvent(event)) {
305
+ const reasoning = runState.completedReasoning;
306
+ const toolActivities = [];
307
+ for (const toolResult of event.toolResults) {
308
+ const tool = state.tools.get(toolResult.id);
309
+ if (tool && !tool.logged) {
310
+ const activityId = `action-${tool.id}`;
311
+ const activity = toolToActivity(tool.toolCall, toolResult, reasoning, {
312
+ id: activityId,
313
+ expertKey: event.expertKey,
314
+ runId: event.runId,
315
+ previousActivityId: runState.lastActivityId,
316
+ delegatedBy: runState.delegatedBy,
317
+ });
318
+ toolActivities.push(activity);
319
+ runState.lastActivityId = activityId;
320
+ tool.logged = true;
321
+ }
322
+ }
323
+ if (toolActivities.length > 0) {
324
+ // Wrap in group if multiple tool results
325
+ const wrapped = wrapInGroupIfParallel(toolActivities, reasoning, {
326
+ expertKey: event.expertKey,
327
+ runId: event.runId,
328
+ delegatedBy: runState.delegatedBy,
329
+ });
330
+ for (const item of wrapped) {
331
+ addActivity(item);
332
+ }
333
+ runState.completedReasoning = undefined;
334
+ }
335
+ }
336
+ }
337
+ //# sourceMappingURL=event-to-activity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-to-activity.js","sourceRoot":"","sources":["../../../src/utils/event-to-activity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { ActivityOrGroup } from "@perstack/core";
2
+ /**
3
+ * Represents a group of activities belonging to the same run
4
+ */
5
+ export type RunGroup = {
6
+ runId: string;
7
+ expertKey: string;
8
+ activities: ActivityOrGroup[];
9
+ delegatedBy?: {
10
+ expertKey: string;
11
+ runId: string;
12
+ };
13
+ };
14
+ /**
15
+ * Groups activities by their runId while preserving order.
16
+ *
17
+ * This function groups activities so that each run can be displayed in its own
18
+ * visual section (e.g., separate <Static> components in Ink).
19
+ *
20
+ * @param activities - Array of activities or groups to group
21
+ * @returns Array of RunGroup objects, ordered by first appearance
22
+ */
23
+ export declare function groupActivitiesByRun(activities: ActivityOrGroup[]): RunGroup[];
24
+ //# sourceMappingURL=group-by-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-by-run.d.ts","sourceRoot":"","sources":["../../../src/utils/group-by-run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,eAAe,EAAE,CAAA;IAC7B,WAAW,CAAC,EAAE;QACZ,SAAS,EAAE,MAAM,CAAA;QACjB,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;CACF,CAAA;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,QAAQ,EAAE,CAsB9E"}