#Revise work in one Agent conversation
An application can ask an Agent to draft an incident brief, supply a correction, and obtain a revised answer in the same native conversation. The application chooses when to continue; the operator bounds how many turns may run.
Use the ordinary native Agent package. In its Binding, allow two turns with an inline policy:
Choose your installed client and model; this is not a product default. Review the changed grant. One-shot calls remain unchanged. The HTTP Agent package does not implement continuing conversations and rejects them before dispatch.
#Build a two-turn Flow
With Jig installed and a native client configured, create an ordinary project and caller:
The published Jig alpha supplies new --use. It copies the selected Agent
contract and writes an ordinary editable slot declaration; you supply the
caller's code and the operator chooses its powers.
The Bun command installs an authoring dependency and records it in the worker's
manifest. The project installation supplies the already-declared ACP package
whose Agent Run contract is selected by --use; it grants no additional powers.
Jig separately prepares reviewed execution dependencies. Choose
your native client; codex here is an example, not a default.
In bindings/agent.ts, set the native slot to
{ kind: 'acp', client: 'codex', maxTurns: 2 }. Add requires as shown below
to the generated agent slot in flows/worker/FLOW.meta.json.
Replace flows/worker/FLOW.ts with the complete caller below. Then run:
Review shows the code, dependencies and two-turn authority before approval.
Resolution permission can contact dependency-selected destinations before that
approval; see dependency preparation. For later edits,
review again. Inspect the returned turn's type and result.outcome: a clean
conversation close alone does not establish a successful revision.
#Declare and implement the caller
The caller declares an agent slot using the complete
Agent Run contract bundle, imported in the step above.
new --use finds the nearest project or ancestor installation. You can also
supply a descriptor path directly. For an existing Flow, use
jig import-contract and declare
the corresponding slot in its metadata.
This validates and copies the descriptor and all referenced channel agreements,
without running the package or approving work. The new directory belongs to
your project. In the worker's FLOW.meta.json:
The example needs conversation and supplies the optional events port through
onEvent. Without observation, require only conversation. Review checks the
selected package's declarations before the caller starts; the two-turn grant
above independently permits the follow-up. Neither check guarantees an answer.
Use the optional Agent library helper to keep turn correlation and endpoint cleanup out of application code:
The caller's done means it returned a settled conversation packet; inspect
output.turn to distinguish an answer from an unsuccessful or cancelled turn.
Operational errors still fail the Run. completed.value is the
callback result, completed.turns retains received answers and unsuccessful
turns, and completed.settlement is the final invocation result. The helper
closes the conversation and waits for that actual result before returning.
It does not grant authority or determine whether an answer is correct.
After two successful turns, expect output.turn.type: 'result',
output.turn.turn: 1, and output.turn.result.outcome: 'done'. The answer is in
output.turn.result.output.text; its wording depends on the selected Agent.
output.settlement separately reports { outcome: 'done', output: { turns: 2 } }.
Observation is complete only when the public update stream closed cleanly.
Try changing the correction while keeping the cause uncertain. Review the source
again if you change the caller. If the initial turn is blocked or limit, this
caller returns that turn without requesting a revision; a clean settlement does
not turn that outcome into an answer.
To interrupt an active turn, call conversation.prompt(...), then await
conversation.interrupt() and that same prompt's promise. It is safe to request
interruption immediately: the helper waits for the prompt acknowledgement before
sending the interrupt. accepted means the request was accepted, not that the
turn was cancelled; natural completion can win, in which case the control may be
not-running and the prompt still returns its result. Leaving a live turn
unfinished at callback return fails rather than detaching it.
AgentConversationError retains received turns, any known settlement, and
both primary and cleanup errors; ordinary try/catch remains sufficient.
Its failure summary includes the first exposed error's bounded message. Inspect
the retained errors when deliberately recovering.
Optional onEvent filters or displays public updates synchronously without
manual channel setup. Inspect completed.observation?.status: incomplete
preserves observation errors without replacing the actual execution result.
Asynchronous routing can instead use a caller-created events writer; do not
combine it with onEvent. There is no privileged host echo of filtered text.
#Connect the channels directly
The helper uses only the public contract; other languages and implementations
can compose it directly. Inside a Flow, allocate two named direct channels and pass opposite
ends to the Agent. conversation: true starts turn zero. The following excerpt
assumes validated facts and correction strings from the application's input:
Consume replies while the call runs. After the result for turn zero, inspect
its complete result.outcome and result.output. A completed draft permits an
explicit follow-up:
An accepted control is not an answer. Wait for the correlated result,
cancelled, or error reply for turn one. Then close the settled conversation:
Never wait only for a reply: race each pending read against work and the Run's
cancellation signal. A rejected call may have no connected reply producer.
Dispose the endpoints kept locally (commands.send and replies.receive).
Endpoints offered in the call's channels map belong to host-owned terminal
cleanup, even if the call fails before any reply arrives. Do not guess transfer
from received messages or close every endpoint after a failed call.
Using a call-specific abort signal cancels the local wait promptly; awaiting that cancelled promise does not prove that the Agent has stopped. The SDK retains wire settlement and the host accounts for owned cleanup before publishing the root result. Normal conversation close followed by the actual, non-cancelled invocation result is the path for confirmed settlement before starting subsequent work. These are ordinary call and channel lifecycle rules, not a new Agent-specific SDK. An application should retain every answer it actually received and distinguish incomplete work from a finished revision.
#Interrupt without replacing the conversation
Keep the follow-up promise, request interruption, then await that same promise:
The control reply (accepted or not-running) is not the turn result. The
settled turn is either cancelled or an ordinary result if completion won the
race. Do not start subsequent work until the turn promise settles.
At the channel level, send {type: 'interrupt', turn: 1} while turn one is
running. Its accepted reply means the method accepted that control. Only the
later cancelled reply establishes native turn settlement. A completion racing
interruption can instead return an ordinary result. Wait for either terminal
turn reply before continuing.
Busy or stale controls are rejected, not queued. The host independently refuses
prompts beyond maxTurns. A native interruption that does not settle within
five seconds terminates the client; it does not enable another prompt.
Connect the optional events channel to show selected text or plans. Its values
carry the turn number, but progress can be incomplete and never substitutes for
the essential replies. A failed progress display need not stop the conversation.
#Hand work to a fresh conversation
An application can use these controls for an application-owned summary handoff. One worker drafts, while another publishes preliminary analysis through an ordinary FLOW channel and continues preparing independent review questions. Ordinary commentary uses a follow-up in the same conversation. A validated replacement of source files or appended instructions triggers handoff: interrupt if still active, await the actual turn, request a summary in the same conversation, then settle the predecessor before starting one successor.
The parent connects the workers directly; no logging service or host scheduler is involved:
Both start with the initial facts and instructions. The optional replacement
contains separately supplied files and ordered instructions for the reviewer
to publish; model output cannot create that authority. The successor receives the
latest validated context separately from the model's summary and review notes;
neither generated text can replace instructions or extend authority. The example
also retains each branch's result when the other fails. Its finite update batch
must finish before successor dispatch, so accepted updates cannot be silently
left behind. Drafting requests at most three model turns, review at most two,
all within the original root deadline and host grants.
That is a new conversation with explicit context, not native session restoration. Its root input is a supplied snapshot, not an interactive instruction inbox; file text is data, not live workspace access. The worker's optional revision channel can carry updated files and appended instructions from another parent. An unwired or cleanly empty channel needs no replacement. Its output is for human review, not permission to publish; interruption can prevent the final packet from arriving. This demonstrates lifecycle and context preservation, not that summary handoff improves model answers.
#Restore after a clean close
A later Run can request the earlier native conversation through an opaque reference. The published Agent and Jig alphas include this interface. Qualify the installed client's save-and-restore path before relying on it. The initial retention profile is Codex 0.154.0; successful live follow-up alone does not qualify restoration.
In the Agent Binding, separately grant retention and review the changed authority:
Request retention in the initial Agent input. A one-shot call needs no conversation channels:
Check the ordinary answer, then inspect the final first.output.session.
{status:'retained',reference} provides a UUID to keep as application data.
{status:'unavailable',reason} means no reusable state was committed; an otherwise
valid answer remains usable. Receipt availability requires actual clean native
exit, validated collection and complete cleanup, so accepting a close command
or receiving the answer does not predict it. Forced closure cannot retain a
session.
Use reason to explain what happened without rerunning completed work:
An unavailable receipt is not a reusable reference. Storage or cleanup errors remain invocation failures, not optional retention loss.
In a later authorized Run, pass the retained reference with the next instructions:
retainedReference is the UUID from the previous receipt. The host restores
the native conversation and reapplies current reviewed configuration before
the new prompt. It uses current credentials separately from conversation data.
The previous transcript is not submitted again as application input, and a
failed restoration does not silently start a fresh conversation.
Each reference can be claimed once. Use the new final receipt for any successor; do not retry the old reference after a failed claim. Restoration requires the same authorized recipient and ancestry in the same protected project with the matching native profile. Changed accepted code or configuration may invalidate access. A reference identifies state and grants no permission by itself.
For correction within one root Run, request session: {retain: true, lifetime: 'run'}.
The reference survives the Agent call and can be restored after separate checks.
Restoration inherits this lifetime. References cannot cross root Runs, and root
settlement removes their stored state. Omit lifetime only when later Runs need
the conversation. Both modes require the same reviewed retention grant and bounds.
The project retains at most 16 available snapshots of at most 8 MiB each. References expire after 24 hours; physical pruning happens on the next store access. The profile retains only bounded validated native conversation records, never credentials, arbitrary workspaces or tool authority. Expiry is not a secure-erasure guarantee.
For a continuing conversation, put session beside instructions in its
initial input. The receipt is in the final invocation output—
completed.settlement.output.session when using the helper—and never in an
individual turn reply. Later prompt controls cannot request another retention
policy. The HTTP Agent package rejects session requests before dispatch.
If session handling is required by the complete method, also add sessions to
its Agent dependency's requires list. This checks implementation claims; it
does not replace the native retention grant or guarantee a successor receipt.
A settings-conditional session path can retain ordinary runtime refusal and
authored recovery without making every one-shot call require sessions.
The Agent Run contract defines the request and receipt; Finite ACP defines native qualification, authorization and cleanup.
#Limits
Essential replies are bounded to 64 KiB each; ask for concise answers. Blocked reply delivery fails after five seconds rather than silently losing a result. All turns share the original deadline, byte budgets, and native owner. The maximum grant is eight turns; no current conversation can extend its own grant.
Each live invocation remains finite. Explicit restoration does not grant durable replay, automatic handoff or native workspace tools. The exact contract defines controls, failure cases, and the separate final result. Client startup, live follow-up, interruption, and restoration need distinct qualification; support for one does not establish the others.