Skip to content

Add Agent Config Core: harness capability model behind agent config surfaces#2158

Merged
morgmart merged 2 commits into
mainfrom
agent-config-core
Jul 20, 2026
Merged

Add Agent Config Core: harness capability model behind agent config surfaces#2158
morgmart merged 2 commits into
mainfrom
agent-config-core

Conversation

@morgmart

Copy link
Copy Markdown
Contributor

Context

PR 2.6 of the agent-config plan (plan of record: Harness-Provider-Model). Follows #2148 (flag reduction) and #2156 (honest model resting states + safe harness switching), both merged.

The problem this PR exists to solve: every config surface hand-assumes all harnesses are shaped like Buzz Agent/Goose (Provider → Model → generic Effort). That assumption is how we shipped false controls — a Codex model id like gpt-5.5[low] next to a separate generic Effort field, and Claude/Goose effort saved through BUZZ_AGENT_THINKING_EFFORT, a key those harnesses never read. #2156 patched the symptoms (hid the false controls); this PR builds the seam that makes the truth structural, before the dialog-adoption PRs (5a/5b) spread the old assumptions to more surfaces.

What we learned (and verified) while building this

  1. The backend already had the correct harness capability table. KnownAcpRuntime in the Tauri backend declares each harness's real model/provider/effort env keys and uses them at spawn — but none of that crossed the IPC boundary, so the frontend hardcoded its own guesses. That gap is the root cause of the false-control bugs.
  2. Goose effort is real and env-supported (verified against aaif-goose/goose source): GOOSE_THINKING_EFFORT is read from env (overriding config.yaml), valid levels are model/provider-specific inside Goose core, and effort is also an ACP session preference. Today's UI writes Buzz Agent's key for Goose — a silent no-op.
  3. Claude Code effort is a native ACP config option (id: "effort", category thought_level) that our pre-spawn probe currently filters out (it only keeps category == "model" options).
  4. Codex encodes effort in model ids — model owns effort; a separate control would be a second steering wheel.

