Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(get-conversation): send domainGuidance once per run, not per call

merged#2794CedarCopilot

CedarCopilot wants to merge 1 commit into staging from fix/domain-guidance-per-run-dedup

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Sep 15, 2026, 8:34 AM
  2. Sep 15, 2026, 8:42 AM
  3. Merged
    Sep 15, 2026, 8:48 AM
  4. Live on prod
    Sep 15, 2026, 8:48 AM
  5. Observed 0 hours
    Sep 15, 2026, 8:48 AM
  6. Unobserved

    Live on prod, no production signal yet

    Sep 15, 2026, 8:48 AM
  7. Pipelines steady after this deploy
    Sep 15, 2026, 8:48 AM

Behaviors Libra is checking

The get-conversation operation sends static domainGuidance once per domain per run and omits it on repeat fetches within that run.Not checked
prod

Libra has verdicts on 0 of 1 tracked behaviors on prod; 1 is still being checked. Libra checks hourly for 3 days after each deploy.

Summary

get-conversation's domainGuidance field is a static, per-domain reference string , confirmed against real production traces (its length never varies for a given domain: avg == max across every sampled call). It's cheap to compute, but the tool resent the same ~8KB of identical text on every single get-conversation call within a run, even when the calling agent had already seen it moments earlier for the same domain.

The fix: track whether this run has already seen domainGuidance for a given aopName on the shared requestContext (the same mechanism strategist-updates.ts/conversation-field-updates.ts already use to share rawEventContent across dispatch calls), and omit the field on repeat lookups within the same run. The output schema already marks domainGuidance optional, so its absence on a later call is a normal, documented case , updated the schema description to say so explicitly.

Estimated savings

Derived from real Understudy billing + trace data, not assumed:

  • domainGuidance is ~15.3% of get-conversation's total output bytes (338,086 of 2,202,560 chars across 44 sampled calls).
  • But only repeat calls for the same domain within a run actually benefit , checked this directly: of 37 sampled traces, only 6 had more than one get-conversation call, and of 32 total calls observed across those traces, 7 were a 2nd-or-later occurrence (~22%).
  • get-conversation is 48.5% of all tool-result bytes in automation's "new content" cost pool ($124.27/day, from automation's real 6-day cost-breakdown: uncached_input + cache_write).
  • Estimated recoverable: 15.3% Ɨ 48.5% Ɨ 22% Ɨ $124.27/day ā‰ˆ $2/day (~$60/month, ~$730/year). Small, but zero-risk and free to ship , this is a pure dedup with no behavior change to anything the agent actually needs, just one fewer repeat of static reference text.

Scope note , what this PR deliberately does NOT touch

The larger opportunity in get-conversation's output is the fields[] array (51% of the payload, of which description text is ~56%). That looked like a bigger win at first, but investigating getFieldDescription (conversation-context.ts) showed the description text carries load-bearing write instructions in some cases , valid enum options for select/list fields, JSON format rules, signal rubrics. A blind length cap risks truncating the actual contract the agent needs to write a correct value, not just cost. Left alone pending a more surgical follow-up that only trims free-text prose and never touches the appended operational instructions.

Test plan

  • Typecheck clean on the changed file (pnpm run types from apps/server , the only errors in the full build are pre-existing, unrelated better-auth plugin-export issues, not touching this file)
  • Confirm in practice that repeat get-conversation calls within a run actually omit domainGuidance as expected (e.g. watch a multi-lookup automation run's captures)

šŸ¤– Generated with Claude Code

https://claude.ai/code/session_01JfEdawy9Y7huYi1j59saZN

Greptile Summary

This PR deduplicates static domain guidance across repeated conversation fetches that share a run-scoped request context.

  • Records a per-AOP marker after returning domain guidance for the first time.
  • Omits the guidance from subsequent fetches for that AOP in the same context.
  • Documents the conditional omission in the output schema.
  • The behavior is straightforward, but its stateful boundary is not covered by an automated regression test.

Confidence Score: 4/5

The PR appears safe to merge, with a non-blocking gap in regression coverage for the new request-context deduplication behavior.

The synchronous marker update avoids a concurrency race, inspected execution paths use run-scoped contexts, and current guidance is deterministic by AOP name; only automated coverage of the stateful contract is missing.

**Files Needing At

Show production surfaces and changed-file mapping

Production surfaces

Libra has not measured any production surfaces for this change yet.

Changed files → surfaces

  • apps/server/src/mastra/tools/conversation/fetchConversationTool.tsno production surface mapped