Files
Arvin Xu 93fc45ff77 ♻️ refactor(agent-runtime): carve principal, plan and host slots out of state.metadata (#19513)
Third and last step of the state restructure (#19498 world/binding, #19505 origin). The remaining creation-time facts in `state.metadata` fall into three business groups, each now a typed slot on `AgentState`:

- `principal` — under whose authority the run acts and what it may do: `actor.{shareVisitor, bot, deviceScope}`, `policy.deviceAccess`, `audit.{clientIp, userAgent}`. Decided at creation and re-presented, never re-derived, at each dispatch boundary.
- `plan` — how the run executes: `execution` (the resolved `ExecutionPlan`), `skills`, `stream`, `eval`, `workingDirectory`. The duplicated `metadata.modelRuntimeConfig` is dropped in favour of the existing top-level `modelRuntimeConfig`.
- `host` — what the host needs to deliver and retry the run: `hooks` (serialized webhook configs) and `queue.{retries, retryDelay}`. Carried by the runtime without interpretation.

`ExecutionPlan` / `ExecutionPlanUnroutedReason` move to `@lobechat/types` so the runtime can type the slot; `src/helpers/executionTarget` re-exports them. `normalizeAgentState` lifts the legacy keys on load and folds a legacy `metadata.modelRuntimeConfig` into the top-level slot when it is absent. `HookDispatcher.dispatch` accepts the wire-shape `SerializedAgentHook[]` the slot carries and narrows to `SerializedHook` itself; `isAgentShareRun` takes the state; `resolveRunActiveDeviceId` / `resolveRunProjectSkills` read `plan` and `principal`; the dynamic intervention resolvers receive the plan's working directory alongside the ledger.

`metadata` is now the run ledger only: what the runtime and host write while the operation executes.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 13:18:32 +08:00
..