feat(agent): show PostHog products used below each turn#2476
Merged
Conversation
When the agent uses a PostHog resource via the MCP `exec` dispatcher during a turn, surface a chip row under that turn's final message listing the products touched (Experiments, Feature flags, SQL, Error tracking, …). A turn with no PostHog calls shows no row. Detection and classification live in the agent (main/business layer); the renderer is strictly UI: - packages/agent/src/posthog-products.ts: classify an exec sub-tool's domain into a stable product id (admin/meta domains hidden; unknown → generic "PostHog"). Exported via @posthog/agent. - PostToolUse hook records the product behind each executed `call` onto a per-turn Set on the session; reset at prompt start. - At turn end the agent emits a new `_posthog/resources_used` notification with the turn's products, then clears the accumulator. - Renderer: buildConversationItems handles the notification and places a `resources_used` item under the final message; ResourcesUsedView renders the chips. Tests: posthog-products classification, and buildConversationItems placement / empty-payload handling. Generated-By: PostHog Code Task-Id: f2ff4d75-f51e-4618-9e64-68ca4be237fa
Adds [resources_used]-tagged debug logging across the full chain so we can see where the per-turn PostHog products row breaks: - PostToolUse hook (hooks.ts): logs the SDK's actual tool_name for any posthog tool, whether isPostHogExecTool matched, and the extracted sub-tool — catches a tool-name/regex mismatch. - claude-agent.ts: logs each classified resource as it's recorded, and whether emitResourcesUsed fires + what it emits. - buildConversationItems.ts (renderer): logs any resource notification the builder receives and whether the RESOURCES_USED branch matched. Agent logs land in the dev logs; renderer logs in chromium.log. Temporary diagnostic — to be reverted once the root cause is found. Generated-By: PostHog Code Task-Id: f2ff4d75-f51e-4618-9e64-68ca4be237fa
A turn that counts feature flags via `SELECT count() FROM feature_flags` was tagged only "SQL" — the classifier saw the execute-sql sub-tool and had no visibility into what the query was about. The chip reflected the mechanism, not the product the user asked about. Now, for execute-sql, the raw command (which embeds the HogQL) is threaded through the PostToolUse hook to a new classifier that extracts FROM/JOIN tables and maps them to products (feature_flags -> Feature flags, experiments -> Experiments, events/persons -> Product analytics, session_replay_events -> Session replay, surveys, logs). A query touching no mapped table falls back to the generic "SQL" chip, so nothing vanishes. - posthog-products.ts: TABLE_PRODUCT map, extractSqlTables, classifyPostHogSqlQuery, classifyPostHogExecCall (returns 0..n products; SQL can touch several tables). - hooks.ts / options.ts: onPostHogResourceUsed now also receives the raw command. - claude-agent.ts: accumulates all products from classifyPostHogExecCall. - Exported the new helpers; added classifyPostHogSqlQuery / classifyPostHogExecCall tests. Generated-By: PostHog Code Task-Id: f2ff4d75-f51e-4618-9e64-68ca4be237fa
SQL table → product attribution is an exact-name match, but taking the last dotted segment meant a schema-qualified warehouse table like `stripe.feature_flags` would wrongly map to Feature flags. Now a qualified reference only maps when its schema is a known PostHog schema (`system`); any other prefix (a warehouse source) is left unmapped. Exact matching also means similarly-named tables such as `statsig_feature_flags` or `feature_flags_archive` never match a product — they fall back to the generic SQL chip. Added tests covering both cases. Generated-By: PostHog Code Task-Id: f2ff4d75-f51e-4618-9e64-68ca4be237fa
…omposer Reworks the resources-used display from a per-turn inline row into a persistent bar above the chat composer that fills in live as resources are used and shows each product only once for the whole session. Agent: - Session accumulator renamed turnResources -> sessionResources; it now lives for the whole session and is never reset between turns. - Detection emits `_posthog/resources_used` immediately for each newly-seen product (session-wide dedup), instead of buffering one emit at turn end. Removed the two turn-end emit sites and the per-prompt reset. Renderer: - New SessionResourcesBar (mirrors PlanStatusBar) rendered above the composer in SessionView. accumulateSessionResources derives the deduped, first-seen-ordered product list from the session's events, so it works for both live streaming and log replay. - Removed the inline conversation-item path: buildConversationItems no longer emits a resources_used item, the SessionUpdateView case/type are gone, and ResourcesUsedView is deleted. Tests updated/added: accumulateSessionResources (dedup, ordering, empty), buildConversationItems no longer renders an inline item, agent session-field rename. Generated-By: PostHog Code Task-Id: f2ff4d75-f51e-4618-9e64-68ca4be237fa
…rder The resources bar sat in a full-width `bg-gray-2` band with a top border, which read as a heavy separate strip. Remove both so it inherits the chat area's background and sits flush above the composer. Generated-By: PostHog Code Task-Id: f2ff4d75-f51e-4618-9e64-68ca4be237fa
Each resource chip now links to its product's page on posthog.com (e.g. Feature flags → /docs/feature-flags), opened via openUrlInBrowser (os.openExternal). Doc URLs verified against posthog.com/docs. The map is Partial — products without a dedicated docs page (apm) stay non-clickable rather than linking somewhere misleading. Clickable chips get a pointer cursor, hover state, and a title tooltip. Also adds bottom margin (mb-3) so the bar sits less tightly against the composer. Generated-By: PostHog Code Task-Id: f2ff4d75-f51e-4618-9e64-68ca4be237fa
Strips the temporary [resources_used]-tagged debug logging now that the feature is verified: the PostToolUse hook's posthog-tool log and its logger param, and the two debug logs in createOnPostHogResourceUsed / emitResourcesUsed. Detection, classification, and emission are unchanged. Generated-By: PostHog Code Task-Id: f2ff4d75-f51e-4618-9e64-68ca4be237fa
- Fix stale comment on onPostHogResourceUsed (it accumulates session-wide and deduped, not a per-turn summary). - Trim @posthog/agent index to only re-export the PostHogProductId type; the classifier functions and POSTHOG_PRODUCTS const aren't used outside the package (claude-agent.ts imports them via the relative path), so the re-exports were dead public-API surface. Generated-By: PostHog Code Task-Id: f110e589-9df9-40fc-9fff-7ff10356aca6
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/posthog-products.test.ts:10-61
**Prefer parameterised tests here**
Several test cases pack multiple independent assertions into a single `it()` block rather than using `it.each`. When one assertion fails it silences the rest, making failures harder to diagnose. The three most obvious candidates:
- `"maps resource sub-tools to their product"` (lines 10–29): 10 input/output pairs
- `"classifies query-* sub-tools by query type"` (lines 31–48): 8 pairs
- `"returns null for admin/meta/introspection domains"` (lines 56–61): 4 pairs
The same pattern appears in `classifyPostHogSqlQuery` (e.g. `"attributes a query to the product behind its tables"` has 3 pairs; `"does not match a warehouse table…"` has 2). Each of these could be an `it.each` table.
Reviews (1): Last reviewed commit: "Merge branch 'main' into posthog-code/sh..." | Re-trigger Greptile |
Adds a "Code" chip (links to posthog.com/code) to the session resources bar and surfaces it whenever the agent reads a file from the codebase: - posthog-products.ts: new `code` product. - PostToolUse hook: fires `onCodeFileRead` on any `Read` tool use; the agent records the `code` product through the same session-wide dedup + emit path as MCP resources. Detection lives in the hook (not the enrichment hook) so it isn't gated on PostHog instrumentation being present in the file. - SessionResourcesBar.tsx: CodeIcon + docs URL for the chip. Fixes the failing unit-test suite: SessionResourcesBar.test.ts imported the component, which transitively pulls in the tRPC client (via openUrlInBrowser) and throws "Could not find electronTRPC global" under vitest. Extracted the pure `accumulateSessionResources` into its own dependency-free module (mirroring buildConversationItems.ts) and pointed the renamed test at it. Addresses the review comment: parameterised the multi-assertion blocks in posthog-products.test.ts with `it.each` so a single failing case no longer masks the rest. Generated-By: PostHog Code Task-Id: f110e589-9df9-40fc-9fff-7ff10356aca6
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.
When the agent uses a PostHog resource via the MCP
execdispatcher during a turn, surface a chip row under that turn's final message listing the products touched (Experiments, Feature flags, SQL, Error tracking, …). A turn with no PostHog calls shows no row.Detection and classification live in the agent (main/business layer); the renderer is strictly UI:
callonto a per-turn Set on the session; reset at prompt start._posthog/resources_usednotification with the turn's products, then clears the accumulator.resources_useditem under the final message; ResourcesUsedView renders the chips.Tests: posthog-products classification, and buildConversationItems placement / empty-payload handling.
Generated-By: PostHog Code
Task-Id: f2ff4d75-f51e-4618-9e64-68ca4be237fa
Problem
Changes
How did you test this?
Automatic notifications