fix: close #332 gaps — agentId, Direct Line privacy masking, standing L3 obligation, web-ui render - #446
Merged
Merged
Conversation
…anding L3 obligation Verified-in-code gap-closure for issue #332 (trustworthy sub-agent delegation), following up on the L1/L2/L3 core merged in PR #335. - agentId enrichment: RunAgentInvocation now carries the resolved agentId (plugin-api + channel-sdk mirror), threaded through RunTraceCollector.beginInvocation and all 3 orchestrator call sites, and surfaced in the AgentConsultation projection — closes the label-collision gap where two distinctly-configured sub-agents sharing a display label were indistinguishable in agentsConsulted. Also stored on the AgentInvocation graph node (in-memory + neon KG backends). - Direct Line privacy-masking bypass (real gap, not just a missing test): executeDirectLine called `tool.handle()` directly, bypassing the `dispatchTool` choke point entirely — so a directed specialist's verbatim answer was NEVER routed through the Privacy Shield v4 masking cascade, contradicting the documented "still PII-masked" contract on DelegatedAnswer. Fixed by routing through `this.dispatchTool(...)` instead (same masking cascade every other domain-tool dispatch already gets). - L3 forced-delegation obligation had no production producer. Added an opt-in, standing `requiredConsultToolName` orchestrator option: when set, every ordinary turn carries that obligation automatically (a per-turn `expectedDomainTool` still takes precedence). Absent → byte-identical prior behaviour. - Streaming `agentsConsulted` parity: the streaming `done` event (web-ui path) only carried raw `runTrace`; extracted the L1 projection into an exported `deriveAgentsConsulted()` helper (shared by `toSemanticAnswer` and all 3 streaming done-event sites) so every channel gets the identical harness-built array, not a client-reimplemented one. 30 new/updated tests in directLine.test.ts (was 20, now 30 total in that file); full middleware suite 3823/3823 green; lint clean.
…Line web-ui had zero render of the #332 transparency/Direct-Line fields — confirmed the biggest of the 7 verified gaps, since it meant no channel reliably showed users the trust guarantees the core feature provides. - New `<AgentsConsultedFooter>`: compact, tamper-evident chips showing which sub-agent(s) were consulted this turn (label + status + step count), sourced from the harness-built `agentsConsulted` array. - New `<DelegatedAnswerCard>`: the attributed, byte-for-byte verbatim Direct Line answer, visually distinct from ordinary orchestrator narration, with a "not orchestrator-verified" caption. Rendered as plain text (not through the Markdown component) to guarantee visual fidelity to the harness-owned segment. `status: 'error'` renders the faithful failure message, never a cover-up. - `content` still carries the verbatim text too (backend graceful-degrade design), so `MessageRow` strips the known verbatim prefix before handing the remainder to the normal Markdown block — the guarded-mode additive note still renders, without the answer appearing twice. - Wired `agentsConsulted`/`delegatedAnswer` through the local wire-format types (`chatStreamEvents.ts`) and `Message` (`chatSessions.ts`); the backend commit already emits both fields on every relevant `done` event. - i18n: new `directLine.*` keys in en.json + de.json (house rule: no i18nexus, direct JSON edits, EN source of truth). Gates green: tsc --noEmit clean, eslint 0 errors, i18n:check OK (1671 keys), next build succeeds.
8 tasks
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
Follow-up to #332 (Trustworthy sub-agent delegation), whose L1/L2/L3 core merged in #335. A fresh audit against live code + GitHub state found the "implemented + shipped" status comment was accurate for code-complete but premature on "live-and-verified" — 7 gaps survived uncaught for 18 days. This PR closes the ones with a code fix; the rest are closed by process actions (see below).
What this PR fixes
agentId enrichment —
RunAgentInvocationnow carries the resolvedagentId(wasagentNameonly), threaded throughRunTraceCollector.beginInvocationand all 3 orchestrator call sites, surfaced in theAgentConsultationprojection. Closes the label-collision gap: two distinctly-configured sub-agents sharing a display label were indistinguishable inagentsConsulted.Direct Line privacy-masking bypass (a real gap, not just a missing test) —
executeDirectLinecalledtool.handle()directly, bypassing thedispatchToolchoke point entirely, so a directed specialist's verbatim answer was never routed through the Privacy Shield v4 masking cascade — contradicting the documented "still PII-masked" contract onDelegatedAnswer. Fixed by routing throughthis.dispatchTool(...)(the same masking cascade every other domain-tool dispatch already gets). New tests prove PII is masked when a privacy guard is active and pass-through when none is configured (documented contract).L3 forced-delegation had no production producer — added an opt-in, standing
requiredConsultToolNameorchestrator option. A per-turnexpectedDomainToolstill wins; absent both → byte-identical prior behaviour.web-ui rendered neither
agentsConsultednordelegatedAnswer— the biggest of the 7 gaps, since it meant no channel reliably showed the trust guarantees to users. Added<AgentsConsultedFooter>and<DelegatedAnswerCard>, wired through the streamingdoneevent (which previously only carried rawrunTrace; extracted a sharedderiveAgentsConsulted()helper so streaming and non-streaming channels build the identical harness-sourced array).What's closed by process, not code (see linked issue/PR activity)
byte5ai/omadia-channel-teamsis now standalone and already contains this work plus further fixes. Closed the old monorepo PR as superseded: byte5ai/omadia-byte5-plugins#19.Verification
npm run lintclean.directLine.test.ts: 20 → 30 tests (agentId enrichment, PII-masking, standing-obligation, streaming-parity).tsc --noEmitclean,eslint0 errors,npm run i18n:checkOK (1671 keys, en/de),next buildsucceeds.Refs #332