Decisions encoded in this PR

  • Backend runtime metadata is the single harness-capability source. AcpRuntimeCatalogEntry now carries model_env_var / provider_env_var / thinking_env_var from the same KnownAcpRuntime table spawn uses. The frontend core is a projection of the backend's answer, not a rival copy. (We explicitly rejected duplicating the table in TypeScript with a "keep in sync" comment — two copies of the truth drifting is how we got here.)
  • Field descriptors separate "where the value lives today" from "how the harness should receive it." Each effort descriptor carries currentPersistence (honest: still the legacy BUZZ_AGENT_THINKING_EFFORT key for Buzz Agent and Goose) and targetApplication (the harness's real key/option). This makes the migration state readable from the types — a PR 2.7 author cannot be misled into writing Goose keys that the read path doesn't see.
  • Absence has a named reason, not a boolean. Codex effort is omitted as ownedByModelId; Claude effort exists but renders as deferredUntilNativeOptionsAvailable (its native option isn't plumbed through discovery yet). When 2.7 plumbs it, one enum case changes and every surface picks it up.
  • The clearing policy is named types, not flags (formalizing what Fix harness default model states in onboarding #2156 shipped): onContextChange: "resetDependentValues" (harness/provider change clears dependent values everywhere) vs onCatalogMismatch: "explainOnly" | "onboardingCleanup" (an async catalog miss never silently erases state outside onboarding's named cleanup). The core resolves which applies from scope; render code never picks.
  • "Metadata unknown" ≠ "harness lacks the capability." Both consumers (Settings defaults editor, onboarding config step) now gate on the runtime catalog query settling and show an explicit loading/error state, instead of passing undefined and having fields silently vanish. (Caught in review: previously the Settings provider/effort controls could flash in late or disappear permanently if discovery failed.)

What this PR does

  • Rust: exposes the three env-key declarations on AcpRuntimeCatalogEntry (one construction site, populated from KnownAcpRuntime). Extracts KnownAcpRuntime + docs into discovery/runtime_metadata.rs — a responsibility split that also keeps discovery.rs under the size guard without deleting anyone's comments.
  • TS core: new features/agents/lib/agentConfigCore.ts — pure, no React. deriveAgentConfigFieldModel(config, runtime, scope) → field descriptors (kind, optionSource, currentPersistence, targetApplication, render, value) + named omissions + the clearing policy. Unit-tested per harness × scope (5 tests).
  • Renderer: AgentConfigFields derives provider/effort field presence from the core (deleting the showProviderField prop the plan had scheduled for PR 3 — both callers computed it identically), reads/writes/clears effort through the descriptor's currentPersistence key, and derives the onboarding-cleanup gate from the policy instead of a disclosure-string comparison.
  • E2E bridge: mock catalogs get metadata backfilled only when a fixture omits the field — an explicit null is preserved, so specs can still model a harness without a capability.

Behavior is unchanged: all four harnesses render exactly the fields they did after #2156, onboarding pixels untouched (onboarding-agent-defaults.spec.ts 35/35 green as the acceptance gate), just ci green.

What this PR defers (deliberately)

  • PR 2.7 — harness-native effort wiring (the behavior change): migrate Goose persistence to GOOSE_THINKING_EFFORT and source its per-model levels from Goose core/ACP; widen the pre-spawn probe to keep Claude's thought_level option and apply it at launch. The core's currentPersistence/targetApplication split is the written spec for that PR.
  • PR 3 — harness picker moves inside the component; Settings honors the real default harness.
  • PR 5a/5b — dialog adoption of the core.
  • Consolidating runtimeSupportsLlmProviderSelection onto the catalog metadata (they agree today; tracked for 2.7/3).

Testing

  • just ci (fmt, clippy, desktop lint, unit tests, builds)
  • agentConfigCore.test.mjs: field model per harness (Buzz Agent, Goose, Claude, Codex) and clearing policy per scope
  • Full desktop unit suite (3,209 tests)
  • onboarding-agent-defaults.spec.ts 35/35 (onboarding behavior pin)
  • Note: pre-push relay integration tests test_global_conn_cap / test_conn_counter_no_leak (buzz-pair-relay) fail identically on a clean main checkout — pre-existing, unrelated to this branch.

@morgmart
morgmart requested a review from a team as a code owner July 20, 2026 05:58
@morgmart
morgmart enabled auto-merge (squash) July 20, 2026 06:29

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking behavioral or security findings on 1831b71255f7fde38ae21e64e29d85655497f22d. This is a good seam: static backend runtime metadata becomes the capability source, the IPC exposes only env-variable names (not values/secrets), and frontend use is limited to field derivation/object-key selection. The explicit current-vs-target persistence split also avoids silently changing Goose/Claude behavior in this structural PR. Main risk is future drift in the temporary harness-ID special cases, which the focused core tests and follow-up plan make visible. CI is green. Approval withheld because this head is 11 commits behind current main and overlaps tauri.ts/e2eBridge.ts; rebase and fresh green CI are required before the approval gate.

@morgmart
morgmart merged commit 6881a33 into main Jul 20, 2026
25 checks passed
@morgmart
morgmart deleted the agent-config-core branch July 20, 2026 14:16
wpfleger96 added a commit that referenced this pull request Jul 20, 2026
…vider

* origin/main: (111 commits)
  fix: skip membership lookup for open relays (#2107)
  fix(desktop): make invite QR downloadable (#2168)
  Archive managed agents when deleted (#2135)
  perf(relay): cache Git pack hydration (#2169)
  chore(deps): update rust crate rustls to v0.23.42 (#2151)
  chore(deps): update dependency @tanstack/react-virtual to v3.14.6 (#2153)
  Add Agent Config Core: harness capability model behind agent config surfaces (#2158)
  chore(deps): update all non-major dependencies (#2152)
  chore(deps): update rust crate getrandom to v0.4.3 (#2150)
  fix(relay): bound and observe Git read operations (#2167)
  fix(desktop): derive default clone URL for relay-hosted repos (#2166)
  fix(desktop): mask composer rounded corners (#2165)
  feat(desktop): add PR merge conflict recovery (#2164)
  fix(desktop): mask scrolled content behind channel and thread composers (#2163)
  feat(desktop): add inline PR diff comments (#2162)
  feat(desktop): add commit-scoped PR review decisions (#2161)
  fix(desktop): batch project work item queries (#2160)
  feat(desktop): make missing project checkouts actionable (#2159)
  Fix harness default model states in onboarding (#2156)
  relay: gate push enqueue on live leases; batch matcher pipeline (T1b/T1a-repair/T2b) (#2145)
  ...
wpfleger96 added a commit that referenced this pull request Jul 20, 2026
…rics

* origin/main: (96 commits)
  fix(desktop): prefer live agent mentions (#2149)
  fix(desktop): close focused threads on Escape (#2154)
  fix: skip membership lookup for open relays (#2107)
  fix(desktop): make invite QR downloadable (#2168)
  Archive managed agents when deleted (#2135)
  perf(relay): cache Git pack hydration (#2169)
  chore(deps): update rust crate rustls to v0.23.42 (#2151)
  chore(deps): update dependency @tanstack/react-virtual to v3.14.6 (#2153)
  Add Agent Config Core: harness capability model behind agent config surfaces (#2158)
  chore(deps): update all non-major dependencies (#2152)
  chore(deps): update rust crate getrandom to v0.4.3 (#2150)
  fix(relay): bound and observe Git read operations (#2167)
  fix(desktop): derive default clone URL for relay-hosted repos (#2166)
  fix(desktop): mask composer rounded corners (#2165)
  feat(desktop): add PR merge conflict recovery (#2164)
  fix(desktop): mask scrolled content behind channel and thread composers (#2163)
  feat(desktop): add inline PR diff comments (#2162)
  feat(desktop): add commit-scoped PR review decisions (#2161)
  fix(desktop): batch project work item queries (#2160)
  feat(desktop): make missing project checkouts actionable (#2159)
  ...
tlongwell-block pushed a commit that referenced this pull request Jul 20, 2026
Main moved ~29 commits (incl. #2135 managed-agent archive-on-delete,
#2158 agent config core, #2107 open-relay membership skip). Auto-merge
clean; semantic gates re-run on the merged tree.

Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
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