operator: triage the ambient fleet scan off-context, escalate only findings#376
Merged
Conversation
…ndings The ambient snapshot + previews had been injected into the operator's own conversation, so every tick (and every real user turn) ran near the budget ceiling on a frontier model, with stale per-tick snapshots crowding out real context and driving compaction. Now each tick runs a one-shot monitor triage -- a separate, ideally cheaper completion (AGENTD_OPERATOR_MONITOR_MODEL, falls back to the operator's model) -- that judges the data-only snapshot + previews OFF the operator's context and returns a concise finding or "nothing". Only a finding becomes an operator turn; quiet ticks never touch the operator. So the operator carries findings, not scans, and only wakes when there's something. - build_ambient_observation now produces the data-only scan (instructions moved to the monitor system prompt); compute_ambient_snapshot summary trimmed. - run_ambient_triage: one-shot completion, no tools, discard sink; parse_triage _finding turns the reply into a compact operator observation or None. - AmbientTick arm: scan -> triage -> finding | continue (no turn). Verified live: from a real fleet, the monitor returned 3 evidenced findings -- incl. a session blocked on a risky-command approval and one finished with a release outcome -- the compact findings the operator would see, not the previews. Pure parser unit-tested; spec 0022 added.
edwin-zvs
force-pushed
the
operator-monitor-subagent
branch
from
June 6, 2026 17:23
167afb3 to
5b0ac13
Compare
This was referenced Jun 6, 2026
edwin-zvs
added a commit
that referenced
this pull request
Jun 6, 2026
… suppression (#380) The operator panel showed the operator's response to each ambient/observation turn ("noted", "Worked", a finding) but not the INPUT that triggered it -- the observation is a Message event, never rendered to the panel's PTY. So a user watching the panel saw context-free "noted / Worked / noted ..." and couldn't tell what was being noted. Now, before the response streams, the operator echoes the OBSERVATION trigger into the panel (dim), with the monitor's instruction boilerplate stripped so only the substance shows -- an ambient monitor finding or a fleet event. The panel reads question -> answer. Also removes the dead ambient-turn PTY/message suppression: it keyed on the stale "ambient operator loop tick" string (the loop's observation became "ambient fleet monitor flagged" in #376), so it never fired -- and the intent is now to SHOW responses with their trigger, not hide them. Leaving it was a trap (fixing its string would have hidden the wanted responses). The typewriter monolog (#379) is unaffected -- it consumes the response Message stream; the echo is PTY-only. - interactive.rs: observation_panel_echo() + emit it before the user Message; removed ambient_turn detection + both suppression blocks. - Test: observation_panel_echo strips the marker/boilerplate, keeps substance, returns None for real user input. 38 interactive tests pass. Spec 0024.
This was referenced Jun 6, 2026
Merged
edwin-zvs
added a commit
that referenced
this pull request
Jun 7, 2026
…widget Sharpen the operator's surfacing rule. The text monolog is literally the operator's monolog -- it types over the matrix animation, fades, and the user has no way to reply. So text is for low-stakes, passing narration only. Anything the user should act on, decide, or be reliably notified of MUST be an Operator widget (widgets persist and carry action links). Also fixes stale/contradictory guidance left by the #376 monitor split: - The ambient paragraph keyed on "OBSERVATION: ambient operator loop tick", which the operator no longer receives (it gets "ambient fleet monitor flagged"), so its guidance never fired. Updated the string. - Removed "Prefer updating/removing compact Operator widgets over chatting," which contradicted the FYI-text guidance; SURFACING is now the single rule. Guard test asserts the stale string is gone, the new string + principle are present, and the contradiction stays removed. Spec 0023 updated.
edwin-zvs
added a commit
that referenced
this pull request
Jun 7, 2026
…widget (#386) * operator: text monolog is FYI-only; anything needing a response is a widget Sharpen the operator's surfacing rule. The text monolog is literally the operator's monolog -- it types over the matrix animation, fades, and the user has no way to reply. So text is for low-stakes, passing narration only. Anything the user should act on, decide, or be reliably notified of MUST be an Operator widget (widgets persist and carry action links). Also fixes stale/contradictory guidance left by the #376 monitor split: - The ambient paragraph keyed on "OBSERVATION: ambient operator loop tick", which the operator no longer receives (it gets "ambient fleet monitor flagged"), so its guidance never fired. Updated the string. - Removed "Prefer updating/removing compact Operator widgets over chatting," which contradicted the FYI-text guidance; SURFACING is now the single rule. Guard test asserts the stale string is gone, the new string + principle are present, and the contradiction stays removed. Spec 0023 updated. * ci: re-trigger (previous run hung ~4h)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #369/#371. Addresses the context-accumulation problem with the ambient loop.
Problem
The ambient loop runs in the operator's own session, and #371 made each tick rich (fleet snapshot + up to 10 PTY-screen previews). Those got
push_msg!'d into the operator's persistent conversation, so:zarvis.jsonlgrew between compactions.Per the design discussion: the snapshot/previews are throwaway, and continuity is already handled elsewhere (the delta is adapter state; widgets persist on disk). So the bulk shouldn't live in the operator's context at all.
Change: scan → cheap triage → escalate only findings
Each tick now runs a one-shot monitor triage — a separate completion, ideally on a cheaper model — that judges the data-only snapshot + previews off the operator's context and returns a concise finding or
nothing:nothing→ the loopcontinues; the operator is never touched.AGENTD_OPERATOR_MONITOR_MODELselects the monitor model (falls back to the operator's). The triage is stateless and bounded, so its cost doesn't grow over time and is cheap with a small model. The monitor triages mechanically (no user-context); the operator filters with context.Pieces
build_ambient_observationnow yields a data-only scan (judgment instructions moved toAMBIENT_MONITOR_SYSTEM); snapshot summary trimmed accordingly.run_ambient_triage(one-shotcomplete, no tools, discard sink) +parse_triage_finding(reply → compact observation orNone).AmbientTickarm:scan → triage → finding | continue 'outer.Verification
parse_triage_findingunit-tested (filtersnothing/empty; formats findings); 36interactivetests pass; full build clean."? approve [risky] shell(git add … && git push … && gh pr create …)") and one finished with a release outcome — i.e. the compact findings the operator would see, not the previews. On a quiet fleet it returnsnothingand the operator isn't woken.Spec
0022added. Code inagentd-adapter-zarvis.Relationship to
40ec9f6("Run Operator ambient loop only while fleet active")That commit landed on main after this branch was first pushed; this PR is now rebased on top of it. They are complementary, not conflicting (clean rebase, builds, tests pass):
40ec9f6controls when a tick fires — only while the fleet is active — and drops the interval from 300s to 60s.Notably,
40ec9f6alone made the operator run a full frontier turn every 60s while the fleet is active — i.e. the exact context-accumulation / cost problem this PR fixes, made ~5× more frequent by the faster interval. So this PR matters more now. With the 60s cadence, configuringAGENTD_OPERATOR_MONITOR_MODELto a cheap model is recommended. (Minor: the active-gate and the scan eachlist()the fleet once per fired tick — a redundant call that could be folded together in a follow-up.)