Skip to content

feat(apm): agent file-read enrichment#2836

Open
jonmcwest wants to merge 1 commit into
06-19-feat_apm_enrichment_engine_shared_primitives_enricher_query_formatfrom
06-22-feat_apm_agent_file-read_enrichment
Open

feat(apm): agent file-read enrichment#2836
jonmcwest wants to merge 1 commit into
06-19-feat_apm_enrichment_engine_shared_primitives_enricher_query_formatfrom
06-22-feat_apm_agent_file-read_enrichment

Conversation

@jonmcwest

@jonmcwest jonmcwest commented Jun 22, 2026

Copy link
Copy Markdown

Problem

APM (Application Performance Monitoring) line-level stats were never reaching the host log sink because ClaudeAcpAgent always created its own isolated Logger instance. Additionally, file enrichment had no APM annotation capability — production span statistics were not being surfaced as inline comments when the agent read source files.

Changes

  • ClaudeAcpAgent now accepts an optional logger in its options and uses it in place of the internally constructed one, so enrichment logs flow through the host's log sink (e.g. main.log). The acp-connection adapter passes a child logger scoped to "ClaudeAcpAgent".
  • enrichFileForAgent now runs event annotation and APM stat fetching concurrently via Promise.all. When APM stats are available for a supported language, formatApmInlineComments annotates the file content with per-line span data before returning.
  • A getApmLineStats helper manages a path-keyed in-memory cache with a 5-minute TTL. Cache misses trigger a fetchApmLineStats call with a 15-second timeout (sized for the worst-case 24h query window). Transient fetch failures are not cached, allowing retries on the next read. Empty results are cached to avoid redundant fetches for untraced files.
  • resolveEnricherConfig is extracted as a shared helper used by both the event enrichment path (5s timeout) and the APM path (15s timeout).
  • Import resolution errors inside buildWrapperContext are now caught per-import so a single failing resolution cannot abort the entire file read.
  • createEnrichment wires up the apmStatsCache and a concrete fetchApmLineStats implementation backed by PostHogApi.getApmLineStats, and clears the cache on dispose.

How did you test this?

  • Added claude-agent.logger.test.ts verifying that a host-provided logger receives enrichment log events with the correct prefix and payload.
  • Extended file-enricher.test.ts with an "APM enrichment caching" suite covering: cache hit on repeated reads, empty-result caching, stat re-application after an edit, no caching on transient failure, graceful degradation when getApiKey rejects, timeout value assertion, TTL expiry triggering a refetch, and resilience when the event-annotation branch throws.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

jonmcwest commented Jun 22, 2026

Copy link
Copy Markdown
Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit d02ea61.

@jonmcwest jonmcwest marked this pull request as ready for review June 22, 2026 11:17
@greptile-apps

greptile-apps Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
packages/agent/src/enrichment/file-enricher.ts:97-102
**`formatApmInlineComments` called without any error guard**

Every other failure surface in this function — `enrichEventsForAgent`, `getApmLineStats` — returns `null` on error. `formatApmInlineComments` processes external API data (`apmStats`) but is called bare, so an unexpected throw (e.g. a line number out of range, a null stat field, or an edge-case in the formatter) would propagate to the caller as an unhandled rejection instead of silently degrading. Wrapping it in a `try/catch` that falls back to `eventAnnotated ?? content` would keep the defensive pattern consistent.

### Issue 2 of 3
packages/agent/src/enrichment/file-enricher.ts:85-88
**`getApiKey()` called twice in parallel for dual-enrichable files**

Both `enrichEventsForAgent` (via `resolveEnricherConfig(deps, 5_000)`) and `getApmLineStats` (via `resolveEnricherConfig(deps, APM_QUERY_TIMEOUT_MS)`) concurrently call `deps.apiConfig.getApiKey()` for any TypeScript/JS file that contains posthog calls and is also APM-traced — a common scenario in PostHog's own front-end code. If `getApiKey` triggers a token refresh, two parallel refreshes race each other. The reason the timeouts differ (5 s vs 15 s) is valid, but the key itself is invariant to the timeout; resolving it once and passing it into both sub-paths would eliminate the redundant call without changing semantics.

### Issue 3 of 3
packages/agent/src/enrichment/file-enricher.test.ts:316-368
**Cache-behaviour tests could be consolidated into a parameterised suite**

Three consecutive tests — "serves stats from cache (one fetch)", "caches an empty result…", and "a transient fetch failure is not cached" — share the exact same fixture shape (call `enrichFileForAgent` twice with the same path, assert `fetchApmSpy` call count). The team preference is for parameterised tests; a `test.each` table over `[fetchImpl, expectedCallCount, expectedFirstResult]` would express the three variants with less duplication while keeping all assertions intact.

Reviews (1): Last reviewed commit: "feat(apm): agent file-read enrichment" | Re-trigger Greptile

Comment thread packages/agent/src/enrichment/file-enricher.ts
Comment thread packages/agent/src/enrichment/file-enricher.ts
Comment thread packages/agent/src/enrichment/file-enricher.test.ts Outdated
@jonmcwest jonmcwest force-pushed the 06-22-feat_apm_agent_file-read_enrichment branch from 696d183 to d02ea61 Compare June 22, 2026 14:39
@jonmcwest jonmcwest requested a review from k11kirky June 23, 2026 10:56
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