Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions posthog/test/ai/test_prompts.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -820,9 +820,15 @@ def test_mutating_a_result_config_does_not_pollute_the_cache(
self, mock_get_session
):
"""Callers often mutate config before spreading it into an LLM call; that must not leak into later cache hits."""
# Nested values included: a shallow copy would pass the top-level mutations
# below but leak the nested one into the cache.
nested_config = {
"model": "gpt-4o",
"tools": [{"name": "search", "parameters": {"depth": 1}}],
}
mock_get = mock_get_session.return_value.get
mock_get.return_value = MockResponse(
json_data={**self.mock_prompt_response, "config": self.mock_config}
json_data={**self.mock_prompt_response, "config": nested_config}
)

prompts = Prompts(self.create_mock_posthog())
Expand All@@ -831,11 +837,18 @@ def test_mutating_a_result_config_does_not_pollute_the_cache(
assert first.config is not None
first.config["temperature"] = 0.9
first.config.pop("model")
first.config["tools"][0]["parameters"]["depth"] = 99

second = prompts.get("test-prompt", with_metadata=True)

self.assertEqual(second.source, "cache")
self.assertEqual(second.config, self.mock_config)
self.assertEqual(
second.config,
{
"model": "gpt-4o",
"tools": [{"name": "search", "parameters": {"depth": 1}}],
},
)

@parameterized.expand(
[
Expand Down
6 changes: 4 additions & 2 deletions references/public_api_snapshot.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -425,13 +425,15 @@ attribute posthog.ai.openai_agents.processor.log = logging.getLogger('posthog')
attribute posthog.ai.otel.spans.AI_SPAN_PREFIXES = ('gen_ai.', 'llm.', 'ai.', 'traceloop.')
attribute posthog.ai.otel.spans.DEFAULT_HOST = 'https://us.i.posthog.com'
attribute posthog.ai.prompts.APP_ENDPOINT = 'https://us.posthog.com'
attribute posthog.ai.prompts.CachedPrompt.config = config
attribute posthog.ai.prompts.CachedPrompt.fetched_at = fetched_at
attribute posthog.ai.prompts.CachedPrompt.label = label
attribute posthog.ai.prompts.CachedPrompt.name = name
attribute posthog.ai.prompts.CachedPrompt.prompt = prompt
attribute posthog.ai.prompts.CachedPrompt.version = version
attribute posthog.ai.prompts.DEFAULT_CACHE_TTL_SECONDS = 300
attribute posthog.ai.prompts.PromptCacheKey = tuple[str, Optional[int], Optional[str]]
attribute posthog.ai.prompts.PromptResult.config: Optional[Dict[str, Any]] = None
attribute posthog.ai.prompts.PromptResult.label: Optional[str] = None
attribute posthog.ai.prompts.PromptResult.name: Optional[str] = None
attribute posthog.ai.prompts.PromptResult.prompt: str
Expand DownExpand Up@@ -887,8 +889,8 @@ class posthog.ai.openai.openai_providers.AzureOpenAI(posthog_client: Optional[Po
class posthog.ai.openai_agents.processor.PostHogTracingProcessor(client: Optional[Client] = None, distinct_id: Optional[Union[str, Callable[[Trace], Optional[str]]]] = None, privacy_mode: bool = False, groups: Optional[Dict[str, Any]] = None, properties: Optional[Dict[str, Any]] = None)
class posthog.ai.otel.exporter.PostHogTraceExporter(api_key: str, host: str = DEFAULT_HOST)
class posthog.ai.otel.processor.PostHogSpanProcessor(api_key: str, host: str = DEFAULT_HOST)
class posthog.ai.prompts.CachedPrompt(prompt: str, fetched_at: float, name: str, version: int, label: Optional[str] = None)
class posthog.ai.prompts.PromptResult(source: PromptSource, prompt: str, name: Optional[str] = None, version: Optional[int] = None, label: Optional[str] = None)
class posthog.ai.prompts.CachedPrompt(prompt: str, fetched_at: float, name: str, version: int, label: Optional[str] = None, config: Optional[Dict[str, Any]] = None)
class posthog.ai.prompts.PromptResult(source: PromptSource, prompt: str, name: Optional[str] = None, version: Optional[int] = None, label: Optional[str] = None, config: Optional[Dict[str, Any]] = None)
class posthog.ai.prompts.Prompts(posthog: Optional[Any] = None, *, personal_api_key: Optional[str] = None, project_api_key: Optional[str] = None, host: Optional[str] = None, default_cache_ttl_seconds: Optional[int] = None, capture_errors: bool = False)
class posthog.ai.stream.AsyncStreamWrapper(generator: AsyncGenerator[T, None], stream: Optional[Any] = None)
class posthog.ai.types.FormattedFunctionCall
Expand Down