Skip to content

feat(llm-gateway): tag helper calls with $ai_span_name for analytics#2981

Merged
VojtechBartos merged 3 commits into
mainfrom
vojtab/llm-gateway-tag-helper-stage
Jul 1, 2026
Merged

feat(llm-gateway): tag helper calls with $ai_span_name for analytics#2981
VojtechBartos merged 3 commits into
mainfrom
vojtab/llm-gateway-tag-helper-stage

Conversation

@VojtechBartos

@VojtechBartos VojtechBartos commented Jun 29, 2026

Copy link
Copy Markdown
Member

Problem

Helper LLM calls (commit messages, PR descriptions) emit $ai_generation events that look identical to the agent's main turns — no way to filter to just "PR description generations" or just "commit message generations" in LLM analytics.

Changes

  • Set $ai_span_name on each helper call so they can be filtered:
    • generateCommitMessage$ai_span_name = "commit_message"
    • generatePrTitleAndBody$ai_span_name = "pr_description"
  • Add a posthogProperties option to LlmGatewayService.prompt() that forwards entries as x-posthog-property-* headers; the gateway already lifts those onto the captured event.
  • Pull the x-posthog-property-* builder into @posthog/shared/posthog-property-headers so the agent (ANTHROPIC_CUSTOM_HEADERS lines) and LlmGatewayService (fetch headers) share one sanitize + iteration path, with two thin format adapters.

Test plan

  • Helper forwards posthogProperties as x-posthog-property-* headers (null/undefined dropped, header values sanitized).
  • Both git-pr.ts callers tagged with the right span name.
  • Shared builder covers sanitize edge cases (newline collapse, non-latin1 strip, falsy primitives kept).

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit a6f79a1.

@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "feat(llm-gateway): tag helper calls with..." | Re-trigger Greptile

Comment on lines +40 to +46
for (const [key, value] of Object.entries(properties)) {
if (value === null || value === undefined) continue;
const sanitized = String(value)
.replace(/[\r\n]+/g, " ")
.replace(/[^\x20-\x7e\x80-\xff]/g, "");
headers[`x-posthog-property-${key}`] = sanitized;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Header key names are not sanitized

Values are sanitized against invalid HTTP header bytes, but the key portion of x-posthog-property-${key} is forwarded verbatim. HTTP header field names must consist only of token characters (RFC 7230 §3.2.6); a key containing spaces, colons, or control characters would produce an invalid header name that undici would reject at runtime. All current callers use ai_stage (safe), but the Record<string, ...> type places no constraint on keys, so a future caller could silently break requests.

Comment on lines +42 to +44
const sanitized = String(value)
.replace(/[\r\n]+/g, " ")
.replace(/[^\x20-\x7e\x80-\xff]/g, "");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Sanitization logic duplicated from packages/agent

The two-step regex — collapse newlines then strip non-latin1 bytes — is identical to the private sanitizeHeaderValue function in packages/agent/src/utils/gateway.ts (lines 37–39). Both functions also share the same JSDoc rationale. If the sanitization rules ever need updating (e.g. to also strip tab characters), both sites would need to change in sync. Extracting a shared utility would satisfy OnceAndOnlyOnce, assuming the package dependency direction allows it.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, will re-share

@VojtechBartos VojtechBartos force-pushed the vojtab/llm-gateway-tag-helper-stage branch from 4922166 to 25e2ed9 Compare June 29, 2026 13:59
@VojtechBartos VojtechBartos changed the title feat(llm-gateway): tag helper calls with ai_stage for analytics feat(llm-gateway): tag helper calls with $ai_span_name for analytics Jun 29, 2026
@VojtechBartos VojtechBartos self-assigned this Jun 30, 2026
@VojtechBartos VojtechBartos requested a review from a team June 30, 2026 07:50
@VojtechBartos VojtechBartos marked this pull request as ready for review June 30, 2026 07:50
@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Reviews (2): Last reviewed commit: "feat(llm-gateway): tag helper calls with..." | Re-trigger Greptile

Helper LLM calls (commit messages, PR descriptions) currently surface as `$ai_generation` events that are indistinguishable from the agent's main generations — they share `ai_product = posthog_code` with no further metadata, so observability queries can't filter to a specific helper.

- Add a free-form `posthogProperties` option to `LlmGatewayService.prompt()` that forwards each entry as an `x-posthog-property-<key>` header. The gateway lifts those headers onto the captured `$ai_generation` event, mirroring the agent-server's existing `buildGatewayPropertyHeaders` pattern.
- Tag the commit-message and PR-description helpers via the standard `$ai_span_name` property ("commit_message" / "pr_description") so they're filterable in LLM analytics alongside spans from elsewhere in the system.
Both the agent (ANTHROPIC_CUSTOM_HEADERS) and the new LlmGatewayService (fetch headers) need to turn a property map into x-posthog-property-* headers with the same sanitize rules. Pull the iteration + sanitize into @posthog/shared/posthog-property-headers and expose two thin adapters: buildPosthogPropertyHeaderRecord for fetch and buildPosthogPropertyHeaderLines for the SDK env-var format.
@VojtechBartos VojtechBartos force-pushed the vojtab/llm-gateway-tag-helper-stage branch from 0eb1f47 to a6f79a1 Compare July 1, 2026 09:01
@VojtechBartos VojtechBartos enabled auto-merge (squash) July 1, 2026 09:01
@VojtechBartos VojtechBartos merged commit d394d5e into main Jul 1, 2026
23 checks passed
@VojtechBartos VojtechBartos deleted the vojtab/llm-gateway-tag-helper-stage branch July 1, 2026 09:07
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.

2 participants