> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sec0.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent State

> Propagate canonical agent state across hops via headers for full custody and analytics.

`sec0-sdk/agent-state` provides the primitives for **propagating agent state across hops** in the Sec0 runtime. It ensures state is predictable, header-safe, and supports opt-in analytics for intent-vs-execution deviation tracking.

## Runtime Contextual Agent Governance

In a multi-hop agentic system, a single user request can traverse an orchestrator, multiple agents, tool servers, and external APIs. Each hop needs **context** about who initiated the request, what the objective is, and what happened at previous hops to make governance decisions. Sec0 solves this by encoding runtime context into a canonical agent state payload that flows with every call.

```mermaid theme={null}
sequenceDiagram
    participant U as User
    participant O as Orchestrator
    participant A as Agent
    participant MW as Middleware
    participant TS as Tool Server

    U->>O: Request
    Note over O: @sec0.orchestrator()<br/>Sets objective, plan chain<br/>Creates runId + traceId

    O->>A: Delegate (x-agent-state)
    Note over A: @sec0.agent()<br/>Reads parent state<br/>Sets agent variables<br/>Appends to custody chain

    A->>MW: callTool (x-agent-state)
    Note over MW: Extracts nodeId from state<br/>Fetches agent-scoped policy<br/>Evaluates compliance rules<br/>using objective + context

    MW->>TS: Forward (policy: allow)
    TS-->>MW: Result
    Note over MW: Signs audit envelope<br/>with agent context

    MW-->>A: Result + audit
    A-->>O: Result + updated state
    O-->>U: Response
```

At each hop, the agent state carries:

| Context     | Purpose                                  | Governance Use                                                                      |
| ----------- | ---------------------------------------- | ----------------------------------------------------------------------------------- |
| `nodeId`    | Identifies which agent/hop is executing  | Resolves [agent-scoped policy](/docs/reference/agent-scoped-policies) for this node |
| `runId`     | Links all hops in a single request graph | Correlates audit trail across distributed hops                                      |
| `variables` | Scoped key-value pairs per hop type      | Compliance rules can inspect objective, plan, and execution state                   |
| `metadata`  | Arbitrary data attached by each hop      | Enriches audit envelopes with model, temperature, etc.                              |
| `parentRef` | Reference to the parent hop              | Reconstructs the hop graph for deviation analysis                                   |

This means the middleware can enforce **contextual** governance: a compliance rule can evaluate not just the tool input/output, but also the agent's stated objective, the orchestrator's plan, and the full chain of prior hops. See the [Agent Scoped Policies](/docs/reference/agent-scoped-policies) reference for how `nodeId` drives per-agent policy selection, and the [Instrumentation Config](/docs/reference/instrumentation-config) reference for how hops are configured.

## How Agent State Works

As a request flows through an agentic runtime (agent, orchestrator, gateway, tool), each hop can:

1. **Read** the incoming agent state from headers
2. **Enrich** it with hop-specific variables and metadata
3. **Forward** the updated state to the next hop

This creates a continuous context chain that enables downstream hops to make informed decisions and enables audit analytics across the full request graph.

## State Structure

```typescript theme={null}
interface AgentStatePayload {
  nodeId: string;            // Logical node identifier (required)
  runId?: string;            // Run/inference identifier
  parentRef?: string;        // Parent hop reference

  variables?: {              // Scoped variables by hop type
    AGENT?: Record<string, any>;
    ORCHESTRATOR?: Record<string, any>;
    GATEWAY?: Record<string, any>;
    SERVER?: Record<string, any>;
    TOOL?: Record<string, any>;
  };

  metadata?: Record<string, any>;  // Arbitrary metadata
}
```

### Variable Scopes

Each hop type writes to its own scope, preventing collisions:

| Scope          | Written By             | Typical Contents                         |
| -------------- | ---------------------- | ---------------------------------------- |
| `AGENT`        | Agent hops             | Objective, execution reflections, status |
| `ORCHESTRATOR` | Orchestrator hops      | Plan chain, workflow metadata            |
| `GATEWAY`      | Gateway hops           | AP2 analytics, risk telemetry            |
| `SERVER`       | Server/middleware hops | Server-level signals, decision data      |
| `TOOL`         | Tool hops              | Tool-specific state                      |

## Header Transport

Agent state is propagated across HTTP/MCP boundaries via three canonical headers:

| Header          | Content                           |
| --------------- | --------------------------------- |
| `x-node-id`     | The node identifier               |
| `x-agent-ref`   | The run/inference reference       |
| `x-agent-state` | Base64-encoded full state payload |

### Encoding

```typescript theme={null}
import { encodeAgentStateHeaders } from "sec0-sdk/agent-state";

const headers = encodeAgentStateHeaders({
  nodeId: "planner",
  runId: "run-123",
  variables: {
    AGENT: { objective: "Find a PCP within 10 miles" },
  },
});
// Returns: { "x-node-id": "planner", "x-agent-ref": "run-123", "x-agent-state": "..." }
```

### Decoding

```typescript theme={null}
import { extractAgentStateFromHeaders } from "sec0-sdk/agent-state";

const state = extractAgentStateFromHeaders(req.headers);
// state.nodeId, state.runId, state.variables, state.metadata
```

### Merging Variables

```typescript theme={null}
import { mergeAgentVariables } from "sec0-sdk/agent-state";

// Merge new data into a specific scope (existing keys are overwritten)
const merged = mergeAgentVariables(existingVars, "GATEWAY", {
  gateway: "sec0.gateway@1.0.0",
  status: "ok",
});
```

## Analytics Conventions

`sec0-sdk/agent-state` defines opt-in analytics payloads that higher-level components can include in agent state variables. These are **never** automatically enabled. Application authors must explicitly turn on the relevant telemetry flags.

### Gateway Analytics

When analytics are enabled on the gateway, the `GATEWAY` scope contains:

```typescript theme={null}
{
  analytics: {
    version: 1,
    ap2?: {
      intent_id?: string;
      cart_id?: string;
      issuer_did?: string;
      subject_did?: string;
      constraints_sha256?: string;
      cart_sha256?: string;
      reason?: string;
    },
    risk?: {
      decision?: string;         // allow | deny | would_deny
      risk_tags?: string[];      // ['egress_violation', ...]
      egress_domain?: string;
      fs_path?: string;
      latency_ms?: number;
      idempotency_key?: string;
    }
  }
}
```

### Orchestrator Plan Chain

Orchestrators can record their planned intent chain:

```typescript theme={null}
{
  orchestrator_plan: {
    version: 1,
    steps: [
      {
        id: "step-1",
        type: "tool",              // "tool" | "agent" | "action"
        target_tool?: "fetch@1.0",
        target_node_id?: "sub-agent",
        expected_args_sha256?: "...",
        metadata?: { model: "gpt-4o-mini" }
      }
    ]
  }
}
```

### Agent Execution Reflection

Agents can reflect what actually occurred:

```typescript theme={null}
{
  agent_execution: {
    version: 1,
    runs: [
      {
        plan_step_id: "step-1",
        tool_invoked: "fetch@1.0",
        actual_args_sha256: "...",
        status: "ok",
        deviation_reason?: "unexpected_args",
        metadata?: { retries: 1 }
      }
    ]
  }
}
```

By keeping both plan and execution records in agent state, analytics can compute deviation metrics without inspecting raw prompts or payloads.

### Safety Rules

1. **Derived only**: Never store raw mandates, secrets, or configuration in agent state
2. **Version everything**: Each payload has a `version` field for forward compatibility
3. **Opt-in**: Higher-level SDKs require an explicit toggle before adding telemetry to agent state
