@perstack/react
v0.0.44
Published
React hooks and utilities for Perstack integration
Readme
@perstack/react
React hooks and utilities for Perstack integration.
Installation
npm install @perstack/react
# or
pnpm add @perstack/reactUsage
useLogStore
The main hook for managing Perstack events. It separates events into:
- LogEntry[] - Accumulated log from RunEvent (state machine transitions)
- RuntimeState - Current state from RuntimeEvent (runtime environment)
import { useLogStore } from "@perstack/react"
function MyComponent() {
const { logs, runtimeState, isComplete, eventCount, addEvent, appendHistoricalEvents } =
useLogStore()
// Add events from your event source
useEffect(() => {
const eventSource = new EventSource("/api/events")
eventSource.onmessage = (e) => {
addEvent(JSON.parse(e.data))
}
return () => eventSource.close()
}, [addEvent])
return (
<div>
{logs.map((entry) => (
<LogRow key={entry.id} action={entry.action} />
))}
{Object.entries(runtimeState.streaming.runs).map(([runId, run]) => (
<div key={runId}>
{run.isReasoningActive && (
<div>[{run.expertKey}] Reasoning: {run.reasoning}</div>
)}
{run.isRunResultActive && (
<div>[{run.expertKey}] Generating: {run.runResult}</div>
)}
</div>
))}
</div>
)
}useRuntimeState
A lower-level hook for managing RuntimeState separately.
import { useRuntimeState } from "@perstack/react"
function MyComponent() {
const { runtimeState, handleRuntimeEvent, clearStreaming, resetRuntimeState } = useRuntimeState()
// Returns true if the event was handled (RuntimeEvent)
// Returns false if the event should be processed elsewhere (RunEvent)
const wasHandled = handleRuntimeEvent(event)
}Utility Functions
For advanced use cases, you can use the utility functions directly:
import {
createInitialLogProcessState,
processRunEventToLog,
toolToCheckpointAction,
} from "@perstack/react"
// Create processing state
const state = createInitialLogProcessState()
// Process RunEvent into LogEntry
const logs = []
processRunEventToLog(state, event, (entry) => logs.push(entry))
// Convert a single tool call + result to CheckpointAction
const action = toolToCheckpointAction(toolCall, toolResult, reasoning)API
useLogStore()
Returns an object with:
logs: Array ofLogEntryrepresenting completed actions (append-only)runtimeState: CurrentRuntimeStateincluding streaming stateisComplete: Whether the run is completeeventCount: Total number of processed eventsaddEvent(event): Add a new event to processappendHistoricalEvents(events): Append historical events to logs
Note: Logs are append-only and never cleared. This is required for compatibility with Ink's <Static> component.
useRuntimeState()
Returns an object with:
runtimeState: CurrentRuntimeStatehandleRuntimeEvent(event): Process a RuntimeEvent, returnstrueif handledclearStreaming(): Reset streaming stateresetRuntimeState(): Reset entire runtime state
Types
LogEntry
Wraps CheckpointAction with an ID for React key purposes:
type LogEntry = {
id: string
action: CheckpointAction
}RuntimeState
Captures current runtime environment state:
type RuntimeState = {
query?: string
expertName?: string
model?: string
runtime?: string
runtimeVersion?: string
skills: Map<string, SkillState>
dockerBuild?: DockerBuildState
dockerContainers: Map<string, DockerContainerState>
proxyAccess?: ProxyAccessState
streaming: StreamingState
}StreamingState
Real-time streaming state, organized by run ID to support parallel execution:
type PerRunStreamingState = {
expertKey: string
reasoning?: string
runResult?: string
isReasoningActive?: boolean
isRunResultActive?: boolean
}
type StreamingState = {
runs: Record<string, PerRunStreamingState>
}When multiple experts run in parallel (e.g., parallel delegation), each run's streaming content is tracked separately by its runId.
License
Apache-2.0
