feat(agent): route signal_report tasks to signals gateway product#2288
Merged
Conversation
Attribute LLM gateway spend per task type so signals/report-generation cost can be tracked separately from background_agents and posthog_code: - internal task with origin_product "signal_report" -> "signals" - any other internal task -> "background_agents" - any other task -> "posthog_code" Extracted the decision into resolveGatewayProduct in @posthog/agent so the rule lives next to the GatewayProduct type and is independently testable. Generated-By: PostHog Code Task-Id: 31cea4e3-e0d7-49e7-bd01-d41bcafabe53
Send `x-posthog-property-task_origin_product` and `x-posthog-property-task_internal` to the LLM gateway via ANTHROPIC_CUSTOM_HEADERS. The gateway lifts any `x-posthog-property-*` header onto the captured `$ai_generation` event, so this lands task metadata on every generation we drive through Claude — letting LLM analytics break spend down by task origin without needing the gateway-product alone to encode it. The OpenAI/codex path has no equivalent custom-headers env var, so forwarding is Anthropic-only today. Also inline the one-shot `signal_report` constant — the literal only appears once now that `resolveGatewayProduct` is the single decision point. Generated-By: PostHog Code Task-Id: 31cea4e3-e0d7-49e7-bd01-d41bcafabe53
Extend ANTHROPIC_CUSTOM_HEADERS with the IDs the agent server already has in scope (from the JWT payload) so every $ai_generation captured by the gateway can be joined back to the task, run, and triggering user without an extra hop. Generated-By: PostHog Code Task-Id: 31cea4e3-e0d7-49e7-bd01-d41bcafabe53
Contributor
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
packages/agent/src/utils/gateway.test.ts:4-42
The five `resolveGatewayProduct` cases share identical structure — call the function with `{isInternal, originProduct}`, assert the returned `GatewayProduct` — which is the canonical candidate for `it.each`. The first test also bundles two distinct inputs (`isInternal: false` and the default call) into one assertion block, hiding which input failed when the test breaks. A parameterised table makes the full input/output contract visible at a glance and is consistent with the team's stated preference.
```suggestion
describe("resolveGatewayProduct", () => {
it.each([
{ isInternal: false, originProduct: undefined, expected: "posthog_code" },
{ isInternal: undefined, originProduct: undefined, expected: "posthog_code" },
{ isInternal: false, originProduct: "signal_report", expected: "posthog_code" },
{ isInternal: true, originProduct: undefined, expected: "background_agents" },
{ isInternal: true, originProduct: "session_summaries", expected: "background_agents" },
{ isInternal: true, originProduct: "signal_report", expected: "signals" },
])(
"isInternal=$isInternal originProduct=$originProduct → $expected",
({ isInternal, originProduct, expected }) => {
expect(resolveGatewayProduct({ isInternal, originProduct })).toBe(expected);
},
);
});
```
Reviews (1): Last reviewed commit: "feat(agent): forward task_id, task_run_i..." | Re-trigger Greptile |
Per review feedback, collapse the five near-identical resolveGatewayProduct tests into a single it.each table so the input/output contract is visible at a glance and each row reports independently on failure. Generated-By: PostHog Code Task-Id: 31cea4e3-e0d7-49e7-bd01-d41bcafabe53
andrewm4894
approved these changes
May 21, 2026
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.
Problem
Signals/report-generation traffic currently bills to the
background_agentsLLM gateway product, sharing a cost pool with every other internal task (Slack-triggered runs, session-summary work, etc.). This makes it hard to track signals spend separately and apply a dedicated budget.Changes
Route LLM gateway calls so each task type lands in the right product bucket:
origin_product = \"signal_report\"→signalsbackground_agentsposthog_codeThe decision was pulled out of
AgentServer.configureEnvironmentinto a small pure helper,resolveGatewayProduct, exported from@posthog/agentnext to theGatewayProducttype so the rule is independently testable and easy to reuse.Files touched:
Pairs with the gateway-side change posthog/posthog#59433 which adds the per-user cost limit for the
signalsproduct ($500/7d burst, $1000/30d sustained).How did you test this?
I'm an agent. I ran:
I did not run the full test suite or any manual / end-to-end testing.
Publish to changelog?
no