{
  "schemaVersion": "1.0",
  "title": "Actions and sessions",
  "description": "Use this page to understand how an AIP client identifies, observes, cancels, and resumes work. It is for application and connector developers who need to track an invocation beyond one request or transport connection.",
  "canonical": "https://getaip.org/docs/concepts/actions-and-sessions",
  "route": "/docs/concepts/actions-and-sessions",
  "source": "docs/concepts/actions-and-sessions.md",
  "protocol": "Agent Interoperability Protocol",
  "protocolVersion": "1.0",
  "section": "Core Concepts",
  "documentType": "Concept",
  "language": "en",
  "revision": {
    "lastReviewedRevision": "97be86e9efedf07ecf1783b03800f683f107fb04",
    "documentationSourceRevision": "9192fef3695ad294994f2712f6d156241e5e92fb",
    "basis": "frontmatter"
  },
  "downloads": {
    "md": "/docs/download/concepts/actions-and-sessions.md",
    "txt": "/docs/download/concepts/actions-and-sessions.txt",
    "json": "/docs/download/concepts/actions-and-sessions.json",
    "pdf": "/docs/download/concepts/actions-and-sessions.pdf"
  },
  "content": {
    "format": "text/markdown",
    "markdown": "---\ntitle: Actions and sessions\ndescription: Track AIP work and session context safely across queues, streams, and reconnects\nkind: explanation\naudience: developer\nappliesTo: \"1.x\"\nwritingStandard: \"aip-docs/1.0\"\nlastReviewedRevision: \"97be86e9efedf07ecf1783b03800f683f107fb04\"\n---\n\n# Actions and sessions\n\nUse this page to understand how an AIP client identifies, observes, cancels,\nand resumes work. It is for application and connector developers who need to\ntrack an invocation beyond one request or transport connection.\n\nAn action is one requested capability invocation. A session is an optional\nrelationship between two principals that can group related messages and work.\nThey have different identities, lifecycles, and recovery rules.\n\nThis distinction matters when a request is queued, a stream reconnects, a\nworker restarts, or a provider responds after the original transport has gone\naway. The transport connection is not the identity of the work.\n\nState-backed does not always mean process-durable: the reviewed runtime has\npluggable stores, including in-memory implementations. Deployment configuration\ndetermines which state survives a process or host loss. The types and runtime\nbehavior on this page apply to AIP 1.0 at source revision\n`97be86e9efedf07ecf1783b03800f683f107fb04`.\n\n## Keep four identifiers separate\n\n| Identifier | Scope | Use |\n|---|---|---|\n| `act_...` | One capability invocation | Submit, cancel, and query one unit of work |\n| `sess_...` | A relationship between an initiator and responder | Group messages and resume session context |\n| `msg_...` | One protocol envelope | Detect or correlate message delivery and replay |\n| `corr_...` | A related request or trace flow | Associate messages without merging their identities |\n\nThese are the forms produced by the typed constructors and required by their\nchecked parsers. The identifier types use transparent serialization, so a\ndeserialization boundary must invoke a checked parser or an equivalent prefix\ncheck; deserialization alone does not enforce the form.\n\nAn action can exist without a session. When a session is used, its ID is carried\nby the enclosing `Envelope.session_id`; it is not a field of `Action`. The\nruntime copies that trusted message context into its queued action record and\nexposes it later in `ActionStatus`.\n\nDo not substitute one identifier for another. Reusing an action ID for a\ndifferent capability, input, or principal is an identity conflict. Retrying the\nsame business intent is governed by the capability's idempotency contract and\nkey scope, not by inventing a new meaning for an existing action ID.\n\n## What an action carries\n\nAn `Action` always contains an `id`, `capability_id`, and structured JSON\n`input`. Every other field is optional or defaults to an empty collection:\n\n| Field | Purpose | Important boundary |\n|---|---|---|\n| `mode` | Selects `sync`, `async`, or `streaming` | Omission is treated as `sync`; the capability contract must support the selected mode |\n| `idempotency_key` | Identifies repeat business intent | Its required presence, collision behavior, scope, and retention come from the capability contract |\n| `timeout_ms` | Supplies a caller timeout | The runtime combines it with the capability service-level contract and deployment behavior |\n| `conversation` | Carries structured conversation context | It is not the AIP session lifecycle |\n| `memory_context` | Carries application state or context | Runtime transport metadata is kept outside the caller-owned durable action contract |\n| `delegation_chain` | Records delegated authorization hops | The path is checked for continuity and cycles; authority still comes from trusted context |\n| `federation` | Describes cross-domain routing context | It does not authenticate a remote domain by itself |\n| `callback` | Names an asynchronous delivery target and profile | Delivery state is tracked separately from action completion |\n| `observability` | Carries trace, span, and diagnostic fields | It is correlation metadata, not authorization |\n| `compliance` | Carries requested regimes and classification | Runtime policy remains authoritative |\n| `identity` | Projects tenant, account, user, and credential references | The runtime replaces caller claims with resolved identity at the trusted ingress path |\n| `approval` | References a decision authorizing this invocation | The decision must match the durable approval record and policy snapshot |\n| `transaction` | Selects execute, plan, commit, reconcile, or recovery intent | Transaction admission and result state are separate from the action lifecycle |\n\nAfter trusted identity and transaction normalization, the runtime retains the\ndurable action as the caller-facing work contract. Connector-facing enrichment,\nqueue leases, retry metadata, approval records, transaction records, receipts,\nand stream chunks live in separate runtime state.\n\n## One action has several status surfaces\n\nAIP deliberately separates acceptance, execution observation, and result data.\nReading one surface as if it were another creates false completion claims.\n\n### Acknowledgement\n\n`Ack.status` has five wire values:\n\n| Value | Meaning |\n|---|---|\n| `accepted` | Accepted for processing |\n| `rejected` | Rejected before processing |\n| `queued` | Accepted into a queue |\n| `streaming` | Accepted and a stream will follow |\n| `cached` | A prior idempotent result was selected |\n\nAn acknowledgement is not a successful business result. In the reviewed local\nsubmission path, an asynchronous action that passes preflight is queued and\nreturns `queued`. A contract or credential violation, approval pause,\ntransaction preview, or resolved idempotent replay can instead return an\n`ActionResult` immediately; other runtime failures can return a protocol error.\n\n### Result\n\n`ActionResult.status` is one of `completed`, `failed`, `cancelled`,\n`pending_approval`, or `requires_human`. A result can also contain structured\noutput, user-facing message parts, memory updates, usage, a receipt reference,\nor a typed protocol error.\n\nOnly `completed`, `failed`, and `cancelled` settle ordinary action execution.\n`pending_approval` and `requires_human` preserve a governed pause; the runtime\nprojects both as `pending_approval` in the lifecycle view. A failed result must\ncarry a structured error.\n\n### Lifecycle view\n\n`ActionStatus` combines queue, result, transaction, approval, receipt, and\nstream state into an operational read model. Its stable enum contains:\n\n| State | Interpretation at the reviewed runtime |\n|---|---|\n| `unknown` | No visible queue record, result, or requested retained chunk was found |\n| `accepted` | Reserved wire state; the current projection does not produce it |\n| `queued` | A queue record is waiting for execution |\n| `running` | A worker owns an executing queue record |\n| `streaming` | No result exists and at least one retained chunk was requested and found |\n| `pending_approval` | The result or queue state requires approval or human input |\n| `cancelling` | Reserved wire state; the current projection does not produce it |\n| `cancelled` | Cancellation is recorded as the action result or queue state |\n| `completed` | A completed result or completed queue state exists |\n| `failed` | A failed result or failed queue state exists |\n| `expired` | Queue state expired under retention policy |\n| `dead_lettered` | Retry processing parked the record with a dead-letter reason |\n\nThe runtime treats `cancelled`, `completed`, `failed`, `expired`, and\n`dead_lettered` as terminal lifecycle states. `unknown` is a query outcome, not\nan execution stage. The projection can change as separate records arrive, so a\nclient should retain the action ID and read the latest authorized view.\n\n## Mode changes the response pattern\n\n| Mode | Reviewed runtime path | Caller responsibility |\n|---|---|---|\n| Omitted or `sync` | Validates, authorizes, executes inline, and returns `ActionResult` | Bound the request and retain the action ID when the outcome is uncertain |\n| `async` | Performs preflight, stores a queued record, and normally returns `Ack(queued)` | Persist the action ID and query status, result, or events |\n| `streaming` | Executes through the non-async path, records chunks, and returns a final `ActionResult` | Consume ordered chunks and still use the result or lifecycle view as settlement authority |\n\nThe capability contract, not caller preference, decides which modes are\nadmitted. A long-running or approval-prone operation is normally easier to\nrecover when submitted asynchronously, but the provider's actual contract is\nauthoritative.\n\nAt the reviewed revision, asynchronous submission checks the contract,\ncredential context, authorization, approval, transaction preconditions,\nidempotency, and handler presence before queueing. Capability input-schema\nvalidation occurs when the worker enters the normal processing path, so a\nqueued acknowledgement is not proof that the input will execute.\n\n## Stream chunks are ordered action records\n\nEvery `StreamChunk` contains an action ID, a monotonically increasing\n`sequence`, a `kind`, and optional structured data or rich message content.\nKinds are `data`, `progress`, `tool`, `thought`, `preview`,\n`pending_approval`, `error`, and `done`.\n\nThe reviewed lifecycle backend applies these rules atomically per action:\n\n- the exact same sequence and content is classified as a replay and is not\n  inserted twice;\n- the same sequence with different content is rejected;\n- a new sequence must be greater than every retained earlier sequence;\n- no chunk may follow a retained `done` or `error` chunk;\n- protocol-edge ingestion rejects chunks for an unknown or already settled\n  action.\n\nAction-event reads can return events and retained chunks behind one cursor.\nClients should checkpoint that cursor and chunk sequence, handle reconnects\nidempotently, and treat the terminal action state as authoritative. These\nstorage checks do not create an exactly-once guarantee for every transport,\ncallback receiver, or external consumer.\n\n## Cancellation stops runtime work, not committed history\n\n`Cancel` can target either an action or a session. For an action, the reviewed\nruntime authorizes write access, signals the active cancellation token, calls\nthe handler's cancellation path when the action is active, and records\ncancellation in the lifecycle and queue stores. For a session, it performs an\nauthorized transition to `cancelled` when that transition is legal.\n\nA cancelled AIP result proves what the runtime recorded. It does not prove that\nan external provider reversed a side effect that had already committed.\nProvider uncertainty belongs in transaction reconciliation and compensation;\nblindly retrying a mutating action after a cancellation timeout can duplicate\nwork.\n\nThe `cancelling` enum value leaves room for an intermediate read state, but the\nreviewed lifecycle projection does not currently emit it. Do not wait for that\nstate before reading the actual result and transaction evidence.\n\n## Operational reads are authorization boundaries\n\nThe native read model supports four action operations:\n\n| Operation | Selectors and optional data |\n|---|---|\n| Read status | Action ID, tenant boundary, result, receipt chain, and retained chunks |\n| Read result | Action ID, tenant boundary, receipt metadata, and terminal event hints |\n| List actions | Lifecycle, capability, session, principal, approval, transaction, tenant, cursor, and result or receipt inclusion |\n| Read events | Action ID, tenant, cursor, kinds, retained chunks, and follow preference |\n\nList and event limits are validated in the range 1–1000. Status and result\nrequests accept `wait_ms` only up to 30,000 milliseconds. At the reviewed\nrevision, the in-process runtime lookup is immediate and does not consume\n`wait_ms`; callers should not infer long-poll behavior from the field alone.\nThe HTTP events binding implements follow mode separately through SSE.\n\nThese queries require transport-established identity and apply owner, delegated\nscope, tenant, and sensitive-field policy. A caller that cannot see an action\nmust not use `unknown` or `not_found` to infer whether another tenant owns it.\n\n## A session is optional negotiated context\n\nThe protocol `Session` stores five facts: `id`, lifecycle `state`,\n`created_at`, `initiator`, and `responder`. `SessionView` adds the latest known\nupdate time, an optional expiration, a count of non-terminal bound actions, and\noperational links.\n\nA native handshake requests profiles and optional capabilities. The reviewed\ngateway requires the claimed client to match the transport-authenticated\nprincipal, negotiates a shared profile, creates an `active` session, and returns\nits ID plus an opaque resume token. If no profile matches, it rejects the\nhandshake and creates no session.\n\nThe `SessionState` transition model permits:\n\n| Current state | Allowed next states |\n|---|---|\n| `new` | `active` |\n| `active` | `queued`, `processing`, `cancelled` |\n| `queued` | `processing`, `cancelled`, `failed` |\n| `processing` | `streaming`, `waiting_for_human`, `completed`, `failed`, `cancelled` |\n| `streaming` | `completed`, `failed`, `cancelled`, `waiting_for_human` |\n| `waiting_for_human` | `processing`, `completed`, `cancelled`, `failed` |\n| `completed`, `failed`, or `cancelled` | `settled` |\n| `settled` | None |\n\nThis is the legal state graph, not a promise that action execution automatically\ndrives every session transition. The reviewed session manager creates sessions\ndirectly as `active`; explicit runtime paths perform later transitions. Closing\na session transitions it to `cancelled`, so it can fail when the current state\ndoes not permit that edge.\n\n## Resume tokens are rotating credentials\n\nThe reviewed runtime returns a random resume token when creating a session. It\nstores a SHA-256 hash, binds the token to the authenticated session owner, gives\nit an expiration, and rotates it atomically after a resume credential passes\nthe owner, validity, and expiry checks. Reusing the old token is rejected.\n\nA resume request supplies the session ID, current token, and optional last event\ncursor. On success, the response contains the session view, session-scoped\nevents after the cursor, a next cursor, and the replacement token.\n\nThe reviewed runtime bounds one resume replay read to 100 events. Cancelled,\nfailed, and settled sessions cannot resume. Invalid, expired, and replayed credentials that\nreach token verification collapse to `session.resume_rejected`; owner or scope\nauthorization can fail earlier. A non-resumable lifecycle state returns\n`session.closed`.\n\nThe store rotates a valid token before the runtime rejects a closed lifecycle\nstate, and that error response does not expose the replacement. Do not attempt\nresume on a session already known to be cancelled, failed, or settled.\n\nTreat a resume token like a bearer credential:\n\n- never put it in a URL, log, trace field, or analytics event;\n- persist the replacement before discarding the previous response;\n- serialize concurrent resume attempts so only one receives the next valid\n  token;\n- pair the token with transport authentication for the same owner;\n- close the session, or use a deployment-owned revocation path when one is\n  exposed, if continued resume access is no longer safe.\n\nSession resume replays retained session events, not arbitrary application\nmemory or provider history. Retention and cross-process survival depend on the\nconfigured event and session stores.\n\n## Trust and data boundaries\n\n- An action or session ID selects a record; it does not authorize access to it.\n  The gateway and runtime use transport-established identity, owner, delegated\n  scope, and verified tenant context for reads and mutations.\n- `Action.input`, conversation context, memory, identity projections, results,\n  chunks, and receipts can contain sensitive data. Inclusion flags do not\n  bypass sensitive-field authorization or retention policy.\n- The caller supplies business intent, but the trusted ingress replaces\n  self-asserted action identity with resolved identity before execution.\n- A resume token proves possession of one rotating session credential. It does\n  not replace transport authentication or grant action access outside that\n  owner's policy.\n- AIP records describe runtime state. The external provider remains the source\n  of truth for side effects whose completion is uncertain.\n\n## Design choices and trade-offs\n\nKeeping actions independent from sessions lets a client invoke one operation\nwithout negotiating a long-lived relationship and lets many actions share one\nsession when continuity matters. The cost is that clients must preserve action,\nsession, message, and correlation identifiers explicitly instead of relying on\none connection-local handle.\n\nSeparate acknowledgement, result, and lifecycle types prevent queue admission\nfrom masquerading as business completion. They also require clients to choose\nthe correct read surface and reconcile records that can arrive at different\ntimes.\n\nPluggable stores make the runtime usable in tests, single-process deployments,\nand persistent installations. They also make durability an explicit deployment\nproperty. Rotating resume tokens limit replay, but require serialized resume\nattempts and careful replacement-token persistence.\n\nStable enums include `accepted` and `cancelling` even though the reviewed\nprojection does not produce them. That preserves a vocabulary for other\nbindings or later implementations, while requiring documentation to distinguish\nwire capacity from observed implementation behavior.\n\n## What these models do not guarantee\n\n- An action ID does not make a non-idempotent provider call safe to retry.\n- An acknowledgement does not prove execution or external commit.\n- A `done` stream chunk does not replace the final action result.\n- A session does not authenticate its participants without the transport and\n  gateway trust path.\n- Session grouping does not make multiple actions one atomic transaction.\n- Cancellation does not compensate an already committed side effect.\n- A lifecycle enum value does not prove the reviewed runtime currently emits\n  that value.\n- A state-backed record survives a restart only when its configured backend is\n  persistent and correctly operated.\n\n## Related pages\n\n- [Capabilities and contracts](capabilities.md)\n- [Approvals and policy](approvals-and-policy.md)\n- [Transactions and compensation](transactions-and-compensation.md)\n- [Identity and trust](identity-and-trust.md)\n- [HTTP API](../reference/http-api.md)\n",
    "text": "Actions and sessions\n\nUse this page to understand how an AIP client identifies, observes, cancels,\nand resumes work. It is for application and connector developers who need to\ntrack an invocation beyond one request or transport connection.\n\nAn action is one requested capability invocation. A session is an optional\nrelationship between two principals that can group related messages and work.\nThey have different identities, lifecycles, and recovery rules.\n\nThis distinction matters when a request is queued, a stream reconnects, a\nworker restarts, or a provider responds after the original transport has gone\naway. The transport connection is not the identity of the work.\n\nState-backed does not always mean process-durable: the reviewed runtime has\npluggable stores, including in-memory implementations. Deployment configuration\ndetermines which state survives a process or host loss. The types and runtime\nbehavior on this page apply to AIP 1.0 at source revision\n97be86e9efedf07ecf1783b03800f683f107fb04.\n\nKeep four identifiers separate\n\n| Identifier | Scope | Use |\n\n| act... | One capability invocation | Submit, cancel, and query one unit of work |\n| sess... | A relationship between an initiator and responder | Group messages and resume session context |\n| msg... | One protocol envelope | Detect or correlate message delivery and replay |\n| corr... | A related request or trace flow | Associate messages without merging their identities |\n\nThese are the forms produced by the typed constructors and required by their\nchecked parsers. The identifier types use transparent serialization, so a\ndeserialization boundary must invoke a checked parser or an equivalent prefix\ncheck; deserialization alone does not enforce the form.\n\nAn action can exist without a session. When a session is used, its ID is carried\nby the enclosing Envelope.sessionid; it is not a field of Action. The\nruntime copies that trusted message context into its queued action record and\nexposes it later in ActionStatus.\n\nDo not substitute one identifier for another. Reusing an action ID for a\ndifferent capability, input, or principal is an identity conflict. Retrying the\nsame business intent is governed by the capability's idempotency contract and\nkey scope, not by inventing a new meaning for an existing action ID.\n\nWhat an action carries\n\nAn Action always contains an id, capabilityid, and structured JSON\ninput. Every other field is optional or defaults to an empty collection:\n\n| Field | Purpose | Important boundary |\n\n| mode | Selects sync, async, or streaming | Omission is treated as sync; the capability contract must support the selected mode |\n| idempotencykey | Identifies repeat business intent | Its required presence, collision behavior, scope, and retention come from the capability contract |\n| timeoutms | Supplies a caller timeout | The runtime combines it with the capability service-level contract and deployment behavior |\n| conversation | Carries structured conversation context | It is not the AIP session lifecycle |\n| memorycontext | Carries application state or context | Runtime transport metadata is kept outside the caller-owned durable action contract |\n| delegationchain | Records delegated authorization hops | The path is checked for continuity and cycles; authority still comes from trusted context |\n| federation | Describes cross-domain routing context | It does not authenticate a remote domain by itself |\n| callback | Names an asynchronous delivery target and profile | Delivery state is tracked separately from action completion |\n| observability | Carries trace, span, and diagnostic fields | It is correlation metadata, not authorization |\n| compliance | Carries requested regimes and classification | Runtime policy remains authoritative |\n| identity | Projects tenant, account, user, and credential references | The runtime replaces caller claims with resolved identity at the trusted ingress path |\n| approval | References a decision authorizing this invocation | The decision must match the durable approval record and policy snapshot |\n| transaction | Selects execute, plan, commit, reconcile, or recovery intent | Transaction admission and result state are separate from the action lifecycle |\n\nAfter trusted identity and transaction normalization, the runtime retains the\ndurable action as the caller-facing work contract. Connector-facing enrichment,\nqueue leases, retry metadata, approval records, transaction records, receipts,\nand stream chunks live in separate runtime state.\n\nOne action has several status surfaces\n\nAIP deliberately separates acceptance, execution observation, and result data.\nReading one surface as if it were another creates false completion claims.\n\nAcknowledgement\n\nAck.status has five wire values:\n\n| Value | Meaning |\n\n| accepted | Accepted for processing |\n| rejected | Rejected before processing |\n| queued | Accepted into a queue |\n| streaming | Accepted and a stream will follow |\n| cached | A prior idempotent result was selected |\n\nAn acknowledgement is not a successful business result. In the reviewed local\nsubmission path, an asynchronous action that passes preflight is queued and\nreturns queued. A contract or credential violation, approval pause,\ntransaction preview, or resolved idempotent replay can instead return an\nActionResult immediately; other runtime failures can return a protocol error.\n\nResult\n\nActionResult.status is one of completed, failed, cancelled,\npendingapproval, or requireshuman. A result can also contain structured\noutput, user-facing message parts, memory updates, usage, a receipt reference,\nor a typed protocol error.\n\nOnly completed, failed, and cancelled settle ordinary action execution.\npendingapproval and requireshuman preserve a governed pause; the runtime\nprojects both as pendingapproval in the lifecycle view. A failed result must\ncarry a structured error.\n\nLifecycle view\n\nActionStatus combines queue, result, transaction, approval, receipt, and\nstream state into an operational read model. Its stable enum contains:\n\n| State | Interpretation at the reviewed runtime |\n\n| unknown | No visible queue record, result, or requested retained chunk was found |\n| accepted | Reserved wire state; the current projection does not produce it |\n| queued | A queue record is waiting for execution |\n| running | A worker owns an executing queue record |\n| streaming | No result exists and at least one retained chunk was requested and found |\n| pendingapproval | The result or queue state requires approval or human input |\n| cancelling | Reserved wire state; the current projection does not produce it |\n| cancelled | Cancellation is recorded as the action result or queue state |\n| completed | A completed result or completed queue state exists |\n| failed | A failed result or failed queue state exists |\n| expired | Queue state expired under retention policy |\n| deadlettered | Retry processing parked the record with a dead-letter reason |\n\nThe runtime treats cancelled, completed, failed, expired, and\ndeadlettered as terminal lifecycle states. unknown is a query outcome, not\nan execution stage. The projection can change as separate records arrive, so a\nclient should retain the action ID and read the latest authorized view.\n\nMode changes the response pattern\n\n| Mode | Reviewed runtime path | Caller responsibility |\n\n| Omitted or sync | Validates, authorizes, executes inline, and returns ActionResult | Bound the request and retain the action ID when the outcome is uncertain |\n| async | Performs preflight, stores a queued record, and normally returns Ack(queued) | Persist the action ID and query status, result, or events |\n| streaming | Executes through the non-async path, records chunks, and returns a final ActionResult | Consume ordered chunks and still use the result or lifecycle view as settlement authority |\n\nThe capability contract, not caller preference, decides which modes are\nadmitted. A long-running or approval-prone operation is normally easier to\nrecover when submitted asynchronously, but the provider's actual contract is\nauthoritative.\n\nAt the reviewed revision, asynchronous submission checks the contract,\ncredential context, authorization, approval, transaction preconditions,\nidempotency, and handler presence before queueing. Capability input-schema\nvalidation occurs when the worker enters the normal processing path, so a\nqueued acknowledgement is not proof that the input will execute.\n\nStream chunks are ordered action records\n\nEvery StreamChunk contains an action ID, a monotonically increasing\nsequence, a kind, and optional structured data or rich message content.\nKinds are data, progress, tool, thought, preview,\npendingapproval, error, and done.\n\nThe reviewed lifecycle backend applies these rules atomically per action:\n• the exact same sequence and content is classified as a replay and is not\n  inserted twice;\n• the same sequence with different content is rejected;\n• a new sequence must be greater than every retained earlier sequence;\n• no chunk may follow a retained done or error chunk;\n• protocol-edge ingestion rejects chunks for an unknown or already settled\n  action.\n\nAction-event reads can return events and retained chunks behind one cursor.\nClients should checkpoint that cursor and chunk sequence, handle reconnects\nidempotently, and treat the terminal action state as authoritative. These\nstorage checks do not create an exactly-once guarantee for every transport,\ncallback receiver, or external consumer.\n\nCancellation stops runtime work, not committed history\n\nCancel can target either an action or a session. For an action, the reviewed\nruntime authorizes write access, signals the active cancellation token, calls\nthe handler's cancellation path when the action is active, and records\ncancellation in the lifecycle and queue stores. For a session, it performs an\nauthorized transition to cancelled when that transition is legal.\n\nA cancelled AIP result proves what the runtime recorded. It does not prove that\nan external provider reversed a side effect that had already committed.\nProvider uncertainty belongs in transaction reconciliation and compensation;\nblindly retrying a mutating action after a cancellation timeout can duplicate\nwork.\n\nThe cancelling enum value leaves room for an intermediate read state, but the\nreviewed lifecycle projection does not currently emit it. Do not wait for that\nstate before reading the actual result and transaction evidence.\n\nOperational reads are authorization boundaries\n\nThe native read model supports four action operations:\n\n| Operation | Selectors and optional data |\n\n| Read status | Action ID, tenant boundary, result, receipt chain, and retained chunks |\n| Read result | Action ID, tenant boundary, receipt metadata, and terminal event hints |\n| List actions | Lifecycle, capability, session, principal, approval, transaction, tenant, cursor, and result or receipt inclusion |\n| Read events | Action ID, tenant, cursor, kinds, retained chunks, and follow preference |\n\nList and event limits are validated in the range 1–1000. Status and result\nrequests accept waitms only up to 30,000 milliseconds. At the reviewed\nrevision, the in-process runtime lookup is immediate and does not consume\nwaitms; callers should not infer long-poll behavior from the field alone.\nThe HTTP events binding implements follow mode separately through SSE.\n\nThese queries require transport-established identity and apply owner, delegated\nscope, tenant, and sensitive-field policy. A caller that cannot see an action\nmust not use unknown or notfound to infer whether another tenant owns it.\n\nA session is optional negotiated context\n\nThe protocol Session stores five facts: id, lifecycle state,\ncreatedat, initiator, and responder. SessionView adds the latest known\nupdate time, an optional expiration, a count of non-terminal bound actions, and\noperational links.\n\nA native handshake requests profiles and optional capabilities. The reviewed\ngateway requires the claimed client to match the transport-authenticated\nprincipal, negotiates a shared profile, creates an active session, and returns\nits ID plus an opaque resume token. If no profile matches, it rejects the\nhandshake and creates no session.\n\nThe SessionState transition model permits:\n\n| Current state | Allowed next states |\n\n| new | active |\n| active | queued, processing, cancelled |\n| queued | processing, cancelled, failed |\n| processing | streaming, waitingforhuman, completed, failed, cancelled |\n| streaming | completed, failed, cancelled, waitingforhuman |\n| waitingforhuman | processing, completed, cancelled, failed |\n| completed, failed, or cancelled | settled |\n| settled | None |\n\nThis is the legal state graph, not a promise that action execution automatically\ndrives every session transition. The reviewed session manager creates sessions\ndirectly as active; explicit runtime paths perform later transitions. Closing\na session transitions it to cancelled, so it can fail when the current state\ndoes not permit that edge.\n\nResume tokens are rotating credentials\n\nThe reviewed runtime returns a random resume token when creating a session. It\nstores a SHA-256 hash, binds the token to the authenticated session owner, gives\nit an expiration, and rotates it atomically after a resume credential passes\nthe owner, validity, and expiry checks. Reusing the old token is rejected.\n\nA resume request supplies the session ID, current token, and optional last event\ncursor. On success, the response contains the session view, session-scoped\nevents after the cursor, a next cursor, and the replacement token.\n\nThe reviewed runtime bounds one resume replay read to 100 events. Cancelled,\nfailed, and settled sessions cannot resume. Invalid, expired, and replayed credentials that\nreach token verification collapse to session.resumerejected; owner or scope\nauthorization can fail earlier. A non-resumable lifecycle state returns\nsession.closed.\n\nThe store rotates a valid token before the runtime rejects a closed lifecycle\nstate, and that error response does not expose the replacement. Do not attempt\nresume on a session already known to be cancelled, failed, or settled.\n\nTreat a resume token like a bearer credential:\n• never put it in a URL, log, trace field, or analytics event;\n• persist the replacement before discarding the previous response;\n• serialize concurrent resume attempts so only one receives the next valid\n  token;\n• pair the token with transport authentication for the same owner;\n• close the session, or use a deployment-owned revocation path when one is\n  exposed, if continued resume access is no longer safe.\n\nSession resume replays retained session events, not arbitrary application\nmemory or provider history. Retention and cross-process survival depend on the\nconfigured event and session stores.\n\nTrust and data boundaries\n• An action or session ID selects a record; it does not authorize access to it.\n  The gateway and runtime use transport-established identity, owner, delegated\n  scope, and verified tenant context for reads and mutations.\n• Action.input, conversation context, memory, identity projections, results,\n  chunks, and receipts can contain sensitive data. Inclusion flags do not\n  bypass sensitive-field authorization or retention policy.\n• The caller supplies business intent, but the trusted ingress replaces\n  self-asserted action identity with resolved identity before execution.\n• A resume token proves possession of one rotating session credential. It does\n  not replace transport authentication or grant action access outside that\n  owner's policy.\n• AIP records describe runtime state. The external provider remains the source\n  of truth for side effects whose completion is uncertain.\n\nDesign choices and trade-offs\n\nKeeping actions independent from sessions lets a client invoke one operation\nwithout negotiating a long-lived relationship and lets many actions share one\nsession when continuity matters. The cost is that clients must preserve action,\nsession, message, and correlation identifiers explicitly instead of relying on\none connection-local handle.\n\nSeparate acknowledgement, result, and lifecycle types prevent queue admission\nfrom masquerading as business completion. They also require clients to choose\nthe correct read surface and reconcile records that can arrive at different\ntimes.\n\nPluggable stores make the runtime usable in tests, single-process deployments,\nand persistent installations. They also make durability an explicit deployment\nproperty. Rotating resume tokens limit replay, but require serialized resume\nattempts and careful replacement-token persistence.\n\nStable enums include accepted and cancelling even though the reviewed\nprojection does not produce them. That preserves a vocabulary for other\nbindings or later implementations, while requiring documentation to distinguish\nwire capacity from observed implementation behavior.\n\nWhat these models do not guarantee\n• An action ID does not make a non-idempotent provider call safe to retry.\n• An acknowledgement does not prove execution or external commit.\n• A done stream chunk does not replace the final action result.\n• A session does not authenticate its participants without the transport and\n  gateway trust path.\n• Session grouping does not make multiple actions one atomic transaction.\n• Cancellation does not compensate an already committed side effect.\n• A lifecycle enum value does not prove the reviewed runtime currently emits\n  that value.\n• A state-backed record survives a restart only when its configured backend is\n  persistent and correctly operated.\n\nRelated pages\n• Capabilities and contracts (capabilities.md)\n• Approvals and policy (approvals-and-policy.md)\n• Transactions and compensation (transactions-and-compensation.md)\n• Identity and trust (identity-and-trust.md)\n• HTTP API (../reference/http-api.md)\n"
  },
  "integrity": {
    "algorithm": "sha256",
    "sourceDigest": "04e3421e499d34585a09199ba8409984d68e32263536f55c05bcdf24a48e0aad"
  }
}
