feat: dedicated AI endpoint routing#656
Conversation
Prompt To Fix All With AIFix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
posthog/consumer.py:147-152
**AI events silently dropped when analytics send fails**
If `_send(analytics_events, EVENTS_ENDPOINT)` exhausts its retries and raises, the exception propagates immediately — the `_send(ai_events, AI_EVENTS_ENDPOINT)` call is never reached. Both sub-lists were dequeued from the shared queue and `task_done()` will be called for every item in `upload()`, so the AI events are permanently lost without any send being attempted. The docstring says "a failure on one does not re-send the other" which implies symmetric independence, but the ordering creates a dependency: analytics failure silently kills AI delivery too.
### Issue 2 of 3
posthog/consumer.py:147-148
`is_ai_event` is evaluated for every item in `batch` twice — once per list comprehension. A single partitioning loop halves the predicate calls and says the intent once.
```suggestion
ai_events, analytics_events = [], []
for item in batch:
(ai_events if is_ai_event(item.get("event")) else analytics_events).append(item)
```
### Issue 3 of 3
posthog/test/test_dedicated_ai_endpoint.py:46-74
**Sync-mode tests could be parameterised**
The three `TestDedicatedAiEndpointSyncMode` methods differ only in `(flag_enabled, event_name, expected_path)` — a table-driven `subTest` or `parameterized.expand` would express all three cases in one method, which aligns with the team's preference for parameterised tests.
Reviews (1): Last reviewed commit: "feat: dedicated ai endpoint routing" | Re-trigger Greptile |
posthog-python Compliance ReportDate: 2026-06-10 11:12:15 UTC ✅ All Tests Passed!45/45 tests passed Capture Tests✅ 29/29 tests passed View Details
Feature_Flags Tests✅ 16/16 tests passed View Details
|
| EVENTS_ENDPOINT = "/batch/" | ||
| AI_EVENTS_ENDPOINT = "/i/v0/ai/batch/" |
There was a problem hiding this comment.
is the whole HTTP contract the very same? as in retry logic, request and response payload, etc?
There was a problem hiding this comment.
Actually I just noticed that beyond capping batch sizes on the backend, we also pre-emptively do it on the SDK. Just bumped the AI event size to the 8MB we're gonna be trialing.
Didn't touch batching size for the moment because it was a more comprehensive change, affecting non-AI events too. This means that for events larger than the batch size, we'll just send them as a 1 event batch, this seems reasonable for now.
…dicated_ai_endpoint Generated-By: PostHog Code Task-Id: 142d3917-41e8-4bb5-ad6c-5778e13041c2
marandaneto
left a comment
There was a problem hiding this comment.
approving to unblock, but still this comment left #656 (comment)
Problem
AI Observability wants
$ai_*events isolated into their own batch to a dedicated capture endpoint so AI and analytics workloads stop affecting each other, and different settings can be applied to each.Changes
Sends
$ai_prefixed events to a dedicated endpoint.Gated behind
_internal_dedicated_ai_endpoint. When off, behaviour is byte-identical to today.💚 How did you test it?
I'm an agent (Claude Code), paired with Carlos. Added
posthog/test/test_dedicated_ai_endpoint.py(6 cases): consumer routing of mixed batches to the two endpoints, AI-only batches, the disabled no-op, and thesync_modepath for both AI and non-AI events. New tests pass; the touched suites (test_consumer,test_request,test_client_fork) also pass. No manual testing claimed.📝 Checklist
If releasing new changes
sampo addto generate a changeset file🤖 Agent context
Authored with Claude Code (agent), paired with Carlos, as the python port of the posthog-js change. Design note: python's consumer materializes each batch in memory before POSTing (no persisted contiguous-removal invariant like posthog-node), so the clean approach here is to partition the batch at flush in the consumer rather than maintain separate queues. We target the existing analytics
/batch/handler via a dedicated path (/i/v0/ai/batch/) — not the dead multipart/i/v0/aiendpoint. Still pending before this is live: the backend route alias + charts Contour ingress entry, and confirmation the AI pipeline's per-message size limit is raised (WarpStream, per RFC #1111) so oversized events stop being dropped. Requires human review.