Skip to content

feat(agent): add engine-neutral model-turn journal contract - #337

Open
gmjneko wants to merge 11 commits into
agentic-ai-java:mainfrom
gmjneko:feat/t14-neutral-journal-contract
Open

gmjneko wants to merge 11 commits into
agentic-ai-java:mainfrom
gmjneko:feat/t14-neutral-journal-contract

Conversation

@gmjneko

@gmjneko gmjneko commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

This pr implements the engine-neutral journal neutral contract and shared implementation. so maintainers can review whether the plan is appropriate.

Since I see that many follow-up tasks depend on this task, I am concerned that there may be aspects of the design here that I have not fully considered.

Relate to #125

Scope

Module Changes
argi-agent-core Adds the agent.durable package with ModelTurnRecorder, ModelTurnCodec, stable journal identity types, recovery policy types, documentation, and reference tests.

Design

1. Separate journal preparation from storage coordination

  • ModelTurnRecorder is stateless. It prepares immutable journal entries and validates replay.
  • ModelTurnCodec handles versioned payloads, request fingerprints, canonical tool arguments, and tool-definition fingerprints.
  • The runtime owns RunStore.commit, leases, revisions, checkpoints, and snapshot updates.
  • Storage failures propagate from the runtime and are not treated as model failures.

2. Use stable logical identities

Callers provide Turn(runId, turnId) and restore the same identity during recovery.

Tool plans are identified by their logical turn and response ordinal within the run. Provider-generated tool-call IDs and model attempt numbers do not change task identity.

Request fingerprints, model-call reservations, terminal responses, and tool plans are journaled. Request bodies are not persisted. Messages, generation options, and disclosed tool definitions participate in the request fingerprint.

3. Persist before invoking or dispatching

The reference execution sequence is:

Replay committed snapshot
  -> Commit model-call reservation
  -> Call model
  -> Commit response + all tool plans + checkpoint
  -> Dispatch tools

A complete recorded result is replayed without another model call. Revision conflicts require reloading the snapshot and repeating replay before reserving another attempt.

4. Make recovery and re-asking explicit

Replay validates the run identity, request fingerprint, entry types and versions, and the complete tool-plan set. Inconsistent or incomplete records fail closed.

ModelTurnAttemptPolicy.DEFAULT uses FAIL_CLOSED with one total model-call reservation. Recovery re-asking is allowed only when the caller explicitly uses MissingResponsePolicy.REASK, and it remains bounded by maxAttempts.

Committed reservations survive interruption and recovery and are never refunded. Streaming deltas are diagnostic only and cannot authorize model or tool execution.

The policy is caller-owned and is not persisted in RunSpec or the journal schema. The caller must keep the same policy for the logical run across recovery.

Validation scope

Reference tests use the existing MemoryRunStore to simulate recovery within one process. Durable backend integration, execution-position recovery, tool receipts, and exactly-once execution remain runtime responsibilities and are outside this PR.

Validation completed with:

./mvnw -o -B test

All reactor modules passed.

@gmjneko
gmjneko marked this pull request as ready for review October 30, 2026 09:56
@yuluo-yx

Copy link
Copy Markdown
Contributor

/cc @Aias00 ptal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants