diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 804c8c8f..ea1215d2 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -19,3 +19,29 @@ - [ ] Ran `sampo add` to generate a changeset file + +## 🤖 Agent context + + + + + +**Autonomy:** Human-driven (agent-assisted) — or — Fully autonomous + + + diff --git a/.sampo/changesets/ancient-queen-tursas.md b/.sampo/changesets/ancient-queen-tursas.md new file mode 100644 index 00000000..d3e94302 --- /dev/null +++ b/.sampo/changesets/ancient-queen-tursas.md @@ -0,0 +1,5 @@ +--- +pypi/posthog: patch +--- + +Increase the default background flush interval to 5 seconds diff --git a/AI_POLICY.md b/AI_POLICY.md new file mode 100644 index 00000000..db671481 --- /dev/null +++ b/AI_POLICY.md @@ -0,0 +1,45 @@ +# AI contributions policy + +PostHog is built with plenty of AI assistance. +This policy exists because of a growing volume of low-quality, AI-generated contributions that waste maintainer time. + +## The standard + +**You own what you submit.** +Understand your code, test it, and be ready to explain why it's correct and how it interacts with the rest of the system (without re-prompting an LLM). +This is no different from what we'd expect of any contribution; AI makes it easier to skip the work – please don't skip the work. + +**Prove it works.** +Before submitting, please verify the change actually works end-to-end — don't rely on "it compiles" or "tests pass" alone. + +Add tests for new behavior, smoke test the change in an example project where applicable, and describe your test strategy in the PR description: what you tested, how you tested it, and what edge cases you considered. + +For changes with user-visible UI, include a short demo (screenshot, screen recording, or GIF) of the feature working in the PR description. Ideally you demo more than just the happy path. + +PRs that clearly weren't run or tested will be closed under this policy. + +**Disclose AI usage.** +Our [PR template](.github/pull_request_template.md) includes an Agent context section — please use it (most agents will pick it up automatically). +If an agent co-authored or authored your PR, say so and leave context about the tools and session. +This helps reviewers calibrate. + +**Prefer PRs over AI-generated issues.** +If AI helped you find a bug, fix it and open a pull request — don't paste the AI's output into an issue. +Unreviewed, AI-generated bug reports and security disclosures will be closed without response. + +**Don't submit unsolicited AI-generated PR reviews.** +If you didn't write the code and aren't a maintainer, don't point an LLM at someone else's PR and leave its output as a review comment. +This is generally never helpful. + +## What happens when contributions don't meet this bar + +- **First time:** We'll close the PR/issue with a link to this policy and a brief explanation. +- **Two or more closures:** We'll block the account. + +## Why we're not anti-AI + +We think the best contributions today often involve AI. +A contributor who uses an LLM to help them understand unfamiliar code, draft a first pass, or catch edge cases they'd miss is probably _more_ productive than someone doing everything by hand. +The key difference is that they're driving the AI, not the other way around. + +If you're new to open-source contributing and want to learn, we're genuinely happy to help — open an issue, ask questions, submit small PRs. diff --git a/examples/example-ai-openai-agents/uv.lock b/examples/example-ai-openai-agents/uv.lock index cddac858..98804206 100644 --- a/examples/example-ai-openai-agents/uv.lock +++ b/examples/example-ai-openai-agents/uv.lock @@ -788,14 +788,14 @@ wheels = [ [[package]] name = "pyjwt" -version = "2.12.1" +version = "2.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, ] [package.optional-dependencies] diff --git a/examples/example-ai-pydantic-ai/uv.lock b/examples/example-ai-pydantic-ai/uv.lock index 075144ca..f77891c6 100644 --- a/examples/example-ai-pydantic-ai/uv.lock +++ b/examples/example-ai-pydantic-ai/uv.lock @@ -1919,7 +1919,7 @@ wheels = [ [[package]] name = "posthog" -version = "7.17.0" +version = "7.19.1" source = { directory = "../../" } dependencies = [ { name = "backoff" }, @@ -1945,6 +1945,7 @@ requires-dist = [ { name = "django-stubs", marker = "extra == 'dev'" }, { name = "freezegun", marker = "extra == 'test'", specifier = "==1.5.1" }, { name = "google-genai", marker = "extra == 'test'" }, + { name = "griffe", marker = "extra == 'dev'" }, { 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" }, @@ -2492,14 +2493,14 @@ wheels = [ [[package]] name = "pyjwt" -version = "2.12.1" +version = "2.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, ] [package.optional-dependencies] diff --git a/posthog/client.py b/posthog/client.py index 20d1a9f9..800cc577 100644 --- a/posthog/client.py +++ b/posthog/client.py @@ -185,7 +185,7 @@ def __init__( send=True, on_error=None, flush_at=100, - flush_interval=0.5, + flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, diff --git a/posthog/consumer.py b/posthog/consumer.py index 6f0450f0..9f208662 100644 --- a/posthog/consumer.py +++ b/posthog/consumer.py @@ -40,7 +40,7 @@ def __init__( flush_at=100, host=None, on_error=None, - flush_interval=0.5, + flush_interval=5.0, gzip=False, retries=10, timeout=15, diff --git a/references/public_api_snapshot.txt b/references/public_api_snapshot.txt index cab2d743..e6645985 100644 --- a/references/public_api_snapshot.txt +++ b/references/public_api_snapshot.txt @@ -744,8 +744,8 @@ class posthog.ai.types.ToolInProgress class posthog.args.OptionalCaptureArgs class posthog.args.OptionalSetArgs class posthog.bucketed_rate_limiter.BucketedRateLimiter(bucket_size: Number, refill_rate: Number, refill_interval_seconds: Number, on_bucket_rate_limited: Optional[Callable[[Hashable], None]] = None, clock: Callable[[], float] = time.monotonic) -class posthog.client.Client(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=0.5, gzip=False, max_retries=3, sync_mode=False, timeout=15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds=3, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, _dedicated_ai_endpoint=False) -class posthog.consumer.Consumer(queue, api_key, flush_at=100, host=None, on_error=None, flush_interval=0.5, gzip=False, retries=10, timeout=15, historical_migration=False, dedicated_ai_endpoint=False) +class posthog.client.Client(project_api_key: str, host=None, debug=False, max_queue_size=10000, send=True, on_error=None, flush_at=100, flush_interval=5.0, gzip=False, max_retries=3, sync_mode=False, timeout=15, thread=1, poll_interval=30, personal_api_key=None, disabled=False, disable_geoip=True, is_server=True, historical_migration=False, feature_flags_request_timeout_seconds=3, super_properties=None, enable_exception_autocapture=False, log_captured_exceptions=False, project_root=None, privacy_mode=False, before_send=None, flag_fallback_cache_url=None, enable_local_evaluation=True, flag_definition_cache_provider: Optional[FlagDefinitionCacheProvider] = None, capture_exception_code_variables=False, code_variables_mask_patterns=None, code_variables_ignore_patterns=None, in_app_modules: list[str] | None = None, enable_exception_autocapture_rate_limiting=False, exception_autocapture_bucket_size=ExceptionCapture.DEFAULT_BUCKET_SIZE, exception_autocapture_refill_rate=ExceptionCapture.DEFAULT_REFILL_RATE, exception_autocapture_refill_interval_seconds=ExceptionCapture.DEFAULT_REFILL_INTERVAL_SECONDS, _dedicated_ai_endpoint=False) +class posthog.consumer.Consumer(queue, api_key, flush_at=100, host=None, on_error=None, flush_interval=5.0, gzip=False, retries=10, timeout=15, historical_migration=False, dedicated_ai_endpoint=False) class posthog.contexts.ContextScope(parent=None, fresh: bool = False, capture_exceptions: bool = True, client: Optional[Client] = None) class posthog.exception_capture.ExceptionCapture(client: Client, rate_limiting_enabled=False, bucket_size=DEFAULT_BUCKET_SIZE, refill_rate=DEFAULT_REFILL_RATE, refill_interval_seconds=DEFAULT_REFILL_INTERVAL_SECONDS) class posthog.exception_utils.AnnotatedValue(value, metadata) diff --git a/sdk_compliance_adapter/adapter.py b/sdk_compliance_adapter/adapter.py index e0ed1b4b..032dea68 100644 --- a/sdk_compliance_adapter/adapter.py +++ b/sdk_compliance_adapter/adapter.py @@ -225,7 +225,7 @@ def init(): api_key = data.get("api_key") host = data.get("host") flush_at = data.get("flush_at", 100) - flush_interval_ms = data.get("flush_interval_ms", 500) + flush_interval_ms = data.get("flush_interval_ms", 5000) max_retries = data.get("max_retries", 3) enable_compression = data.get("enable_compression", False)