Skip to content

fix: close #332 gaps — agentId, Direct Line privacy masking, standing L3 obligation, web-ui render - #446

Merged
Weegy merged 3 commits into
mainfrom
worktree-issue-332-gap-closure
Jul 6, 2026
Merged

fix: close #332 gaps — agentId, Direct Line privacy masking, standing L3 obligation, web-ui render#446
Weegy merged 3 commits into
mainfrom
worktree-issue-332-gap-closure

Conversation

@Weegy

@Weegy Weegy commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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

  1. agentId enrichmentRunAgentInvocation now carries the resolved agentId (was agentName only), threaded through RunTraceCollector.beginInvocation and all 3 orchestrator call sites, surfaced in the AgentConsultation projection. Closes the label-collision gap: two distinctly-configured sub-agents sharing a display label were indistinguishable in agentsConsulted.

  2. Direct Line privacy-masking bypass (a 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(...) (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).

  3. L3 forced-delegation had no production producer — added an opt-in, standing requiredConsultToolName orchestrator option. A per-turn expectedDomainTool still wins; absent both → byte-identical prior behaviour.

  4. web-ui rendered neither agentsConsulted nor delegatedAnswer — 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 streaming done event (which previously only carried raw runTrace; extracted a shared deriveAgentsConsulted() 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)

  • Teams connector "PR chore(deps,ci): Bump actions/setup-node from 4 to 6 #19" — turned out to be based on a stale premise: private plugins were split into individual repos as a hard rule; byte5ai/omadia-channel-teams is now standalone and already contains this work plus further fixes. Closed the old monorepo PR as superseded: byte5ai/omadia-byte5-plugins#19.
  • Sticky direct-line mode (an explicitly-deferred v1 open question) — now has a real tracking issue instead of only living in chat history/memory: Direct Line: sticky multi-turn mode (persistent specialist session) #445.
  • Live production deployment verification — out of scope for this PR (needs operator/production access); tracked as a follow-up.

Verification

  • Full middleware suite: 3823/3823 passing (0 regressions), npm run lint clean.
  • directLine.test.ts: 20 → 30 tests (agentId enrichment, PII-masking, standing-obligation, streaming-parity).
  • web-ui: tsc --noEmit clean, eslint 0 errors, npm run i18n:check OK (1671 keys, en/de), next build succeeds.

Refs #332

Weegy added 2 commits July 6, 2026 09:50
…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.
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.

1 participant