fix(aio): never drop or leak multimodal content in ai capture#762
fix(aio): never drop or leak multimodal content in ai capture#762carlos-marchal-ph wants to merge 1 commit into
Conversation
|
| ) | ||
| if ( | ||
| item.get("type") == "image_url" | ||
| and isinstance(item.get("image_url"), dict) | ||
| and "url" in item["image_url"] | ||
| strong | ||
| and len(value) >= _STRONG_CONTEXT_MIN_LEN | ||
| and _BASE64_BODY_RE.match(value) | ||
| ): |
There was a problem hiding this comment.
Short media bypasses redaction
When multimodal capture is disabled and a recognized media field contains valid raw base64 shorter than 200 characters, this length check leaves the value unchanged, causing raw Anthropic, Gemini, or OpenAI media data to be included in the captured AI event.
Knowledge Base Used: AI Observability (posthog/ai)
Prompt To Fix With AI
This is a comment left during a code review.
Path: posthog/ai/sanitization.py
Line: 121-126
Comment:
**Short media bypasses redaction**
When multimodal capture is disabled and a recognized media field contains valid raw base64 shorter than 200 characters, this length check leaves the value unchanged, causing raw Anthropic, Gemini, or OpenAI media data to be included in the captured AI event.
**Knowledge Base Used:** [AI Observability (posthog/ai)](https://app.greptile.com/posthog-org-19734/-/custom-context/knowledge-base/posthog/posthog-python/-/docs/ai-observability.md)
How can I resolve this? If you propose a fix, please make it concise.
posthog-python Compliance ReportDate: 2026-07-24 15:06:03 UTC ✅ All Tests Passed!111/111 tests passed Capture_V1 Tests✅ 94/94 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
|
💡 Motivation and Context
AI capture silently dropped or mangled content, and base64 redaction failed in both directions.
Dropped/mangled:
tool_calls, Responses API output items (streaming and non-streaming), and image-generation outputs were lost or given wrong type labels.ChatCompletionMessageback intomessagesraised.Redaction:
Fix routes every AI content property through one choke point (
finalize_ai_content→redact_media) with structural, media-type-aware redaction, and normalizes typed SDK objects to plain dicts so nothing collapses to a repr string.💚 How did you test it?
New tests added with the change:
test_capture_contract.py,test_capture_pipeline.py— end-to-end capture behavior across providers and streaming/non-streaming paths.test_openai_converter.py,test_gemini_converter.py,test_anthropic_converter.py,test_processor_content.py) andtest_media.py.test_sanitization.pyfor the structural redactor (leak paths, over-redaction, media-specific placeholders).ruff formatandruff checkclean on all touched files.📝 Checklist
If releasing new changes
sampo addto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted) — Carlos is DRI.
The multimodal capture fix was human-authored. Claude Code (Opus 4.8) did a final cleanup pass: stripped the inline comments and newly-added docstrings this change introduced, keeping only those that guard against a specific breakage (ordering constraints, the base64-leak boundary, the single-choke-point invariant, and the back-compat wrappers/param that look deletable), and tightened the changelog entry to one sentence. Comments and docstrings that pre-existed or that the change only updated for accuracy were left alone.