refactor(protocol): type sub-agent completion as MessageSource::AgentResult#196
Merged
Merged
Conversation
…Result
Sub-agent completion results were encoded as a `<agent-result name=...>`
string baked into the envelope body. That buried a real domain concept
(completion vs. ordinary peer-agent message) in text, forcing every
consumer to deal with it differently: the uplink string-parsed the marker
as a control signal, the TUI showed the raw XML tags to users, and ACP had
no mapping.
Promote it to a typed `MessageSource::AgentResult { child }` variant. The
envelope body stays raw; the `<agent-result>` wrapper is rebuilt only at
LLM projection time, so the model sees the same marker while observers
render structurally. Cross-hub completion detection now matches the typed
source instead of parsing bytes.
Also clears two adjacent debts surfaced while doing this:
- SSOT the turn-trigger LLM-text prefixes (`[from:]`/`[scheduled]`/
`<agent-result>`) into `trigger_llm_text`, shared by the wire projection
and the Anthropic request builder (previously duplicated, drift-prone).
- DegenerationDetector reused a hand-rolled boundary list that dropped
peer-agent envelopes its own comment claimed to clear; switch it to the
`MessageSource::is_task_boundary` SSOT.
Notes:
- The `<agent-result name=...>` marker uses the bare child name even for
cross-hub completions (hub path stripped) to match the prior contract.
- Agent completions deliberately drop the redundant `[from: <child>]`
prefix — the marker already identifies the source.
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.
Summary
<agent-result name=...>string to a typedMessageSource::AgentResult { child }variant, so the semantic lives in the type system rather than being string-parsed/string-rendered by each consumer.<agent-result>wrapper is rebuilt only at LLM projection time. Cross-hub completion detection now matches the typed source instead of byte-scanning the content.trigger_llm_text(shared by wire projection + Anthropic builder), and fix DegenerationDetector to reuseMessageSource::is_task_boundary(its hand-rolled list silently dropped peer-agent envelopes its comment claimed to clear).Changes
MessageSource::AgentResult { child }variant +label/is_task_boundary/prepend_hub/prepend_hub_if_localarms.TurnTrigger::AgentResultvariant.completion.rs/finish.rs) emit raw body + typed source;uplink.rsdetects completion by source type (removedextract_agent_result_namebyte-parser).trigger_llm_textSSOT (prefix.rs); refactortrigger.rsinto text + origin projection.trigger_usercollapses onto the sharedtrigger_llm_text.turn_trigger_mapmaps AgentResult source (bare child name);degeneration_detectorreusesis_task_boundary.render_inbox_originshows a✅ result from <child>badge instead of raw XML tags.Notes
<agent-result name=...>marker uses the bare child name even for cross-hub completions (hub path stripped) to match the prior contract.[from: <child>]prefix — the marker already identifies the source._loopal/inbox.enqueued.source now emits the newAgentResultwire variant (serde pass-through); IDE clients should handle it.Test plan
bazel test //..., clippy, rustfmt)