Compare commits

..
Author SHA1 Message Date
zeekay 81fb40cde3 corona→corona: academic Corona now only in lp-220-p3q-corona 2026-06-11 10:25:54 -07:00
Hanzo AI 001ac2f65b chore: symlink AGENTS.md and CLAUDE.md to LLM.md 2026-04-01 14:13:28 -07:00
Hanzo AI b5f5dade80 chore: rename docker-compose.yml to compose.yml 2026-03-03 14:00:00 -08:00
Hanzo Dev 29a74b090a rebrand: remove all compat aliases, zero posthog refs
- Remove Posthog = Insights alias from __init__.py
- Remove PosthogContextMiddleware alias from django.py
- Remove PostHogTracingProcessor alias from processor.py
- Change $lib from "posthog-python" to "insights-python"
- Change ingestion URLs from posthog.com to insights.hanzo.ai
- Rename all posthog_* kwargs to insights_* across AI wrappers
- Rename __posthog_exception_captured to __insights_exception_captured
- Rename posthog_context_stack contextvar to insights_context_stack
- Rename posthog🎏 Redis prefix to insights🎏
- Rename $$_posthog_redacted_* sentinels to $$_insights_redacted_*
- Remove POSTHOG_MW_* Django settings fallback, X-POSTHOG-* headers
- Rename Prompts(posthog=) param to Prompts(client=)
- Update APP_ENDPOINT to us.insights.hanzo.ai
- Update all tests, examples, docs, mypy config
2026-03-13 20:29:13 -07:00
Hanzo Dev 24318fe57c rebrand: Posthog->Insights, package hanzo-insights
- Rename main class Posthog -> Insights (Posthog kept as alias)
- Rename PosthogContextMiddleware -> InsightsContextMiddleware (alias kept)
- Rename PostHogTracingProcessor -> InsightsTracingProcessor (alias kept)
- Add `insights/` re-export package so `from insights import Insights` works
- Update all imports from `posthog` to `hanzo_insights` across source and tests
- Update docstrings, comments, error messages, user agent string
- Update README, example.py, .env.example, Makefile, LLM.md
- Django middleware now supports INSIGHTS_MW_* settings (POSTHOG_MW_* still works)
- Django middleware accepts X-INSIGHTS-* headers (X-POSTHOG-* still works)
- Keep protocol-level values ($lib, ingestion URLs, sentinel strings) for server compat
- Keep posthog_* parameter names in AI wrappers for API compat
- All 681 tests pass
2026-03-13 19:58:09 -07:00
Hanzo Dev e14fe3824d docs: add LLM.md project guide 2026-03-11 10:32:50 -07:00
Hanzo Dev 894c008b5d chore: rename package from hanzoanalytics to hanzo-insights
Package name: hanzo-insights (import as hanzo_insights)
2026-03-06 22:44:19 -08:00
Hanzo Dev 867d7d0aed Rename package from posthog/posthoganalytics to hanzoanalytics
Full rebrand: module directory, pyproject.toml, setup.py, all imports.
2026-03-06 22:42:05 -08:00
Radu RaiceaandGitHub afb978e1f8 feat(llma): support prompt versions in prompts sdk (#454)
* feat(llma): support prompt versions in prompts sdk

* fix(llma): enforce clear_cache version requires name
2026-03-06 10:29:07 +01:00
github-actions[bot] d73abc6d93 chore: Release v7.9.7 2026-03-05 22:09:29 +00:00
a96ed6616c Add warning log for local flag evaluation cold start (#452)
* Add warning log when local flag evaluation called before flags loaded

When feature_enabled() is called with only_evaluate_locally=True before
flag definitions are fetched, the SDK silently returns None. This adds a
warning log so users can diagnose the issue immediately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Move cold start warning to only fire for only_evaluate_locally=True

The warning was in _locally_evaluate_flag which runs for all flag
evaluations, including those that fall back to server-side evaluation.
Move it to the caller where only_evaluate_locally is known, so it only
fires when the caller explicitly opted out of the server fallback.

* Narrow cold start warning to only fire when flags were never fetched

Use `is None` instead of `not` to avoid firing when flags are loaded
but empty (401, 402, no personal_api_key), which already have their
own specific error logs.

* add changeset

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 13:36:05 -08:00
fb8677bd18 fix(llma): use distinct_id from outer context if not provided (#449)
* fix(llma): use distinct_id from outer context if not provided

* fix(llma): distinct_id from context is now explicitly passed to capture method

* fix(llma): fix $process_person_profile with outer context distinct_id, add tests

- Fix personless check to consider outer context distinct_id (not just the
  explicit param), so events from users who set distinct_id via outer context
  are not incorrectly marked as personless.
- Fix typo: "district_id" -> "distinct_id" in comments.
- Add test coverage for distinct_id resolution: no id (personless), explicit
  param, outer context, and explicit overriding outer context.

* chore: add sampo changeset for distinct_id context fix

* style: ruff format

---------

Co-authored-by: Andrew Maguire <andrewm4894@gmail.com>
2026-03-05 15:11:40 +00:00
github-actions[bot] 369b530db9 chore: Release v7.9.6 2026-03-02 21:28:45 +00:00
451cbc85be refactor: add PROPERTY_OPERATORS constant for match_property (#448)
* feat: add semver targeting support to local flag evaluation

Implement 9 semver comparison operators (semver_eq, semver_neq, semver_gt, semver_gte, semver_lt, semver_lte, semver_tilde, semver_caret, semver_wildcard) for feature flag local evaluation. Uses regex-based parsing that matches the server-side sortableSemver behavior to handle v-prefix, whitespace, pre-release suffixes, and non-standard version formats.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* fix: guard against ReDoS in semver regex parsing

Add input length limit before regex search to prevent polynomial
backtracking on adversarial input (CodeQL py/polynomial-redos).

* fix: replace regex with string parsing to resolve ReDoS warning

Replace SEMVER_EXTRACT_RE regex with simple string splitting to
eliminate nested quantifiers that CodeQL flagged as polynomial-redos.

* refactor: inline semver operator tuple to match existing patterns

* refactor: add PROPERTY_OPERATORS constant for match_property

Extract all operator strings into a single source-of-truth tuple and
validate against it early in match_property, replacing the fallthrough
at the end of the function.

* refactor: split PROPERTY_OPERATORS into composable sub-groups

Break the flat tuple into category-specific tuples (EQUALITY_OPERATORS,
STRING_OPERATORS, etc.) that compose into PROPERTY_OPERATORS via
concatenation. The semver dispatch code now references
SEMVER_OPERATORS and SEMVER_COMPARISON_OPERATORS instead of
repeating the full operator lists inline.

* fix: add unreachable fallthrough to satisfy mypy return check

* add release

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 21:12:09 +00:00
github-actions[bot] af050f03f8 chore: Release v7.9.5 2026-03-02 20:53:53 +00:00
37beabd1d3 feat: add semver targeting support to local flag evaluation (#447)
* feat: add semver targeting support to local flag evaluation

Implement 9 semver comparison operators (semver_eq, semver_neq, semver_gt, semver_gte, semver_lt, semver_lte, semver_tilde, semver_caret, semver_wildcard) for feature flag local evaluation. Uses regex-based parsing that matches the server-side sortableSemver behavior to handle v-prefix, whitespace, pre-release suffixes, and non-standard version formats.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* fix: guard against ReDoS in semver regex parsing

Add input length limit before regex search to prevent polynomial
backtracking on adversarial input (CodeQL py/polynomial-redos).

* fix: replace regex with string parsing to resolve ReDoS warning

Replace SEMVER_EXTRACT_RE regex with simple string splitting to
eliminate nested quantifiers that CodeQL flagged as polynomial-redos.

* refactor: inline semver operator tuple to match existing patterns

* add changeset

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 20:52:37 +00:00
github-actions[bot] 9214babf55 chore: Release v7.9.4 2026-02-25 15:28:29 +00:00
Carlos MarchalandGitHub a2ea0bbfe7 fix: revert manual release and add sampo changeset for ai_tokens_source (#445) 2026-02-25 16:25:53 +01:00
Andrew MaguireandGitHub 91f8c39c53 feat(llma): add $ai_tokens_source property to detect token value overrides (#444)
* feat: add $ai_tokens_source property to detect token value overrides

When users pass token properties (e.g. $ai_input_tokens) via
posthog_properties, these override the SDK-computed values. This new
$ai_tokens_source property ("sdk" or "passthrough") lets us distinguish
whether token values came from the SDK or were externally injected,
which is critical for diagnosing cost calculation discrepancies.

* chore: bump version to 7.9.4

* chore: add changelog entry for 7.9.4

* chore: fix ruff formatting

* chore: remove unused pytest import
2026-02-25 13:38:53 +00:00
Michael BiancoandGitHub c689530d82 fix: use $ip not $ip_addess (#356) 2026-02-20 07:46:13 +01:00
github-actions[bot] ad2ef1ef39 chore: Release v7.9.3 2026-02-18 22:20:09 +00:00
Rafael AudibertandGitHub 54a0d98d6f Small fixes for python publishing (#441)
* fix: Avoid setting dynamic version

Version is now fixed because of sampo, so we can get rid of this

* feat: add changeset

* docs: Add new RELEASING section to README
2026-02-18 22:17:26 +00:00
github-actions[bot] 6ba2d8af81 chore: Release v7.9.2 2026-02-18 22:05:00 +00:00
Rafael AudibertandGitHub d6c97b371f chore: Migrate releases to sampo (#398)
* chore: Migrate releases to `sampo`

This is much closer to what we have in `posthog-js`, let's see if it's a good thing!

There's still a lot to do before deploying this:
- updating CI
- updating README with instructions

* Add sampo changeset

* chore: Update  to relase Python via Slack + sampo

* Update release.yml

* fix: Use pyproject.toml version as source of truth
2026-02-18 19:02:19 -03:00
Radu RaiceaandGitHub ef7c513b59 fix(ai): bind prompt reads to project token (#433)
* fix(ai): bind prompt reads to project token

* chore(release): bump version to 7.8.7
2026-02-17 16:58:59 +00:00
c877700b43 chore: release v7.9.0 (#434)
chore: bump version to 7.9.0

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:32:05 +01:00
AndersandGitHub 0fa03d328e feat: Support device_id as bucketing identifier for local evaluation (#424)
* feat: Support device_id as bucketing identifier for local evaluation

Add support for `bucketing_identifier` field on feature flags to allow
using `device_id` instead of `distinct_id` for hashing/bucketing in
local evaluation.
2026-02-16 11:05:09 +01:00
AndersandGitHub 0639f0f31a test(flags): make wrong-key load_feature_flags deterministic (#432) 2026-02-13 15:53:22 +01:00
Aleksander BłaszkiewiczandGitHub f8a5f109c1 feat: limit max number of items in collection to scan (#430)
* feat: limit max number of items in collection to scan

* feat: changelog

* fix: format

* feat: test

* feat: replace entire collection instead of truncating
2026-02-11 14:59:11 +01:00
Aleksander BłaszkiewiczandGitHub 005709ff76 feat: further optimize code variables regex search (#429)
* feat: initial

* fix: ruff
2026-02-09 23:59:03 +01:00
Aleksander BłaszkiewiczandGitHub 100e0c08a4 fix: long variables pattern matching (#428) 2026-02-09 17:45:23 +01:00
AndersandGitHub 2791ee0175 fix: Retry on 408 and respect Retry-After header (#426)
* fix: Retry on 408 and respect Retry-After header

408 (Request Timeout) was incorrectly treated as a non-retryable client
error. Retry-After response headers were ignored during backoff. Replace
backoff library usage with a manual retry loop that honours Retry-After
when present and falls back to exponential backoff otherwise.

* fix: Parse HTTP-date Retry-After values

Retry-After can be seconds or an HTTP-date per RFC 7231. Fall back to
email.utils.parsedate_to_datetime when the numeric parse fails.

* fix: Don't retry on unclassifiable APIError status

When APIError.status is "N/A" (no HTTP status), treat it as
non-retryable to avoid unexpected retry loops on errors the SDK
cannot classify.

* test: Add retry delay tests for Retry-After and exponential backoff

Verify time.sleep is called with the Retry-After value when present,
uses exponential backoff (2^attempt) when absent, and that 408 is
retried.
2026-02-09 12:15:49 +00:00
Aleksander BłaszkiewiczandGitHub 07a5261f0f fix: openai image sanitization (#425) 2026-02-06 14:15:57 +01:00
f409515bfa fix: openAI input image sanitization (#384)
Co-authored-by: Aleksander Błaszkiewicz <kqmdjc8@gmail.com>
2026-02-06 13:53:02 +01:00
Gabriel GrinbergandGitHub c50b7b2e78 Fix feature flag 401 errors causing HTTP request storm (#422)
* Fix feature flag 401 errors causing HTTP request storm

Set feature_flags = [] on 401 error to prevent repeated requests.

* Clear flag_cache, group_type_mapping, cohorts on 401
2026-02-04 10:31:10 -05:00
Radu RaiceaandGitHub cbc74eb1d4 fix(llma): default prompts url (#423) 2026-02-04 15:10:00 +00:00
Radu RaiceaandGitHub 786ef4d612 fix(llma): small fixes for prompt management (#420)
* fix(llma): small fixes for prompt management

* fix(llma): tests

* fix(llma): tests
2026-02-04 09:49:19 +02:00
José SequeiraandGitHub cd351653c0 feat: SDK Compliance (#397)
* feat: SDK Compliance
2026-01-30 16:12:43 +01:00
Radu RaiceaandGitHub ea320eab5a feat(llma): add prompt management (#417)
* feat(llma): add prompt management

* chore(llma): bump version

* fix(llma): use SDK session with retry logic for prompt fetching

Use _get_session() from posthog/request.py instead of raw requests.get()
to benefit from the SDK's existing retry configuration on transient
network failures.
2026-01-30 08:43:04 -05:00
ea56c52be4 feat(llma): pass raw provider usage metadata for backend cost calculations (#411)
* feat: pass raw provider usage metadata for backend cost calculations

Add raw_usage field to TokenUsage type to capture raw provider usage metadata (OpenAI, Anthropic, Gemini). This enables the backend to extract modality-specific token counts (text vs image vs audio) for accurate cost calculations.

- Add raw_usage field to TokenUsage TypedDict
- Update all provider converters to capture raw usage:
  - OpenAI: capture response.usage and chunk usage
  - Anthropic: capture usage from message_start and message_delta events
  - Gemini: capture usage_metadata from responses and chunks
- Pass raw usage as $ai_usage property in PostHog events
- Update merge_usage_stats to handle raw_usage in both modes
- Add tests verifying $ai_usage is captured for all providers

Backend will extract provider-specific details and delete $ai_usage after processing to avoid bloating properties.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add serialize_raw_usage helper to ensure JSON serializability

Address PR review feedback from @andrewm4894:

1. **Serialization**: Add serialize_raw_usage() helper with fallback chain:
   - .model_dump() for Pydantic models (OpenAI/Anthropic)
   - .to_dict() for protobuf-like objects
   - vars() for simple objects
   - str() as last resort
   This ensures we never pass unserializable objects to PostHog client.

2. **Data loss prevention**: Change from replacing to merging raw_usage in
   incremental mode. For Anthropic streaming, message_start has input token
   details and message_delta has output token details - merging preserves
   both instead of losing input data.

3. **Test coverage**: Enhanced tests to verify:
   - JSON serializability with json.dumps()
   - Expected structure of raw_usage dicts
   - Coverage for both non-streaming and streaming modes
   - Fixed Gemini test mocks to return proper dicts from model_dump()

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor: move raw_usage serialization from utils to converters

Address PR feedback from @andrewm4894 - serialize in converters, not utils.

**Problem:**
Utils was receiving raw Pydantic/protobuf objects and serializing them,
which meant provider-specific knowledge leaked into generic code.

**Solution:**
Move serialization into converters where provider context exists:

Converters (NEW):
- OpenAI: serialize_raw_usage(response.usage) → dict
- Anthropic: serialize_raw_usage(event.usage) → dict
- Gemini: serialize_raw_usage(metadata) → dict

Utils (SIMPLIFIED):
- Just passes dicts through, no serialization needed
- Merge operations work with dicts only

**Benefits:**
1. Type correctness: raw_usage is always Dict[str, Any]
2. Separation of concerns: converters handle provider formats
3. Fail fast: serialization errors in converters with context
4. Cleaner abstraction: utils doesn't know about Pydantic/protobuf

**Flow:**
Provider object → Converter serializes → dict → Utils → PostHog

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add type annotation for current_raw to satisfy mypy

Fix mypy error: "Need type annotation for 'current_raw'"

Extract value first, then apply explicit type annotation with ternary
conditional to satisfy mypy's type checker.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-28 11:51:02 +02:00
Andrew MaguireandGitHub 6d3e769256 feat(ai): add OpenAI Agents SDK integration (#408)
* feat(ai): add OpenAI Agents SDK integration

Add PostHogTracingProcessor that implements the OpenAI Agents SDK
TracingProcessor interface to capture agent traces in PostHog.

- Maps GenerationSpanData to $ai_generation events
- Maps FunctionSpanData, AgentSpanData, HandoffSpanData, GuardrailSpanData
  to $ai_span events with appropriate types
- Supports privacy mode, groups, and custom properties
- Includes instrument() helper for one-liner setup
- 22 unit tests covering all span types

* feat(openai-agents): add $ai_group_id support for linking conversation traces

- Capture group_id from trace and include as $ai_group_id on all events
- Add _get_group_id() helper to retrieve group_id from trace metadata
- Pass group_id through all span handlers (generation, function, agent, handoff, guardrail, response, custom, audio, mcp, generic)
- Enables linking multiple traces in the same conversation thread

* feat(openai-agents): add enhanced span properties

- Add $ai_total_tokens to generation and response spans (required by PostHog cost reporting)
- Add $ai_error_type for cross-provider error categorization (model_behavior_error, user_error, input_guardrail_triggered, output_guardrail_triggered, max_turns_exceeded)
- Add $ai_output_choices to response spans for output content capture
- Add audio pass-through properties for voice spans:
  - first_content_at (time to first audio byte)
  - audio_input_format / audio_output_format
  - model_config
  - $ai_input for TTS text input
- Add comprehensive tests for all new properties

* Add $ai_framework property and standardize $ai_provider for OpenAI Agents

- Add $ai_framework="openai-agents" to all events for framework identification
- Standardize $ai_provider="openai" on all events (previously some used "openai_agents")
- Follows pattern from posthog-js where $ai_provider is the underlying LLM provider

* chore: bump version to 7.7.0 for OpenAI Agents SDK integration

* fix: add openai_agents package to setuptools config

Without this, the module is not included in the distribution
and users get an ImportError after pip install.

* fix: correct indentation in on_trace_start properties dict

* fix: prevent unbounded growth of span/trace tracking dicts

Add max entry limit and eviction for _span_start_times and
_trace_metadata dicts. If on_span_end or on_trace_end is never
called (e.g., due to an SDK exception), these dicts could grow
indefinitely in long-running processes.

* fix: resolve distinct_id from trace metadata in on_span_end

Previously on_span_end always called _get_distinct_id(None), which
meant callable distinct_id resolvers never received the trace object
for spans. Now the resolved distinct_id is stored at trace start and
looked up by trace_id during span end.

* refactor: extract _base_properties helper to reduce duplication

All span handlers repeated the same 6 base fields (trace_id, span_id,
parent_id, provider, framework, latency) plus the group_id conditional.
Extract into a shared helper to reduce ~100 lines of boilerplate.

* test: add missing edge case tests for openai agents processor

- test_generation_span_with_no_usage: zero tokens when usage is None
- test_generation_span_with_partial_usage: only input_tokens present
- test_error_type_categorization_by_type_field_only: type field without
  matching message content
- test_distinct_id_resolved_from_trace_for_spans: callable resolver
  uses trace context for span events
- test_eviction_of_stale_entries: memory leak prevention works

* fix: handle non-dict error_info in span error parsing

If span.error is a string instead of a dict, calling .get() would
raise AttributeError. Now falls back to str() for non-dict errors.

* style: apply ruff formatting

* style: replace lambda assignments with def (ruff E731)

* fix: restore full CHANGELOG.md history

The rebase conflict resolution accidentally truncated the changelog
to only the most recent entries. Restored all historical entries.

* fix: preserve personless mode for trace-id fallback distinct IDs

When no distinct_id is provided, _get_distinct_id falls back to
trace_id or "unknown". Since these are non-None strings, the
$process_person_profile=False check in _capture_event never fired,
creating unwanted person profiles keyed by trace IDs.

Track whether the user explicitly provided a distinct_id and use
that flag to control personless mode, matching the pattern used
by the langchain and openai integrations.

* fix: restore changelog history and fix personless mode edge cases

Two fixes from bot review:

1. CHANGELOG.md was accidentally truncated to 38 lines during rebase
   conflict resolution. Restored all 767 lines of history.

2. Personless mode now follows the same pattern as langchain/openai
   integrations: _get_distinct_id returns None when no user-provided
   ID is available, and callers set $process_person_profile=False
   before falling back to trace_id. This covers the edge case where
   a callable distinct_id returns None.

* fix: handle None token counts in generation span

Guard against input_tokens or output_tokens being None when computing
$ai_total_tokens to avoid TypeError.

* fix: check error_type_raw for all error categories

Check both error_type_raw and error_message for guardrail and
max_turns errors, consistent with how ModelBehaviorError and
UserError are already checked.

* fix: add type hints to instrument() function

* refactor: rename _safe_json to _ensure_serializable for clarity

The function validates JSON serializability and falls back to str(),
not serializes. Rename and update docstring to make the contract clear.

* refactor: emit $ai_trace at trace end instead of start

Move the $ai_trace event from on_trace_start to on_trace_end to
capture full metadata including latency, matching the LangChain
integration approach. on_trace_start now only stores metadata for
use by spans.

* style: fix ruff formatting

* fix: add TYPE_CHECKING imports for type hints in instrument()
2026-01-27 21:15:16 +00:00
AndersandGitHub ef6ef12d81 feat: add device_id to flags request payload (#407)
* feat: add device_id to flags request payload

Add device_id parameter to all feature flag methods, similar to how
distinct_id is handled. The device_id is included in the flags request
payload sent to the server.

- Add device_id parameter to Client methods and module-level functions
- Add context support via set_context_device_id() for automatic fallback
- Add tests for explicit device_id and context-based device_id
- Bump version to 7.6.0
2026-01-19 17:22:34 +01:00
Paul D'AmbraandGitHub 0dab1e7f34 Fix link formatting in CHANGELOG.md (#406)
Updated link formatting for clarity in changelog.
2026-01-08 19:59:24 -03:00
Paul D'AmbraandGitHub 982af288d2 chore: check for syntax warnings (#404) 2026-01-08 21:26:22 +00:00
cbdb9adf40 fix: avoid return from finally block to fix Python 3.14 SyntaxWarning (#361)
* fix: Avoid return from finally: block

This fixes a SyntaxWarning on Python 3.14.

```
❯ uvx --no-cache --python 3.14.0 --with posthog==6.7.11 python -c "import posthog"
Installed 11 packages in 5ms
.../lib/python3.14/site-packages/posthog/consumer.py:92: SyntaxWarning: 'return' in a 'finally' block
  return success
````

* add versioning info

---------

Co-authored-by: Paul D'Ambra <paul.dambra@gmail.com>
2026-01-08 21:18:11 +00:00
Tom PiccirelloandGitHub 664696f3eb feat: add CodeQL Advanced workflow (#405)
This is required to be able to run CodeQL against external contributors' PRs.
2026-01-07 22:17:54 -03:00
Paul D'AmbraGitHubClaudegreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
ad27f5ef47 chore: add SDK version support table to README (#402)
* docs: add Python version support table to README

Add a table documenting which SDK versions introduced or dropped
support for different Python versions, based on CHANGELOG.md entries.

* fix: correct Python 3.14 support version to 7.4.3

* Apply suggestions from code review

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-01-07 19:32:43 -03:00
Paul D'AmbraandGitHub c5d0280e3b chore: add a test to describe upload behaviour when there are errors (#403)
* chore: add a test to describe upload behaviour when there are errors

* refactor the test file

* add typehints to the test file
2026-01-07 22:16:15 +00:00
af034835aa feat: llma / error tracking integration (#376)
* feat: llma / error tracking integration

* capture all metadata in llm event

* instrument with contexts

* bump version

* indentation

* linting

* tests

* raise

* test: add exception capture integration tests for langchain

Add 6 tests covering the new LLMA + error tracking integration:
- capture_exception called on span/generation errors
- $exception_event_id added to AI events
- No capture when autocapture disabled
- AI properties passed to exception event
- Handles None return from capture_exception

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: pass context tags to capture() for test compatibility

- Export get_tags() from posthog module
- Explicitly pass context tags to capture() in AI utils
- Fix $ai_model fallback to extract from response.model
- Fix ruff formatting in langchain test_callbacks.py

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: disable auto-capture exceptions in LLM context

The new_context() defaults to capture_exceptions=True which would
auto-capture any exception regardless of enable_exception_autocapture
setting. This was inconsistent with LangChain callbacks which
explicitly check the setting.

Pass capture_exceptions=False to let exception handling be controlled
explicitly by the enable_exception_autocapture setting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: isolate LLM context with fresh=True to avoid tag inheritance

Use fresh=True to start with a clean context for each LLM call.
This avoids inheriting $ai_* tags from parent contexts which could
cause mismatched AI metadata due to the tag merge order bug in
contexts.py (parent tags incorrectly override child tags).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: correct tag merge order so child tags take precedence

The collect_tags() method had a bug where parent tags would overwrite
child tags, despite the comment saying the opposite. This fix ensures
child context tags properly override parent tags.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: remove fresh=True now that tag merge order is fixed

With the collect_tags() bug fixed, child tags properly override parent
tags. LLM events can now inherit useful parent context tags (request_id,
user info, etc.) while still having their $ai_* tags take precedence.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: add test for child tags overriding parent tags

Verifies that in non-fresh contexts, child tags properly override
parent tags with the same key while still inheriting other parent tags.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: add TODO for OpenAI/Anthropic/Gemini exception capture

Document that exception capture needs to be added for the direct SDK
wrappers, similar to how it's implemented in LangChain callbacks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: David Newell <david@Mac.communityfibre.co.uk>
Co-authored-by: Andrew Maguire <andrewm4894@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 13:11:20 +00:00
AndersandGitHub 649e04335d fix(release): restore GitHub release creation with gh CLI (#401)
The "Create GitHub release" step was broken in PR #386, which removed
the GITHUB_TOKEN env var from the actions/create-release action. The
action requires the token to be passed explicitly, so releases were
being published to PyPI but GitHub tags/releases were not created.

This replaces the archived actions/create-release@v1 with the gh CLI,
which is already used elsewhere in this workflow. The gh CLI properly
uses GH_TOKEN for authentication.
2026-01-06 14:27:28 +01:00
Carlos MarchalandGitHub f21a5984e3 fix: double counting anthropic langchain (#399) 2026-01-05 16:56:17 +01:00
Hugues PouillotandGitHub b64c2d97f9 feat: add in_app configuration for python SDK (#396)
* add in_app configuration for python SDK

* bump version

* add in_app_modules to init script as well
2025-12-22 12:02:48 +01:00
Andrew MaguireGitHubClaude Opus 4.5greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
16cd501674 fix(llma): extract model from response for OpenAI stored prompts (#395)
* fix: extract model from response for OpenAI stored prompts

When using OpenAI stored prompts, the model is defined in the OpenAI
dashboard rather than passed in the API request. This change adds a
fallback to extract the model from the response object when not
provided in kwargs.

Fixes PostHog/posthog#42861

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Apply suggestion from @greptile-apps[bot]

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Apply suggestion from @greptile-apps[bot]

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* test: add tests for model extraction fallback and bump to 7.4.1

- Add 8 tests covering model extraction from response for stored prompts
- Fix utils.py to add 'unknown' fallback for consistency
- Bump version to 7.4.1
- Update CHANGELOG.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style: format utils.py with ruff

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: remove 'unknown' fallback from non-streaming to match original behavior

Non-streaming originally returned None when model wasn't in kwargs.
Streaming keeps "unknown" fallback as that was the original behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: add test for None model fallback in non-streaming

Verifies that non-streaming returns None (not "unknown") when model
is not available in kwargs or response, matching original behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-12-21 21:17:32 +00:00
Dustin ByrneandGitHub ddfa1ee93c fix: Respect send_feature_flags setting and deprecate send_feature_flag_events in get_feature_flag_payload (#391)
* fix: Respect `send_feature_flags` when local eval is enabled

* fix: Deprecate `send_feature_flag_events` in `get_feature_flag_payload`
2025-12-17 13:04:10 -05:00
Phil HaackandGitHub 4bbccef790 feat(flags): Add retry support for feature flag requests (#392)
* Add urllib3-based retry for feature flag requests

Use urllib3's built-in Retry mechanism for feature flag POST requests
instead of application-level retry logic. This is simpler and leverages
well-tested library code.

Key changes:
- Add `RETRY_STATUS_FORCELIST` = [408, 500, 502, 503, 504]
- Add `_build_flags_session()` with POST retries and `status_forcelist`
- Update `flags()` to use dedicated flags session
- Add tests for retry configuration and session usage

The flags session retries on:
- Network failures (connect/read errors)
- Transient server errors (408, 500, 502, 503, 504)

It does NOT retry on:
- 429 (rate limit) - need to wait, not hammer
- 402 (quota limit) - won't resolve with retries

* Make examples run without requiring personal api key

* Add integration tests for network retry behavior

Add tests that verify actual retry behavior, not just configuration:

- test_retries_on_503_then_succeeds: Spins up a local HTTP server that
  returns 503 twice then 200, verifying 3 requests are made
- test_connection_errors_are_retried: Verifies connection errors trigger
  retries by measuring elapsed time with backoff

Both tests use dynamically allocated ports for CI safety.

* Bump version to 7.4.0
2025-12-16 23:41:38 +00:00
Phil HaackandGitHub 6fe1102993 feature: Add $feature_flag_error property to track flag evaluation failures (#390)
* Add $feature_flag_error property to track flag evaluation failures

Track errors in feature flag evaluation by adding a `$feature_flag_error` property to the `$feature_flag_called` event.

* Refactor requests exception imports through request.py

Export RequestsTimeout and RequestsConnectionError from posthog/request.py
to keep all requests library imports in one place and avoid mypy issues.

* Address PR review feedback

- Fix fallback logic to only trigger on actual exceptions, not when
  errors_while_computing or flag_missing is set from a successful API response
- Change log.exception() to log.warning() for expected operational errors
  (quota limits, timeouts, connection errors, API errors) to reduce log noise
- Keep log.exception() only for truly unexpected errors (unknown_error)
- Extract stale cache fallback into _get_stale_flag_fallback() helper method

* Add tests for stale cache fallback and error absence

- Add TestFeatureFlagErrorWithStaleCacheFallback test class with 4 tests:
  - test_timeout_error_returns_stale_cached_value
  - test_connection_error_returns_stale_cached_value
  - test_api_error_returns_stale_cached_value
  - test_error_without_cache_returns_none

- Add negative assertions to verify $feature_flag_error is absent on success:
  - test_get_feature_flag_result_boolean_local_evaluation
  - test_get_feature_flag_result_variant_local_evaluation
  - test_get_feature_flag_result_boolean_decide
  - test_get_feature_flag_result_variant_decide

* Report combined errors when both errors_while_computing and flag_missing

When the server returns errorsWhileComputingFlags=true AND the requested
flag is not in the response, report both conditions as a comma-separated
string: "errors_while_computing_flags,flag_missing"

This provides better debugging context when both conditions occur.

* Add FeatureFlagError constants class for error type values

- Add FeatureFlagError class to types.py with constants:
  - ERRORS_WHILE_COMPUTING, FLAG_MISSING, QUOTA_LIMITED
  - TIMEOUT, CONNECTION_ERROR, UNKNOWN_ERROR
  - api_error(status) static method for dynamic error strings

- Update client.py to use FeatureFlagError constants instead of
  magic strings

- Update all tests to use constants for maintainability

This improves maintainability by:
- Single source of truth for error values
- IDE autocomplete and typo detection
- Documentation of analytics-stable values

* Remove print statements from test failure handlers

* Fix mypy type error in FeatureFlagError.api_error method

Accept Union[int, str] to match APIError.status type.
2025-12-15 17:06:24 -08:00
Dustin ByrneandGitHub af561acd9d feat: Add FlagDefinitionCacheProvider interface (#387)
* feat: Add FlagDefinitionCacheProvider interface

* feat: Add a Redis example for FlagDefinitionCacheProvider

* style: ruff format

* style: ruff format

* refactor: clean up mypy errors

* chore: mypy-baseline sync

* fix: Type Redis as Redis[str]

* fix: Adhere to strict typing

The defined types don't leave room for missing or optional keys. We'll
use the types as they're defined.
2025-12-12 11:31:55 -05:00
Tom PiccirelloandGitHub b8073984eb Publish to PyPI using Trusted Publisher (#388)
Twine [supports Trusted Publisher](https://github.com/pypa/twine/pull/1194/), but their documentation is a bit sparse.
2025-12-11 13:10:18 -08:00
Tom PiccirelloandGitHub 082a0e67cd Replace PAT with default GITHUB_TOKEN (#386)
* Replace PAT with default GITHUB_TOKEN

A PAT isn't needed for either of these Actions.

* Only expose env vars to step that needs them
2025-12-11 12:39:38 -08:00
Carlos MarchalandGitHub da9b730da1 feat(llma): multimodal-capture (#378) 2025-12-11 15:00:53 +00:00
Aleksander BłaszkiewiczandGitHub 381dc1c9ab fix: remove unused $exception_message and $exception_type (#383)
* fix: remove unused

* fix: remove exception type

* fix: wip
2025-12-10 11:33:14 +00:00
Dustin ByrneandGitHub e24b1038f3 feat: Allow customization of socket options (#385)
* feat: Allow customization of socket options

This allows clients to configure (e.g.) socket keep alive probes

* test: Prevent leaking modified _session

* chore: Add a type ignore

* feat: Add `disable_connection_reuse` config method

Disables connection pooling

* set_socket_options is idempotent
2025-12-09 01:52:24 -05:00
Aleksander BłaszkiewiczandGitHub f1b454b10d feat: mask values (#382)
* feat: mask values

* feat: wip

* fix: ruff

* feat: wip

* feat: wip

* fix: ruff

* fix: ruff

* feat: wip

* feat: wip

* feat: version bump
2025-12-05 19:35:56 +01:00
Dustin ByrneandGitHub 304218f78f fix: capture enriches with local eval when enabled (#380)
Captured events now use local evaluation results when
`send_feature_flags` is `True` and local evaluation is enabled.
2025-12-04 15:07:02 -05:00
Phil HaackandGitHub 671af32b02 feat(flags): Add ETag support for local evaluation polling (#381)
* Add ETag support for local evaluation polling

Add support for HTTP conditional requests using ETags to reduce bandwidth
when polling for feature flag definitions. When flag definitions haven't
changed, the server returns 304 Not Modified and the SDK skips processing.

- Add GetResponse dataclass to encapsulate response data, ETag, and status
- Update get() to send If-None-Match header and handle 304 responses
- Store ETag in client and pass it on subsequent polling requests
- Skip flag processing when 304 Not Modified is received

* Use _session rather than requests

Benefits:

1. Reuses TCP connections via keep-alive
2. 2 retries on connect/read errors
3. Faster handshakes

* Add unit tests for get() function

Test HTTP-level behavior including:
- ETag extraction from response headers
- If-None-Match header sent when etag provided
- 304 Not Modified response handling
- Fallback when 304 has no ETag header
- Error response handling (APIError)
- Authorization and User-Agent headers
- Timeout and URL construction

* Add defensive null check for response.data

Guard against unexpected None data in non-304 responses to prevent
TypeError when accessing dictionary keys.

* Clear stored ETag when server stops sending one

If the server stops including ETag headers in responses, clear the
stored ETag so we don't keep sending a stale If-None-Match header.

* Mask API tokens in log messages

Keep first 10 chars visible for identification while hiding the rest.
Addresses CodeQL security warning about logging sensitive data.

* Ran ruff format
2025-12-02 13:11:38 -08:00
Dylan MartinandGitHub 50a177e39a feat(flags): included evaluated_at properties in $feature_flag_called events (#374)
* format

* update tests

* bump version
2025-12-01 22:02:09 -05:00
Radu RaiceaandGitHub b7dfe68da7 feat(llma): add Gemini async (#375) 2025-11-27 11:35:54 -05:00
Carlos MarchalandGitHub b997548400 feat: add python 3.14 support (#373) 2025-11-25 16:43:34 +01:00
github-actions[bot] e54f8a3811 Update generated references 2025-11-15 12:44:50 +00:00
Aleksander BłaszkiewiczandGitHub e38bfb5e49 feat: use repr in code variables (#372) 2025-11-15 13:43:55 +01:00
Tue HaulundandGitHub b2c4043e09 fix: avoid overwriting consumer list when using more than one consumer (#370)
fix: avoid overwriting consumer list when using more than one consumer thread
2025-11-12 13:05:05 +01:00
github-actions[bot] f2f4fa6874 Update generated references 2025-11-11 18:13:36 +00:00
Carlos MarchalandGitHub 748553236d chore(llma): update SDKs (#367) 2025-11-11 18:12:33 +00:00
github-actions[bot] 15a9c1b861 Update generated references 2025-11-11 17:57:26 +00:00
Alessandro PogliaghiandGitHub 9972fa3f0b feat(ph-ai): PostHog properties dict in GenerationMetadata (#366) 2025-11-11 17:56:32 +00:00
github-actions[bot] 99422f02ab Update generated references 2025-11-11 08:57:51 +00:00
Carlos MarchalandGitHub 1dcfb99413 fix(llma): Langchain cache token double subtraction for non-Anthropic providers (#369) 2025-11-11 09:56:57 +01:00
Julian BezandGitHub 4303f78759 fix: add ruff check to CI and fix all lint errors (#360)
- Add 'Lint with ruff' step to CI workflow (was only running format check)
- Fix F401: Add explicit re-exports for public API types in __init__.py
- Fix F811: Rename duplicate test_openai_reasoning_tokens to test_openai_reasoning_tokens_o4_mini
- Fix E731: Convert lambda to def function in test_middleware.py
- Fix unused imports in client.py and test files (auto-fixed)

Without ruff check in CI, lint errors were accumulating on master undetected.
2025-11-10 12:45:52 +01:00
github-actions[bot] 1ec7afdc5f Update generated references 2025-11-07 15:57:55 +00:00
Aleksander BłaszkiewiczandGitHub 3a8876d1a9 fix: code variables without client (#368)
* fix: pass variables from init to client

* chore: version+changelog
2025-11-07 16:57:01 +01:00
Luke BeltonandGitHub a338772b84 fix docstring for set (#364) 2025-11-06 16:02:49 +00:00
github-actions[bot] 08bf769a6c Update generated references 2025-11-06 15:13:17 +00:00
Aleksander BłaszkiewiczandGitHub 8c64f43476 feat: add code variables capture (#365)
* feat: add code variables capture

* feat: bump version and add changelog
2025-11-06 16:12:17 +01:00
github-actions[bot] bb5f1b7130 Update generated references 2025-11-04 19:44:04 +00:00
Radu RaiceaandGitHub 34540a5d93 feat(llma): send number of web searches (#359)
* feat(llma): send number of web searches

* feat(llma): add more tests

* chore(llma): bump version

* fix(llma): feedback

* fix(llma): fix Gemini

* fix(llma): fix OpenAI's Chat Completions streaming
2025-11-04 19:43:11 +00:00
github-actions[bot] 0e502fa086 Update generated references 2025-11-03 12:29:46 +00:00
Julian BezandGitHub aa04cd6a7f fix(django): handle request.user in async middleware context (#358) 2025-11-03 12:28:57 +00:00
github-actions[bot] c141ab0c77 Update generated references 2025-11-02 18:58:55 +00:00
997f8228da fix(llma): cache cost calculation in the LangChain callback (#346)
* fix(llma): cache cost calculation in the LangChain callback

* fix: format

* Update posthog/ai/langchain/callbacks.py

Co-authored-by: Radu Raicea <radu@raicea.com>

* Bump version to 6.7.13

Master has already released 6.7.12 with other fixes, so this PR will be 6.7.13

---------

Co-authored-by: Radu Raicea <radu@raicea.com>
Co-authored-by: Andrew Maguire <andrewm4894@gmail.com>
2025-11-02 18:58:04 +00:00
github-actions[bot] 183ecc8edf Update generated references 2025-11-02 17:10:28 +00:00
Andrew MaguireandGitHub 2ff0810472 fix(llma): LangChain 1.0+ compatibility for CallbackHandler (#363)
* fix: Add LangChain 1.0+ compatibility for CallbackHandler imports

- Use try/except to import from langchain_core first (LangChain 1.0+)
- Fall back to legacy langchain imports for older versions
- Maintains backward compatibility with LangChain 0.x
- All existing tests pass (45 passed)

Fixes #362

* test: Add regression test for AgentAction/AgentFinish imports

- Tests that AgentAction and AgentFinish can be imported
- Tests on_agent_action and on_agent_finish callbacks with mock data
- Ensures compatibility with both LangChain 0.x and 1.0+
- Catches the import issue that was previously only tested with API keys

This addresses a test coverage gap identified during code review.

* chore: Add CHANGELOG entry for LangChain 1.0+ compatibility fix

* fix: Remove unused type: ignore comments for mypy

The type: ignore comments were only needed when the except block
executes, but CI runs with LangChain 1.0+ so the try block succeeds.
Mypy flags these as unused-ignore errors.

* chore: bump version to 6.7.12 for langchain 1.0 compatibility
2025-11-02 17:09:33 +00:00
Julian BezandGitHub 2cb5f02b1b fix(django): restore process_exception to capture view exceptions (#350)
Restores the process_exception method that was removed in v6.7.5 (PR #328),
which broke exception capture from Django views and downstream middleware.

Django converts view exceptions into responses before they propagate through
the middleware stack's __call__ method, so the context manager's exception
handler never sees them. Django provides these exceptions via the
process_exception hook instead.

Changes:
- Add process_exception method to capture exceptions from views and downstream
  middleware with proper request context and tags
- Add tests verifying process_exception behavior and settings (capture_exceptions,
  request_filter)
2025-10-29 10:40:08 +00:00
github-actions[bot] 450d96a5f1 Update generated references 2025-10-28 13:06:45 +00:00
Andrew MaguireandGitHub 5b4bab5fd7 chore: bump version to 6.7.11 for AI framework feature (#354)
Update version and changelog for PR #347
2025-10-28 13:05:50 +00:00
156170e34b feat(ai): Add $ai_framework property for framework integrations (#347)
* Add $ai_lib_metadata to AI integrations

Adds framework identification metadata to all AI events for easier filtering
and analytics. Each integration now includes a $ai_lib_metadata property with
schema version and framework name.

- LangChain: Hardcoded to "langchain"
- Native wrappers (Anthropic, OpenAI, Gemini): Uses provider name
- Ready for future frameworks (pydantic-ai, crewai, llamaindex)

This enables PostHog queries to easily distinguish between:
- Direct SDK wrapper usage
- Framework-mediated usage (LangChain, etc.)
- Different framework types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add \$ai_lib_metadata to sync/async paths and tests

- Added \$ai_lib_metadata to call_llm_and_track_usage (sync)
- Added \$ai_lib_metadata to call_llm_and_track_usage_async (async)
- Added test assertion in test_basic_completion
- Placed metadata at end of properties for consistency

All tests pass successfully.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Refactor: use unified utility function for $ai_lib_metadata

Creates a single `get_ai_lib_metadata(framework)` utility function to generate
the $ai_lib_metadata object, replacing inline implementations across the
codebase.

Changes:
- Add get_ai_lib_metadata() utility to utils.py
- Update LangChain callbacks to use utility function
- Update call_llm_and_track_usage() to use utility function
- Update call_llm_and_track_usage_async() to use utility function
- Update capture_streaming_event() to use utility function

Benefits:
- Consistency across all integrations
- Single source of truth for metadata structure
- Easier to extend with version detection later

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add $ai_lib_metadata assertions to provider tests

Add missing $ai_lib_metadata assertions to Anthropic, Gemini, and LangChain tests to match the validation already present in OpenAI tests. Each test now verifies the metadata field contains the correct schema version and framework name.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Simplify to $ai_framework property, only for actual frameworks

Changes:
- Replace complex $ai_lib_metadata object with simple $ai_framework string
- Only include $ai_framework when using actual framework (LangChain)
- Remove $ai_framework from direct provider calls (OpenAI, Anthropic, Gemini)
- Update all tests to reflect new behavior

Before: {"schema": "v1", "frameworks": [{"name": "langchain"}]}
After: "langchain" (only when using LangChain framework)

This eliminates wasteful redundancy where framework=provider for direct calls.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-28 09:59:20 +00:00
Julian BezandGitHub 141ced6402 chore: standardize workflow extensions to .yml (#349)
Rename workflow files from .yaml to .yml for consistency with existing
workflows (ci.yml, call-flags-project-board.yml).

This resolves naming confusion and standardizes all GitHub Actions
workflow files to use the .yml extension.
2025-10-24 14:17:27 +00:00
webjunkieandgithub-actions[bot] b1c193bcb1 Update generated references 2025-10-24 14:16:57 +00:00
Julian BezandGitHub 5e6f642650 fix(django): make middleware truly hybrid-compatible with sync and async Django stacks (#348)
Address code review feedback and critical issues from PR #328.

Changes:
- Keep __call__ as sync method that conditionally routes to __acall__ for async paths
- Use markcoroutinefunction() to properly mark instances when async is detected
- Detect async/sync at init time via iscoroutinefunction(get_response)
- Remove process_exception method - it was non-functional (Django doesn't call it on new-style middleware without MiddlewareMixin)
- Fix markcoroutinefunction fallback to be a simple no-op instead of accessing private API
- Exception capture works correctly via contexts.new_context() which has built-in exception handling
- Add comprehensive test coverage for sync, async, and hybrid middleware behavior
- Add async exception capture tests
- Refactor tests to use proper middleware initialization

This implementation follows Django's recommended hybrid middleware pattern where
both sync_capable and async_capable are True, allowing Django to pass requests
without conversion while the middleware adapts based on the detected mode.

The sync path behavior is identical to version 6.7.4 (pre-async), ensuring perfect
backward compatibility for WSGI deployments.

Addresses #329
Related to #328
2025-10-24 15:50:21 +02:00
Phil HaackandGitHub c892dc7a8a Bump version to 6.7.9 (#345) 2025-10-22 20:53:07 +00:00
Phil HaackandGitHub 52e023072e fix(flags): multi-condition flags with static cohorts returning wrong variants (#343)
* Fix multi-condition flags with static cohorts returning wrong variants

When a feature flag has multiple conditions and one contains a static
cohort, the SDK now correctly falls back to the API instead of
evaluating subsequent conditions locally and returning incorrect variants.

Introduce RequiresServerEvaluation exception to distinguish between:
- Missing server-side data (static cohorts) → immediate API fallback
- Evaluation errors (bad regex, missing properties) → try next condition

Changes:
- Add RequiresServerEvaluation exception class
- Update match_cohort() to throw RequiresServerEvaluation for static cohorts
- Update match_property_group() to propagate RequiresServerEvaluation
- Update match_feature_flag_properties() to handle both exception types
- Update client.py to catch both exceptions for API fallback
- Export RequiresServerEvaluation in __init__.py
- Add test for multi-condition static cohort scenario

All 84 feature flag tests pass.

* Add unit test for payloads

* ruff format
2025-10-21 13:40:36 -07:00
Radu RaiceaandGitHub 19d0562d41 fix(llma): missing await in OpenAI's streaming implementation (#342)
* fix(llma): missing async for OpenAI async

* chore(llma): bump version

* chore(llma): bump version
2025-10-16 14:46:26 +00:00
gewenyu99andgithub-actions[bot] ccbd9c23b7 Update generated references 2025-10-16 00:02:49 +00:00
Vincent (Wen Yu) GeandGitHub 71919f7125 fix: Check for references directory and generate 6.7.7 specs (#341)
* Fix check for directory and generate 6.7.7 specs

* Delete references
2025-10-15 20:02:16 -04:00
Vincent (Wen Yu) GeandGitHub 4d9a4b689e Run SDK generation after release job (#340)
* run after release job

* use bot pat

* Fix token placement

* Run this with a gh cli command
2025-10-15 19:45:33 -04:00
Manoel Aranda NetoandGitHub 890bb4b5f8 fix: remove deprecated attribute from exception events (#338) 2025-10-14 10:33:49 +00:00
Tom PiccirelloandGitHub 98a5bca68d chore: switch to fine-grained PAT (#337) 2025-10-13 10:19:12 -07:00
Vincent (Wen Yu) GeGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
898859b546 Add workflow to create and save versioned references (#332)
* Updates script to persist references

* Workflow to generate references to a folder

* Get rid of references, to be generated

* Update .github/workflows/generate-references.yaml

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Update .github/workflows/generate-references.yaml

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Review comments

* Update .github/workflows/generate-references.yaml

* Pin hashes and only run on releases

* Pin uv

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-09-30 17:02:57 -04:00
Carlos MarchalandGitHub c3ec12c4a6 feat: auto update llm sdks (#333)
* feat: auto update llm sdks

* fix: apply PR comments
2025-09-25 13:40:42 +02:00
Andy ZhaoandGitHub 65bf587fee fix: don't sort condition sets with variant overrides to the top (#330)
* fix: don't sort condition sets with variant overrides to the top

* fix test

* update test

* update version and change log
2025-09-22 14:10:43 -04:00
Dustin ByrneandGitHub 6b28b80b7a fix: Prevent core Client methods from raising exceptions (#327)
* fix: Prevent core Client methods from raising exceptions

The goal is to ensure that our client doesn't cause a panic in an
end-user application. This change updates
capture/set/set_once/group_identify/alias to swallow and log any
exceptions that occur. Note that this won't prevent errors from
propagating via the `on_error` callback if an error occurs while
processing the queue.

* test: Remove assertions that capture raises

These tests were broken anyways. Capture would only raise because it was
being called with no arguments, not because api_key or host are None.
2025-09-17 15:47:07 -04:00
Oliver BrowneandGitHub 466bc358b2 feat(err): add __acall__ to django middleware (#328)
* add __acall__

* fix types
2025-09-16 15:40:11 +03:00
Carlos MarchalandGitHub 2508f0193d fix/system prompt sometimes missing (#326)
* fix: always capture system prompt

* chore: bump version

* fix: gemini system prompt capture

* chore: imports at top

* fix: test

The mock we were passing from this test
reporetd that it had a `system instruction` field,
breaking assumptions

* chore: lint

* fix: better code organization

* chore: lint
2025-09-05 17:28:55 +02:00
Radu RaiceaandGitHub 7e6009bc3e fix(llma): gemini missing cached and reasoning tokens (#323)
* fix(llma): Gemini missing cached and reasoning tokens

* chore(llma): bump version

* chore(llma): run ruff
2025-09-04 14:21:32 -04:00
Radu RaiceaandGitHub 63d8c8dc0f fix(llma): streaming providers with tool calls (#319)
* fix(llma): tool calls in streaming Anthropic

* fix(llma): Gemini content

* fix(llma): extract converters for providers

* fix(llma): continuation of DRY refactoring

* fix(llma): add $ai_tools to streaming Gemini

* fix(llma): tool calls in streaming Gemini

* fix(llma): tool calls in streaming OpenAI Chat Completions

* fix(llma): fix test

* fix(llma): run ruff

* fix(llma): fix types

* fix(llma): run ruff

* chore(llma): run mypy baseline sync

* chore(llma): bump version

* fix(llma): fix test

* chore(llma): update CHANGELOG

* fix(llma): Responses API streaming tokens

* fix(llma): run ruff

* fix(llma): run ruff
2025-09-03 20:02:38 +00:00
Dylan MartinandGitHub 2d418d1224 technically incorrect (#321) 2025-09-02 17:02:41 -07:00
Carlos MarchalandGitHub a70ed0506e feat(llma): redact base64 images (#318) 2025-09-01 09:13:07 +02:00
Phil HaackandGitHub b7817791aa Bump version to 6.7.0 (#317) 2025-08-26 22:32:04 +00:00
Phil HaackandGitHub b7c71b09aa fix(flags): flag dependency evaluation for multivariate flags (#316) 2025-08-25 14:20:45 -07:00
Vincent (Wen Yu) GeGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
4dacaed27b Add categories to doc specs (#313)
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-08-21 11:48:54 -04:00
Juraj MajerikandGitHub 6947dc6635 chore: bump version to 6.6.1 (#314) 2025-08-21 16:14:27 +02:00
Juraj MajerikandGitHub 44dddb1a4a Fix NoneType error when group_properties is None (#312) 2025-08-19 12:01:12 -07:00
Phil HaackandGitHub 413fb5af77 feat(flags): implement local evaluation of flag dependency filters (#311) 2025-08-19 09:43:46 -07:00
Phil HaackGitHubCopilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
7f087e25b3 chore: Improvements to example.py (#310)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-08-18 21:46:58 -07:00
Dylan MartinandGitHub ae38bbabc1 feat(flags): support passing in lists of flag keys to the /flags endpoint instead of evaluating every flag every time we fall back (#307) 2025-08-18 16:10:34 -07:00
David NewellandGitHub cb75671cd9 feat: we should capture which properties were added as tags (#304) 2025-08-08 11:44:34 +01:00
Vincent (Wen Yu) GeandGitHub edc0d1a1ed Remove placeholder for params, waste space (#298) 2025-08-07 15:20:27 -04:00
Phil HaackandGitHub 82a7f7c171 fix(flags): Pass project API key in remote_config requests (#303) 2025-08-06 21:17:30 +00:00
Radu RaiceaandGitHub 698f79b257 feat(llmo): support Vertex AI (#302)
* feat(llmo): support Vertex AI

* chore(llmo): run formatter

* fix(llmo): fix types error

* chore(llmo): run formatter

* chore(llmo): bump version
2025-08-05 15:33:10 -04:00
Radu RaiceaandGitHub 947ee46661 fix(llmo): tool calls are broken for most providers (#299)
* fix(llmo): set the $ai_tools properly for all providers

* fix(llmo): remove privacy mode from $ai_tools

* chore(llmo): bump version

* chore(llmo): run formatter

* fix(llmo): properly set tool calls in $ai_output_choices

* chore(llmo): bump version

* chore(llmo): run formatter

* fix(llmo): fix types error

* feat(llmo): change $ai_output_choices to have an array of content

* chore(llmo): run formatter

* feat(llmo): create text type object

* chore(llmo): update CHANGELOG.md
2025-08-05 14:02:37 -04:00
Phil HaackGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
d5bac13022 feat: Expose get_feature_flag_result method in public API (#284)
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-08-05 10:14:29 -07:00
Dylan MartinandGitHub f73774f616 fix (#300) 2025-08-01 17:32:58 -07:00
Radu RaiceaandGitHub 6ecd4f7efb bug(llmo): fix anthropic tool call response (#297)
* bug(llmo): fix anthropic's tool call response

* bug(llmo): fix tool calls response handling for anthropic

* bug(llmo): run formatter

* bug(llmo): bump version

* bug(llmo): add date to changelog
2025-07-31 17:13:44 -04:00
Georgiy TarasovandGitHub 864d718412 fix(ai): capture tool calls in reasoning models (#292)
* fix: capture tool calls in reasoning models

* fix: check for empty tool calls
2025-07-23 11:51:58 +02:00
Dylan MartinandGitHub 5a5326b66a feat(flags): make the sendFeatureFlags parameter more declarative and ergonomic (#283) 2025-07-22 15:20:54 -07:00
Radu RaiceaandGitHub 3289cfe3af feat(llmo): Use default PH client for LangChain (#293)
* feat(llmo): Use default PH client for langchain

* chore: Run formatter

* feat: Test the CallbackHandler without any PH client

* chore: Run formatter
2025-07-22 14:09:47 -07:00
2fb3c980a5 feat(llmo): Make it optional to pass posthog client (#291)
Co-authored-by: Peter Kirkham <peter@posthog.com>
2025-07-22 06:53:47 +00:00
David NewellandGitHub f8efe050f2 fix: capture django processed exceptions (#287) 2025-07-16 21:54:01 +02:00
Vincent (Wen Yu) GeandGitHub f600b0e7de Init reference doc generation (#280) 2025-07-15 13:53:13 -04:00
Phil HaackandGitHub 4ef129d646 fix: Ignore new flag filter type in local evaluation (#285) 2025-07-11 16:33:23 +00:00
Dylan MartinandGitHub 633504ea56 feat(flags): decouple local evaluation from personal API keys; support decrypting remote config payloads without relying on the feature flags poller (#282) 2025-07-10 08:03:37 -07:00
Oliver BrowneandGitHub 1830d7917d fix: add middleware setting for custom client (#281)
* Add middleware setting for custom client

* mypy

* comment
2025-07-09 17:06:20 +03:00
Dylan MartinandGitHub 70da872508 feat(flags): add a flag_fallback_cache that tracks feature flag evaluation results and uses them as fallback values whenever the /flags API isn't available (#275) 2025-07-07 07:13:35 +00:00
Oliver BrowneandGitHub ae0a4e7b57 fix: default send_feature_flags false for capture_exception (#278)
* default send_feature_flags false

* bump version
2025-07-02 22:21:25 +03:00
Oliver BrowneandGitHub 66bf50c6ac fix(err): permit disabling person processing (#277)
* whoops

* bump version
2025-07-01 15:26:57 +03:00
Oliver BrowneGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>David Newell
5f5b68cbbb feat: prep for 6.0.0, bunch of breaking changes (#273)
* alright

* fix exports

* Update posthog/test/test_before_send.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Update posthog/__init__.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Update posthog/__init__.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix tests after rebase

* update examples

* update mypy baseline

* Revert "update mypy baseline"

This reverts commit da395dd7cc075d1f5b1c03d748544e4abcd75bb9.

* try again

* whatever

* request user

* fix middleware

* getattr is_authenticated

* allow using custom client for exception capture

* update comments

* fix circular import

* type arguments, use TypedDict

* fix setup

* mypy

* whoops

* ok

* further mypy

* mypy sync

* docs and fixes

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: David Newell <david@posthog.com>
2025-06-27 14:57:02 +03:00
Lucas RicoyandGitHub aa494972b0 docs: update release details on readme (#272) 2025-06-21 00:38:18 +01:00
Lucas RicoyGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
59174b81b5 feat: bump version to 5.4.0 with session_id on page method (#271)
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-06-21 00:18:57 +01:00
Lucas RicoyandGitHub 25b221cc2e chore: ensure session_id context works with page method (#269) 2025-06-20 23:49:53 +01:00
Oliver BrowneandGitHub 18f3f89759 fix(err): always safe_str exception values (#267)
* always safe_str

* bump version
2025-06-19 14:38:17 +00:00
Oliver BrowneandGitHub a13acafb81 feat(err): construct full trace if no traceback available (#266)
* construct full trace if no traceback available

* delete asserts

* bump version
2025-06-19 16:47:42 +03:00
Oliver BrowneandGitHub eb3b524d72 document prep_local (#265) 2025-06-18 19:50:32 +01:00
Oliver BrowneandGitHub d5da699816 feat: session and identity integrate with context now (#264)
* session and identity in context

* bump version

* make django integration use context distinct id and session functions

* don't use self

* fix comments

* fix middleware tests

* clarify fresh and distinct id's

* Fix exported modules, add makefile command to test changes locally

* tiny fix
2025-06-18 19:27:27 +03:00
b521c2acbd feat(err): add django middleware (#263)
* fix exactly-once capture

* add middleware

* fix typing

* ignore unreacable

* Revert "ignore unreacable"

This reverts commit 0458f0efa6c8e52ecfb1eeb41c57a76d84578164.

* add unreachable ignore

* move unreachable ignore

* switch to use request.headers

* clarify comment

* Update posthog/integrations/django.py

Co-authored-by: David Newell <d.newell1@outlook.com>

* explain typle

* fix comment

* explain that tags become properties

* fix tests

---------

Co-authored-by: David Newell <d.newell1@outlook.com>
2025-06-17 17:54:32 +03:00
Oliver BrowneandGitHub fe0a680e3f fix: delete sentry integration (#262)
* delete relevant files

* bump uv lock, bump major version as deprecation

* README.md

* try mypy sync

* Revert "try mypy sync"

This reverts commit e1b98b26e59132e52eff6389afd42cb1b07a6a0b.

* try looking at the github action
2025-06-16 18:38:53 +03:00
Oliver BrowneandGitHub eba2b112dc fix(err): just check if the passed exceptions is a BaseException (#261)
* just check if it's an exception first

* version bump
2025-06-13 19:36:00 +00:00
Georgiy TarasovandGitHub 5c2897a767 feat(ai): langchain cached and reasoning tokens (#258)
* fix: reasoning and cached tokens

* test: new flows

* fix: missing field

* chore: bump

* fix: make sure we send write/read/reasoning tokens
2025-06-13 15:02:06 +02:00
Phil HaackandGitHub c85e361642 Add flags project board workflow (#259) 2025-06-12 16:33:42 +00:00
Oliver BrowneandGitHub c2afc4d27a fix: change scoped export, add capturing param (#257)
* change export, add capturing param

* capturing -> capture_exceptions
2025-06-12 10:29:32 +01:00
Peter KirkhamandGitHub 4625267f16 feat: add support for parse via responses (#256) 2025-06-11 05:39:24 +01:00
David NewellandGitHub 2e4ec31e8e remove 'import posthog' (#255) 2025-06-10 11:05:22 +01:00
David NewellandGitHub 5b853fe9a1 fix: makefile import (#254) 2025-06-09 19:20:31 +01:00
David NewellandGitHub 4521db34a1 feat: more django context (#252) 2025-06-09 14:32:42 +01:00
Paul D'AmbraandGitHub 5c84dcfccf feat: add before_send callback (#249) 2025-06-09 13:56:46 +01:00
Paul D'AmbraandGitHub c4ca591227 fix changelog to match pypi (#253) 2025-06-09 12:09:15 +01:00
Paul D'AmbraandGitHub 00c476328c chore: more fiddling to get release working (#251)
* chore: more fiddling to get release working

* fix

* fix
2025-06-09 11:50:30 +01:00
Paul D'AmbraandGitHub 7e018382ab chore: use uv run when releasing (#250) 2025-06-09 10:11:12 +00:00
Paul D'AmbraandGitHub 312140ff25 fix: makefile for posthog_analytics release (#248) 2025-06-09 10:51:04 +01:00
Paul D'AmbraandGitHub 7db912f06f chore: pyproject and CI update (#247) 2025-06-07 14:08:47 +03:00
Dylan MartinandGitHub 3b07b6ed47 chore(flags): roll everyone onto /flags (#246) 2025-06-06 16:36:10 -07:00
Oliver BrowneandGitHub 8b136d433b fix: lets try again (#244)
* maybe

* bump version
2025-06-06 16:25:47 +02:00
ce2a9bebc6 fix: python release attempt 3 (#242)
* fix: maybe the classifier is deprecated

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* ruff

* bump version for release

---------

Co-authored-by: Oliver Browne <oliver@posthog.com>
2025-06-06 15:16:31 +03:00
Oliver BrowneandGitHub 6fb9e6d4c0 fix: bump for release (#243)
* bump for release

* changelog

* changelog
2025-06-06 11:59:58 +00:00
Oliver BrowneGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>David Newell
c62e60b9d3 feat(err): add context manager and tag functions (#239)
* add context maanager and tag functions

* Update posthog/scopes.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* ran black

* black locally disagrees with ci. python is awful

* bleh

* isort

* fix mypyp thing

* Revert "fix mypyp thing"

This reverts commit 21ad8733610967cad0bbf8451508ca1189be543c.

* update baseline

* lets try again

* alright lets try again

* revert to baseline

* try ignoring it i guess

* black

* try supporting async too

* black

* mypy

* formatting

* fix changelog

* fix comment

* we only support python 3.9+

* change decorator name

* fix example

* isort

* auto-capture in with blocks

* fix tests

* black

* inherit tags by default

* assert swap

* add tags to all events

* rm comment

* Update example.py

Co-authored-by: David Newell <d.newell1@outlook.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: David Newell <d.newell1@outlook.com>
2025-06-06 14:49:15 +03:00
Paul D'AmbraandGitHub 93d10d4d10 fix: release action failed (#241) 2025-06-05 15:50:27 +01:00
Paul D'AmbraandGitHub a03e2a066f fix: opinionated setup and clean fn fix (#240) 2025-06-05 14:25:56 +01:00
fc8812806c pin actions versions (#210)
* pin actions versions
---------

Co-authored-by: Paweł Szczur <orian@users.noreply.github.com>
2025-05-27 08:25:50 +00:00
Paweł SzczurandGitHub 9b43c0544d fix: feature flag request use geoip_disable (#235)
* make feature flag request use geoip_disable
2025-05-27 10:18:55 +02:00
Peter KirkhamandGitHub ed12f1b208 feat: support gemini (#237) 2025-05-24 00:23:34 +01:00
Peter KirkhamandGitHub af6882ea00 feat: composition over inheritance (#236) 2025-05-23 01:34:04 +01:00
Rafael AudibertandGitHub 8253c66412 feat: Remove deprecated monotonic lib (#231) 2025-04-29 11:14:59 -03:00
Rafael AudibertandGitHub 11461049fd chore: Release automatically when changed version.py (#232) 2025-04-29 11:14:50 -03:00
Phil HaackGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
74ea024265 feat: Add new FeatureFlagResult class and tests (#227)
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-24 10:09:29 -07:00
Phil HaackandGitHub 265de15b6b chore: Add parameters to bin/test (#228) 2025-04-23 13:53:28 -07:00
Phil HaackGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
62618b7547 chore: Make condition_index optional. Also added some scripts for local dev. (#223)
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-18 11:59:49 -07:00
Dylan MartinandGitHub 849a81decf chore(flags): latest version of posthog-python now uses /flags by default, except for a few exceptions (#222)
* wahahaha

* fix tests

* whoops don't forget to roll it out
2025-04-15 17:13:26 -04:00
Dylan MartinandGitHub c08d05d894 fix(flags): pass in the correct hashes. (#221)
* shoot

* cut customer token

* bump version

* dump posthog api from excluded
2025-04-15 16:09:47 -04:00
Dylan MartinandGitHub c07e7c87ee ubunut 20-04 is EOL (#220) 2025-04-15 13:44:19 -04:00
Dylan MartinandGitHub 0a3c06086a chore(flags): roll 10% of posthog-python /decide traffic (and all of PostHog's personal SDK traffic) to /flags (#218)
* init

* moved the constants

* formatting

* mypy

* fr do some damn formatting

* don't exclude posthog

* make it a set

* differentiate

* fix AI test

* use the same type everywhere

* ready to release
2025-04-15 12:57:49 -04:00
8ce657630f test(llm-observability): Account for LangGraph 0.3.29 changes (#219)
* test(llm-observability): Account for LangGraph 0.3.29 changes

* formatting

---------

Co-authored-by: dylan <dylan@posthog.com>
2025-04-15 12:36:15 -04:00
David NewellandGitHub 28ef3c7e8e fix: add field to proxy client setup (#217) 2025-04-11 13:57:26 +01:00
David NewellandGitHub 00d2f9066f chore: update license (#213) 2025-04-10 15:30:54 +01:00
David NewellandGitHub 3a07d907f7 feat: log captured exceptions (#215) 2025-04-10 12:14:29 +01:00
David NewellandGitHub bd08b51ac8 fix failing ai test (#216) 2025-04-10 12:01:25 +01:00
Frank HamandandGitHub a5c738f2cb bump version (#209) 2025-03-26 16:10:26 +00:00
Frank HamandandGitHub e337ff51a9 update automatic retries to include read errors (#208)
in e.g. lambda environments the connection can time out between invocations,
this comes through to the client as a "RemoteDisconnected" error, which it
turns out urllib classifies as a "read" error not a connection error (as
it's possible to get this error after data has been sent)
2025-03-26 16:02:08 +00:00
Phil HaackandGitHub 4ab73eeac2 feat(flags): Add more details such as version, id, and reason to $feature_flag_called events (#207)
* Flesh out Decide response types

* Ensure we normalize get_decide

In a back compat manner.

* Populate feature_flags_by_key when setting feature_flags

Since `self.feature_flags_by_key` is derived from `self.feature_flags`, and we often set the latter in unit tests, but forget to set the former, our tests can be wonky.

This ensures that when we set `self.feature_flags`, we always set `self. feature_flags_by_key`

* Annotate types

* Lookup local flag by key

Fixes #121

* Refactor local flag evaluation into its own method

* Include extra details in `$feature_flag_called` events

* Fix up type annotations, tests, and formatting

* Update lib to decide v4

* Bump version and add changelog
2025-03-25 16:27:24 -07:00
RossandGitHub 7635457f90 feat: Support serializing dataclasses (#206)
* Support serializing dataclasses

* Update version

* Run black

* Fix for Python 3.9
2025-03-17 14:28:33 +00:00
Peter KirkhamandGitHub 041adad7fb feat: add support for responses api (#205)
* feat: add suppoort for responses api

* fix: test

* fix: black

* fix: test - hopefully

* fix: test - hopefully #2

* fix: test - hopefully #3

* fix: test - hopefully #4

* fix: greptaile catch

* fix: mypy is not my friend

* fix: isort usort weallsort

* fix: noredef

* fix: mypy baseline

* fix: mypy

* fix: mypy
2025-03-14 05:16:52 +00:00
David NewellandGitHub 2c972ab7bc fix: distro requirement for analytics package (#204) 2025-03-12 14:12:15 +00:00
Peter KirkhamandGitHub 7b16bcb62e fix: azure open ai delta check (#203) 2025-03-10 21:35:36 +00:00
Peter KirkhamandGitHub dc765e6ee1 feat: cached tokens (#202)
* feat: cached tokens

* feat: add tool support

* chore: local test

* chore: isort black

* chore: bump v

* chore: remove import

* fix: types

* fix: black

* fix: mypy unpacking of None

* chore: mypy baseline

* feat: mypy fix

* fix: did things and stuff

* fix: mypy yourpy whos py?

* fix: things can be None

* fix: move test

* fix remove exampels from package

* fix: losing my py
2025-03-06 22:37:21 +00:00
Dylan MartinandGitHub f36daa199f chore(flags): improved some logs for quota limiting (#197)
* haha okay

* tests workin

* format

* use case-sensitive comparisons

* omg LOL

* fix tests

* jeez

* this will probably work

* now do local eval

* okay

* yo

* formatting

* fix import order

* type check

* ai yi yi

* code review

* format

* do it

* merge conflict UGH

* black formatting

* bump version

* correct changelog
2025-03-03 14:00:52 -05:00
Peter KirkhamGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
44a8637e5a feat: azure export w/ async (#200)
* feat: azure export w/ async

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-02-28 20:40:09 +00:00
Michael MatlokaandGitHub f874fe53cb feat(llm-observability): $ai_tools capture in Langchain (#199) 2025-02-27 17:50:20 +00:00
Paul D'AmbraandGitHub f84ad25963 feat: add some platform info to events (#198) 2025-02-26 12:26:17 +00:00
Peter KirkhamandGitHub f05e716224 fix: async client (#196) 2025-02-23 13:10:43 +00:00
Dylan MartinandGitHub a74b8a7fcc feat(feature-flags): support quota limiting for feature flags (#195)
* haha okay

* tests workin

* format

* use case-sensitive comparisons

* omg LOL

* fix tests

* jeez

* this will probably work

* now do local eval

* okay

* yo

* formatting

* fix import order

* type check

* ai yi yi

* code review

* format
2025-02-21 15:45:51 -05:00
Dylan MartinandGitHub 38eba50f21 fix(flags): remove lower() when evaluating feature flag payloads – these payloads are case-sensitive! (#191)
* haha okay

* tests workin

* format

* use case-sensitive comparisons

* omg LOL

* fix tests

* jeez
2025-02-19 19:51:40 -05:00
Peter KirkhamandGitHub beac1539dc fix: support usage as part of generation (#192) 2025-02-18 00:17:52 +00:00
HavenGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>Manoel Aranda Neto
0375c7eb7f feat(flags): Add method for fetching decrypted remote config flag payload (#180)
* feat(flags): Add method for fetching decrypted remote config flag payload

* tweak

* tweak

* tweak

* Update posthog/__init__.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* tweak

* get example script working

* format

* sort import

* tweak

* bump minor version

* Update posthog/version.py

Co-authored-by: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com>

* Use flag key instead of id

* tweak

* tweak

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com>
2025-02-13 14:21:05 -08:00
Frank HamandandGitHub 9705b53da6 automatically retry connection errors (#190)
* automatically retry connection errors

from the docs for max_retries: this applies only to failed DNS lookups,
 socket connections and connection timeouts

* run tests on multiple python versions

* update freezegun
2025-02-12 12:29:01 +00:00
Phil HaackandGitHub b91c5acc95 Add mypy to CI (#189) 2025-02-11 09:50:45 -08:00
Phil HaackandGitHub 50e1df93a0 Use casefold to compare strings case insensitively (#184) 2025-02-11 08:06:20 -08:00
Rafael AudibertandGitHub 0634ee8cbd fix: Move code under mypy type (#188)
* fix: Move code under mypy type

This is incorrect, we should've added these slightly lower in the method definition to avoid mypy from breaking

* feat: Bump to 3.12.1
2025-02-11 12:01:08 -03:00
Phil HaackandGitHub 99c72f6ef0 Remove the usage of is_simple_flag (#186) 2025-02-10 18:52:54 -08:00
Phil HaackandGitHub 30b8ec24e7 Stop capturing all feature flags on $feature_flag_called event. (#181) 2025-02-10 17:39:03 -08:00
Peter KirkhamandGitHub 0692b846af feat: add beta parse method support (#185) 2025-02-11 00:43:36 +00:00
Phil HaackandGitHub 49de45888e Deprecate the context argument (#182) 2025-02-10 15:26:29 -08:00
Phil HaackandGitHub 53de042ffb Allow specifying the flag in the example script (#157)
* Allow specifying the flag in the example script

* Reformat

* Run isort
2025-02-07 09:28:00 +09:00
Phil HaackandGitHub 7c7287f303 Move accessing variants outside of loop (#175)
* Move accessing variants outside of loop

`flag_variants` doesn't depend on condition so it doesn't make sense to declare it in the loop.

* Fix assertion

* Remove incorrect comment

Comment seems superfluous anyways.

* Break out of the loop when the key is found

The purpose of the loop is to loop through the flag keys and evaluate the one where `flag["key"] == key`. Once that key is found, there's no need to continue the loop.

* Complete the test

Looks like the test was missing an assert.

* Precompute valid variant keys outside loop
2025-02-07 09:24:17 +09:00
Peter KirkhamandGitHub 198aecf9c7 fix: langchain tool parent add (#179) 2025-02-05 19:03:14 +00:00
277868e12a feat(llm-observability): LangChain spans (#176)
* feat: refactor to dataclasses

* feat: spans

* test: fix part 1

* test: fix part 2

* test: fix part 3

* test: fix part n

* test: add langgraph agent test

* chore: bump and linters

* chore: bump

* fix: correctly capture a parent id when a custom trace_id is set

* test: multiple spans parent_ids

* fix: exception serialization

* refactor: ai_trace_name -> ai_span_name and ai_generation_id -> ai_span_id

* fix: logs typos

* Add minor breaking change note to changelog

* fix: naming

---------

Co-authored-by: Michael Matloka <michael@matloka.com>
2025-01-28 14:23:22 +01:00
Georgiy TarasovandGitHub 833833bfbc fix: serialize pydantic models (#177) 2025-01-27 17:38:49 +00:00
Peter KirkhamandGitHub 999aead498 feat(ai): add error handling to python ai sdk (#174) 2025-01-24 21:09:49 +00:00
Georgiy TarasovandGitHub 07dbf46fbb fix(llm-observability): parallel traces (#172)
* fix: parallel traces

* fix: linters

* chore: bump

* fix: better naming for clarity
2025-01-23 17:27:46 +01:00
Michael Matloka 4aa32ee6fa fix: Actually fix LangChain callback in posthoganalytics 2025-01-22 16:27:36 +01:00
Michael MatlokaandGitHub 869f87af26 fix: Account for import posthog in posthoganalytics release (#171) 2025-01-22 13:50:39 +00:00
Peter KirkhamandGitHub 9a12b71dcc chore: bump (#170) 2025-01-21 23:33:47 +00:00
Michael MatlokaandGitHub 8e05c1951c feat(llm-observability): LangChain tracing, with LangGraph tests (#169) 2025-01-21 23:18:55 +00:00
91ac7bc82f fix(llm-observability): capture system prompt for anthropic (#167)
Co-authored-by: Peter Kirkham <peter@posthog.com>
2025-01-17 21:04:37 +00:00
ef0b92d9ff Feat: Add Anthropic to Python SDK (#165)
Co-authored-by: Georgiy Tarasov <gtarasov.work@gmail.com>
2025-01-17 20:33:48 +00:00
Georgiy TarasovandGitHub 267ab0440b fix(llm-observability): flatten langchain's additional_kwargs (#166)
* fix: flatten additional_kwargs

* fix: remove print
2025-01-17 17:59:38 +01:00
Peter KirkhamandGitHub cd510cc386 feat: privacy_mode (#164) 2025-01-15 01:28:52 +00:00
Georgiy TarasovandGitHub c377be7140 feat(llm-observability): add new packages for posthoganalytics (#163) 2025-01-14 10:50:46 +01:00
Georgiy TarasovandGitHub 113de04672 fix(llm-observability): include the ai packages (#162)
* fix: setuptools

* fix: include packages
2025-01-14 10:27:05 +01:00
Peter KirkhamandGitHub 2adef77a18 fix: update to export module (#161) 2025-01-14 01:25:00 +00:00
Peter KirkhamandGitHub 211075dabe feat: Embeddings + Personless events + Destructure property JSON (#160) 2025-01-14 00:35:09 +00:00
Georgiy TarasovandGitHub a38360d087 feat(llm-observability): add langchain integration (#159)
* feat(ai): LangChain integration v0.1

* test: langchain integration tests

* test: langchain-openai for v2 and v3

* chore: reorganize imports

* fix: ci

* fix: set python on ci to 3.9

* fix: upgrade ci for python 3.9

* fix: fallback for distinct_id

* fix: personless events for omitted distinct_ids

* fix: review comments

* feat: base url retrieval
2025-01-13 18:40:02 +01:00
e6e4368852 Feat: Add llm observability to python sdk (#158)
Co-authored-by: Michael Matloka <michael@matloka.com>
2025-01-11 01:34:27 +00:00
Sibin M SandGitHub 93623e8a5a [FEATURE]Add distinct_id to group_identify (#155)
* [FEATURE]Add distinct_id to group_identify

* [TESTS]Updated test cases for adding distinct_id to group_identify

* [LINT-FIX]client.py and test_client.py

* [CHORE]Verion bump and changelog update
2025-01-03 16:00:35 -05:00
Dylan MartinandGitHub bead19a9c2 fix: CI (#156)
* test CI

* heck it, upgrade python

* okay don't do anything silly with the cache hits i guess

* more CI upgrades :crossedfingers

* upgrade all CI to latest versions, then

* jk this is how python works

* whackamole

* what even

* yeesh

* this can't be it

* if this breaks ill kms

* dark magic dark MAGIC

* im giving up on my dreams
2025-01-03 15:50:21 -05:00
Dylan MartinandGitHub cc0568b0a6 Update CODEOWNERS (#154) 2025-01-02 12:52:51 -05:00
Dylan MartinandGitHub ddd744b51a fix(flags): bump the version (#148) 2024-11-27 17:15:38 -05:00
5c4cc35bfe fix(flags): correctly emit feature flag events with the FF response on get_feature_flag_payload calls (#143)
* this is the fix, needs tests

* fix test

* tests

* yeah

* please work

* ran the formatter

* code review feedback

* how'd this get here

* bump version add changelog

* Update CHANGELOG.md

Co-authored-by: David Newell <d.newell1@outlook.com>

---------

Co-authored-by: David Newell <d.newell1@outlook.com>
2024-11-25 14:51:06 -05:00
cde24f1525 fix(err): fix distinct_id, set personless and use a uuid (#144)
Co-authored-by: David Newell <david@posthog.com>
2024-11-25 12:09:57 +00:00
David NewellandGitHub fdc154deb9 chore: add type to stack (#142) 2024-11-19 12:46:52 +00:00
David NewellandGitHub 65abf5f34a chore: add lang to frames (#139) 2024-10-24 16:18:02 +01:00
David NewellandGitHub e4358be3d2 feat: add super properties (#138) 2024-10-03 17:07:47 +01:00
5e73f7b018 Remove deprecated datetime.utcnow() in favour of datetime.now(tz=tzutc()) (#124)
Co-authored-by: Neil Kakkar <neilkakkar@gmail.com>
2024-09-24 11:09:15 +01:00
Neil KakkarandGitHub 2898d08d8f fix(errors): Make sure project root exists to judge in app frames (#136)
* fix(errors): Make sure project root exists to judge in app frames

* prep release
2024-09-16 11:11:28 +01:00
Neil KakkarandGitHub 6afa42bb2e fix: Update Django integration for manual capture (#135) 2024-09-10 09:27:47 +01:00
Neil KakkarandGitHub 9886e6fbaa feat(errors): Add manual exception capture (#134)
* feat(errors): Add manual exception capture

* prep release

* use backwards compatible helper

* add tests
2024-09-09 11:40:51 +01:00
Neil KakkarandGitHub b468a9064a fix(setup): Make sure all packages are bundled (#133)
* fix(setup): Make sure all packages are bundled

* prep release

* black
2024-09-03 08:13:10 +01:00
Neil KakkarandGitHub 7576234533 fix(setup): Make sure all packages are bundled (#132)
* fix(setup): Make sure all packages are bundled

* prep release
2024-09-03 07:23:54 +01:00
Neil KakkarandGitHub 7cd12b1421 feat(errors): Add django integration and in app frames (#131) 2024-09-03 06:10:36 +01:00
Neil KakkarandGitHub 749f7b5940 feat(error-capture): Add basic exception autocapture (#128) 2024-08-28 06:59:41 +01:00
Phani RajandGitHub 98e82f9ae6 bump version to 3.5.2 (#130) 2024-08-21 11:58:02 -05:00
Phani RajandGitHub 32ad34f8b1 fix(feature flags): Guard for None values when comparing person Properties (#129)
* Guard for None values when comparing person Properties
2024-08-21 11:18:20 -05:00
Frank HamandandGitHub e0ae599d97 Switch us-api.i hosts to just us.i (#119)
We dropped the -api as it's a bit confusing (is capture really api?)
2024-08-14 08:41:10 +01:00
Neil KakkarandGitHub 07396e64a2 Create CODEOWNERS (#122) 2024-05-02 18:02:13 +01:00
Neil KakkarandGitHub 0e264a8cb2 fix(flags): Add a shorter configurable timeout for flag requests (#120) 2024-03-04 14:25:11 +00:00
Brett HoernerandGitHub 6785720db1 Bump to 3.4.2 (#118) 2024-02-20 08:43:10 -07:00
Brett HoernerandGitHub 97955fe0c9 Add historical_migration option to toplevel Client (#117) 2024-02-15 06:42:43 -07:00
Neil KakkarandGitHub 1b21afe570 chore: Use ingestion hosts for event capture (#116) 2024-02-13 11:19:21 +00:00
Neil KakkarandGitHub af424c833d fix(routing): Update hosts to point to right ingestion host (#115) 2024-02-05 12:14:14 +00:00
Neil KakkarandGitHub 40b5bea6c6 chore(flags): Update type hints for newer mypy versions (#114)
* chore(flags): Update type hints for newer mypy versions

* black
2024-01-30 16:06:10 +00:00
Neil KakkarandGitHub 230d9c2dbb fix(flags): Update relative date op names (#113) 2024-01-26 15:52:46 +00:00
635db706e8 Module functions to also return the same as its Client equivalent (#111)
Co-authored-by: Neil Kakkar <neilkakkar@gmail.com>
2024-01-19 11:13:52 +00:00
Neil KakkarandGitHub 4b9667ccb3 fix(flags): Don't override existing props when adding flags (#110) 2024-01-10 14:34:23 +00:00
Neil KakkarandGitHub 80a38aca2c feat(flags): Add local props and flags to all calls (#106) 2024-01-09 11:30:10 +00:00
Neil KakkarandGitHub 5159528070 feat(flags): Add relative date operators, fix numeric ops (#105) 2024-01-09 11:22:18 +00:00
Xavier VelloandGitHub e72101c03b feat: increase message and batch sizes (#108) 2023-12-04 16:27:26 +01:00
Daniil OkhlopkovandGitHub cf886de444 Update LICENSE (#104) 2023-10-25 16:08:07 +01:00
Neil KakkarandGitHub 8196da17cd fix(flags): Ensure feature properties exist on feature flag called ev… (#101)
* fix(flags): Ensure feature properties exist on feature flag called events

* fix

* make flake8 happy, will this bork?
2023-08-17 18:03:28 +01:00
Neil KakkarandGitHub e6116112f1 fix: disable behaviour for feature flags (#99) 2023-04-21 13:10:02 +01:00
fac1a3a16d Disable geoip for capture and decide calls by default (#98)
Co-authored-by: Neil Kakkar <neilkakkar@gmail.com>
2023-04-17 12:06:57 +01:00
Eric DuongandGitHub 2679ca6f38 version 2.5.0 (#97) 2023-04-10 15:13:25 -04:00
Eric DuongandGitHub 508182500b chore: change package to be an instantiable client (#96)
* initial try

* change init file to a class

* remove commas

* format

* sort

* restore original and add renamed client

* format

* move disabled

* format

* handle changing var for global instance

* add test
2023-04-10 14:33:07 -04:00
Neil KakkarandGitHub a543fb74f9 Fix analytics package dependencies (#95) 2023-03-30 10:34:59 -04:00
Neil KakkarandGitHub 9916f64e8e Add CI to ensure no prints (#94) 2023-03-17 15:22:59 +00:00
Neil KakkarandGitHub 22489ffe9f Release for print fix (#93) 2023-03-17 12:41:16 +00:00
Jann KleenandGitHub 289a26c2fe Remove print() call (#92) 2023-03-17 12:37:01 +00:00
Neil KakkarandGitHub ccee7b666b feat(flags): Enable local evaluation for all cohorts (#91) 2023-03-16 10:47:29 +00:00
Eric DuongandGitHub 5302613832 fix test (#90) 2023-02-14 14:24:10 -05:00
Eric DuongandGitHub a7804baa52 fix: add function for active variants (#89)
* add function for active variants

* format
2023-02-14 10:45:14 -05:00
Eric DuongandGitHub d226d469e3 add changelog entry and update versoin (#87) 2023-02-07 10:47:26 -05:00
Eric DuongandGitHub c078c0944c chore: Remove upper bound (#85)
* remove upper bound

* format
2023-02-07 10:36:26 -05:00
80523e03a2 fix: change api error to log (#83)
* change api error to log

* change implementation

* sort

* format

* raise when debug is true

* Update posthog/test/test_feature_flags.py

* format

---------

Co-authored-by: Neil Kakkar <neilkakkar@gmail.com>
2023-02-07 10:17:56 -05:00
Eric DuongandGitHub e76bfb16ee update version and changelog (#84) 2023-01-31 13:05:04 -05:00
Eric DuongandGitHub 57e30aca08 feat(feature-flags): JSON payload function (#81)
* implementation with test

* format

* v=3 and get_all_payloads

* format

* fix bug

* format

* address comments

* format

* add tests

* format

* add resiliency

* fix lookup

* remove check

* address comments

* example.py

* format

* format
2023-01-31 12:47:32 -05:00
Luke Harries 36b87e5d0b Revert "added regression tests"
This reverts commit 51f3cf6d06.
2023-01-24 17:31:30 +00:00
Luke Harries 51f3cf6d06 added regression tests 2023-01-24 17:11:37 +00:00
Neil KakkarandGitHub 34ee449a7e feat(flags): Add support for variant overrides (#77) 2022-11-14 12:15:33 +00:00
Neil KakkarandGitHub ce5aff1fe8 fix: datetime comparison issues (#75) 2022-09-15 15:26:38 +01:00
Neil KakkarandGitHub 93ae071693 Update CHANGELOG.md 2022-09-14 14:22:28 +01:00
Eric DuongandGitHub 5f1ba52ad5 feat: add date comparison to local evaluation (#74) 2022-09-14 13:53:44 +01:00
Neil KakkarandGitHub 5d6672315c fix: Remove defaults for feature flag calls (#72) 2022-08-12 12:20:54 +01:00
Neil KakkarandGitHub f490dd571a fix(feature-flags): Add more options to make using library easier (#70) 2022-08-04 13:53:20 +01:00
Neil KakkarandGitHub 78c7cb9ab2 Bump version to 2.0.0 and add breaking changes changelog (#69) 2022-08-02 12:10:32 +01:00
Neil KakkarandGitHub f0fd79841d feat(feature-flags): Enable local evaluation of flags (#68) 2022-07-29 14:10:51 +01:00
59dba76dea Add get feature flag method (#67)
* get feature flag method

* remove groups param from method

* use personal api key

* add groups

* add capture

* black reformat

* black?

* Update posthog/client.py

Co-authored-by: Neil Kakkar <neilkakkar@gmail.com>

* add to init

* formatting

Co-authored-by: Neil Kakkar <neilkakkar@gmail.com>
2022-06-30 11:48:53 -04:00
Neil KakkarandGitHub ccde499d53 bump version to 1.4.9 (#66) 2022-06-13 12:18:50 +01:00
62ea178d23 Have an option to send feature variants with the .capture(...) calls (#65)
Co-authored-by: Utku Zihnioglu <utku@webshare.io>
2022-06-13 12:13:35 +01:00
Tim GlaserandGitHub 0ec3a21498 bump version 1.4.8 (#61)
* bump version 1.4.8

* Update CHANGELOG.md
2022-05-12 08:12:11 +01:00
796e5df626 Feature: Enable multi variate feature flags for Python library (#60)
* Capturing $feature_flag_called at the end of client.feature_enabled method

* Enabling multi-variants for feature flags

Co-authored-by: Utku Zihnioglu <utku@webshare.io>
Co-authored-by: Tim Glaser <tim@posthog.com>
2022-05-12 08:10:54 +01:00
7f20286af7 Capturing $feature_flag_called at the end of client.feature_enabled method (#57)
Co-authored-by: Utku Zihnioglu <utku@webshare.io>
2022-05-12 08:05:26 +01:00
Tim Glaser 594b5f37e6 Bump version 1.4.7 2022-04-25 14:08:08 +01:00
Tim GlaserandGitHub a6ebb02d43 fix: Personal api key not required (#56)
* fix: Personal api key not required

* formatting

* Fix false
2022-04-25 14:07:08 +01:00
Tim GlaserandGitHub 9e31b3fdbb docs:Remove id: from example (#55) 2022-04-11 16:01:27 +02:00
Marius Andra 85feb84d87 1.4.6 2022-03-30 08:45:14 +02:00
Marius AndraandGitHub 6ca9b0002a Support custom UUID values (#53)
* feat(uuid): add support for custom uuids

* fix deprecated assert

* do not send "none" uuid

* you can have it in any color you want, as long as it's black
2022-03-30 08:42:43 +02:00
Paolo D'AmicoandGitHub 0723332b09 Update version.py (#49) 2022-01-05 06:46:28 -06:00
Paolo D'AmicoandGitHub c9ede4b953 Use Sentry DSN to obtain project ID (#48) 2022-01-05 06:15:51 -06:00
Karl-Aksel PuulmannandGitHub f7626714e2 Update version to 1.4.4 2021-11-25 11:45:18 +02:00
Karl-Aksel PuulmannandGitHub 8ac068d9a7 Groups: Feature flags support (#45)
* Fix a documentation typo

* Feature flags & groups support

* Update examples
2021-11-25 09:55:40 +02:00
Karl-Aksel PuulmannandGitHub 521a508c0b Update version to 1.4.3 2021-10-28 18:42:58 +03:00
Karl-Aksel PuulmannandGitHub 589475336b Basic group analytics support (#44)
* Make setup instructions work

* Add basic group analytics support to library

* Resolve formatting issues
2021-10-27 10:25:33 +03:00
Michael Matloka bd6f14a7cd Update pip install 2021-06-22 14:41:11 +02:00
Michael MatlokaandGitHub 41b3668b77 Update README.md 2021-06-22 14:39:02 +02:00
Michael MatlokaandGitHub c333f434fd Update README.md 2021-06-22 14:38:44 +02:00
Michael MatlokaandGitHub 4d3707d31c Bump version to 1.4.2 2021-06-22 14:38:15 +02:00
Michael Matloka d4fa6c6df7 Use PyPI API token instead of username and password 2021-06-22 14:30:53 +02:00
Michael Matloka 69d416e897 Ensure wheel 2021-06-22 14:24:27 +02:00
Michael Matloka e37c75e509 Fix make target in release workflow 2021-06-22 14:21:01 +02:00
Michael MatlokaandGitHub 0617277bd0 Add release workflow (#42)
* Add release workflow

* Update README.md
2021-06-22 14:19:31 +02:00
Yakko MajuriandGitHub 2b620e0f68 Fix integrity issues (#41)
* Fix integrity issues

* fix black, tests

* add test for new behavior

* run black properly

* remove accidental commit
2021-06-16 11:06:14 -03:00
Yakko MajuriandGitHub b239002483 Better handling on feature_enabled (#40) 2021-06-07 11:39:17 +01:00
Mandeep GillandGitHub e706401495 Remove pinning of backoff dependency (#38) 2021-06-04 14:26:36 -03:00
Neil Kakkar 7596674578 Release 1.4.1 2021-05-28 10:19:56 +01:00
Mandeep GillandGitHub b37047ab4d Bump backoff dependency to 1.10.0 (#36) 2021-05-26 19:02:15 +02:00
Michael MatlokaandGitHub 9df7af697b Fix 1.4.0 date in CHANGELOG.md 2021-05-20 15:44:53 +02:00
Michael MatlokaandGitHub 16685b1875 Update CHANGELOG.md 2021-05-18 17:21:59 +02:00
Michael MatlokaandGitHub 953140e207 Add PyPI badge to README 2021-05-18 17:20:36 +02:00
Michael Matloka 280e16fb2e Release 1.4.0 2021-05-18 17:16:37 +02:00
Neil KakkarandGitHub 4050c060d7 Add support for project_api_key. (#32)
* add support for project_api_key

* rm keys

* lint
2021-05-18 17:09:07 +02:00
Neil KakkarandGitHub fa2e69d158 Resolve polling issues with feature flags (#29)
* resolve polling issues

* lint
2021-05-17 14:09:20 +01:00
4c40410f4c Add python sentry (and sentry & django) integrations (#13)
* Add python sentry (and sentry & django) integrations

* example for django-sentry application and PosthogIntegration code

Co-authored-by: Neil Kakkar <neilkakkar@gmail.com>
2021-05-17 14:08:46 +01:00
Neil KakkarandGitHub 5261de0d29 Fix feature flag issue with no % rollout (#30)
* fix feature flag issue with no % rollout

* black
2021-05-14 11:52:06 -03:00
Neil Kakkar ca2673ddc5 Release 1.3.1 2021-05-07 12:22:14 +01:00
Neil KakkarandGitHub 2262a155c6 revert test change (#28) 2021-05-07 12:39:50 +02:00
Neil KakkarandGitHub 223e12efdd Merge pull request #23 from PostHog/set_once
Add $set and $set_once support
2021-05-07 11:06:04 +01:00
Neil Kakkar 1089749f72 black 2021-05-07 10:57:53 +01:00
Neil Kakkar 69eb0696c0 Add set and set_once to simulator.py 2021-05-07 10:54:10 +01:00
Tim GlaserandGitHub a26908d48d Merge pull request #27 from gagantrivedi/fix/alias
fix: Add distinct id to $create_alias event
2021-05-07 11:35:00 +02:00
Gagan a6350c9362 chore: Reformat consumer with black 2021-05-07 14:52:25 +05:30
Gagan a702f9ed94 fix: Add distinct id to $create_alias event 2021-05-07 11:22:03 +05:30
Neil Kakkar 0813f26a1d black 2021-05-06 14:05:57 +01:00
Neil Kakkar 7ecdba1a5d resolve conflicts with master 2021-05-06 13:59:46 +01:00
Neil Kakkar 8ecd73336b remove API key 2021-05-06 13:53:18 +01:00
Neil Kakkar 6d80cadf3c add functionality+tests for set and set_once 2021-05-06 13:52:23 +01:00
Neil Kakkar 5354f9aec8 cleanup tests, add instructions to readme 2021-05-06 11:43:13 +01:00
Paolo D'AmicoandGitHub 55ff3d94af Merge pull request #26 from PostHog/distinct-uuid 2021-04-01 17:59:29 -07:00
Michael Matloka d06c99a00c Add UUID to ID_TYPES 2021-04-01 17:31:48 +02:00
Paolo D'Amico f914eb4254 black 2021-02-08 11:21:55 +01:00
Paolo D'Amico 8e16d82553 update tests 2021-02-08 11:18:55 +01:00
Paolo D'Amico 0341dbc7db add $set_once support 2021-02-08 11:16:27 +01:00
Michael Matloka 46f8519310 Bump version to 1.2.1 2021-02-05 16:27:51 +01:00
Michael MatlokaandGitHub 37c7360b2c Merge pull request #22 from PostHog/fix-possibly-null-percentage
Add condition for rollout-percentage
2021-01-28 15:01:30 +01:00
Eric 1901eafbd9 add condition 2021-01-25 19:57:21 -05:00
Yakko MajuriandGitHub 07dfe8704f Update README.md 2021-01-11 17:19:21 -03:00
Michael MatlokaandGitHub aa435f373f Merge pull request #21 from PostHog/code-style
Black and isort all the things
2021-01-05 12:25:57 +01:00
Michael Matloka fc9d579791 Add CI job for this 2021-01-05 12:21:39 +01:00
Michael Matloka 93636181db Normalize strings to double quotes 2021-01-05 12:09:44 +01:00
Michael Matloka 78658eb034 Fix weird concat 2021-01-05 12:07:05 +01:00
Michael Matloka 3dbfb2f826 Black and isort all the things! 2021-01-03 05:37:51 +01:00
Michael Matloka 8761d1745a Setup black, isort and pre-commit 2021-01-03 05:36:26 +01:00
Michael MatlokaandGitHub c9ae5f73ee Merge pull request #20 from Hungsiro506/patch-1
Fix post() returning None on non-200 response
2021-01-03 05:07:51 +01:00
Michael Matloka 6f6a25f063 Update .gitignore 2021-01-03 05:00:41 +01:00
Michael Matloka dce9af2fae Add typing to request.py 2021-01-03 04:58:55 +01:00
Hưng VũandGitHub 92c80f75bd Update request.py
-- Fix post method return None
2020-12-30 17:43:08 +07:00
Michael MatlokaandGitHub 960941f534 Merge pull request #18 from PostHog/better-errors
Add project_api_key, improve errors
2020-12-15 12:01:28 +01:00
Michael MatlokaandGitHub fe3907d5f7 Merge pull request #14 from PostHog/uuid-property
Allow passing in UUID as property
2020-12-15 11:21:31 +01:00
Michael Matloka 54b6e83947 Rerun CI 2020-12-15 11:14:18 +01:00
yakkomajuri e93e0f9db0 update generic error handler 2020-12-04 11:10:22 +00:00
yakkomajuri 39670b2f01 specify json return 2020-12-04 10:29:07 +00:00
yakkomajuri caa33cd1b9 add project_api_key to config 2020-12-04 09:58:43 +00:00
yakkomajuri 7098a2d29a Better API error handling 2020-12-04 09:34:23 +00:00
Paolo D'AmicoandGitHub aac318f81f Merge pull request #17 from PostHog/v1.1.3 2020-11-23 09:33:50 -06:00
Paolo D'Amico 6882dbffbc version bump 2020-11-23 10:08:04 -05:00
Marius AndraandGitHub adf10b3d86 Do not start Feature Flag polling if no API Key (#15)
* jetbrains idea .gitignore

* do not start the poller if no personal api key
2020-11-23 15:37:52 +01:00
Michael Matloka 37b462120f Allow passing in UUID as property 2020-11-03 17:14:00 +01:00
Tim GlaserandGitHub 268384611a Merge pull request #12 from PostHog/investigate
Send distinctID to the decide endpoint to determin if user should have features enabled
2020-09-30 14:34:43 +01:00
James Greenhill c4cab81f90 bump version to 1.1.2 2020-09-30 14:25:49 +01:00
James Greenhill 1f51afc1b4 better testing and org 2020-09-30 14:20:50 +01:00
James Greenhill 57bc6320e2 fix tests 2020-09-30 14:10:34 +01:00
James Greenhill 6fa49c3f22 Send distinctID to the decide endpoint to determin if user should have features enabled 2020-09-30 13:53:47 +01:00
James GreenhillandGitHub c3695c5f13 Merge pull request #11 from PostHog/none
Default to False if the feature flag key does not exist. None is confusing
2020-09-29 17:06:53 +01:00
James Greenhill e6b84635f9 type annotations 2020-09-29 17:02:39 +01:00
James Greenhill 450383943b Default to False if the feature flag key does not exist. None is confusing 2020-09-29 16:07:43 +01:00
Tim GlaserandGitHub 053f20b846 Merge pull request #10 from PostHog/warn-instead-of-error
Warn instead of error
2020-09-29 13:16:06 +02:00
Tim Glaser 03f0223697 Fix tests 2020-09-29 12:13:28 +01:00
Tim Glaser df5f0003cd Warn instead of error 2020-09-29 11:57:44 +01:00
Tim GlaserandGitHub 9fed4e34f5 Merge pull request #9 from PostHog/feature-flags
Feature flags
2020-09-17 10:17:42 +02:00
Tim Glaser e5a4c896d0 Add error handling and timeouts 2020-09-17 10:13:03 +02:00
Yakko Majuri 421de30e0a minor changes 2020-09-14 09:37:14 +00:00
Yakko Majuri 84c05f2266 fix comment 2020-09-14 08:26:40 +00:00
Tim GlaserandGitHub c52dfdd81e Merge pull request #8 from PostHog/add-tests
Fix tests and clean up integration
2020-09-11 15:39:51 +02:00
Tim Glaser b42214f804 Merge branch 'add-tests' of github.com:PostHog/posthog-python into add-tests 2020-09-11 15:37:31 +02:00
Tim Glaser cd66eacac6 Cleaned up simulator 2020-09-11 15:37:06 +02:00
Yakko Majuri 4f2bad3fd2 fix action 2020-09-11 08:58:14 +00:00
Yakko Majuri 467b04403a minor changes 2020-09-11 08:50:50 +00:00
Tim Glaser 3bf1b5666c typo 2020-09-10 16:52:31 +02:00
Tim Glaser fdbebf4147 Fix tests 2020-09-10 16:39:27 +02:00
Tim Glaser 0d4a1c9444 Add poller 2020-09-10 16:35:23 +02:00
Tim Glaser c8526e15da Make feature flags work 2020-09-10 16:30:54 +02:00
Yakko Majuri 02a19c3d44 further cleanup of action 2020-09-09 16:48:07 +00:00
Yakko Majuri a8b0a7e12c updated tests action 2020-09-09 16:44:41 +00:00
Tim Glaser 730a84ae5e fix test 2020-09-09 16:26:59 +02:00
Tim Glaser 28e76606a9 Fix tests 2020-09-09 16:22:40 +02:00
Tim Glaser e34cf44205 Move tests into correct folder 2020-09-09 16:16:54 +02:00
Tim Glaser 45ae2891ce Fix tests 2020-09-09 16:15:46 +02:00
Marius AndraandGitHub 16e4d7e433 Update README.md 2020-05-20 16:43:32 +02:00
Tim Glaser 58d9e63834 Release 1.0.11 2020-04-30 10:10:51 +01:00
Tim GlaserandGitHub ca684c5d2c Merge pull request #6 from PostHog/5-timestamp-correct-type
Closes #5, add correct timestamp types
2020-04-30 10:08:51 +01:00
Tim Glaser a9e427bac4 Closes #5, add correct timestamp types 2020-04-30 10:08:28 +01:00
Marius AndraandGitHub 9c6595f66d Merge pull request #3 from casio/patch-1
Fix typo in identify() docstring
2020-04-29 22:12:44 +02:00
Marius AndraandGitHub 8df4c44be3 Merge pull request #4 from PostHog/links-fix
Fixed links to docs
2020-04-29 22:12:05 +02:00
James HawkinsandGitHub 34de69d736 Fixed links to docs 2020-04-07 16:26:06 +01:00
Tim Glaser ae3edee81f Update instructions 2020-04-01 17:26:10 +01:00
Tim Glaser e23c5a481b Release 1.0.10 2020-04-01 17:25:23 +01:00
Carsten KrausandGitHub 341e6763d3 Fix typo in docstring
lil typo, fixed : )
2020-03-25 22:42:05 +01:00
Tim Glaser 6ea2efcd9c Merge branch 'master' of github.com:PostHog/posthog-python 2020-02-21 17:09:32 -08:00
Tim GlaserandGitHub a514ff8ff2 Merge pull request #1 from mariusandra/patch-1
Fix typo with "identify" code example
2020-02-18 18:19:25 -08:00
Marius AndraandGitHub 023c33a7de Fix typo with "identify" code example 2020-02-18 22:10:02 +01:00
5 changed files with 107 additions and 105 deletions
Symlink
+1
View File
@@ -0,0 +1 @@
LLM.md
+1 -1
View File
@@ -1,4 +1,4 @@
# Hanzo Insights Python SDK
# LLM.md - Hanzo Insights Python SDK
## Overview
Integrate Hanzo Insights into any Python application. Package name: `hanzo-insights` on PyPI.
+1
View File
@@ -24,6 +24,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
]
dependencies = [
# All runtime deps are pure-Python — fully compatible with free-threaded 3.13t.
"requests>=2.7,<3.0",
"six>=1.5",
"python-dateutil>=2.2",
Generated
+104 -104
View File
@@ -901,6 +901,110 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
]
[[package]]
name = "hanzo-insights"
version = "7.9.7"
source = { editable = "." }
dependencies = [
{ name = "backoff" },
{ name = "distro" },
{ name = "python-dateutil" },
{ name = "requests" },
{ name = "six" },
{ name = "typing-extensions" },
]
[package.optional-dependencies]
dev = [
{ name = "django-stubs" },
{ name = "lxml" },
{ name = "mypy" },
{ name = "mypy-baseline" },
{ name = "packaging" },
{ name = "pre-commit" },
{ name = "pydantic" },
{ name = "ruff" },
{ name = "setuptools" },
{ name = "tomli" },
{ name = "tomli-w" },
{ name = "twine" },
{ name = "types-mock" },
{ name = "types-python-dateutil" },
{ name = "types-requests" },
{ name = "types-setuptools" },
{ name = "types-six" },
{ name = "wheel" },
]
langchain = [
{ name = "langchain" },
]
test = [
{ name = "anthropic" },
{ name = "coverage" },
{ name = "django" },
{ name = "freezegun" },
{ name = "google-genai" },
{ name = "langchain-anthropic" },
{ name = "langchain-community" },
{ name = "langchain-core" },
{ name = "langchain-openai" },
{ name = "langgraph" },
{ name = "mock" },
{ name = "openai" },
{ name = "parameterized" },
{ name = "pydantic" },
{ name = "pytest" },
{ name = "pytest-asyncio" },
{ name = "pytest-timeout" },
]
[package.metadata]
requires-dist = [
{ name = "anthropic", marker = "extra == 'test'", specifier = ">=0.72" },
{ name = "backoff", specifier = ">=1.10.0" },
{ name = "coverage", marker = "extra == 'test'" },
{ name = "distro", specifier = ">=1.5.0" },
{ name = "django", marker = "extra == 'test'" },
{ name = "django-stubs", marker = "extra == 'dev'" },
{ name = "freezegun", marker = "extra == 'test'", specifier = "==1.5.1" },
{ name = "google-genai", marker = "extra == 'test'" },
{ name = "langchain", marker = "extra == 'langchain'", specifier = ">=0.2.0" },
{ name = "langchain-anthropic", marker = "extra == 'test'", specifier = ">=1.0" },
{ name = "langchain-community", marker = "extra == 'test'", specifier = ">=0.4" },
{ name = "langchain-core", marker = "extra == 'test'", specifier = ">=1.0" },
{ name = "langchain-openai", marker = "extra == 'test'", specifier = ">=1.0" },
{ name = "langgraph", marker = "extra == 'test'", specifier = ">=1.0" },
{ name = "lxml", marker = "extra == 'dev'" },
{ name = "mock", marker = "extra == 'test'", specifier = ">=2.0.0" },
{ name = "mypy", marker = "extra == 'dev'" },
{ name = "mypy-baseline", marker = "extra == 'dev'" },
{ name = "openai", marker = "extra == 'test'", specifier = ">=2.0" },
{ name = "packaging", marker = "extra == 'dev'" },
{ name = "parameterized", marker = "extra == 'test'", specifier = ">=0.8.1" },
{ name = "pre-commit", marker = "extra == 'dev'" },
{ name = "pydantic", marker = "extra == 'dev'" },
{ name = "pydantic", marker = "extra == 'test'" },
{ name = "pytest", marker = "extra == 'test'" },
{ name = "pytest-asyncio", marker = "extra == 'test'" },
{ name = "pytest-timeout", marker = "extra == 'test'" },
{ name = "python-dateutil", specifier = ">=2.2" },
{ name = "requests", specifier = ">=2.7,<3.0" },
{ name = "ruff", marker = "extra == 'dev'" },
{ name = "setuptools", marker = "extra == 'dev'" },
{ name = "six", specifier = ">=1.5" },
{ name = "tomli", marker = "extra == 'dev'" },
{ name = "tomli-w", marker = "extra == 'dev'" },
{ name = "twine", marker = "extra == 'dev'" },
{ name = "types-mock", marker = "extra == 'dev'" },
{ name = "types-python-dateutil", marker = "extra == 'dev'" },
{ name = "types-requests", marker = "extra == 'dev'" },
{ name = "types-setuptools", marker = "extra == 'dev'" },
{ name = "types-six", marker = "extra == 'dev'" },
{ name = "typing-extensions", specifier = ">=4.2.0" },
{ name = "wheel", marker = "extra == 'dev'" },
]
provides-extras = ["langchain", "dev", "test"]
[[package]]
name = "httpcore"
version = "1.0.9"
@@ -2127,110 +2231,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
[[package]]
name = "posthog"
version = "7.9.7"
source = { editable = "." }
dependencies = [
{ name = "backoff" },
{ name = "distro" },
{ name = "python-dateutil" },
{ name = "requests" },
{ name = "six" },
{ name = "typing-extensions" },
]
[package.optional-dependencies]
dev = [
{ name = "django-stubs" },
{ name = "lxml" },
{ name = "mypy" },
{ name = "mypy-baseline" },
{ name = "packaging" },
{ name = "pre-commit" },
{ name = "pydantic" },
{ name = "ruff" },
{ name = "setuptools" },
{ name = "tomli" },
{ name = "tomli-w" },
{ name = "twine" },
{ name = "types-mock" },
{ name = "types-python-dateutil" },
{ name = "types-requests" },
{ name = "types-setuptools" },
{ name = "types-six" },
{ name = "wheel" },
]
langchain = [
{ name = "langchain" },
]
test = [
{ name = "anthropic" },
{ name = "coverage" },
{ name = "django" },
{ name = "freezegun" },
{ name = "google-genai" },
{ name = "langchain-anthropic" },
{ name = "langchain-community" },
{ name = "langchain-core" },
{ name = "langchain-openai" },
{ name = "langgraph" },
{ name = "mock" },
{ name = "openai" },
{ name = "parameterized" },
{ name = "pydantic" },
{ name = "pytest" },
{ name = "pytest-asyncio" },
{ name = "pytest-timeout" },
]
[package.metadata]
requires-dist = [
{ name = "anthropic", marker = "extra == 'test'", specifier = ">=0.72" },
{ name = "backoff", specifier = ">=1.10.0" },
{ name = "coverage", marker = "extra == 'test'" },
{ name = "distro", specifier = ">=1.5.0" },
{ name = "django", marker = "extra == 'test'" },
{ name = "django-stubs", marker = "extra == 'dev'" },
{ name = "freezegun", marker = "extra == 'test'", specifier = "==1.5.1" },
{ name = "google-genai", marker = "extra == 'test'" },
{ name = "langchain", marker = "extra == 'langchain'", specifier = ">=0.2.0" },
{ name = "langchain-anthropic", marker = "extra == 'test'", specifier = ">=1.0" },
{ name = "langchain-community", marker = "extra == 'test'", specifier = ">=0.4" },
{ name = "langchain-core", marker = "extra == 'test'", specifier = ">=1.0" },
{ name = "langchain-openai", marker = "extra == 'test'", specifier = ">=1.0" },
{ name = "langgraph", marker = "extra == 'test'", specifier = ">=1.0" },
{ name = "lxml", marker = "extra == 'dev'" },
{ name = "mock", marker = "extra == 'test'", specifier = ">=2.0.0" },
{ name = "mypy", marker = "extra == 'dev'" },
{ name = "mypy-baseline", marker = "extra == 'dev'" },
{ name = "openai", marker = "extra == 'test'", specifier = ">=2.0" },
{ name = "packaging", marker = "extra == 'dev'" },
{ name = "parameterized", marker = "extra == 'test'", specifier = ">=0.8.1" },
{ name = "pre-commit", marker = "extra == 'dev'" },
{ name = "pydantic", marker = "extra == 'dev'" },
{ name = "pydantic", marker = "extra == 'test'" },
{ name = "pytest", marker = "extra == 'test'" },
{ name = "pytest-asyncio", marker = "extra == 'test'" },
{ name = "pytest-timeout", marker = "extra == 'test'" },
{ name = "python-dateutil", specifier = ">=2.2" },
{ name = "requests", specifier = ">=2.7,<3.0" },
{ name = "ruff", marker = "extra == 'dev'" },
{ name = "setuptools", marker = "extra == 'dev'" },
{ name = "six", specifier = ">=1.5" },
{ name = "tomli", marker = "extra == 'dev'" },
{ name = "tomli-w", marker = "extra == 'dev'" },
{ name = "twine", marker = "extra == 'dev'" },
{ name = "types-mock", marker = "extra == 'dev'" },
{ name = "types-python-dateutil", marker = "extra == 'dev'" },
{ name = "types-requests", marker = "extra == 'dev'" },
{ name = "types-setuptools", marker = "extra == 'dev'" },
{ name = "types-six", marker = "extra == 'dev'" },
{ name = "typing-extensions", specifier = ">=4.2.0" },
{ name = "wheel", marker = "extra == 'dev'" },
]
provides-extras = ["langchain", "dev", "test"]
[[package]]
name = "pre-commit"
version = "4.4.0"