AgentStateProvider
为一棵子树提供一个仲裁器;用 hooks 喂它、读它。
| 没有会话 | |||
headless 的 build 会话被记录——它出现在表里——但从不显示。当它出错时就不再是 headless,会接管脸,因为出错需要人。
useArbiter
在组件生命周期内运行一个仲裁器,并在显示的状态或说明变化时重渲染——底下会话来去而结果不变时不会。
选项在挂载时读取一次,与 createCharacter 是同一份契约。接受所有 ArbiterOptions 字段;每条规则的作用见集成指南的仲裁一节。
AgentStateProvider 与 useAgentState
AgentStateProvider 用它的 props 调用 useArbiter 并共享结果。把它放在页面显示智能体的那部分之上;从事件到达的任何地方喂它——WebSocket 处理器、useStateChannel、钩子脚本——再在渲染角色的组件里用 useAgentState 读取。
useAgentState 在 provider 之外会抛出,因为没有合理的默认值可退。useOptionalAgentState 则返回 null,给两种情况都能工作的组件用——通道 hooks 用它找默认的接收方。
HUD 与状态同行
一条消息可以在 tips 之外带一个 hud——见协议。仲裁器把它留在胜出会话的 ArbiterResult 上,value 以 hud 暴露出来,于是表盘和脸走同一套仲裁:优先级落败的会话不能把自己的进度环画在胜者的表情外面。可以直接传给角色,也可以让 AgentHud 替你读 provider。
useAgentHud() 返回同一个表盘,没有 provider 时返回 null,给只想要那个环的组件用。
通道
两个 hooks 从 React 树之外把消息带进来。不给显式 onUpdate 时,两者都投递到最近的 provider。
useStateChannel 只接受来自 allowOrigin(默认页面自身来源)的 { type: 'aora:state', payload } 消息。只有当页面本身就是沙箱化的小组件时才传 '*'。useEventSourceChannel 把每个事件的 data 解析为一条协议消息;EventSource 自己会重连,所以 hook 只报告状态。两者都接受 enabled: false 以在不卸载的情况下断开。
两者都让每条消息经过 normalize,所以畸形消息会进 onError,永远到不了仲裁器。
不用 React
provider 只是薄薄一层。同一个仲裁器在任何地方都能跑:
API
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
children* | string | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<AwaitedReactNode> | null | — | — |
cancel | ((handle: unknown) => void) | — | — |
idleState | "idle" | "sleeping" | "drowsy" | "bored" | "waking" | "powering-down" | "listening" | "thinking" | "searching" | "reading" | "writing" | "working" | "loading" | "progress" | "radar" | "orbit" | "dictating" | "uploading" | "sending" | "receiving" | "messaging" | "waiting" | "spawning" | "composing" | "dragging" | "happy" | "excited" | "laughing" | "playful" | "proud" | "celebrate" | "bouncing" | "shy" | "sad" | "angry" | "confused" | "suspicious" | "surprised" | "scared" | "curious" | "humming" | "alerting" | "notifying" | "refusing" | — | What to show when no session is visible. Default `idle`. |
maxSessions | number | — | Upper bound on tracked sessions; the stalest is evicted. Default 32. |
minDisplayMs | number | { defaultMs?: number | undefined; byState?: Partial<Record<"idle" | "sleeping" | "drowsy" | "bored" | "waking" | "powering-down" | "listening" | "thinking" | "searching" | "reading" | "writing" | "working" | "loading" | "progress" | "radar" | "orbit" | "dictating" | "uploading" | "sending" | "receiving" | "messaging" | "waiting" | "spawning" | "composing" | "dragging" | "happy" | "excited" | "laughing" | "playful" | "proud" | "celebrate" | "bouncing" | "shy" | "sad" | "angry" | "confused" | "suspicious" | "surprised" | "scared" | "curious" | "humming" | "alerting" | "notifying" | "refusing", number>> | undefined; } | — | Dwell before a state may be replaced. A number, or per-state overrides. Default 900 ms. |
now | (() => number) | — | Injectable clock and timers. |
onApply | ((result: ArbiterResult) => void) | — | Called whenever the displayed state changes. |
oneshot | readonly ("idle" | "sleeping" | "drowsy" | "bored" | "waking" | "powering-down" | "listening" | "thinking" | "searching" | "reading" | "writing" | "working" | "loading" | "progress" | "radar" | "orbit" | "dictating" | "uploading" | "sending" | "receiving" | "messaging" | "waiting" | "spawning" | "composing" | "dragging" | "happy" | "excited" | "laughing" | "playful" | "proud" | "celebrate" | "bouncing" | "shy" | "sad" | "angry" | "confused" | "suspicious" | "surprised" | "scared" | "curious" | "humming" | "alerting" | "notifying" | "refusing")[] | — | Override which states are events. Defaults to the protocol's one-shot ids. |
priority | Partial<Record<"idle" | "sleeping" | "drowsy" | "bored" | "waking" | "powering-down" | "listening" | "thinking" | "searching" | "reading" | "writing" | "working" | "loading" | "progress" | "radar" | "orbit" | "dictating" | "uploading" | "sending" | "receiving" | "messaging" | "waiting" | "spawning" | "composing" | "dragging" | "happy" | "excited" | "laughing" | "playful" | "proud" | "celebrate" | "bouncing" | "shy" | "sad" | "angry" | "confused" | "suspicious" | "surprised" | "scared" | "curious" | "humming" | "alerting" | "notifying" | "refusing", number>> | — | Priority overrides, by state. Higher wins. |
schedule | ((fn: () => void, ms: number) => unknown) | — | — |
sessionTtlMs | number | — | Forget a session after this long without an update. Default 120 s. |
tickMs | number | — | How often to expire silent sessions. Default 15 s; 0 disables. |