7.0 KiB
Developer Guide — Multi-turn Transaction State
This document defines the operational contract for multi-turn transactions in Agent Framework OCI. It is normative for hosts and templates that use AgentRuntime, LangGraph checkpoints, and transactional tools.
1. Goal
A transaction may span multiple turns:
User: cancel my order
Framework: provide the order number
User: PED-1001
Framework: confirm cancellation?
User: yes
Framework: execute the tool
The framework must preserve the transaction across all turns without relying on LLM reclassification, keyword routing, or re-extraction of parameters already collected.
2. Canonical transaction state
The canonical in-flight transaction is active_transaction.
active_transaction: dict[str, Any]
last_transaction: dict[str, Any]
Every AgentState used by a host that enables multi-turn transactions MUST declare both fields. LangGraph uses the state schema for checkpoint persistence, so a field created dynamically by the runtime alone is not a safe durable contract.
Minimal example:
from typing import Any, TypedDict
class AgentState(TypedDict, total=False):
# ...normal fields...
selected_tool_call: dict[str, Any]
pending_tool_call: dict[str, Any]
active_transaction: dict[str, Any]
last_transaction: dict[str, Any]
transaction_status: str
missing_parameters: list[str]
confirmation_required: bool
confirmation_received: bool
3. Field responsibilities
| Field | Responsibility | Rule |
|---|---|---|
active_transaction |
Canonical in-flight transaction | Must survive checkpoint/resume while active. |
last_transaction |
Snapshot of the latest terminal transaction | Used for audit/evidence; does not automatically reactivate a transaction. |
transaction_status |
Current logical status | E.g. COLLECTING_PARAMETERS, AWAITING_CONFIRMATION, COMPLETED, CANCELLED, OUT_OF_SCOPE. |
missing_parameters |
Parameters still required | Must reflect canonical transaction state, not only the current message. |
selected_tool_call |
Auxiliary/backward-compatible state | Must not replace active_transaction as canonical state. |
pending_tool_call |
Auxiliary/backward-compatible state | May support compatibility but is not the primary latch. |
next_state |
Workflow routing guidance | Keeps the correct node/agent during collection/confirmation. |
transaction_pre_validation |
Pre-validation evidence | Stores validation before confirmation/execution. |
transaction_evidence |
Execution evidence | Stores results and the transaction execution trail. |
4. Recommended lifecycle
IDLE
↓ transactional intent
COLLECTING_PARAMETERS
↓ complete parameters
PRE_VALIDATION (when configured)
↓ eligible
AWAITING_CONFIRMATION
↓ positive confirmation
EXECUTING
↓
COMPLETED
Alternative terminal outcomes include CANCELLED, OUT_OF_SCOPE, and FAILED.
5. Incremental parameter merge
A later answer must complement the existing transaction instead of rebuilding it from the latest text only.
existing = dict((state.get("active_transaction") or {}).get("arguments") or {})
new_values = {"amount": "71.99"}
arguments = {**existing, **new_values}
Previously collected arguments must remain available on subsequent turns.
6. Routing precedence during an active transaction
When active_transaction is in COLLECTING_PARAMETERS, the message must first be evaluated as a possible answer to pending parameters.
Normative precedence:
- clearly fills a pending parameter → continue transaction;
- explicit cancel/abandon → cancel transaction;
- unambiguous new intent → interrupt and route;
- generic keyword in the same domain/agent → do not interrupt;
- ambiguous message → keep transaction and clarify.
| Current state | Message | Correct result |
|---|---|---|
retail_order_cancel, missing order_id |
PED-1001 |
Continue cancellation and fill order_id. |
retail_order_cancel, missing order_id |
the order is PED-1001 |
Continue cancellation; order must not switch to tracking. |
contestation, missing amount |
R$ 71.99 |
Continue contestation and fill amount. |
| pending cancellation | forget it, show my bill |
Explicit interruption is allowed. |
| pending cancellation | track my order |
Unambiguous shift to tracking is allowed. |
7. Checkpoint and resume
Before normal routing, restore the checkpoint with the same conversation identity (tenant_id, agent_id, session_id/conversation_key according to the host contract).
An active transaction must be resumed before generic keyword routing or LLM continuity. COLLECTING_PARAMETERS without active_transaction should be treated as inconsistent state and diagnosed rather than silently restarting the tool.
8. Framework vs. agent responsibility
Framework owns latch persistence, argument merge, collection/confirmation states, resume precedence, deterministic confirmation, idempotency/evidence, and checkpoint/resume.
The agent owns domain tools, required parameters, domain messages, domain eligibility/pre-validation, and customer-facing final responses. It must not create a parallel transaction engine.
9. New host/template checklist
AgentStatedeclaresactive_transaction.AgentStatedeclareslast_transaction.transaction_statusandmissing_parametersare declared when used.- Checkpoint provider is compatible with the state schema.
- The same conversation identity is reused across turns.
- New parameters are merged with previously collected arguments.
- Pending parameter answers take precedence over generic keyword routing.
- Explicit intent shifts remain possible.
- Transactional agent responses propagate
transaction_state_patch(state)where required by the template. - Multi-turn tests cover collection, confirmation, interruption, and resume.
10. Minimum regression tests
Test order cancellation with a pending order_id, contestation with a subject collected on the first turn and amount on the second, explicit interruption to a different intent, and checkpoint/resume using the same conversation identity.
11. Anti-patterns
- rebuilding the transaction from only the latest message;
- using
selected_tool_callas the only latch source; - removing
active_transactionbecause it appears redundant; - allowing a generic keyword such as
orderto interruptorder_idcollection; - keeping parameters only in node-local variables;
- duplicating transaction confirmation in the agent prompt;
- clearing the latch before a terminal state.
12. Project references
specs/SPEC-002-Agent-Runtime.mdspecs/SPEC-010-Agent-Development.mdtemplates/agent_template_backend/app/state.pylibs/agent_framework/src/agent_framework/runtime/agent_runtime.pylibs/agent_framework/src/agent_framework/routing/enterprise_router.pyTuning-Performance/Deterministic_Transactional_Workflow/Tuning-Performance/Transaction_Pre_Validation/Tuning-Performance/Transaction_Evidence/