| 1 | # Agent Core Simplification |
| 2 | |
| 3 | This document tracks the agent-core simplification effort: the behavioral |
| 4 | contract of the simplified loop, the metrics used to compare before/after, and |
| 5 | where each contract item is tested. The Chinese version lives in |
| 6 | `AGENT_CORE_SIMPLIFICATION.zh-CN.md`. |
| 7 | |
| 8 | ## Target loop |
| 9 | |
| 10 | ```text |
| 11 | build request |
| 12 | -> provider stream |
| 13 | -> clean final: done |
| 14 | -> tool call: execute, next step |
| 15 | -> request error: unified retry |
| 16 | -> unhandled error: explicit failure |
| 17 | ``` |
| 18 | |
| 19 | ## Product decisions |
| 20 | |
| 21 | - Normal requests are executor-only; the planner is opt-in (`planner_model`). |
| 22 | - Normal agents ship with synthetic continuation disabled; Goal, review, |
| 23 | guardian, and typed-report flows keep their own constraints. |
| 24 | - Compaction defaults to a single summary; chunked/tree-reduce recovery is |
| 25 | explicit only (manual `/compact` and marked recovery workflows). |
| 26 | - Final readiness, tool safety, cancellation, budgets, and explicit whole-file |
| 27 | read pauses stay as hard boundaries. Ordinary partial reads do not freeze |
| 28 | independent work; see [Read evidence lifecycle](READ_EVIDENCE_LIFECYCLE.md). |
| 29 | - Old configs and old session state stay readable for one release; the new |
| 30 | runtime never executes the old fallbacks. |
| 31 | |
| 32 | ## Metrics baseline |
| 33 | |
| 34 | Reuse the existing usage and e2ebench instrumentation; no new fallback |
| 35 | telemetry is added. Capture before/after per phase with: |
| 36 | |
| 37 | - `reasonix run --metrics <path>` — per-run `RunMetrics`: token/cost totals, |
| 38 | `usage_by_source` (executor/planner/subagent/compaction/... request calls), |
| 39 | `retries`, `compactions`, `steps`. |
| 40 | - `go run ./cmd/e2ebench -task <task> -json` — per-task request counts, |
| 41 | `usage_by_source`, trajectory digest (stream retries, reasoning replays, |
| 42 | empty-final retries, TTFT, requests by source), wall time, cache hit/miss. |
| 43 | |
| 44 | | Metric | Source | |
| 45 | |---|---| |
| 46 | | model requests per normal turn | `usage_by_source["executor"].Calls` / trajectory `ExecutorRequests` | |
| 47 | | planner requests | `usage_by_source["planner"].Calls` / trajectory `PlannerRequests` | |
| 48 | | reviewer/evaluator/guardian requests | `usage_by_source["recovery_reviewer"|"goal_evaluator"]`, guardian assessment usage | |
| 49 | | synthetic continuations | executor requests per clean turn above 1; trajectory `EmptyFinalRetries` | |
| 50 | | stream retries | trajectory `StreamRetries` / `RunMetrics.Retries` | |
| 51 | | compaction requests and summary spans | `RunMetrics.Compactions`, compaction telemetry notice (`spans=`, `reqs=`) | |
| 52 | | first text latency | trajectory `TTFTMs` | |
| 53 | | turn latency | `RunMetrics.DurationMs` / bench `WallMs` | |
| 54 | | tool execution success | bench task solved rate / `SolvedThenBroken` | |
| 55 | | protocol-error terminations | trajectory retry-exhausted outcomes | |
| 56 | |
| 57 | Compare at least: normal Q&A, normal code edit, long-context/tool-heavy |
| 58 | (`context-pressure` tasks). Goal per phase: a normal request is one executor |
| 59 | request chain, no implicit planner/reviewer/evaluator requests, no extra |
| 60 | continuation after a clean final, default compaction never enters multi-span |
| 61 | summaries, and hard-safety failure rates do not increase. |
| 62 | |
| 63 | ## Contract tests |
| 64 | |
| 65 | New consolidated suite: `internal/agent/agent_contract_test.go`. |
| 66 | |
| 67 | | Contract item | Test | |
| 68 | |---|---| |
| 69 | | clean final makes exactly one model request | `TestContractCleanFinalMakesOneModelRequest` | |
| 70 | | tool call executes, loop advances | `TestContractToolCallAdvancesToNextStep` | |
| 71 | | thinking survives the unified retry (frozen request) | `TestContractThinkingSurvivesUnifiedRetry` | |
| 72 | | no long-lived fallback state after retry exhaustion | `TestContractNoLongLivedFallbackStateAfterRetryExhaustion` | |
| 73 | | clean final adds no synthetic continuation | `TestContractCleanFinalAddsNoSyntheticContinuation` | |
| 74 | | reasoning-only clean stop completes | `TestRunAcceptsReasoningOnlyFinalAnswer` | |
| 75 | | zero content retries via unified `EMPTY_RESPONSE` path | `TestRunRetriesZeroContentWithTheSameFrozenRequest` | |
| 76 | | exhausted retries return an explicit protocol error | `TestRunStopsAfterExhaustedZeroContentRetriesWithoutCommittingEmptyMessages` | |
| 77 | | strict-provider missing reasoning: one frozen-request retry | `TestRunSilentlyRecoversMissingToolCallReasoning` and the replay suites in `loop_e2e_test.go`/`retry_e2e_test.go` (#9776 repair) | |
| 78 | | incomplete-read gate | `incomplete_read_test.go` | |
| 79 | | final readiness | `final_readiness_test.go` | |
| 80 | | cancellation | `cancel_test.go` | |
| 81 | | task/token/cost budgets | `run_budget_test.go` | |
| 82 | | tool permission/malformed args | `argument_validation_test.go`, gate tests | |
| 83 | | ordinary request skips planner | `TestCoordinatorOrdinaryRequestDoesNotCallPlanner`, `TestDecidePlannerRouteExplicitOnly` | |
| 84 | | planner prose without `submit_plan` fails | `TestCoordinatorPlanAndExecuteRequiresSubmittedPlan` | |
| 85 | | planner failure does not run executor | `TestCoordinatorFailsClosedWhenPlannerFails` | |
| 86 | | unusable `planner_model` is a config error | `TestBuildFailsWhenPlannerModelIsUnresolvable` | |
| 87 | | ordinary Agent adds no todo continuation | `TestStandardTodoContinuationDisabledByDefault` | |
| 88 | | pressure compaction stays single-summary | `TestPressureCompactionDoesNotCallChunkedFold` | |
| 89 | | missing guardian/recovery models fail closed | `TestBuildFailsWhenGuardianModelIsUnresolvable`, `TestBuildFailsWhenRecoveryModelIsUnresolvable` | |
| 90 | |
| 91 | ## Gates |
| 92 | |
| 93 | Every phase runs: |
| 94 | |
| 95 | ```bash |
| 96 | go test -count=1 ./internal/agent/... ./internal/control/... ./internal/config/... ./internal/boot/... |
| 97 | go test -race ./internal/agent/... ./internal/provider/... |
| 98 | go vet ./... |
| 99 | go run ./tools/repolint |
| 100 | ``` |
| 101 |