|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Union |
| 4 | + |
| 5 | +if TYPE_CHECKING: |
| 6 | + from claude_agent_sdk.types import ClaudeAgentOptions, ResultMessage |
| 7 | + |
| 8 | + from posthog.client import Client |
| 9 | + |
| 10 | +try: |
| 11 | + import claude_agent_sdk # noqa: F401 |
| 12 | +except ImportError: |
| 13 | + raise ModuleNotFoundError( |
| 14 | + "Please install the Claude Agent SDK to use this feature: 'pip install claude-agent-sdk'" |
| 15 | + ) |
| 16 | + |
| 17 | +from posthog.ai.claude_agent_sdk.client import PostHogClaudeSDKClient |
| 18 | +from posthog.ai.claude_agent_sdk.processor import PostHogClaudeAgentProcessor |
| 19 | + |
| 20 | +__all__ = [ |
| 21 | + "PostHogClaudeAgentProcessor", |
| 22 | + "PostHogClaudeSDKClient", |
| 23 | + "instrument", |
| 24 | + "query", |
| 25 | +] |
| 26 | + |
| 27 | + |
| 28 | +def instrument( |
| 29 | + client: Optional[Client] = None, |
| 30 | + distinct_id: Optional[Union[str, Callable[[ResultMessage], Optional[str]]]] = None, |
| 31 | + privacy_mode: bool = False, |
| 32 | + groups: Optional[Dict[str, Any]] = None, |
| 33 | + properties: Optional[Dict[str, Any]] = None, |
| 34 | +) -> PostHogClaudeAgentProcessor: |
| 35 | + """ |
| 36 | + Create a PostHog-instrumented query wrapper for the Claude Agent SDK. |
| 37 | +
|
| 38 | + Returns a PostHogClaudeAgentProcessor whose .query() method is a drop-in |
| 39 | + replacement for claude_agent_sdk.query() that automatically emits |
| 40 | + $ai_generation, $ai_span, and $ai_trace events. |
| 41 | +
|
| 42 | + Args: |
| 43 | + client: Optional PostHog client instance. If not provided, uses the default client. |
| 44 | + distinct_id: Optional distinct ID to associate with all events. |
| 45 | + Can also be a callable that takes a ResultMessage and returns a distinct ID. |
| 46 | + privacy_mode: If True, redacts sensitive information in tracking. |
| 47 | + groups: Optional PostHog groups to associate with events. |
| 48 | + properties: Optional additional properties to include with all events. |
| 49 | +
|
| 50 | + Returns: |
| 51 | + PostHogClaudeAgentProcessor: A processor whose .query() method wraps claude_agent_sdk.query(). |
| 52 | +
|
| 53 | + Example: |
| 54 | + ```python |
| 55 | + from posthog.ai.claude_agent_sdk import instrument |
| 56 | +
|
| 57 | + ph = instrument(distinct_id="my-app", properties={"env": "prod"}) |
| 58 | +
|
| 59 | + async for message in ph.query(prompt="Hello", options=options): |
| 60 | + print(message) |
| 61 | + ``` |
| 62 | + """ |
| 63 | + return PostHogClaudeAgentProcessor( |
| 64 | + client=client, |
| 65 | + distinct_id=distinct_id, |
| 66 | + privacy_mode=privacy_mode, |
| 67 | + groups=groups, |
| 68 | + properties=properties, |
| 69 | + ) |
| 70 | + |
| 71 | + |
| 72 | +async def query( |
| 73 | + *, |
| 74 | + prompt: Any, |
| 75 | + options: Optional[ClaudeAgentOptions] = None, |
| 76 | + transport: Any = None, |
| 77 | + posthog_client: Optional[Client] = None, |
| 78 | + posthog_distinct_id: Optional[ |
| 79 | + Union[str, Callable[[ResultMessage], Optional[str]]] |
| 80 | + ] = None, |
| 81 | + posthog_trace_id: Optional[str] = None, |
| 82 | + posthog_properties: Optional[Dict[str, Any]] = None, |
| 83 | + posthog_privacy_mode: bool = False, |
| 84 | + posthog_groups: Optional[Dict[str, Any]] = None, |
| 85 | +): |
| 86 | + """ |
| 87 | + Drop-in replacement for claude_agent_sdk.query() with PostHog instrumentation. |
| 88 | +
|
| 89 | + All original messages are yielded unchanged. PostHog events ($ai_generation, |
| 90 | + $ai_span, $ai_trace) are emitted automatically. |
| 91 | +
|
| 92 | + Args: |
| 93 | + prompt: The prompt (same as claude_agent_sdk.query) |
| 94 | + options: ClaudeAgentOptions (same as claude_agent_sdk.query) |
| 95 | + transport: Optional transport (same as claude_agent_sdk.query) |
| 96 | + posthog_client: Optional PostHog client instance. |
| 97 | + posthog_distinct_id: Optional distinct ID for this query. |
| 98 | + posthog_trace_id: Optional trace ID (auto-generated if not provided). |
| 99 | + posthog_properties: Extra properties to include with all events. |
| 100 | + posthog_privacy_mode: If True, redacts sensitive content. |
| 101 | + posthog_groups: Optional PostHog groups. |
| 102 | +
|
| 103 | + Example: |
| 104 | + ```python |
| 105 | + from posthog.ai.claude_agent_sdk import query |
| 106 | +
|
| 107 | + async for message in query( |
| 108 | + prompt="Hello", |
| 109 | + options=options, |
| 110 | + posthog_distinct_id="my-app", |
| 111 | + posthog_properties={"pr_number": 123}, |
| 112 | + ): |
| 113 | + print(message) |
| 114 | + ``` |
| 115 | + """ |
| 116 | + processor = PostHogClaudeAgentProcessor( |
| 117 | + client=posthog_client, |
| 118 | + distinct_id=posthog_distinct_id, |
| 119 | + privacy_mode=posthog_privacy_mode, |
| 120 | + groups=posthog_groups, |
| 121 | + properties={}, |
| 122 | + ) |
| 123 | + |
| 124 | + async for message in processor.query( |
| 125 | + prompt=prompt, |
| 126 | + options=options, |
| 127 | + transport=transport, |
| 128 | + posthog_trace_id=posthog_trace_id, |
| 129 | + posthog_properties=posthog_properties, |
| 130 | + posthog_privacy_mode=posthog_privacy_mode, |
| 131 | + posthog_groups=posthog_groups, |
| 132 | + ): |
| 133 | + yield message |
0 commit comments