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
This commit is contained in:
+6
-6
@@ -1,11 +1,11 @@
|
||||
# PostHog API Configuration
|
||||
# Hanzo Insights API Configuration
|
||||
# Copy this file to .env and update with your actual values
|
||||
|
||||
# Your project API key (found on the /setup page in PostHog)
|
||||
POSTHOG_PROJECT_API_KEY=phc_your_project_api_key_here
|
||||
# Your project API key (found on the setup page in Insights)
|
||||
INSIGHTS_PROJECT_API_KEY=hi_your_project_api_key_here
|
||||
|
||||
# Your personal API key (for local evaluation and other advanced features)
|
||||
POSTHOG_PERSONAL_API_KEY=phx_your_personal_api_key_here
|
||||
INSIGHTS_PERSONAL_API_KEY=phx_your_personal_api_key_here
|
||||
|
||||
# PostHog host URL (remove this line if using posthog.com)
|
||||
POSTHOG_HOST=http://localhost:8000
|
||||
# Insights host URL (remove this line if using insights.hanzo.ai)
|
||||
INSIGHTS_HOST=http://localhost:8000
|
||||
|
||||
+7
-7
@@ -1,6 +1,6 @@
|
||||
# Before Send Hook
|
||||
|
||||
The `before_send` parameter allows you to modify or filter events before they are sent to PostHog. This is useful for:
|
||||
The `before_send` parameter allows you to modify or filter events before they are sent to Insights. This is useful for:
|
||||
|
||||
- **Privacy**: Removing or masking sensitive data (PII)
|
||||
- **Filtering**: Dropping unwanted events (test events, internal users, etc.)
|
||||
@@ -10,12 +10,12 @@ The `before_send` parameter allows you to modify or filter events before they ar
|
||||
## Basic Usage
|
||||
|
||||
```python
|
||||
import posthog
|
||||
import hanzo_insights
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
def my_before_send(event: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Process event before sending to PostHog.
|
||||
Process event before sending to Insights.
|
||||
|
||||
Args:
|
||||
event: The event dictionary containing 'event', 'distinct_id', 'properties', etc.
|
||||
@@ -27,7 +27,7 @@ def my_before_send(event: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
return event
|
||||
|
||||
# Initialize client with before_send hook
|
||||
client = posthog.Client(
|
||||
client = hanzo_insights.Client(
|
||||
api_key="your-project-api-key",
|
||||
before_send=my_before_send
|
||||
)
|
||||
@@ -166,7 +166,7 @@ def should_drop_event(event: dict[str, Any]) -> bool:
|
||||
|
||||
## Error Handling
|
||||
|
||||
If your `before_send` function raises an exception, PostHog will:
|
||||
If your `before_send` function raises an exception, Insights will:
|
||||
|
||||
1. Log the error
|
||||
2. Continue with the original, unmodified event
|
||||
@@ -184,7 +184,7 @@ def risky_before_send(event: dict[str, Any]) -> Optional[dict[str, Any]]:
|
||||
## Complete Example
|
||||
|
||||
```python
|
||||
import posthog
|
||||
import hanzo_insights
|
||||
from typing import Optional, Any
|
||||
import re
|
||||
|
||||
@@ -227,7 +227,7 @@ def production_before_send(event: dict[str, Any]) -> Optional[dict[str, Any]]:
|
||||
return event # Return original event on error
|
||||
|
||||
# Usage
|
||||
client = posthog.Client(
|
||||
client = hanzo_insights.Client(
|
||||
api_key="your-api-key",
|
||||
before_send=production_before_send
|
||||
)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# LLM.md - Hanzo Posthog Python
|
||||
# LLM.md - Hanzo Insights Python SDK
|
||||
|
||||
## Overview
|
||||
Integrate Hanzo Insights into any python application.
|
||||
Integrate Hanzo Insights into any Python application. Package name: `hanzo-insights` on PyPI.
|
||||
|
||||
## Tech Stack
|
||||
- **Language**: Python
|
||||
- **Language**: Python 3.10+
|
||||
- **Package**: `hanzo_insights` (import name), `hanzo-insights` (pip name)
|
||||
|
||||
## Build & Run
|
||||
```bash
|
||||
@@ -15,24 +16,26 @@ uv run pytest
|
||||
## Structure
|
||||
```
|
||||
posthog-python/
|
||||
BEFORE_SEND.md
|
||||
CHANGELOG.md
|
||||
CODEOWNERS
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
Makefile
|
||||
README.md
|
||||
README_ANALYTICS.md
|
||||
bin/
|
||||
e2e_test.sh
|
||||
example.py
|
||||
hanzo_insights/ # Main package
|
||||
__init__.py # Module-level API, Insights class (alias: Posthog)
|
||||
client.py # Client class
|
||||
ai/ # AI provider integrations (OpenAI, Anthropic, Gemini, LangChain)
|
||||
integrations/ # Framework integrations (Django middleware)
|
||||
test/ # Tests
|
||||
examples/
|
||||
hanzo_insights/
|
||||
integration_tests/
|
||||
mypy-baseline.txt
|
||||
pyproject.toml # Package config (name: hanzo-insights)
|
||||
setup.py # Legacy setup
|
||||
```
|
||||
|
||||
## Key Files
|
||||
- `README.md` -- Project documentation
|
||||
- `pyproject.toml` -- Python project config
|
||||
- `Makefile` -- Build automation
|
||||
- `pyproject.toml` -- Package config, dependencies, test config
|
||||
- `hanzo_insights/__init__.py` -- Public API surface
|
||||
- `hanzo_insights/client.py` -- Client implementation
|
||||
|
||||
## Rebrand Notes
|
||||
- Main class: `Insights` (backward compat alias: `Posthog = Insights`)
|
||||
- Django middleware: `InsightsContextMiddleware` (alias: `PosthogContextMiddleware`)
|
||||
- OpenAI Agents: `InsightsTracingProcessor` (alias: `PostHogTracingProcessor`)
|
||||
- Internal protocol values (`$lib`, `posthog.com` ingestion URLs) kept for server compat
|
||||
- `posthog_*` parameter names in AI wrappers kept for API compat
|
||||
|
||||
@@ -9,37 +9,38 @@ build_release:
|
||||
rm -rf dist/*
|
||||
python setup.py sdist bdist_wheel
|
||||
|
||||
# Builds the `posthoganalytics` PyPI package, which is a mirror of `posthog`
|
||||
# published under a different name for internal use by posthog/posthog.
|
||||
# Builds the `posthoganalytics` PyPI package, which is a mirror of `hanzo_insights`
|
||||
# published under a different name for backward compatibility with the upstream
|
||||
# posthog/posthog project.
|
||||
#
|
||||
# The process works in three phases:
|
||||
# 1. posthog -> posthoganalytics: Copy the source, rewrite all imports,
|
||||
# remove the original posthog/ dir, and build the dist.
|
||||
# 2. posthoganalytics -> posthog: Reverse the import rewrites, copy
|
||||
# everything back into posthog/, and clean up.
|
||||
# 1. hanzo_insights -> posthoganalytics: Copy the source, rewrite all imports,
|
||||
# remove the original hanzo_insights/ dir, and build the dist.
|
||||
# 2. posthoganalytics -> hanzo_insights: Reverse the import rewrites, copy
|
||||
# everything back into hanzo_insights/, and clean up.
|
||||
# 3. Restore pyproject.toml from backup (setup_analytics.py modifies it).
|
||||
#
|
||||
# This ensures the working tree is left in the same state it started in.
|
||||
#
|
||||
# NOTE: This target clears dist/ before building. In the release workflow,
|
||||
# `build_release` (posthog) must be published BEFORE running this target,
|
||||
# otherwise the posthog dist artifacts will be lost.
|
||||
# `build_release` (hanzo_insights) must be published BEFORE running this target,
|
||||
# otherwise the hanzo_insights dist artifacts will be lost.
|
||||
build_release_analytics:
|
||||
rm -rf dist
|
||||
rm -rf build
|
||||
rm -rf posthoganalytics
|
||||
mkdir posthoganalytics
|
||||
cp -r posthog/* posthoganalytics/
|
||||
find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from posthog /from posthoganalytics /g' {} \;
|
||||
find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from posthog\./from posthoganalytics\./g' {} \;
|
||||
cp -r hanzo_insights/* posthoganalytics/
|
||||
find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from hanzo_insights /from posthoganalytics /g' {} \;
|
||||
find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from hanzo_insights\./from posthoganalytics\./g' {} \;
|
||||
find ./posthoganalytics -name "*.bak" -delete
|
||||
rm -rf posthog
|
||||
rm -rf hanzo_insights
|
||||
python setup_analytics.py sdist bdist_wheel
|
||||
mkdir posthog
|
||||
find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from posthoganalytics /from posthog /g' {} \;
|
||||
find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from posthoganalytics\./from posthog\./g' {} \;
|
||||
mkdir hanzo_insights
|
||||
find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from posthoganalytics /from hanzo_insights /g' {} \;
|
||||
find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from posthoganalytics\./from hanzo_insights\./g' {} \;
|
||||
find ./posthoganalytics -name "*.bak" -delete
|
||||
cp -r posthoganalytics/* posthog/
|
||||
cp -r posthoganalytics/* hanzo_insights/
|
||||
rm -rf posthoganalytics
|
||||
rm -f pyproject.toml
|
||||
cp pyproject.toml.backup pyproject.toml
|
||||
@@ -54,14 +55,14 @@ prep_local:
|
||||
cp -r . ../posthog-python-local/
|
||||
cd ../posthog-python-local && rm -rf dist build posthoganalytics .git
|
||||
cd ../posthog-python-local && mkdir posthoganalytics
|
||||
cd ../posthog-python-local && cp -r posthog/* posthoganalytics/
|
||||
cd ../posthog-python-local && find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from posthog /from posthoganalytics /g' {} \;
|
||||
cd ../posthog-python-local && find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from posthog\./from posthoganalytics\./g' {} \;
|
||||
cd ../posthog-python-local && cp -r hanzo_insights/* posthoganalytics/
|
||||
cd ../posthog-python-local && find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from hanzo_insights /from posthoganalytics /g' {} \;
|
||||
cd ../posthog-python-local && find ./posthoganalytics -type f -name "*.py" -exec sed -i.bak -e 's/from hanzo_insights\./from posthoganalytics\./g' {} \;
|
||||
cd ../posthog-python-local && find ./posthoganalytics -name "*.bak" -delete
|
||||
cd ../posthog-python-local && rm -rf posthog
|
||||
cd ../posthog-python-local && rm -rf hanzo_insights
|
||||
cd ../posthog-python-local && sed -i.bak 's/from version import VERSION/from posthoganalytics.version import VERSION/' setup_analytics.py
|
||||
cd ../posthog-python-local && rm setup_analytics.py.bak
|
||||
cd ../posthog-python-local && sed -i.bak 's/"posthog"/"posthoganalytics"/' setup.py
|
||||
cd ../posthog-python-local && sed -i.bak 's/"hanzo_insights"/"posthoganalytics"/' setup.py
|
||||
cd ../posthog-python-local && rm setup.py.bak
|
||||
cd ../posthog-python-local && python -c "import setup_analytics" 2>/dev/null || true
|
||||
@echo "Local copy created at ../posthog-python-local"
|
||||
|
||||
@@ -1,41 +1,51 @@
|
||||
# PostHog Python
|
||||
# Hanzo Insights Python SDK
|
||||
|
||||
<p align="center">
|
||||
<img alt="posthoglogo" src="https://user-images.githubusercontent.com/65415371/205059737-c8a4f836-4889-4654-902e-f302b187b6a0.png">
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://pypi.org/project/posthog/"><img alt="pypi installs" src="https://img.shields.io/pypi/v/posthog"/></a>
|
||||
<img alt="GitHub contributors" src="https://img.shields.io/github/contributors/posthog/posthog-python">
|
||||
<img alt="GitHub commit activity" src="https://img.shields.io/github/commit-activity/m/posthog/posthog-python"/>
|
||||
<img alt="GitHub closed issues" src="https://img.shields.io/github/issues-closed/posthog/posthog-python"/>
|
||||
</p>
|
||||
Integrate [Hanzo Insights](https://insights.hanzo.ai) into any Python application.
|
||||
|
||||
Please see the [Python integration docs](https://posthog.com/docs/integrations/python-integration) for details.
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-insights
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from hanzo_insights import Insights
|
||||
|
||||
client = Insights('<your_project_api_key>', host='https://insights.hanzo.ai')
|
||||
|
||||
# Capture an event
|
||||
client.capture('user_123', 'purchase', properties={'product': 'widget'})
|
||||
|
||||
# Feature flags
|
||||
if client.feature_enabled('new-checkout', 'user_123'):
|
||||
show_new_checkout()
|
||||
```
|
||||
|
||||
## Module-level usage
|
||||
|
||||
```python
|
||||
import hanzo_insights
|
||||
|
||||
hanzo_insights.api_key = '<your_project_api_key>'
|
||||
hanzo_insights.host = 'https://insights.hanzo.ai'
|
||||
|
||||
hanzo_insights.capture('movie_played', distinct_id='user_123', properties={'movie_id': '42'})
|
||||
hanzo_insights.shutdown()
|
||||
```
|
||||
|
||||
## Python Version Support
|
||||
|
||||
| SDK Version | Python Versions Supported | Notes |
|
||||
| ------------- | ---------------------------- | -------------------------- |
|
||||
| 7.3.1+ | 3.10, 3.11, 3.12, 3.13, 3.14 | Added Python 3.14 support |
|
||||
| 7.0.0 - 7.0.1 | 3.10, 3.11, 3.12, 3.13 | Dropped Python 3.9 support |
|
||||
| 4.0.1 - 6.x | 3.9, 3.10, 3.11, 3.12, 3.13 | Python 3.9+ required |
|
||||
| SDK Version | Python Versions Supported |
|
||||
| -------------- | ----------------------------- |
|
||||
| 7.3.1+ | 3.10, 3.11, 3.12, 3.13, 3.14 |
|
||||
| 7.0.0 - 7.0.1 | 3.10, 3.11, 3.12, 3.13 |
|
||||
| 4.0.1 - 6.x | 3.9, 3.10, 3.11, 3.12, 3.13 |
|
||||
|
||||
## Development
|
||||
|
||||
### Testing Locally
|
||||
|
||||
We recommend using [uv](https://docs.astral.sh/uv/). It's super fast.
|
||||
|
||||
1. Run `uv venv env` (creates virtual environment called "env")
|
||||
- or `python3 -m venv env`
|
||||
2. Run `source env/bin/activate` (activates the virtual environment)
|
||||
3. Run `uv sync --extra dev --extra test` (installs the package in develop mode, along with test dependencies)
|
||||
- or `pip install -e ".[dev,test]"`
|
||||
4. you have to run `pre-commit install` to have auto linting pre commit
|
||||
5. Run `make test`
|
||||
6. To run a specific test do `pytest -k test_no_api_key`
|
||||
|
||||
## PostHog recommends `uv` so...
|
||||
We use [uv](https://docs.astral.sh/uv/).
|
||||
|
||||
```bash
|
||||
uv python install 3.12
|
||||
@@ -47,34 +57,23 @@ pre-commit install
|
||||
make test
|
||||
```
|
||||
|
||||
### Running Locally
|
||||
### Running Tests
|
||||
|
||||
Assuming you have a [local version of PostHog](https://posthog.com/docs/developing-locally) running, you can run `python3 example.py` to see the library in action.
|
||||
|
||||
### Testing changes locally with the PostHog app
|
||||
|
||||
You can run `make prep_local`, and it'll create a new folder alongside the SDK repo one called `posthog-python-local`, which you can then import into the posthog project by changing pyproject.toml to look like this:
|
||||
|
||||
```toml
|
||||
dependencies = [
|
||||
...
|
||||
"posthoganalytics" #NOTE: no version number
|
||||
...
|
||||
]
|
||||
...
|
||||
[tools.uv.sources]
|
||||
posthoganalytics = { path = "../posthog-python-local" }
|
||||
```bash
|
||||
make test
|
||||
# or run a specific test:
|
||||
pytest -k test_no_api_key
|
||||
```
|
||||
|
||||
This'll let you build and test SDK changes fully locally, incorporating them into your local posthog app stack. It mainly takes care of the `posthog -> posthoganalytics` module renaming. You'll need to re-run `make prep_local` each time you make a change, and re-run `uv sync --active` in the posthog app project.
|
||||
## Backward Compatibility
|
||||
|
||||
## Releasing
|
||||
For users migrating from `posthog` or `posthoganalytics`, the `Posthog` class name is
|
||||
available as an alias for `Insights`:
|
||||
|
||||
This repository uses [Sampo](https://github.com/bruits/sampo) for versioning, changelogs, and publishing to crates.io.
|
||||
```python
|
||||
from hanzo_insights import Posthog # works, same as Insights
|
||||
```
|
||||
|
||||
1. When making changes, include a changeset: `sampo add`
|
||||
2. Create a PR with your changes and the changeset file
|
||||
3. Add the `release` label and merge to `main`
|
||||
4. Approve the release in Slack when prompted — this triggers version bump, crates.io publish, git tag, and GitHub Release
|
||||
## License
|
||||
|
||||
You can also trigger a release manually via the workflow's `workflow_dispatch` trigger (still requires pending changesets).
|
||||
MIT
|
||||
|
||||
+14
-14
@@ -1,18 +1,18 @@
|
||||
# PostHog Python library example
|
||||
# Hanzo Insights Python library example
|
||||
#
|
||||
# This script demonstrates various PostHog Python SDK capabilities including:
|
||||
# This script demonstrates various Hanzo Insights Python SDK capabilities including:
|
||||
# - Basic event capture and user identification
|
||||
# - Feature flag local evaluation
|
||||
# - Feature flag payloads
|
||||
# - Context management and tagging
|
||||
#
|
||||
# Setup:
|
||||
# 1. Copy .env.example to .env and fill in your PostHog credentials
|
||||
# 1. Copy .env.example to .env and fill in your Insights credentials
|
||||
# 2. Run this script and choose from the interactive menu
|
||||
|
||||
import os
|
||||
|
||||
import posthog
|
||||
import hanzo_insights
|
||||
|
||||
|
||||
def load_env_file():
|
||||
@@ -31,18 +31,18 @@ def load_env_file():
|
||||
load_env_file()
|
||||
|
||||
# Get configuration
|
||||
project_key = os.getenv("POSTHOG_PROJECT_API_KEY", "")
|
||||
personal_api_key = os.getenv("POSTHOG_PERSONAL_API_KEY", "")
|
||||
host = os.getenv("POSTHOG_HOST", "http://localhost:8000")
|
||||
project_key = os.getenv("INSIGHTS_PROJECT_API_KEY", "")
|
||||
personal_api_key = os.getenv("INSIGHTS_PERSONAL_API_KEY", "")
|
||||
host = os.getenv("INSIGHTS_HOST", "http://localhost:8000")
|
||||
|
||||
# Check if project key is provided (required)
|
||||
if not project_key:
|
||||
print("❌ Missing PostHog project API key!")
|
||||
print(" Please set POSTHOG_PROJECT_API_KEY environment variable")
|
||||
print("❌ Missing Insights project API key!")
|
||||
print(" Please set INSIGHTS_PROJECT_API_KEY environment variable")
|
||||
print(" or copy .env.example to .env and fill in your values")
|
||||
exit(1)
|
||||
|
||||
# Configure PostHog with credentials
|
||||
# Configure Insights with credentials
|
||||
hanzo_insights.debug = False
|
||||
hanzo_insights.api_key = project_key
|
||||
hanzo_insights.project_api_key = project_key
|
||||
@@ -54,7 +54,7 @@ local_eval_available = bool(personal_api_key)
|
||||
if personal_api_key:
|
||||
hanzo_insights.personal_api_key = personal_api_key
|
||||
|
||||
print("🔑 PostHog Configuration:")
|
||||
print("🔑 Insights Configuration:")
|
||||
print(f" Project API Key: {project_key[:9]}...")
|
||||
if local_eval_available:
|
||||
print(" Personal API Key: [SET]")
|
||||
@@ -63,7 +63,7 @@ else:
|
||||
print(f" Host: {host}\n")
|
||||
|
||||
# Display menu and get user choice
|
||||
print("🚀 PostHog Python SDK Demo - Choose an example to run:\n")
|
||||
print("🚀 Hanzo Insights Python SDK Demo - Choose an example to run:\n")
|
||||
print("1. Identify and capture examples")
|
||||
local_eval_note = "" if local_eval_available else " [requires personal API key]"
|
||||
print(f"2. Feature flag local evaluation examples{local_eval_note}")
|
||||
@@ -137,7 +137,7 @@ elif choice == "2":
|
||||
if not local_eval_available:
|
||||
print("\n❌ This example requires a personal API key for local evaluation.")
|
||||
print(
|
||||
" Set POSTHOG_PERSONAL_API_KEY environment variable to run this example."
|
||||
" Set INSIGHTS_PERSONAL_API_KEY environment variable to run this example."
|
||||
)
|
||||
hanzo_insights.shutdown()
|
||||
exit(1)
|
||||
@@ -212,7 +212,7 @@ elif choice == "4":
|
||||
if not local_eval_available:
|
||||
print("\n❌ This example requires a personal API key for local evaluation.")
|
||||
print(
|
||||
" Set POSTHOG_PERSONAL_API_KEY environment variable to run this example."
|
||||
" Set INSIGHTS_PERSONAL_API_KEY environment variable to run this example."
|
||||
)
|
||||
hanzo_insights.shutdown()
|
||||
exit(1)
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
"""
|
||||
Redis-based distributed cache for PostHog feature flag definitions.
|
||||
Redis-based distributed cache for Insights feature flag definitions.
|
||||
|
||||
This example demonstrates how to implement a FlagDefinitionCacheProvider
|
||||
using Redis for multi-instance deployments (leader election pattern).
|
||||
|
||||
Usage:
|
||||
import redis
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Posthog
|
||||
|
||||
redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True)
|
||||
cache = RedisFlagCache(redis_client, service_key="my-service")
|
||||
|
||||
posthog = Posthog(
|
||||
client = Insights(
|
||||
"<project_api_key>",
|
||||
personal_api_key="<personal_api_key>",
|
||||
flag_definition_cache_provider=cache,
|
||||
@@ -24,17 +24,17 @@ Requirements:
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from posthog import FlagDefinitionCacheData, FlagDefinitionCacheProvider
|
||||
from hanzo_insights import FlagDefinitionCacheData, FlagDefinitionCacheProvider
|
||||
from redis import Redis
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class RedisFlagCache(FlagDefinitionCacheProvider):
|
||||
"""
|
||||
A distributed cache for PostHog feature flag definitions using Redis.
|
||||
A distributed cache for Insights feature flag definitions using Redis.
|
||||
|
||||
In a multi-instance deployment (e.g., multiple serverless functions or containers),
|
||||
we want only ONE instance to poll PostHog for flag updates, while all instances
|
||||
we want only ONE instance to poll Insights for flag updates, while all instances
|
||||
share the cached results. This prevents N instances from making N redundant API calls.
|
||||
|
||||
The implementation uses leader election:
|
||||
@@ -113,7 +113,7 @@ class RedisFlagCache(FlagDefinitionCacheProvider):
|
||||
|
||||
def should_fetch_flag_definitions(self) -> bool:
|
||||
"""
|
||||
Determines if this instance should fetch flag definitions from PostHog.
|
||||
Determines if this instance should fetch flag definitions from Insights.
|
||||
|
||||
Atomically either:
|
||||
- Acquires the lock if no one holds it, OR
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple test script for PostHog remote config endpoint.
|
||||
Simple test script for Insights remote config endpoint.
|
||||
"""
|
||||
|
||||
import posthog
|
||||
import hanzo_insights
|
||||
|
||||
# Initialize PostHog client
|
||||
# Initialize Insights client
|
||||
hanzo_insights.api_key = "phc_..."
|
||||
hanzo_insights.personal_api_key = "phs_..." # or "phx_..."
|
||||
hanzo_insights.host = "http://localhost:8000" # or "https://us.hanzo_insights.com"
|
||||
hanzo_insights.host = "http://localhost:8000" # or "https://us.posthog.com"
|
||||
hanzo_insights.debug = True
|
||||
|
||||
|
||||
|
||||
+33
-27
@@ -76,11 +76,11 @@ def new_context(fresh=False, capture_exceptions=True, client=None):
|
||||
Args:
|
||||
fresh: Whether to start with a fresh context (default: False)
|
||||
capture_exceptions: Whether to capture exceptions raised within the context (default: True)
|
||||
client: Optional Posthog client instance to use for this context (default: None)
|
||||
client: Optional Insights client instance to use for this context (default: None)
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import new_context, tag, capture
|
||||
from hanzo_insights import new_context, tag, capture
|
||||
with new_context():
|
||||
tag("request_id", "123")
|
||||
capture("event_name", properties={"property": "value"})
|
||||
@@ -100,11 +100,11 @@ def scoped(fresh=False, capture_exceptions=True):
|
||||
|
||||
Args:
|
||||
fresh: Whether to start with a fresh context (default: False)
|
||||
capture_exceptions: Whether to capture and track exceptions with posthog error tracking (default: True)
|
||||
capture_exceptions: Whether to capture and track exceptions with Insights error tracking (default: True)
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import scoped, tag, capture
|
||||
from hanzo_insights import scoped, tag, capture
|
||||
@scoped()
|
||||
def process_payment(payment_id):
|
||||
tag("payment_id", payment_id)
|
||||
@@ -126,7 +126,7 @@ def set_context_session(session_id: str):
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import set_context_session
|
||||
from hanzo_insights import set_context_session
|
||||
set_context_session("session_123")
|
||||
```
|
||||
|
||||
@@ -146,7 +146,7 @@ def set_context_device_id(device_id: str):
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import set_context_device_id
|
||||
from hanzo_insights import set_context_device_id
|
||||
set_context_device_id("device_123")
|
||||
```
|
||||
|
||||
@@ -165,7 +165,7 @@ def identify_context(distinct_id: str):
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import identify_context
|
||||
from hanzo_insights import identify_context
|
||||
identify_context("user_123")
|
||||
```
|
||||
|
||||
@@ -206,7 +206,7 @@ def tag(name: str, value: Any):
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import tag
|
||||
from hanzo_insights import tag
|
||||
tag("user_id", "123")
|
||||
```
|
||||
|
||||
@@ -280,12 +280,12 @@ def capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str]:
|
||||
disable_geoip: Whether to disable GeoIP lookup
|
||||
|
||||
Details:
|
||||
Capture allows you to capture anything a user does within your system, which you can later use in PostHog to find patterns in usage, work out which features to improve or where people are giving up. A capture call requires an event name to specify the event. We recommend using [verb] [noun], like `movie played` or `movie updated` to easily identify what your events mean later on. Capture takes a number of optional arguments, which are defined by the `OptionalCaptureArgs` type.
|
||||
Capture allows you to capture anything a user does within your system, which you can later use in Insights to find patterns in usage, work out which features to improve or where people are giving up. A capture call requires an event name to specify the event. We recommend using [verb] [noun], like `movie played` or `movie updated` to easily identify what your events mean later on. Capture takes a number of optional arguments, which are defined by the `OptionalCaptureArgs` type.
|
||||
|
||||
Examples:
|
||||
```python
|
||||
# Context and capture usage
|
||||
from posthog import new_context, identify_context, tag_context, capture
|
||||
from hanzo_insights import new_context, identify_context, tag_context, capture
|
||||
# Enter a new context (e.g. a request/response cycle, an instance of a background job, etc)
|
||||
with new_context():
|
||||
# Associate this context with some user, by distinct_id
|
||||
@@ -312,7 +312,7 @@ def capture(event: str, **kwargs: Unpack[OptionalCaptureArgs]) -> Optional[str]:
|
||||
```
|
||||
```python
|
||||
# Set event properties
|
||||
from posthog import capture
|
||||
from hanzo_insights import capture
|
||||
capture(
|
||||
"user_signed_up",
|
||||
distinct_id="distinct_id_of_the_user",
|
||||
@@ -339,7 +339,7 @@ def set(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str]:
|
||||
Examples:
|
||||
```python
|
||||
# Set person properties
|
||||
from posthog import capture
|
||||
from hanzo_insights import capture
|
||||
capture(
|
||||
'distinct_id',
|
||||
event='event_name',
|
||||
@@ -366,7 +366,7 @@ def set_once(**kwargs: Unpack[OptionalSetArgs]) -> Optional[str]:
|
||||
Examples:
|
||||
```python
|
||||
# Set property once
|
||||
from posthog import capture
|
||||
from hanzo_insights import capture
|
||||
capture(
|
||||
'distinct_id',
|
||||
event='event_name',
|
||||
@@ -406,7 +406,7 @@ def group_identify(
|
||||
Examples:
|
||||
```python
|
||||
# Group identify
|
||||
from posthog import group_identify
|
||||
from hanzo_insights import group_identify
|
||||
group_identify('company', 'company_id_in_your_db', {
|
||||
'name': 'Awesome Inc.',
|
||||
'employees': 11
|
||||
@@ -451,7 +451,7 @@ def alias(
|
||||
Examples:
|
||||
```python
|
||||
# Alias user
|
||||
from posthog import alias
|
||||
from hanzo_insights import alias
|
||||
alias(previous_id='distinct_id', distinct_id='alias_id')
|
||||
```
|
||||
Category:
|
||||
@@ -484,7 +484,7 @@ def capture_exception(
|
||||
Examples:
|
||||
```python
|
||||
# Capture exception
|
||||
from posthog import capture_exception
|
||||
from hanzo_insights import capture_exception
|
||||
try:
|
||||
risky_operation()
|
||||
except Exception as e:
|
||||
@@ -528,7 +528,7 @@ def feature_enabled(
|
||||
Examples:
|
||||
```python
|
||||
# Boolean feature flag
|
||||
from posthog import feature_enabled, get_feature_flag_payload
|
||||
from hanzo_insights import feature_enabled, get_feature_flag_payload
|
||||
is_my_flag_enabled = feature_enabled('flag-key', 'distinct_id_of_your_user')
|
||||
if is_my_flag_enabled:
|
||||
matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user')
|
||||
@@ -575,12 +575,12 @@ def get_feature_flag(
|
||||
disable_geoip: Whether to disable GeoIP lookup
|
||||
|
||||
Details:
|
||||
`groups` are a mapping from group type to group key. So, if you have a group type of "organization" and a group key of "5", you would pass groups={"organization": "5"}. `group_properties` take the format: { group_type_name: { group_properties } }. So, for example, if you have the group type "organization" and the group key "5", with the properties name, and employee count, you'll send these as: group_properties={"organization": {"name": "PostHog", "employees": 11}}.
|
||||
`groups` are a mapping from group type to group key. So, if you have a group type of "organization" and a group key of "5", you would pass groups={"organization": "5"}. `group_properties` take the format: { group_type_name: { group_properties } }. So, for example, if you have the group type "organization" and the group key "5", with the properties name, and employee count, you'll send these as: group_properties={"organization": {"name": "Hanzo", "employees": 11}}.
|
||||
|
||||
Examples:
|
||||
```python
|
||||
# Multivariate feature flag
|
||||
from posthog import get_feature_flag, get_feature_flag_payload
|
||||
from hanzo_insights import get_feature_flag, get_feature_flag_payload
|
||||
enabled_variant = get_feature_flag('flag-key', 'distinct_id_of_your_user')
|
||||
if enabled_variant == 'variant-key':
|
||||
matched_flag_payload = get_feature_flag_payload('flag-key', 'distinct_id_of_your_user')
|
||||
@@ -628,7 +628,7 @@ def get_all_flags(
|
||||
Examples:
|
||||
```python
|
||||
# All flags for user
|
||||
from posthog import get_all_flags
|
||||
from hanzo_insights import get_all_flags
|
||||
get_all_flags('distinct_id_of_your_user')
|
||||
```
|
||||
Category:
|
||||
@@ -768,7 +768,7 @@ def feature_flag_definitions():
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import feature_flag_definitions
|
||||
from hanzo_insights import feature_flag_definitions
|
||||
definitions = feature_flag_definitions()
|
||||
```
|
||||
|
||||
@@ -780,11 +780,11 @@ def feature_flag_definitions():
|
||||
|
||||
def load_feature_flags():
|
||||
"""
|
||||
Load feature flag definitions from PostHog.
|
||||
Load feature flag definitions from the server.
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import load_feature_flags
|
||||
from hanzo_insights import load_feature_flags
|
||||
load_feature_flags()
|
||||
```
|
||||
|
||||
@@ -800,7 +800,7 @@ def flush():
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import flush
|
||||
from hanzo_insights import flush
|
||||
flush()
|
||||
```
|
||||
|
||||
@@ -816,7 +816,7 @@ def join():
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import join
|
||||
from hanzo_insights import join
|
||||
join()
|
||||
```
|
||||
|
||||
@@ -832,7 +832,7 @@ def shutdown():
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import shutdown
|
||||
from hanzo_insights import shutdown
|
||||
shutdown()
|
||||
```
|
||||
|
||||
@@ -888,5 +888,11 @@ def _proxy(method, *args, **kwargs):
|
||||
return fn(*args, **kwargs)
|
||||
|
||||
|
||||
class Posthog(Client):
|
||||
class Insights(Client):
|
||||
"""Hanzo Insights client for product analytics."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
# Backward compatibility alias
|
||||
Posthog = Insights
|
||||
|
||||
@@ -23,21 +23,21 @@ from hanzo_insights.ai.anthropic.anthropic_converter import (
|
||||
finalize_anthropic_tool_input,
|
||||
)
|
||||
from hanzo_insights.ai.sanitization import sanitize_anthropic
|
||||
from hanzo_insights.client import Client as PostHogClient
|
||||
from posthog import setup
|
||||
from hanzo_insights.client import Client as InsightsClient
|
||||
from hanzo_insights import setup
|
||||
|
||||
|
||||
class Anthropic(anthropic.Anthropic):
|
||||
"""
|
||||
A wrapper around the Anthropic SDK that automatically sends LLM usage events to PostHog.
|
||||
A wrapper around the Anthropic SDK that automatically sends LLM usage events to Insights.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(self, posthog_client: Optional[PostHogClient] = None, **kwargs):
|
||||
def __init__(self, posthog_client: Optional[InsightsClient] = None, **kwargs):
|
||||
"""
|
||||
Args:
|
||||
posthog_client: PostHog client for tracking usage
|
||||
posthog_client: Insights client for tracking usage
|
||||
**kwargs: Additional arguments passed to the Anthropic client
|
||||
"""
|
||||
super().__init__(**kwargs)
|
||||
@@ -58,7 +58,7 @@ class WrappedMessages(Messages):
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""
|
||||
Create a message using Anthropic's API while tracking usage in PostHog.
|
||||
Create a message using Anthropic's API while tracking usage in Insights.
|
||||
|
||||
Args:
|
||||
posthog_distinct_id: Optional ID to associate with the usage event
|
||||
|
||||
@@ -10,7 +10,7 @@ import time
|
||||
import uuid
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from posthog import setup
|
||||
from hanzo_insights import setup
|
||||
from hanzo_insights.ai.types import StreamingContentBlock, TokenUsage, ToolInProgress
|
||||
from hanzo_insights.ai.utils import (
|
||||
call_llm_and_track_usage_async,
|
||||
@@ -24,20 +24,20 @@ from hanzo_insights.ai.anthropic.anthropic_converter import (
|
||||
finalize_anthropic_tool_input,
|
||||
)
|
||||
from hanzo_insights.ai.sanitization import sanitize_anthropic
|
||||
from hanzo_insights.client import Client as PostHogClient
|
||||
from hanzo_insights.client import Client as InsightsClient
|
||||
|
||||
|
||||
class AsyncAnthropic(anthropic.AsyncAnthropic):
|
||||
"""
|
||||
An async wrapper around the Anthropic SDK that automatically sends LLM usage events to PostHog.
|
||||
An async wrapper around the Anthropic SDK that automatically sends LLM usage events to Insights.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(self, posthog_client: Optional[PostHogClient] = None, **kwargs):
|
||||
def __init__(self, posthog_client: Optional[InsightsClient] = None, **kwargs):
|
||||
"""
|
||||
Args:
|
||||
posthog_client: PostHog client for tracking usage
|
||||
posthog_client: Insights client for tracking usage
|
||||
**kwargs: Additional arguments passed to the Anthropic client
|
||||
"""
|
||||
super().__init__(**kwargs)
|
||||
@@ -58,7 +58,7 @@ class AsyncWrappedMessages(AsyncMessages):
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""
|
||||
Create a message using Anthropic's API while tracking usage in PostHog.
|
||||
Create a message using Anthropic's API while tracking usage in Insights.
|
||||
|
||||
Args:
|
||||
posthog_distinct_id: Optional ID to associate with the usage event
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Anthropic-specific conversion utilities.
|
||||
|
||||
This module handles the conversion of Anthropic API responses and inputs
|
||||
into standardized formats for PostHog tracking.
|
||||
into standardized formats for Insights tracking.
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -425,7 +425,7 @@ def format_anthropic_streaming_input(kwargs: Dict[str, Any]) -> Any:
|
||||
kwargs: Keyword arguments passed to Anthropic API
|
||||
|
||||
Returns:
|
||||
Formatted input ready for PostHog tracking
|
||||
Formatted input ready for Insights tracking
|
||||
"""
|
||||
from hanzo_insights.ai.utils import merge_system_prompt
|
||||
|
||||
@@ -445,7 +445,7 @@ def format_anthropic_streaming_output_complete(
|
||||
accumulated_content: Raw accumulated text content as fallback
|
||||
|
||||
Returns:
|
||||
Formatted messages ready for PostHog tracking
|
||||
Formatted messages ready for Insights tracking
|
||||
"""
|
||||
formatted_content = format_anthropic_streaming_content(content_blocks)
|
||||
|
||||
|
||||
@@ -9,18 +9,18 @@ from typing import Optional
|
||||
|
||||
from hanzo_insights.ai.anthropic.anthropic import WrappedMessages
|
||||
from hanzo_insights.ai.anthropic.anthropic_async import AsyncWrappedMessages
|
||||
from hanzo_insights.client import Client as PostHogClient
|
||||
from posthog import setup
|
||||
from hanzo_insights.client import Client as InsightsClient
|
||||
from hanzo_insights import setup
|
||||
|
||||
|
||||
class AnthropicBedrock(anthropic.AnthropicBedrock):
|
||||
"""
|
||||
A wrapper around the Anthropic Bedrock SDK that automatically sends LLM usage events to PostHog.
|
||||
A wrapper around the Anthropic Bedrock SDK that automatically sends LLM usage events to Insights.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(self, posthog_client: Optional[PostHogClient] = None, **kwargs):
|
||||
def __init__(self, posthog_client: Optional[InsightsClient] = None, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._ph_client = posthog_client or setup()
|
||||
self.messages = WrappedMessages(self)
|
||||
@@ -28,12 +28,12 @@ class AnthropicBedrock(anthropic.AnthropicBedrock):
|
||||
|
||||
class AsyncAnthropicBedrock(anthropic.AsyncAnthropicBedrock):
|
||||
"""
|
||||
A wrapper around the Anthropic Bedrock SDK that automatically sends LLM usage events to PostHog.
|
||||
A wrapper around the Anthropic Bedrock SDK that automatically sends LLM usage events to Insights.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(self, posthog_client: Optional[PostHogClient] = None, **kwargs):
|
||||
def __init__(self, posthog_client: Optional[InsightsClient] = None, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._ph_client = posthog_client or setup()
|
||||
self.messages = AsyncWrappedMessages(self)
|
||||
@@ -41,12 +41,12 @@ class AsyncAnthropicBedrock(anthropic.AsyncAnthropicBedrock):
|
||||
|
||||
class AnthropicVertex(anthropic.AnthropicVertex):
|
||||
"""
|
||||
A wrapper around the Anthropic Vertex SDK that automatically sends LLM usage events to PostHog.
|
||||
A wrapper around the Anthropic Vertex SDK that automatically sends LLM usage events to Insights.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(self, posthog_client: Optional[PostHogClient] = None, **kwargs):
|
||||
def __init__(self, posthog_client: Optional[InsightsClient] = None, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._ph_client = posthog_client or setup()
|
||||
self.messages = WrappedMessages(self)
|
||||
@@ -54,12 +54,12 @@ class AnthropicVertex(anthropic.AnthropicVertex):
|
||||
|
||||
class AsyncAnthropicVertex(anthropic.AsyncAnthropicVertex):
|
||||
"""
|
||||
A wrapper around the Anthropic Vertex SDK that automatically sends LLM usage events to PostHog.
|
||||
A wrapper around the Anthropic Vertex SDK that automatically sends LLM usage events to Insights.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(self, posthog_client: Optional[PostHogClient] = None, **kwargs):
|
||||
def __init__(self, posthog_client: Optional[InsightsClient] = None, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._ph_client = posthog_client or setup()
|
||||
self.messages = AsyncWrappedMessages(self)
|
||||
|
||||
@@ -13,7 +13,7 @@ except ImportError:
|
||||
"Please install the Google Gemini SDK to use this feature: 'pip install google-genai'"
|
||||
)
|
||||
|
||||
from posthog import setup
|
||||
from hanzo_insights import setup
|
||||
from hanzo_insights.ai.utils import (
|
||||
call_llm_and_track_usage,
|
||||
capture_streaming_event,
|
||||
@@ -25,12 +25,12 @@ from hanzo_insights.ai.gemini.gemini_converter import (
|
||||
format_gemini_streaming_output,
|
||||
)
|
||||
from hanzo_insights.ai.sanitization import sanitize_gemini
|
||||
from hanzo_insights.client import Client as PostHogClient
|
||||
from hanzo_insights.client import Client as InsightsClient
|
||||
|
||||
|
||||
class Client:
|
||||
"""
|
||||
A drop-in replacement for genai.Client that automatically sends LLM usage events to PostHog.
|
||||
A drop-in replacement for genai.Client that automatically sends LLM usage events to Insights.
|
||||
|
||||
Usage:
|
||||
client = Client(
|
||||
@@ -46,7 +46,7 @@ class Client:
|
||||
)
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -57,7 +57,7 @@ class Client:
|
||||
location: Optional[str] = None,
|
||||
debug_config: Optional[Any] = None,
|
||||
http_options: Optional[Any] = None,
|
||||
posthog_client: Optional[PostHogClient] = None,
|
||||
posthog_client: Optional[InsightsClient] = None,
|
||||
posthog_distinct_id: Optional[str] = None,
|
||||
posthog_properties: Optional[Dict[str, Any]] = None,
|
||||
posthog_privacy_mode: bool = False,
|
||||
@@ -73,7 +73,7 @@ class Client:
|
||||
location: GCP location for Vertex AI
|
||||
debug_config: Debug configuration for the client
|
||||
http_options: HTTP options for the client
|
||||
posthog_client: PostHog client for tracking usage
|
||||
posthog_client: Insights client for tracking usage
|
||||
posthog_distinct_id: Default distinct ID for all calls (can be overridden per call)
|
||||
posthog_properties: Default properties for all calls (can be overridden per call)
|
||||
posthog_privacy_mode: Default privacy mode for all calls (can be overridden per call)
|
||||
@@ -84,7 +84,7 @@ class Client:
|
||||
self._ph_client = posthog_client or setup()
|
||||
|
||||
if self._ph_client is None:
|
||||
raise ValueError("posthog_client is required for PostHog tracking")
|
||||
raise ValueError("posthog_client is required for Insights tracking")
|
||||
|
||||
self.models = Models(
|
||||
api_key=api_key,
|
||||
@@ -105,10 +105,10 @@ class Client:
|
||||
|
||||
class Models:
|
||||
"""
|
||||
Models interface that mimics genai.Client().models with PostHog tracking.
|
||||
Models interface that mimics genai.Client().models with Insights tracking.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient # Not None after __init__ validation
|
||||
_ph_client: InsightsClient # Not None after __init__ validation
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -119,7 +119,7 @@ class Models:
|
||||
location: Optional[str] = None,
|
||||
debug_config: Optional[Any] = None,
|
||||
http_options: Optional[Any] = None,
|
||||
posthog_client: Optional[PostHogClient] = None,
|
||||
posthog_client: Optional[InsightsClient] = None,
|
||||
posthog_distinct_id: Optional[str] = None,
|
||||
posthog_properties: Optional[Dict[str, Any]] = None,
|
||||
posthog_privacy_mode: bool = False,
|
||||
@@ -135,7 +135,7 @@ class Models:
|
||||
location: GCP location for Vertex AI
|
||||
debug_config: Debug configuration for the client
|
||||
http_options: HTTP options for the client
|
||||
posthog_client: PostHog client for tracking usage
|
||||
posthog_client: Insights client for tracking usage
|
||||
posthog_distinct_id: Default distinct ID for all calls
|
||||
posthog_properties: Default properties for all calls
|
||||
posthog_privacy_mode: Default privacy mode for all calls
|
||||
@@ -146,9 +146,9 @@ class Models:
|
||||
self._ph_client = posthog_client or setup()
|
||||
|
||||
if self._ph_client is None:
|
||||
raise ValueError("posthog_client is required for PostHog tracking")
|
||||
raise ValueError("posthog_client is required for Insights tracking")
|
||||
|
||||
# Store default PostHog settings
|
||||
# Store default Insights settings
|
||||
self._default_distinct_id = posthog_distinct_id
|
||||
self._default_properties = posthog_properties or {}
|
||||
self._default_privacy_mode = posthog_privacy_mode
|
||||
@@ -204,7 +204,7 @@ class Models:
|
||||
call_privacy_mode: Optional[bool],
|
||||
call_groups: Optional[Dict[str, Any]],
|
||||
):
|
||||
"""Merge call-level PostHog parameters with client defaults."""
|
||||
"""Merge call-level Insights parameters with client defaults."""
|
||||
|
||||
# Use call-level values if provided, otherwise fall back to defaults
|
||||
distinct_id = (
|
||||
@@ -242,10 +242,10 @@ class Models:
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""
|
||||
Generate content using Gemini's API while tracking usage in PostHog.
|
||||
Generate content using Gemini's API while tracking usage in Insights.
|
||||
|
||||
This method signature exactly matches genai.Client().models.generate_content()
|
||||
with additional PostHog tracking parameters.
|
||||
with additional Insights tracking parameters.
|
||||
|
||||
Args:
|
||||
model: The model to use (e.g., 'gemini-2.0-flash')
|
||||
@@ -258,7 +258,7 @@ class Models:
|
||||
**kwargs: Arguments passed to Gemini's generate_content
|
||||
"""
|
||||
|
||||
# Merge PostHog parameters
|
||||
# Merge Insights parameters
|
||||
distinct_id, trace_id, properties, privacy_mode, groups = (
|
||||
self._merge_posthog_params(
|
||||
posthog_distinct_id,
|
||||
@@ -380,7 +380,7 @@ class Models:
|
||||
capture_streaming_event(self._ph_client, event_data)
|
||||
|
||||
def _format_input(self, contents, **kwargs):
|
||||
"""Format input contents for PostHog tracking"""
|
||||
"""Format input contents for Insights tracking"""
|
||||
|
||||
# Create kwargs dict with contents for merge_system_prompt
|
||||
input_kwargs = {"contents": contents, **kwargs}
|
||||
@@ -397,7 +397,7 @@ class Models:
|
||||
posthog_groups: Optional[Dict[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Merge PostHog parameters
|
||||
# Merge Insights parameters
|
||||
distinct_id, trace_id, properties, privacy_mode, groups = (
|
||||
self._merge_posthog_params(
|
||||
posthog_distinct_id,
|
||||
|
||||
@@ -13,7 +13,7 @@ except ImportError:
|
||||
"Please install the Google Gemini SDK to use this feature: 'pip install google-genai'"
|
||||
)
|
||||
|
||||
from posthog import setup
|
||||
from hanzo_insights import setup
|
||||
from hanzo_insights.ai.utils import (
|
||||
call_llm_and_track_usage_async,
|
||||
capture_streaming_event,
|
||||
@@ -25,12 +25,12 @@ from hanzo_insights.ai.gemini.gemini_converter import (
|
||||
format_gemini_streaming_output,
|
||||
)
|
||||
from hanzo_insights.ai.sanitization import sanitize_gemini
|
||||
from hanzo_insights.client import Client as PostHogClient
|
||||
from hanzo_insights.client import Client as InsightsClient
|
||||
|
||||
|
||||
class AsyncClient:
|
||||
"""
|
||||
An async drop-in replacement for genai.Client that automatically sends LLM usage events to PostHog.
|
||||
An async drop-in replacement for genai.Client that automatically sends LLM usage events to Insights.
|
||||
|
||||
Usage:
|
||||
client = AsyncClient(
|
||||
@@ -46,7 +46,7 @@ class AsyncClient:
|
||||
)
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -57,7 +57,7 @@ class AsyncClient:
|
||||
location: Optional[str] = None,
|
||||
debug_config: Optional[Any] = None,
|
||||
http_options: Optional[Any] = None,
|
||||
posthog_client: Optional[PostHogClient] = None,
|
||||
posthog_client: Optional[InsightsClient] = None,
|
||||
posthog_distinct_id: Optional[str] = None,
|
||||
posthog_properties: Optional[Dict[str, Any]] = None,
|
||||
posthog_privacy_mode: bool = False,
|
||||
@@ -73,7 +73,7 @@ class AsyncClient:
|
||||
location: GCP location for Vertex AI
|
||||
debug_config: Debug configuration for the client
|
||||
http_options: HTTP options for the client
|
||||
posthog_client: PostHog client for tracking usage
|
||||
posthog_client: Insights client for tracking usage
|
||||
posthog_distinct_id: Default distinct ID for all calls (can be overridden per call)
|
||||
posthog_properties: Default properties for all calls (can be overridden per call)
|
||||
posthog_privacy_mode: Default privacy mode for all calls (can be overridden per call)
|
||||
@@ -84,7 +84,7 @@ class AsyncClient:
|
||||
self._ph_client = posthog_client or setup()
|
||||
|
||||
if self._ph_client is None:
|
||||
raise ValueError("posthog_client is required for PostHog tracking")
|
||||
raise ValueError("posthog_client is required for Insights tracking")
|
||||
|
||||
self.models = AsyncModels(
|
||||
api_key=api_key,
|
||||
@@ -105,10 +105,10 @@ class AsyncClient:
|
||||
|
||||
class AsyncModels:
|
||||
"""
|
||||
Async Models interface that mimics genai.Client().aio.models with PostHog tracking.
|
||||
Async Models interface that mimics genai.Client().aio.models with Insights tracking.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient # Not None after __init__ validation
|
||||
_ph_client: InsightsClient # Not None after __init__ validation
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -119,7 +119,7 @@ class AsyncModels:
|
||||
location: Optional[str] = None,
|
||||
debug_config: Optional[Any] = None,
|
||||
http_options: Optional[Any] = None,
|
||||
posthog_client: Optional[PostHogClient] = None,
|
||||
posthog_client: Optional[InsightsClient] = None,
|
||||
posthog_distinct_id: Optional[str] = None,
|
||||
posthog_properties: Optional[Dict[str, Any]] = None,
|
||||
posthog_privacy_mode: bool = False,
|
||||
@@ -135,7 +135,7 @@ class AsyncModels:
|
||||
location: GCP location for Vertex AI
|
||||
debug_config: Debug configuration for the client
|
||||
http_options: HTTP options for the client
|
||||
posthog_client: PostHog client for tracking usage
|
||||
posthog_client: Insights client for tracking usage
|
||||
posthog_distinct_id: Default distinct ID for all calls
|
||||
posthog_properties: Default properties for all calls
|
||||
posthog_privacy_mode: Default privacy mode for all calls
|
||||
@@ -146,9 +146,9 @@ class AsyncModels:
|
||||
self._ph_client = posthog_client or setup()
|
||||
|
||||
if self._ph_client is None:
|
||||
raise ValueError("posthog_client is required for PostHog tracking")
|
||||
raise ValueError("posthog_client is required for Insights tracking")
|
||||
|
||||
# Store default PostHog settings
|
||||
# Store default Insights settings
|
||||
self._default_distinct_id = posthog_distinct_id
|
||||
self._default_properties = posthog_properties or {}
|
||||
self._default_privacy_mode = posthog_privacy_mode
|
||||
@@ -204,7 +204,7 @@ class AsyncModels:
|
||||
call_privacy_mode: Optional[bool],
|
||||
call_groups: Optional[Dict[str, Any]],
|
||||
):
|
||||
"""Merge call-level PostHog parameters with client defaults."""
|
||||
"""Merge call-level Insights parameters with client defaults."""
|
||||
|
||||
# Use call-level values if provided, otherwise fall back to defaults
|
||||
distinct_id = (
|
||||
@@ -242,10 +242,10 @@ class AsyncModels:
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""
|
||||
Generate content using Gemini's API while tracking usage in PostHog.
|
||||
Generate content using Gemini's API while tracking usage in Insights.
|
||||
|
||||
This method signature exactly matches genai.Client().aio.models.generate_content()
|
||||
with additional PostHog tracking parameters.
|
||||
with additional Insights tracking parameters.
|
||||
|
||||
Args:
|
||||
model: The model to use (e.g., 'gemini-2.0-flash')
|
||||
@@ -258,7 +258,7 @@ class AsyncModels:
|
||||
**kwargs: Arguments passed to Gemini's generate_content
|
||||
"""
|
||||
|
||||
# Merge PostHog parameters
|
||||
# Merge Insights parameters
|
||||
distinct_id, trace_id, properties, privacy_mode, groups = (
|
||||
self._merge_posthog_params(
|
||||
posthog_distinct_id,
|
||||
@@ -383,7 +383,7 @@ class AsyncModels:
|
||||
capture_streaming_event(self._ph_client, event_data)
|
||||
|
||||
def _format_input(self, contents, **kwargs):
|
||||
"""Format input contents for PostHog tracking"""
|
||||
"""Format input contents for Insights tracking"""
|
||||
|
||||
# Create kwargs dict with contents for merge_system_prompt
|
||||
input_kwargs = {"contents": contents, **kwargs}
|
||||
@@ -400,7 +400,7 @@ class AsyncModels:
|
||||
posthog_groups: Optional[Dict[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Merge PostHog parameters
|
||||
# Merge Insights parameters
|
||||
distinct_id, trace_id, properties, privacy_mode, groups = (
|
||||
self._merge_posthog_params(
|
||||
posthog_distinct_id,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Gemini-specific conversion utilities.
|
||||
|
||||
This module handles the conversion of Gemini API responses and inputs
|
||||
into standardized formats for PostHog tracking.
|
||||
into standardized formats for Insights tracking.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional, TypedDict, Union
|
||||
@@ -362,7 +362,7 @@ def format_gemini_input_with_system(
|
||||
|
||||
def format_gemini_input(contents: Any) -> List[FormattedMessage]:
|
||||
"""
|
||||
Format Gemini input contents into standardized message format for PostHog tracking.
|
||||
Format Gemini input contents into standardized message format for Insights tracking.
|
||||
|
||||
This function handles various input formats:
|
||||
- String inputs
|
||||
|
||||
@@ -41,7 +41,7 @@ from langchain_core.messages import (
|
||||
from langchain_core.outputs import ChatGeneration, LLMResult
|
||||
from pydantic import BaseModel
|
||||
|
||||
from posthog import setup
|
||||
from hanzo_insights import setup
|
||||
from hanzo_insights.ai.sanitization import sanitize_langchain
|
||||
from hanzo_insights.ai.utils import get_model_params, with_privacy_mode
|
||||
from hanzo_insights.client import Client
|
||||
@@ -80,7 +80,7 @@ class GenerationMetadata(SpanMetadata):
|
||||
tools: Optional[List[Dict[str, Any]]] = None
|
||||
"""Tools provided to the model."""
|
||||
posthog_properties: Optional[Dict[str, Any]] = None
|
||||
"""PostHog properties of the run."""
|
||||
"""Insights properties of the run."""
|
||||
|
||||
|
||||
RunMetadata = Union[SpanMetadata, GenerationMetadata]
|
||||
@@ -89,11 +89,11 @@ RunMetadataStorage = Dict[UUID, RunMetadata]
|
||||
|
||||
class CallbackHandler(BaseCallbackHandler):
|
||||
"""
|
||||
The PostHog LLM observability callback handler for LangChain.
|
||||
The Insights LLM observability callback handler for LangChain.
|
||||
"""
|
||||
|
||||
_ph_client: Client
|
||||
"""PostHog client instance."""
|
||||
"""Insights client instance."""
|
||||
|
||||
_distinct_id: Optional[Union[str, int, UUID]]
|
||||
"""Distinct ID of the user to associate the trace with."""
|
||||
@@ -131,12 +131,12 @@ class CallbackHandler(BaseCallbackHandler):
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
client: PostHog client instance.
|
||||
client: Insights client instance.
|
||||
distinct_id: Optional distinct ID of the user to associate the trace with.
|
||||
trace_id: Optional trace ID to use for the event.
|
||||
properties: Optional additional metadata to use for the trace.
|
||||
privacy_mode: Whether to redact the input and output of the trace.
|
||||
groups: Optional additional PostHog groups to use for the trace.
|
||||
groups: Optional additional Insights groups to use for the trace.
|
||||
"""
|
||||
self._ph_client = client or setup()
|
||||
self._distinct_id = distinct_id
|
||||
|
||||
@@ -24,18 +24,18 @@ from hanzo_insights.ai.openai.openai_converter import (
|
||||
accumulate_openai_tool_calls,
|
||||
)
|
||||
from hanzo_insights.ai.sanitization import sanitize_openai, sanitize_openai_response
|
||||
from hanzo_insights.client import Client as PostHogClient
|
||||
from posthog import setup
|
||||
from hanzo_insights.client import Client as InsightsClient
|
||||
from hanzo_insights import setup
|
||||
|
||||
|
||||
class OpenAI(openai.OpenAI):
|
||||
"""
|
||||
A wrapper around the OpenAI SDK that automatically sends LLM usage events to PostHog.
|
||||
A wrapper around the OpenAI SDK that automatically sends LLM usage events to Insights.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(self, posthog_client: Optional[PostHogClient] = None, **kwargs):
|
||||
def __init__(self, posthog_client: Optional[InsightsClient] = None, **kwargs):
|
||||
"""
|
||||
Args:
|
||||
api_key: OpenAI API key.
|
||||
@@ -67,7 +67,7 @@ class OpenAI(openai.OpenAI):
|
||||
|
||||
|
||||
class WrappedResponses:
|
||||
"""Wrapper for OpenAI responses that tracks usage in PostHog."""
|
||||
"""Wrapper for OpenAI responses that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: OpenAI, original_responses):
|
||||
self._client = client
|
||||
@@ -232,7 +232,7 @@ class WrappedResponses:
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""
|
||||
Parse structured output using OpenAI's 'responses.parse' method, but also track usage in PostHog.
|
||||
Parse structured output using OpenAI's 'responses.parse' method, but also track usage in Insights.
|
||||
|
||||
Args:
|
||||
posthog_distinct_id: Optional ID to associate with the usage event.
|
||||
@@ -260,7 +260,7 @@ class WrappedResponses:
|
||||
|
||||
|
||||
class WrappedChat:
|
||||
"""Wrapper for OpenAI chat that tracks usage in PostHog."""
|
||||
"""Wrapper for OpenAI chat that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: OpenAI, original_chat):
|
||||
self._client = client
|
||||
@@ -276,7 +276,7 @@ class WrappedChat:
|
||||
|
||||
|
||||
class WrappedCompletions:
|
||||
"""Wrapper for OpenAI chat completions that tracks usage in PostHog."""
|
||||
"""Wrapper for OpenAI chat completions that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: OpenAI, original_completions):
|
||||
self._client = client
|
||||
@@ -451,7 +451,7 @@ class WrappedCompletions:
|
||||
|
||||
|
||||
class WrappedEmbeddings:
|
||||
"""Wrapper for OpenAI embeddings that tracks usage in PostHog."""
|
||||
"""Wrapper for OpenAI embeddings that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: OpenAI, original_embeddings):
|
||||
self._client = client
|
||||
@@ -471,7 +471,7 @@ class WrappedEmbeddings:
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""
|
||||
Create an embedding using OpenAI's 'embeddings.create' method, but also track usage in PostHog.
|
||||
Create an embedding using OpenAI's 'embeddings.create' method, but also track usage in Insights.
|
||||
|
||||
Args:
|
||||
posthog_distinct_id: Optional ID to associate with the usage event.
|
||||
@@ -535,7 +535,7 @@ class WrappedEmbeddings:
|
||||
|
||||
|
||||
class WrappedBeta:
|
||||
"""Wrapper for OpenAI beta features that tracks usage in PostHog."""
|
||||
"""Wrapper for OpenAI beta features that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: OpenAI, original_beta):
|
||||
self._client = client
|
||||
@@ -551,7 +551,7 @@ class WrappedBeta:
|
||||
|
||||
|
||||
class WrappedBetaChat:
|
||||
"""Wrapper for OpenAI beta chat that tracks usage in PostHog."""
|
||||
"""Wrapper for OpenAI beta chat that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: OpenAI, original_beta_chat):
|
||||
self._client = client
|
||||
@@ -567,7 +567,7 @@ class WrappedBetaChat:
|
||||
|
||||
|
||||
class WrappedBetaCompletions:
|
||||
"""Wrapper for OpenAI beta chat completions that tracks usage in PostHog."""
|
||||
"""Wrapper for OpenAI beta chat completions that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: OpenAI, original_beta_completions):
|
||||
self._client = client
|
||||
|
||||
@@ -11,7 +11,7 @@ except ImportError:
|
||||
"Please install the OpenAI SDK to use this feature: 'pip install openai'"
|
||||
)
|
||||
|
||||
from posthog import setup
|
||||
from hanzo_insights import setup
|
||||
from hanzo_insights.ai.utils import (
|
||||
call_llm_and_track_usage_async,
|
||||
extract_available_tool_calls,
|
||||
@@ -27,17 +27,17 @@ from hanzo_insights.ai.openai.openai_converter import (
|
||||
format_openai_streaming_output,
|
||||
)
|
||||
from hanzo_insights.ai.sanitization import sanitize_openai, sanitize_openai_response
|
||||
from hanzo_insights.client import Client as PostHogClient
|
||||
from hanzo_insights.client import Client as InsightsClient
|
||||
|
||||
|
||||
class AsyncOpenAI(openai.AsyncOpenAI):
|
||||
"""
|
||||
An async wrapper around the OpenAI SDK that automatically sends LLM usage events to PostHog.
|
||||
An async wrapper around the OpenAI SDK that automatically sends LLM usage events to Insights.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(self, posthog_client: Optional[PostHogClient] = None, **kwargs):
|
||||
def __init__(self, posthog_client: Optional[InsightsClient] = None, **kwargs):
|
||||
"""
|
||||
Args:
|
||||
api_key: OpenAI API key.
|
||||
@@ -70,7 +70,7 @@ class AsyncOpenAI(openai.AsyncOpenAI):
|
||||
|
||||
|
||||
class WrappedResponses:
|
||||
"""Async wrapper for OpenAI responses that tracks usage in PostHog."""
|
||||
"""Async wrapper for OpenAI responses that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: AsyncOpenAI, original_responses):
|
||||
self._client = client
|
||||
@@ -260,7 +260,7 @@ class WrappedResponses:
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""
|
||||
Parse structured output using OpenAI's 'responses.parse' method, but also track usage in PostHog.
|
||||
Parse structured output using OpenAI's 'responses.parse' method, but also track usage in Insights.
|
||||
|
||||
Args:
|
||||
posthog_distinct_id: Optional ID to associate with the usage event.
|
||||
@@ -288,7 +288,7 @@ class WrappedResponses:
|
||||
|
||||
|
||||
class WrappedChat:
|
||||
"""Async wrapper for OpenAI chat that tracks usage in PostHog."""
|
||||
"""Async wrapper for OpenAI chat that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: AsyncOpenAI, original_chat):
|
||||
self._client = client
|
||||
@@ -304,7 +304,7 @@ class WrappedChat:
|
||||
|
||||
|
||||
class WrappedCompletions:
|
||||
"""Async wrapper for OpenAI chat completions that tracks usage in PostHog."""
|
||||
"""Async wrapper for OpenAI chat completions that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: AsyncOpenAI, original_completions):
|
||||
self._client = client
|
||||
@@ -504,7 +504,7 @@ class WrappedCompletions:
|
||||
|
||||
|
||||
class WrappedEmbeddings:
|
||||
"""Async wrapper for OpenAI embeddings that tracks usage in PostHog."""
|
||||
"""Async wrapper for OpenAI embeddings that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: AsyncOpenAI, original_embeddings):
|
||||
self._client = client
|
||||
@@ -525,7 +525,7 @@ class WrappedEmbeddings:
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""
|
||||
Create an embedding using OpenAI's 'embeddings.create' method, but also track usage in PostHog.
|
||||
Create an embedding using OpenAI's 'embeddings.create' method, but also track usage in Insights.
|
||||
|
||||
Args:
|
||||
posthog_distinct_id: Optional ID to associate with the usage event.
|
||||
@@ -590,7 +590,7 @@ class WrappedEmbeddings:
|
||||
|
||||
|
||||
class WrappedBeta:
|
||||
"""Async wrapper for OpenAI beta features that tracks usage in PostHog."""
|
||||
"""Async wrapper for OpenAI beta features that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: AsyncOpenAI, original_beta):
|
||||
self._client = client
|
||||
@@ -607,7 +607,7 @@ class WrappedBeta:
|
||||
|
||||
|
||||
class WrappedBetaChat:
|
||||
"""Async wrapper for OpenAI beta chat that tracks usage in PostHog."""
|
||||
"""Async wrapper for OpenAI beta chat that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: AsyncOpenAI, original_beta_chat):
|
||||
self._client = client
|
||||
@@ -624,7 +624,7 @@ class WrappedBetaChat:
|
||||
|
||||
|
||||
class WrappedBetaCompletions:
|
||||
"""Async wrapper for OpenAI beta chat completions that tracks usage in PostHog."""
|
||||
"""Async wrapper for OpenAI beta chat completions that tracks usage in Insights."""
|
||||
|
||||
def __init__(self, client: AsyncOpenAI, original_beta_completions):
|
||||
self._client = client
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
OpenAI-specific conversion utilities.
|
||||
|
||||
This module handles the conversion of OpenAI API responses and inputs
|
||||
into standardized formats for PostHog tracking. It supports both
|
||||
into standardized formats for Insights tracking. It supports both
|
||||
Chat Completions API and Responses API formats.
|
||||
"""
|
||||
|
||||
@@ -753,7 +753,7 @@ def format_openai_streaming_input(
|
||||
api_type: Either "chat" or "responses"
|
||||
|
||||
Returns:
|
||||
Formatted input ready for PostHog tracking
|
||||
Formatted input ready for Insights tracking
|
||||
"""
|
||||
from hanzo_insights.ai.utils import merge_system_prompt
|
||||
|
||||
|
||||
@@ -17,18 +17,18 @@ from hanzo_insights.ai.openai.openai_async import WrappedEmbeddings as AsyncWrap
|
||||
from hanzo_insights.ai.openai.openai_async import WrappedResponses as AsyncWrappedResponses
|
||||
from typing import Optional
|
||||
|
||||
from hanzo_insights.client import Client as PostHogClient
|
||||
from posthog import setup
|
||||
from hanzo_insights.client import Client as InsightsClient
|
||||
from hanzo_insights import setup
|
||||
|
||||
|
||||
class AzureOpenAI(openai.AzureOpenAI):
|
||||
"""
|
||||
A wrapper around the Azure OpenAI SDK that automatically sends LLM usage events to PostHog.
|
||||
A wrapper around the Azure OpenAI SDK that automatically sends LLM usage events to Insights.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(self, posthog_client: Optional[PostHogClient] = None, **kwargs):
|
||||
def __init__(self, posthog_client: Optional[InsightsClient] = None, **kwargs):
|
||||
"""
|
||||
Args:
|
||||
api_key: Azure OpenAI API key.
|
||||
@@ -61,12 +61,12 @@ class AzureOpenAI(openai.AzureOpenAI):
|
||||
|
||||
class AsyncAzureOpenAI(openai.AsyncAzureOpenAI):
|
||||
"""
|
||||
An async wrapper around the Azure OpenAI SDK that automatically sends LLM usage events to PostHog.
|
||||
An async wrapper around the Azure OpenAI SDK that automatically sends LLM usage events to Insights.
|
||||
"""
|
||||
|
||||
_ph_client: PostHogClient
|
||||
_ph_client: InsightsClient
|
||||
|
||||
def __init__(self, posthog_client: Optional[PostHogClient] = None, **kwargs):
|
||||
def __init__(self, posthog_client: Optional[InsightsClient] = None, **kwargs):
|
||||
"""
|
||||
Args:
|
||||
api_key: Azure OpenAI API key.
|
||||
|
||||
@@ -14,9 +14,9 @@ except ImportError:
|
||||
"Please install the OpenAI Agents SDK to use this feature: 'pip install openai-agents'"
|
||||
)
|
||||
|
||||
from hanzo_insights.ai.openai_agents.processor import PostHogTracingProcessor
|
||||
from hanzo_insights.ai.openai_agents.processor import InsightsTracingProcessor, PostHogTracingProcessor
|
||||
|
||||
__all__ = ["PostHogTracingProcessor", "instrument"]
|
||||
__all__ = ["InsightsTracingProcessor", "PostHogTracingProcessor", "instrument"]
|
||||
|
||||
|
||||
def instrument(
|
||||
@@ -25,23 +25,23 @@ def instrument(
|
||||
privacy_mode: bool = False,
|
||||
groups: Optional[Dict[str, Any]] = None,
|
||||
properties: Optional[Dict[str, Any]] = None,
|
||||
) -> PostHogTracingProcessor:
|
||||
) -> InsightsTracingProcessor:
|
||||
"""
|
||||
One-liner to instrument OpenAI Agents SDK with PostHog tracing.
|
||||
One-liner to instrument OpenAI Agents SDK with Hanzo Insights tracing.
|
||||
|
||||
This registers a PostHogTracingProcessor with the OpenAI Agents SDK,
|
||||
This registers an InsightsTracingProcessor with the OpenAI Agents SDK,
|
||||
automatically capturing traces, spans, and LLM generations.
|
||||
|
||||
Args:
|
||||
client: Optional PostHog client instance. If not provided, uses the default client.
|
||||
client: Optional Insights client instance. If not provided, uses the default client.
|
||||
distinct_id: Optional distinct ID to associate with all traces.
|
||||
Can also be a callable that takes a trace and returns a distinct ID.
|
||||
privacy_mode: If True, redacts input/output content from events.
|
||||
groups: Optional PostHog groups to associate with events.
|
||||
groups: Optional Insights groups to associate with events.
|
||||
properties: Optional additional properties to include with all events.
|
||||
|
||||
Returns:
|
||||
PostHogTracingProcessor: The registered processor instance.
|
||||
InsightsTracingProcessor: The registered processor instance.
|
||||
|
||||
Example:
|
||||
```python
|
||||
@@ -57,7 +57,7 @@ def instrument(
|
||||
properties={"environment": "production"}
|
||||
)
|
||||
|
||||
# Now run agents as normal - traces automatically sent to PostHog
|
||||
# Now run agents as normal - traces automatically sent to Insights
|
||||
from agents import Agent, Runner
|
||||
agent = Agent(name="Assistant", instructions="You are helpful.")
|
||||
result = Runner.run_sync(agent, "Hello!")
|
||||
@@ -65,7 +65,7 @@ def instrument(
|
||||
"""
|
||||
from agents.tracing import add_trace_processor
|
||||
|
||||
processor = PostHogTracingProcessor(
|
||||
processor = InsightsTracingProcessor(
|
||||
client=client,
|
||||
distinct_id=distinct_id,
|
||||
privacy_mode=privacy_mode,
|
||||
|
||||
@@ -20,7 +20,7 @@ from agents.tracing.span_data import (
|
||||
TranscriptionSpanData,
|
||||
)
|
||||
|
||||
from posthog import setup
|
||||
from hanzo_insights import setup
|
||||
from hanzo_insights.client import Client
|
||||
|
||||
log = logging.getLogger("hanzo_insights")
|
||||
@@ -53,27 +53,27 @@ def _parse_iso_timestamp(iso_str: Optional[str]) -> Optional[float]:
|
||||
return None
|
||||
|
||||
|
||||
class PostHogTracingProcessor(TracingProcessor):
|
||||
class InsightsTracingProcessor(TracingProcessor):
|
||||
"""
|
||||
A tracing processor that sends OpenAI Agents SDK traces to PostHog.
|
||||
A tracing processor that sends OpenAI Agents SDK traces to Hanzo Insights.
|
||||
|
||||
This processor implements the TracingProcessor interface from the OpenAI Agents SDK
|
||||
and maps agent traces, spans, and generations to PostHog's LLM analytics events.
|
||||
and maps agent traces, spans, and generations to Insights LLM analytics events.
|
||||
|
||||
Example:
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
from agents.tracing import add_trace_processor
|
||||
from hanzo_insights.ai.openai_agents import PostHogTracingProcessor
|
||||
from hanzo_insights.ai.openai_agents import InsightsTracingProcessor
|
||||
|
||||
# Create and register the processor
|
||||
processor = PostHogTracingProcessor(
|
||||
processor = InsightsTracingProcessor(
|
||||
distinct_id="user@example.com",
|
||||
privacy_mode=False,
|
||||
)
|
||||
add_trace_processor(processor)
|
||||
|
||||
# Run agents as normal - traces automatically sent to PostHog
|
||||
# Run agents as normal - traces automatically sent to Insights
|
||||
agent = Agent(name="Assistant", instructions="You are helpful.")
|
||||
result = Runner.run_sync(agent, "Hello!")
|
||||
```
|
||||
@@ -88,14 +88,14 @@ class PostHogTracingProcessor(TracingProcessor):
|
||||
properties: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""
|
||||
Initialize the PostHog tracing processor.
|
||||
Initialize the Insights tracing processor.
|
||||
|
||||
Args:
|
||||
client: Optional PostHog client instance. If not provided, uses the default client.
|
||||
client: Optional Insights client instance. If not provided, uses the default client.
|
||||
distinct_id: Either a string distinct ID or a callable that takes a Trace
|
||||
and returns a distinct ID. If not provided, uses the trace_id.
|
||||
privacy_mode: If True, redacts input/output content from events.
|
||||
groups: Optional PostHog groups to associate with all events.
|
||||
groups: Optional Insights groups to associate with all events.
|
||||
properties: Optional additional properties to include with all events.
|
||||
"""
|
||||
self._client = client or setup()
|
||||
@@ -173,7 +173,7 @@ class PostHogTracingProcessor(TracingProcessor):
|
||||
properties: Dict[str, Any],
|
||||
distinct_id: Optional[str] = None,
|
||||
) -> None:
|
||||
"""Capture an event to PostHog with error handling.
|
||||
"""Capture an event to Insights with error handling.
|
||||
|
||||
Args:
|
||||
distinct_id: The resolved distinct ID. When the user didn't provide
|
||||
@@ -199,7 +199,7 @@ class PostHogTracingProcessor(TracingProcessor):
|
||||
groups=self._groups,
|
||||
)
|
||||
except Exception as e:
|
||||
log.debug(f"Failed to capture PostHog event: {e}")
|
||||
log.debug(f"Failed to capture Insights event: {e}")
|
||||
|
||||
def on_trace_start(self, trace: Trace) -> None:
|
||||
"""Called when a new trace begins. Stores metadata for spans; the $ai_trace event is emitted in on_trace_end."""
|
||||
@@ -848,7 +848,7 @@ class PostHogTracingProcessor(TracingProcessor):
|
||||
self._span_start_times.clear()
|
||||
self._trace_metadata.clear()
|
||||
|
||||
# Flush the PostHog client if possible
|
||||
# Flush the Insights client if possible
|
||||
if hasattr(self._client, "flush") and callable(self._client.flush):
|
||||
self._client.flush()
|
||||
except Exception as e:
|
||||
@@ -861,3 +861,7 @@ class PostHogTracingProcessor(TracingProcessor):
|
||||
self._client.flush()
|
||||
except Exception as e:
|
||||
log.debug(f"Error in force_flush: {e}")
|
||||
|
||||
|
||||
# Backward compatibility alias
|
||||
PostHogTracingProcessor = InsightsTracingProcessor
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Prompt management for PostHog AI SDK.
|
||||
Prompt management for Hanzo Insights AI SDK.
|
||||
|
||||
Fetch and compile LLM prompts from PostHog with caching and fallback support.
|
||||
Fetch and compile LLM prompts from Insights with caching and fallback support.
|
||||
"""
|
||||
|
||||
import logging
|
||||
@@ -15,7 +15,7 @@ from hanzo_insights.utils import remove_trailing_slash
|
||||
|
||||
log = logging.getLogger("hanzo_insights")
|
||||
|
||||
APP_ENDPOINT = "https://us.hanzo_insights.com"
|
||||
APP_ENDPOINT = "https://us.posthog.com"
|
||||
DEFAULT_CACHE_TTL_SECONDS = 300 # 5 minutes
|
||||
|
||||
PromptVariables = Dict[str, Union[str, int, float, bool]]
|
||||
@@ -54,24 +54,24 @@ def _is_prompt_api_response(data: Any) -> bool:
|
||||
|
||||
class Prompts:
|
||||
"""
|
||||
Fetch and compile LLM prompts from PostHog.
|
||||
Fetch and compile LLM prompts from Insights.
|
||||
|
||||
Can be initialized with a PostHog client or with direct options.
|
||||
Can be initialized with a Insights client or with direct options.
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Insights
|
||||
from hanzo_insights.ai.prompts import Prompts
|
||||
|
||||
# With PostHog client
|
||||
posthog = Posthog('phc_xxx', host='https://us.hanzo_insights.com', personal_api_key='phx_xxx')
|
||||
prompts = Prompts(posthog)
|
||||
# With Insights client
|
||||
client = Insights('phc_xxx', host='https://us.posthog.com', personal_api_key='phx_xxx')
|
||||
prompts = Prompts(client)
|
||||
|
||||
# Or with direct options (no PostHog client needed)
|
||||
# Or with direct options (no Insights client needed)
|
||||
prompts = Prompts(
|
||||
personal_api_key='phx_xxx',
|
||||
project_api_key='phc_xxx',
|
||||
host='https://us.hanzo_insights.com',
|
||||
host='https://us.posthog.com',
|
||||
)
|
||||
|
||||
# Fetch with caching and fallback
|
||||
@@ -101,10 +101,10 @@ class Prompts:
|
||||
Initialize Prompts.
|
||||
|
||||
Args:
|
||||
posthog: PostHog client instance (optional if personal_api_key provided)
|
||||
posthog: Insights client instance (optional if personal_api_key provided)
|
||||
personal_api_key: Direct personal API key (optional if posthog provided)
|
||||
project_api_key: Direct project API key (optional if posthog provided)
|
||||
host: PostHog host (defaults to app endpoint)
|
||||
host: Insights host (defaults to app endpoint)
|
||||
default_cache_ttl_seconds: Default cache TTL (defaults to 300)
|
||||
"""
|
||||
self._default_cache_ttl_seconds = (
|
||||
@@ -132,7 +132,7 @@ class Prompts:
|
||||
version: Optional[int] = None,
|
||||
) -> str:
|
||||
"""
|
||||
Fetch a prompt by name from the PostHog API.
|
||||
Fetch a prompt by name from the Insights API.
|
||||
|
||||
Caching behavior:
|
||||
1. If cache is fresh, return cached value
|
||||
@@ -186,7 +186,7 @@ class Prompts:
|
||||
# 1. Return stale cache (with warning)
|
||||
if cached is not None:
|
||||
log.warning(
|
||||
"[PostHog Prompts] Failed to fetch %s, using stale cache: %s",
|
||||
"[Insights Prompts] Failed to fetch %s, using stale cache: %s",
|
||||
prompt_reference,
|
||||
error,
|
||||
)
|
||||
@@ -195,7 +195,7 @@ class Prompts:
|
||||
# 2. Return fallback (with warning)
|
||||
if fallback is not None:
|
||||
log.warning(
|
||||
"[PostHog Prompts] Failed to fetch %s, using fallback: %s",
|
||||
"[Insights Prompts] Failed to fetch %s, using fallback: %s",
|
||||
prompt_reference,
|
||||
error,
|
||||
)
|
||||
@@ -256,7 +256,7 @@ class Prompts:
|
||||
|
||||
def _fetch_prompt_from_api(self, name: str, version: Optional[int] = None) -> str:
|
||||
"""
|
||||
Fetch prompt from PostHog API.
|
||||
Fetch prompt from Insights API.
|
||||
|
||||
Endpoint:
|
||||
{host}/api/environments/@current/llm_prompts/name/{encoded_name}/
|
||||
@@ -275,12 +275,12 @@ class Prompts:
|
||||
"""
|
||||
if not self._personal_api_key:
|
||||
raise Exception(
|
||||
"[PostHog Prompts] personal_api_key is required to fetch prompts. "
|
||||
"[Insights Prompts] personal_api_key is required to fetch prompts. "
|
||||
"Please provide it when initializing the Prompts instance."
|
||||
)
|
||||
if not self._project_api_key:
|
||||
raise Exception(
|
||||
"[PostHog Prompts] project_api_key is required to fetch prompts. "
|
||||
"[Insights Prompts] project_api_key is required to fetch prompts. "
|
||||
"Please provide it when initializing the Prompts instance."
|
||||
)
|
||||
|
||||
@@ -302,28 +302,28 @@ class Prompts:
|
||||
|
||||
if not response.ok:
|
||||
if response.status_code == 404:
|
||||
raise Exception(f"[PostHog Prompts] {prompt_label} not found")
|
||||
raise Exception(f"[Insights Prompts] {prompt_label} not found")
|
||||
|
||||
if response.status_code == 403:
|
||||
raise Exception(
|
||||
f"[PostHog Prompts] Access denied for {prompt_reference}. "
|
||||
f"[Insights Prompts] Access denied for {prompt_reference}. "
|
||||
"Check that your personal_api_key has the correct permissions and the LLM prompts feature is enabled."
|
||||
)
|
||||
|
||||
raise Exception(
|
||||
f"[PostHog Prompts] Failed to fetch {prompt_label}: HTTP {response.status_code}"
|
||||
f"[Insights Prompts] Failed to fetch {prompt_label}: HTTP {response.status_code}"
|
||||
)
|
||||
|
||||
try:
|
||||
data = response.json()
|
||||
except Exception:
|
||||
raise Exception(
|
||||
f"[PostHog Prompts] Invalid response format for {prompt_label}"
|
||||
f"[Insights Prompts] Invalid response format for {prompt_label}"
|
||||
)
|
||||
|
||||
if not _is_prompt_api_response(data):
|
||||
raise Exception(
|
||||
f"[PostHog Prompts] Invalid response format for {prompt_label}"
|
||||
f"[Insights Prompts] Invalid response format for {prompt_label}"
|
||||
)
|
||||
|
||||
return data["prompt"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Common type definitions for PostHog AI SDK.
|
||||
Common type definitions for Insights AI SDK.
|
||||
|
||||
These types are used for formatting messages and responses across different AI providers
|
||||
(Anthropic, OpenAI, Gemini, etc.) to ensure consistency in tracking and data structure.
|
||||
@@ -41,10 +41,10 @@ FormattedContentItem = Union[
|
||||
|
||||
class FormattedMessage(TypedDict):
|
||||
"""
|
||||
Standardized message format for PostHog tracking.
|
||||
Standardized message format for Insights tracking.
|
||||
|
||||
Used across all providers to ensure consistent message structure
|
||||
when sending events to PostHog.
|
||||
when sending events to Insights.
|
||||
"""
|
||||
|
||||
role: str
|
||||
|
||||
+11
-11
@@ -2,7 +2,7 @@ import time
|
||||
import uuid
|
||||
from typing import Any, Callable, Dict, List, Optional, cast
|
||||
|
||||
from posthog import get_tags, identify_context, new_context, tag, contexts
|
||||
from hanzo_insights import get_tags, identify_context, new_context, tag, contexts
|
||||
from hanzo_insights.ai.sanitization import (
|
||||
sanitize_anthropic,
|
||||
sanitize_gemini,
|
||||
@@ -10,7 +10,7 @@ from hanzo_insights.ai.sanitization import (
|
||||
sanitize_openai,
|
||||
)
|
||||
from hanzo_insights.ai.types import FormattedMessage, StreamingEventData, TokenUsage
|
||||
from hanzo_insights.client import Client as PostHogClient
|
||||
from hanzo_insights.client import Client as InsightsClient
|
||||
|
||||
|
||||
_TOKEN_PROPERTY_KEYS = frozenset(
|
||||
@@ -40,7 +40,7 @@ def serialize_raw_usage(raw_usage: Any) -> Optional[Dict[str, Any]]:
|
||||
Convert raw provider usage objects to JSON-serializable dicts.
|
||||
|
||||
Handles Pydantic models (OpenAI/Anthropic) and protobuf-like objects (Gemini)
|
||||
with a fallback chain to ensure we never pass unserializable objects to PostHog.
|
||||
with a fallback chain to ensure we never pass unserializable objects to Insights.
|
||||
|
||||
Args:
|
||||
raw_usage: Raw usage object from provider SDK
|
||||
@@ -320,7 +320,7 @@ def merge_system_prompt(
|
||||
|
||||
def call_llm_and_track_usage(
|
||||
posthog_distinct_id: Optional[str],
|
||||
ph_client: PostHogClient,
|
||||
ph_client: InsightsClient,
|
||||
provider: str,
|
||||
posthog_trace_id: Optional[str],
|
||||
posthog_properties: Optional[Dict[str, Any]],
|
||||
@@ -469,7 +469,7 @@ def call_llm_and_track_usage(
|
||||
|
||||
async def call_llm_and_track_usage_async(
|
||||
posthog_distinct_id: Optional[str],
|
||||
ph_client: PostHogClient,
|
||||
ph_client: InsightsClient,
|
||||
provider: str,
|
||||
posthog_trace_id: Optional[str],
|
||||
posthog_properties: Optional[Dict[str, Any]],
|
||||
@@ -625,14 +625,14 @@ def sanitize_messages(data: Any, provider: str) -> Any:
|
||||
return data
|
||||
|
||||
|
||||
def with_privacy_mode(ph_client: PostHogClient, privacy_mode: bool, value: Any):
|
||||
def with_privacy_mode(ph_client: InsightsClient, privacy_mode: bool, value: Any):
|
||||
if ph_client.privacy_mode or privacy_mode:
|
||||
return None
|
||||
return value
|
||||
|
||||
|
||||
def capture_streaming_event(
|
||||
ph_client: PostHogClient,
|
||||
ph_client: InsightsClient,
|
||||
event_data: StreamingEventData,
|
||||
):
|
||||
"""
|
||||
@@ -642,15 +642,15 @@ def capture_streaming_event(
|
||||
All provider-specific formatting should be done BEFORE calling this function.
|
||||
|
||||
The function handles:
|
||||
- Building PostHog event properties
|
||||
- Building Insights event properties
|
||||
- Extracting and adding tools based on provider
|
||||
- Applying privacy mode
|
||||
- Adding special token fields (cache, reasoning)
|
||||
- Provider-specific fields (e.g., OpenAI instructions)
|
||||
- Sending the event to PostHog
|
||||
- Sending the event to Insights
|
||||
|
||||
Args:
|
||||
ph_client: PostHog client instance
|
||||
ph_client: Insights client instance
|
||||
event_data: Standardized streaming event data containing all necessary information
|
||||
"""
|
||||
trace_id = event_data.get("trace_id") or str(uuid.uuid4())
|
||||
@@ -747,7 +747,7 @@ def capture_streaming_event(
|
||||
if event_data.get("distinct_id") is None:
|
||||
event_properties["$process_person_profile"] = False
|
||||
|
||||
# Send event to PostHog
|
||||
# Send event to Insights
|
||||
if hasattr(ph_client, "capture"):
|
||||
ph_client.capture(
|
||||
distinct_id=event_data.get("distinct_id") or trace_id,
|
||||
|
||||
+15
-15
@@ -149,15 +149,15 @@ def no_throw(default_return=None):
|
||||
|
||||
class Client(object):
|
||||
"""
|
||||
This is the SDK reference for the PostHog Python SDK.
|
||||
This is the SDK reference for the Hanzo Insights Python SDK.
|
||||
You can learn more about example usage in the [Python SDK documentation](/docs/libraries/python).
|
||||
You can also follow [Flask](/docs/libraries/flask) and [Django](/docs/libraries/django)
|
||||
guides to integrate PostHog into your project.
|
||||
guides to integrate Insights into your project.
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import Posthog
|
||||
posthog = Posthog('<ph_project_api_key>', host='<ph_client_api_host>')
|
||||
from hanzo_insights import Insights
|
||||
client = Insights('<ph_project_api_key>', host='<ph_client_api_host>')
|
||||
hanzo_insights.debug = True
|
||||
if settings.TEST:
|
||||
hanzo_insights.disabled = True
|
||||
@@ -202,7 +202,7 @@ class Client(object):
|
||||
in_app_modules: list[str] | None = None,
|
||||
):
|
||||
"""
|
||||
Initialize a new PostHog client instance.
|
||||
Initialize a new Insights client instance.
|
||||
|
||||
Args:
|
||||
project_api_key: The project API key.
|
||||
@@ -211,9 +211,9 @@ class Client(object):
|
||||
|
||||
Examples:
|
||||
```python
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Insights
|
||||
|
||||
posthog = Posthog('<ph_project_api_key>', host='<ph_app_host>')
|
||||
client = Insights('<ph_project_api_key>', host='<ph_app_host>')
|
||||
```
|
||||
|
||||
Category:
|
||||
@@ -570,7 +570,7 @@ class Client(object):
|
||||
self, event: str, **kwargs: Unpack[OptionalCaptureArgs]
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Captures an event manually. [Learn about capture best practices](https://hanzo_insights.com/docs/product-analytics/capture-events)
|
||||
Captures an event manually. [Learn about capture best practices](https://insights.hanzo.ai/docs/product-analytics/capture-events)
|
||||
|
||||
Args:
|
||||
event: The event name to capture.
|
||||
@@ -589,7 +589,7 @@ class Client(object):
|
||||
```
|
||||
```python
|
||||
# Context usage
|
||||
from posthog import identify_context, new_context
|
||||
from hanzo_insights import identify_context, new_context
|
||||
with new_context():
|
||||
identify_context('distinct_id_of_the_user')
|
||||
hanzo_insights.capture('user_signed_up')
|
||||
@@ -1285,7 +1285,7 @@ class Client(object):
|
||||
self._fetch_feature_flags_from_api()
|
||||
|
||||
def _fetch_feature_flags_from_api(self):
|
||||
"""Fetch feature flags from the PostHog API."""
|
||||
"""Fetch feature flags from the Insights API."""
|
||||
try:
|
||||
# Store old flags to detect changes
|
||||
old_flags_by_key: dict[str, dict] = self.feature_flags_by_key or {}
|
||||
@@ -1334,7 +1334,7 @@ class Client(object):
|
||||
except APIError as e:
|
||||
if e.status == 401:
|
||||
self.log.error(
|
||||
"[FEATURE FLAGS] Error loading feature flags: To use feature flags, please set a valid personal_api_key. More information: https://hanzo_insights.com/docs/api/overview"
|
||||
"[FEATURE FLAGS] Error loading feature flags: To use feature flags, please set a valid personal_api_key. More information: https://insights.hanzo.ai/docs/api/overview"
|
||||
)
|
||||
self.feature_flags = []
|
||||
self.group_type_mapping = {}
|
||||
@@ -1348,11 +1348,11 @@ class Client(object):
|
||||
status=401,
|
||||
message="You are using a write-only key with feature flags. "
|
||||
"To use feature flags, please set a personal_api_key "
|
||||
"More information: https://hanzo_insights.com/docs/api/overview",
|
||||
"More information: https://insights.hanzo.ai/docs/api/overview",
|
||||
)
|
||||
elif e.status == 402:
|
||||
self.log.warning(
|
||||
"[FEATURE FLAGS] PostHog feature flags quota limited, resetting feature flag data. Learn more about billing limits at https://hanzo_insights.com/docs/billing/limits-alerts"
|
||||
"[FEATURE FLAGS] Insights feature flags quota limited, resetting feature flag data. Learn more about billing limits at https://insights.hanzo.ai/docs/billing/limits-alerts"
|
||||
)
|
||||
# Reset all feature flag data when quota limited
|
||||
self.feature_flags = []
|
||||
@@ -1366,7 +1366,7 @@ class Client(object):
|
||||
if self.debug:
|
||||
raise APIError(
|
||||
status=402,
|
||||
message="PostHog feature flags quota limited",
|
||||
message="Insights feature flags quota limited",
|
||||
)
|
||||
else:
|
||||
self.log.error(f"[FEATURE FLAGS] Error loading feature flags: {e}")
|
||||
@@ -2231,7 +2231,7 @@ class Client(object):
|
||||
"""Initialize feature flag cache for graceful degradation during service outages.
|
||||
|
||||
When enabled, the cache stores flag evaluation results and serves them as fallback
|
||||
when the PostHog API is unavailable. This ensures your application continues to
|
||||
when the Insights API is unavailable. This ensures your application continues to
|
||||
receive flag values even during outages.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -159,7 +159,7 @@ def new_context(
|
||||
Category:
|
||||
Contexts
|
||||
"""
|
||||
from posthog import capture_exception
|
||||
from hanzo_insights import capture_exception
|
||||
|
||||
current_context = _get_current_context()
|
||||
new_context = ContextScope(current_context, fresh, capture_exceptions, client)
|
||||
@@ -244,7 +244,7 @@ def set_context_session(session_id: str) -> None:
|
||||
Entering a fresh context will clear the context-level session ID.
|
||||
|
||||
Args:
|
||||
session_id: The session ID to associate with the current context and its children. See https://hanzo_insights.com/docs/data/sessions
|
||||
session_id: The session ID to associate with the current context and its children. See https://insights.hanzo.ai/docs/data/sessions
|
||||
|
||||
Category:
|
||||
Contexts
|
||||
@@ -377,7 +377,7 @@ def scoped(fresh: bool = False, capture_exceptions: bool = True):
|
||||
|
||||
Args:
|
||||
fresh: Whether to start with a fresh context (default: False)
|
||||
capture_exceptions: Whether to capture and track exceptions with posthog error tracking (default: True)
|
||||
capture_exceptions: Whether to capture and track exceptions with Insights error tracking (default: True)
|
||||
|
||||
Example:
|
||||
@hanzo_insights.scoped()
|
||||
|
||||
@@ -8,7 +8,7 @@ from typing import Optional
|
||||
from dateutil import parser
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from posthog import utils
|
||||
from hanzo_insights import utils
|
||||
from hanzo_insights.types import FlagValue
|
||||
from hanzo_insights.utils import convert_to_datetime_aware, is_valid_regex
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ functions) to share flag definitions and reduce API calls.
|
||||
|
||||
Usage:
|
||||
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Insights
|
||||
from hanzo_insights.flag_definition_cache import FlagDefinitionCacheProvider
|
||||
|
||||
cache = RedisFlagDefinitionCache(redis_client, "my-team")
|
||||
posthog = Posthog(
|
||||
client = Insights(
|
||||
"<project_api_key>",
|
||||
personal_api_key="<personal_api_key>",
|
||||
flag_definition_cache_provider=cache,
|
||||
@@ -63,7 +63,7 @@ class FlagDefinitionCacheProvider(Protocol):
|
||||
new definitions from the API. Store the data in your external cache
|
||||
and release any locks.
|
||||
|
||||
4. `shutdown()` - Called when the PostHog client shuts down. Release any
|
||||
4. `shutdown()` - Called when the Insights client shuts down. Release any
|
||||
distributed locks and clean up resources.
|
||||
|
||||
Error Handling:
|
||||
@@ -104,7 +104,7 @@ class FlagDefinitionCacheProvider(Protocol):
|
||||
|
||||
def on_flag_definitions_received(self, data: FlagDefinitionCacheData) -> None:
|
||||
"""
|
||||
Called after successfully receiving new flag definitions from PostHog.
|
||||
Called after successfully receiving new flag definitions from Insights.
|
||||
|
||||
Use this to store the data in your external cache and release any
|
||||
distributed locks acquired in `should_fetch_flag_definitions()`.
|
||||
@@ -117,7 +117,7 @@ class FlagDefinitionCacheProvider(Protocol):
|
||||
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Called when the PostHog client shuts down.
|
||||
Called when the Insights client shuts down.
|
||||
|
||||
Use this to release any distributed locks and clean up resources.
|
||||
This method is called even if `should_fetch_flag_definitions()`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from typing import TYPE_CHECKING, cast
|
||||
from posthog import contexts
|
||||
from hanzo_insights import contexts
|
||||
from hanzo_insights.client import Client
|
||||
|
||||
try:
|
||||
@@ -21,25 +21,26 @@ if TYPE_CHECKING:
|
||||
from typing import Callable, Dict, Any, Optional, Union, Awaitable # noqa: F401
|
||||
|
||||
|
||||
class PosthogContextMiddleware:
|
||||
class InsightsContextMiddleware:
|
||||
"""Middleware to automatically track Django requests.
|
||||
|
||||
This middleware wraps all calls with a posthog context. It attempts to extract the following from the request headers:
|
||||
- Session ID, (extracted from `X-POSTHOG-SESSION-ID`)
|
||||
- Distinct ID, (extracted from `X-POSTHOG-DISTINCT-ID`)
|
||||
This middleware wraps all calls with an Insights context. It attempts to extract the following from the request headers:
|
||||
- Session ID, (extracted from `X-INSIGHTS-SESSION-ID` or `X-POSTHOG-SESSION-ID`)
|
||||
- Distinct ID, (extracted from `X-INSIGHTS-DISTINCT-ID` or `X-POSTHOG-DISTINCT-ID`)
|
||||
- Request URL as $current_url
|
||||
- Request Method as $request_method
|
||||
|
||||
The context will also auto-capture exceptions and send them to PostHog, unless you disable it by setting
|
||||
`POSTHOG_MW_CAPTURE_EXCEPTIONS` to `False` in your Django settings. The exceptions are captured using the
|
||||
global client, unless the setting `POSTHOG_MW_CLIENT` is set to a custom client instance
|
||||
The context will also auto-capture exceptions and send them to Insights, unless you disable it by setting
|
||||
`INSIGHTS_MW_CAPTURE_EXCEPTIONS` (or `POSTHOG_MW_CAPTURE_EXCEPTIONS`) to `False` in your Django settings.
|
||||
The exceptions are captured using the global client, unless the setting `INSIGHTS_MW_CLIENT`
|
||||
(or `POSTHOG_MW_CLIENT`) is set to a custom client instance.
|
||||
|
||||
The middleware behaviour is customisable through 3 additional functions:
|
||||
- `POSTHOG_MW_EXTRA_TAGS`, which is a Callable[[HttpRequest], Dict[str, Any]] expected to return a dictionary of additional tags to be added to the context.
|
||||
- `POSTHOG_MW_REQUEST_FILTER`, which is a Callable[[HttpRequest], bool] expected to return `False` if the request should not be tracked.
|
||||
- `POSTHOG_MW_TAG_MAP`, which is a Callable[[Dict[str, Any]], Dict[str, Any]], which you can use to modify the tags before they're added to the context.
|
||||
- `INSIGHTS_MW_EXTRA_TAGS` (or `POSTHOG_MW_EXTRA_TAGS`), which is a Callable[[HttpRequest], Dict[str, Any]] expected to return a dictionary of additional tags to be added to the context.
|
||||
- `INSIGHTS_MW_REQUEST_FILTER` (or `POSTHOG_MW_REQUEST_FILTER`), which is a Callable[[HttpRequest], bool] expected to return `False` if the request should not be tracked.
|
||||
- `INSIGHTS_MW_TAG_MAP` (or `POSTHOG_MW_TAG_MAP`), which is a Callable[[Dict[str, Any]], Dict[str, Any]], which you can use to modify the tags before they're added to the context.
|
||||
|
||||
You can use the `POSTHOG_MW_TAG_MAP` function to remove any default tags you don't want to capture, or override them with your own values.
|
||||
You can use the `INSIGHTS_MW_TAG_MAP` function to remove any default tags you don't want to capture, or override them with your own values.
|
||||
|
||||
Context tags are automatically included as properties on all events captured within a context, including exceptions.
|
||||
See the context documentation for more information. The extracted distinct ID and session ID, if found, are used to
|
||||
@@ -66,47 +67,52 @@ class PosthogContextMiddleware:
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
if hasattr(settings, "POSTHOG_MW_EXTRA_TAGS") and callable(
|
||||
settings.POSTHOG_MW_EXTRA_TAGS
|
||||
):
|
||||
# Support both INSIGHTS_MW_* and legacy POSTHOG_MW_* setting names
|
||||
def _get_setting(name):
|
||||
insights_name = f"INSIGHTS_MW_{name}"
|
||||
posthog_name = f"POSTHOG_MW_{name}"
|
||||
if hasattr(settings, insights_name):
|
||||
return getattr(settings, insights_name)
|
||||
if hasattr(settings, posthog_name):
|
||||
return getattr(settings, posthog_name)
|
||||
return None
|
||||
|
||||
extra_tags = _get_setting("EXTRA_TAGS")
|
||||
if extra_tags and callable(extra_tags):
|
||||
self.extra_tags = cast(
|
||||
"Optional[Callable[[HttpRequest], Dict[str, Any]]]",
|
||||
settings.POSTHOG_MW_EXTRA_TAGS,
|
||||
extra_tags,
|
||||
)
|
||||
else:
|
||||
self.extra_tags = None
|
||||
|
||||
if hasattr(settings, "POSTHOG_MW_REQUEST_FILTER") and callable(
|
||||
settings.POSTHOG_MW_REQUEST_FILTER
|
||||
):
|
||||
request_filter = _get_setting("REQUEST_FILTER")
|
||||
if request_filter and callable(request_filter):
|
||||
self.request_filter = cast(
|
||||
"Optional[Callable[[HttpRequest], bool]]",
|
||||
settings.POSTHOG_MW_REQUEST_FILTER,
|
||||
request_filter,
|
||||
)
|
||||
else:
|
||||
self.request_filter = None
|
||||
|
||||
if hasattr(settings, "POSTHOG_MW_TAG_MAP") and callable(
|
||||
settings.POSTHOG_MW_TAG_MAP
|
||||
):
|
||||
tag_map = _get_setting("TAG_MAP")
|
||||
if tag_map and callable(tag_map):
|
||||
self.tag_map = cast(
|
||||
"Optional[Callable[[Dict[str, Any]], Dict[str, Any]]]",
|
||||
settings.POSTHOG_MW_TAG_MAP,
|
||||
tag_map,
|
||||
)
|
||||
else:
|
||||
self.tag_map = None
|
||||
|
||||
if hasattr(settings, "POSTHOG_MW_CAPTURE_EXCEPTIONS") and isinstance(
|
||||
settings.POSTHOG_MW_CAPTURE_EXCEPTIONS, bool
|
||||
):
|
||||
self.capture_exceptions = settings.POSTHOG_MW_CAPTURE_EXCEPTIONS
|
||||
capture_exceptions = _get_setting("CAPTURE_EXCEPTIONS")
|
||||
if isinstance(capture_exceptions, bool):
|
||||
self.capture_exceptions = capture_exceptions
|
||||
else:
|
||||
self.capture_exceptions = True
|
||||
|
||||
if hasattr(settings, "POSTHOG_MW_CLIENT") and isinstance(
|
||||
settings.POSTHOG_MW_CLIENT, Client
|
||||
):
|
||||
self.client = cast("Optional[Client]", settings.POSTHOG_MW_CLIENT)
|
||||
mw_client = _get_setting("CLIENT")
|
||||
if isinstance(mw_client, Client):
|
||||
self.client = cast("Optional[Client]", mw_client)
|
||||
else:
|
||||
self.client = None
|
||||
|
||||
@@ -125,13 +131,13 @@ class PosthogContextMiddleware:
|
||||
"""
|
||||
tags = {}
|
||||
|
||||
# Extract session ID from X-POSTHOG-SESSION-ID header
|
||||
session_id = request.headers.get("X-POSTHOG-SESSION-ID")
|
||||
# Extract session ID from X-INSIGHTS-SESSION-ID or X-POSTHOG-SESSION-ID header
|
||||
session_id = request.headers.get("X-INSIGHTS-SESSION-ID") or request.headers.get("X-POSTHOG-SESSION-ID")
|
||||
if session_id:
|
||||
contexts.set_context_session(session_id)
|
||||
|
||||
# Extract distinct ID from X-POSTHOG-DISTINCT-ID header or request user id
|
||||
distinct_id = request.headers.get("X-POSTHOG-DISTINCT-ID") or user_id
|
||||
# Extract distinct ID from X-INSIGHTS-DISTINCT-ID or X-POSTHOG-DISTINCT-ID header or request user id
|
||||
distinct_id = request.headers.get("X-INSIGHTS-DISTINCT-ID") or request.headers.get("X-POSTHOG-DISTINCT-ID") or user_id
|
||||
if distinct_id:
|
||||
contexts.identify_context(distinct_id)
|
||||
|
||||
@@ -314,6 +320,10 @@ class PosthogContextMiddleware:
|
||||
if self.client:
|
||||
self.client.capture_exception(exception)
|
||||
else:
|
||||
from posthog import capture_exception
|
||||
from hanzo_insights import capture_exception
|
||||
|
||||
capture_exception(exception)
|
||||
|
||||
|
||||
# Backward compatibility alias
|
||||
PosthogContextMiddleware = InsightsContextMiddleware
|
||||
|
||||
@@ -137,7 +137,7 @@ def set_socket_options(socket_options: Optional[SocketOptions]) -> None:
|
||||
Configure socket options for all HTTP connections.
|
||||
|
||||
Example:
|
||||
from posthog import set_socket_options
|
||||
from hanzo_insights import set_socket_options
|
||||
set_socket_options([(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)])
|
||||
"""
|
||||
global _session, _flags_session, _socket_options
|
||||
@@ -159,19 +159,19 @@ def disable_connection_reuse() -> None:
|
||||
_pooling_enabled = False
|
||||
|
||||
|
||||
US_INGESTION_ENDPOINT = "https://us.i.hanzo_insights.com"
|
||||
EU_INGESTION_ENDPOINT = "https://eu.i.hanzo_insights.com"
|
||||
US_INGESTION_ENDPOINT = "https://us.i.posthog.com"
|
||||
EU_INGESTION_ENDPOINT = "https://eu.i.posthog.com"
|
||||
DEFAULT_HOST = US_INGESTION_ENDPOINT
|
||||
USER_AGENT = "posthog-python/" + VERSION
|
||||
USER_AGENT = "hanzo-insights-python/" + VERSION
|
||||
|
||||
|
||||
def determine_server_host(host: Optional[str]) -> str:
|
||||
"""Determines the server host to use."""
|
||||
host_or_default = host or DEFAULT_HOST
|
||||
trimmed_host = remove_trailing_slash(host_or_default)
|
||||
if trimmed_host in ("https://app.hanzo_insights.com", "https://us.hanzo_insights.com"):
|
||||
if trimmed_host in ("https://app.posthog.com", "https://us.posthog.com", "https://insights.hanzo.ai"):
|
||||
return US_INGESTION_ENDPOINT
|
||||
elif trimmed_host == "https://eu.hanzo_insights.com":
|
||||
elif trimmed_host == "https://eu.posthog.com":
|
||||
return EU_INGESTION_ENDPOINT
|
||||
else:
|
||||
return host_or_default
|
||||
@@ -231,7 +231,7 @@ def _process_response(
|
||||
and "feature_flags" in response["quotaLimited"]
|
||||
):
|
||||
log.warning(
|
||||
"[FEATURE FLAGS] PostHog feature flags quota limited, resetting feature flag data. Learn more about billing limits at https://hanzo_insights.com/docs/billing/limits-alerts"
|
||||
"[FEATURE FLAGS] Feature flags quota limited, resetting feature flag data. Learn more about billing limits at https://insights.hanzo.ai/docs/billing/limits-alerts"
|
||||
)
|
||||
raise QuotaLimitError(res.status_code, "Feature flags quota limited")
|
||||
return response
|
||||
@@ -375,7 +375,7 @@ class APIError(Exception):
|
||||
self.retry_after = retry_after
|
||||
|
||||
def __str__(self):
|
||||
msg = "[PostHog] {0} ({1})"
|
||||
msg = "[Insights] {0} ({1})"
|
||||
return msg.format(self.message, self.status)
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from posthog import identify_context, new_context
|
||||
from hanzo_insights import identify_context, new_context
|
||||
|
||||
try:
|
||||
from anthropic.types import Message, Usage
|
||||
|
||||
@@ -97,7 +97,7 @@ def test_metadata_capture(mock_client):
|
||||
run_id = uuid.uuid4()
|
||||
with patch("time.time", return_value=1234567890):
|
||||
callbacks._set_llm_metadata(
|
||||
{"kwargs": {"openai_api_base": "https://us.hanzo_insights.com"}},
|
||||
{"kwargs": {"openai_api_base": "https://us.posthog.com"}},
|
||||
run_id,
|
||||
messages=[{"role": "user", "content": "Who won the world series in 2020?"}],
|
||||
invocation_params={"temperature": 0.5},
|
||||
@@ -110,7 +110,7 @@ def test_metadata_capture(mock_client):
|
||||
start_time=1234567890,
|
||||
model_params={"temperature": 0.5},
|
||||
provider="hanzo_insights",
|
||||
base_url="https://us.hanzo_insights.com",
|
||||
base_url="https://us.posthog.com",
|
||||
name="test",
|
||||
end_time=None,
|
||||
posthog_properties=None,
|
||||
@@ -1050,7 +1050,7 @@ def test_base_url_retrieval(mock_client):
|
||||
chain = prompt | ChatOpenAI(
|
||||
api_key="test",
|
||||
model="posthog-mini",
|
||||
base_url="https://test.hanzo_insights.com",
|
||||
base_url="https://test.posthog.com",
|
||||
)
|
||||
callbacks = CallbackHandler(mock_client)
|
||||
with pytest.raises(Exception):
|
||||
@@ -1058,7 +1058,7 @@ def test_base_url_retrieval(mock_client):
|
||||
|
||||
assert mock_client.capture.call_count == 3
|
||||
generation_call = mock_client.capture.call_args_list[1][1]
|
||||
assert generation_call["properties"]["$ai_base_url"] == "https://test.hanzo_insights.com"
|
||||
assert generation_call["properties"]["$ai_base_url"] == "https://test.posthog.com"
|
||||
|
||||
|
||||
def test_groups(mock_client):
|
||||
@@ -1253,7 +1253,7 @@ def test_metadata_tools(mock_client):
|
||||
|
||||
with patch("time.time", return_value=1234567890):
|
||||
callbacks._set_llm_metadata(
|
||||
{"kwargs": {"openai_api_base": "https://us.hanzo_insights.com"}},
|
||||
{"kwargs": {"openai_api_base": "https://us.posthog.com"}},
|
||||
run_id,
|
||||
messages=[{"role": "user", "content": "What's the weather like in SF?"}],
|
||||
invocation_params={"temperature": 0.5, "tools": tools},
|
||||
@@ -1266,7 +1266,7 @@ def test_metadata_tools(mock_client):
|
||||
start_time=1234567890,
|
||||
model_params={"temperature": 0.5},
|
||||
provider="hanzo_insights",
|
||||
base_url="https://us.hanzo_insights.com",
|
||||
base_url="https://us.posthog.com",
|
||||
name="test",
|
||||
tools=tools,
|
||||
end_time=None,
|
||||
|
||||
@@ -36,7 +36,7 @@ class TestPrompts(unittest.TestCase):
|
||||
self,
|
||||
personal_api_key="phx_test_key",
|
||||
project_api_key="phc_test_key",
|
||||
host="https://us.hanzo_insights.com",
|
||||
host="https://us.posthog.com",
|
||||
):
|
||||
"""Create a mock PostHog client."""
|
||||
mock = MagicMock()
|
||||
@@ -65,7 +65,7 @@ class TestPromptsGet(TestPrompts):
|
||||
call_args = mock_get.call_args
|
||||
self.assertEqual(
|
||||
call_args[0][0],
|
||||
"https://us.hanzo_insights.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_key",
|
||||
"https://us.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_key",
|
||||
)
|
||||
self.assertIn("Authorization", call_args[1]["headers"])
|
||||
self.assertEqual(
|
||||
@@ -93,7 +93,7 @@ class TestPromptsGet(TestPrompts):
|
||||
call_args = mock_get.call_args
|
||||
self.assertEqual(
|
||||
call_args[0][0],
|
||||
"https://us.hanzo_insights.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_key&version=1",
|
||||
"https://us.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_key&version=1",
|
||||
)
|
||||
|
||||
@patch("hanzo_insights.ai.prompts._get_session")
|
||||
@@ -347,7 +347,7 @@ class TestPromptsGet(TestPrompts):
|
||||
mock_get = mock_get_session.return_value.get
|
||||
mock_get.return_value = MockResponse(json_data=self.mock_prompt_response)
|
||||
|
||||
posthog = self.create_mock_posthog(host="https://eu.hanzo_insights.com")
|
||||
posthog = self.create_mock_posthog(host="https://eu.posthog.com")
|
||||
prompts = Prompts(posthog)
|
||||
|
||||
prompts.get("test-prompt")
|
||||
@@ -355,9 +355,9 @@ class TestPromptsGet(TestPrompts):
|
||||
call_args = mock_get.call_args
|
||||
self.assertTrue(
|
||||
call_args[0][0].startswith(
|
||||
"https://eu.hanzo_insights.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_key"
|
||||
"https://eu.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_key"
|
||||
),
|
||||
f"Expected URL to start with 'https://eu.hanzo_insights.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_key', got {call_args[0][0]}",
|
||||
f"Expected URL to start with 'https://eu.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_key', got {call_args[0][0]}",
|
||||
)
|
||||
|
||||
@patch("hanzo_insights.ai.prompts._get_session")
|
||||
@@ -427,7 +427,7 @@ class TestPromptsGet(TestPrompts):
|
||||
call_args = mock_get.call_args
|
||||
self.assertEqual(
|
||||
call_args[0][0],
|
||||
"https://us.hanzo_insights.com/api/environments/@current/llm_prompts/name/prompt%20with%20spaces%2Fand%2Fslashes/?token=phc_test_key",
|
||||
"https://us.posthog.com/api/environments/@current/llm_prompts/name/prompt%20with%20spaces%2Fand%2Fslashes/?token=phc_test_key",
|
||||
)
|
||||
|
||||
@patch("hanzo_insights.ai.prompts._get_session")
|
||||
@@ -446,7 +446,7 @@ class TestPromptsGet(TestPrompts):
|
||||
call_args = mock_get.call_args
|
||||
self.assertEqual(
|
||||
call_args[0][0],
|
||||
"https://us.hanzo_insights.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_direct_key",
|
||||
"https://us.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_direct_key",
|
||||
)
|
||||
self.assertEqual(
|
||||
call_args[1]["headers"]["Authorization"], "Bearer phx_direct_key"
|
||||
@@ -461,7 +461,7 @@ class TestPromptsGet(TestPrompts):
|
||||
prompts = Prompts(
|
||||
personal_api_key="phx_direct_key",
|
||||
project_api_key="phc_direct_key",
|
||||
host="https://eu.hanzo_insights.com",
|
||||
host="https://eu.posthog.com",
|
||||
)
|
||||
|
||||
prompts.get("test-prompt")
|
||||
@@ -469,7 +469,7 @@ class TestPromptsGet(TestPrompts):
|
||||
call_args = mock_get.call_args
|
||||
self.assertEqual(
|
||||
call_args[0][0],
|
||||
"https://eu.hanzo_insights.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_direct_key",
|
||||
"https://eu.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_direct_key",
|
||||
)
|
||||
|
||||
@patch("hanzo_insights.ai.prompts._get_session")
|
||||
|
||||
@@ -175,7 +175,7 @@ class TestClient(unittest.TestCase):
|
||||
client = Client(
|
||||
FAKE_TEST_API_KEY,
|
||||
on_error=self.set_fail,
|
||||
host="https://app.hanzo_insights.com",
|
||||
host="https://app.posthog.com",
|
||||
)
|
||||
exception = Exception("test exception")
|
||||
client.capture_exception(exception, distinct_id="distinct_id")
|
||||
@@ -230,7 +230,7 @@ class TestClient(unittest.TestCase):
|
||||
capture_call[1]["properties"]["$exception_list"][0]["stacktrace"][
|
||||
"frames"
|
||||
][0]["filename"],
|
||||
"posthog/test/test_client.py",
|
||||
"hanzo_insights/test/test_client.py",
|
||||
)
|
||||
self.assertEqual(
|
||||
capture_call[1]["properties"]["$exception_list"][0]["stacktrace"][
|
||||
@@ -260,7 +260,7 @@ class TestClient(unittest.TestCase):
|
||||
self.assertFalse(patch_capture.called)
|
||||
self.assertEqual(
|
||||
logs.output[0],
|
||||
"WARNING:posthog:No exception information available",
|
||||
"WARNING:hanzo_insights:No exception information available",
|
||||
)
|
||||
|
||||
def test_capture_exception_logs_when_enabled(self):
|
||||
@@ -270,7 +270,7 @@ class TestClient(unittest.TestCase):
|
||||
Exception("test exception"), distinct_id="distinct_id"
|
||||
)
|
||||
self.assertEqual(
|
||||
logs.output[0], "ERROR:posthog:test exception\nNoneType: None"
|
||||
logs.output[0], "ERROR:hanzo_insights:test exception\nNoneType: None"
|
||||
)
|
||||
|
||||
@mock.patch("hanzo_insights.client.flags")
|
||||
@@ -327,7 +327,7 @@ class TestClient(unittest.TestCase):
|
||||
{
|
||||
"key": "email",
|
||||
"type": "person",
|
||||
"value": "test@hanzo_insights.com",
|
||||
"value": "test@posthog.com",
|
||||
"operator": "exact",
|
||||
}
|
||||
],
|
||||
@@ -477,7 +477,7 @@ class TestClient(unittest.TestCase):
|
||||
self.assertEqual(client.feature_flags_by_key, {})
|
||||
self.assertEqual(client.group_type_mapping, {})
|
||||
self.assertEqual(client.cohorts, {})
|
||||
self.assertIn("PostHog feature flags quota limited", logs.output[0])
|
||||
self.assertIn("Insights feature flags quota limited", logs.output[0])
|
||||
|
||||
@mock.patch("hanzo_insights.client.get")
|
||||
def test_load_feature_flags_unauthorized(self, patch_get):
|
||||
@@ -510,7 +510,7 @@ class TestClient(unittest.TestCase):
|
||||
{
|
||||
"key": "email",
|
||||
"type": "person",
|
||||
"value": "test@hanzo_insights.com",
|
||||
"value": "test@posthog.com",
|
||||
"operator": "exact",
|
||||
}
|
||||
],
|
||||
@@ -655,7 +655,7 @@ class TestClient(unittest.TestCase):
|
||||
self.assertEqual(patch_flags.call_count, 1)
|
||||
patch_flags.assert_called_with(
|
||||
"random_key",
|
||||
"https://us.i.hanzo_insights.com",
|
||||
"https://us.i.posthog.com",
|
||||
timeout=3,
|
||||
distinct_id="distinct_id",
|
||||
groups={},
|
||||
@@ -680,7 +680,7 @@ class TestClient(unittest.TestCase):
|
||||
with mock.patch("hanzo_insights.client.batch_post") as mock_post:
|
||||
client = Client(
|
||||
FAKE_TEST_API_KEY,
|
||||
host="https://app.hanzo_insights.com",
|
||||
host="https://app.posthog.com",
|
||||
on_error=self.set_fail,
|
||||
personal_api_key=FAKE_TEST_API_KEY,
|
||||
disable_geoip=True,
|
||||
@@ -720,7 +720,7 @@ class TestClient(unittest.TestCase):
|
||||
self.assertEqual(patch_flags.call_count, 1)
|
||||
patch_flags.assert_called_with(
|
||||
"random_key",
|
||||
"https://us.i.hanzo_insights.com",
|
||||
"https://us.i.posthog.com",
|
||||
timeout=12,
|
||||
distinct_id="distinct_id",
|
||||
groups={},
|
||||
@@ -1168,7 +1168,7 @@ class TestClient(unittest.TestCase):
|
||||
msg_uuid = client.capture(
|
||||
"test_event",
|
||||
distinct_id="distinct_id",
|
||||
groups={"company": "id:5", "instance": "app.hanzo_insights.com"},
|
||||
groups={"company": "id:5", "instance": "app.posthog.com"},
|
||||
)
|
||||
|
||||
self.assertIsNotNone(msg_uuid)
|
||||
@@ -1180,7 +1180,7 @@ class TestClient(unittest.TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
msg["properties"]["$groups"],
|
||||
{"company": "id:5", "instance": "app.hanzo_insights.com"},
|
||||
{"company": "id:5", "instance": "app.posthog.com"},
|
||||
)
|
||||
|
||||
def test_basic_set(self):
|
||||
@@ -1470,7 +1470,7 @@ class TestClient(unittest.TestCase):
|
||||
"test_event",
|
||||
distinct_id="distinct_id",
|
||||
properties={"$session_id": session_id},
|
||||
groups={"company": "id:5", "instance": "app.hanzo_insights.com"},
|
||||
groups={"company": "id:5", "instance": "app.posthog.com"},
|
||||
)
|
||||
|
||||
self.assertIsNotNone(msg_uuid)
|
||||
@@ -1483,7 +1483,7 @@ class TestClient(unittest.TestCase):
|
||||
self.assertEqual(msg["properties"]["$session_id"], session_id)
|
||||
self.assertEqual(
|
||||
msg["properties"]["$groups"],
|
||||
{"company": "id:5", "instance": "app.hanzo_insights.com"},
|
||||
{"company": "id:5", "instance": "app.posthog.com"},
|
||||
)
|
||||
|
||||
def test_session_id_with_anonymous_event(self):
|
||||
@@ -1920,7 +1920,7 @@ class TestClient(unittest.TestCase):
|
||||
client.get_feature_flag("random_key", "some_id", disable_geoip=True)
|
||||
patch_flags.assert_called_with(
|
||||
"random_key",
|
||||
"https://us.i.hanzo_insights.com",
|
||||
"https://us.i.posthog.com",
|
||||
timeout=3,
|
||||
distinct_id="some_id",
|
||||
groups={},
|
||||
@@ -1936,7 +1936,7 @@ class TestClient(unittest.TestCase):
|
||||
)
|
||||
patch_flags.assert_called_with(
|
||||
"random_key",
|
||||
"https://us.i.hanzo_insights.com",
|
||||
"https://us.i.posthog.com",
|
||||
timeout=3,
|
||||
distinct_id="feature_enabled_distinct_id",
|
||||
groups={},
|
||||
@@ -1950,7 +1950,7 @@ class TestClient(unittest.TestCase):
|
||||
client.get_all_flags_and_payloads("all_flags_payloads_id")
|
||||
patch_flags.assert_called_with(
|
||||
"random_key",
|
||||
"https://us.i.hanzo_insights.com",
|
||||
"https://us.i.posthog.com",
|
||||
timeout=3,
|
||||
distinct_id="all_flags_payloads_id",
|
||||
groups={},
|
||||
@@ -1983,27 +1983,27 @@ class TestClient(unittest.TestCase):
|
||||
}
|
||||
client = Client(
|
||||
FAKE_TEST_API_KEY,
|
||||
host="http://app2.hanzo_insights.com",
|
||||
host="http://app2.posthog.com",
|
||||
on_error=self.set_fail,
|
||||
disable_geoip=False,
|
||||
)
|
||||
client.get_feature_flag(
|
||||
"random_key",
|
||||
"some_id",
|
||||
groups={"company": "id:5", "instance": "app.hanzo_insights.com"},
|
||||
groups={"company": "id:5", "instance": "app.posthog.com"},
|
||||
person_properties={"x1": "y1"},
|
||||
group_properties={"company": {"x": "y"}},
|
||||
)
|
||||
patch_flags.assert_called_with(
|
||||
"random_key",
|
||||
"http://app2.hanzo_insights.com",
|
||||
"http://app2.posthog.com",
|
||||
timeout=3,
|
||||
distinct_id="some_id",
|
||||
groups={"company": "id:5", "instance": "app.hanzo_insights.com"},
|
||||
groups={"company": "id:5", "instance": "app.posthog.com"},
|
||||
person_properties={"distinct_id": "some_id", "x1": "y1"},
|
||||
group_properties={
|
||||
"company": {"$group_key": "id:5", "x": "y"},
|
||||
"instance": {"$group_key": "app.hanzo_insights.com"},
|
||||
"instance": {"$group_key": "app.posthog.com"},
|
||||
},
|
||||
geoip_disable=False,
|
||||
device_id=None,
|
||||
@@ -2014,7 +2014,7 @@ class TestClient(unittest.TestCase):
|
||||
client.get_feature_flag(
|
||||
"random_key",
|
||||
"some_id",
|
||||
groups={"company": "id:5", "instance": "app.hanzo_insights.com"},
|
||||
groups={"company": "id:5", "instance": "app.posthog.com"},
|
||||
person_properties={"distinct_id": "override"},
|
||||
group_properties={
|
||||
"company": {
|
||||
@@ -2024,14 +2024,14 @@ class TestClient(unittest.TestCase):
|
||||
)
|
||||
patch_flags.assert_called_with(
|
||||
"random_key",
|
||||
"http://app2.hanzo_insights.com",
|
||||
"http://app2.posthog.com",
|
||||
timeout=3,
|
||||
distinct_id="some_id",
|
||||
groups={"company": "id:5", "instance": "app.hanzo_insights.com"},
|
||||
groups={"company": "id:5", "instance": "app.posthog.com"},
|
||||
person_properties={"distinct_id": "override"},
|
||||
group_properties={
|
||||
"company": {"$group_key": "group_override"},
|
||||
"instance": {"$group_key": "app.hanzo_insights.com"},
|
||||
"instance": {"$group_key": "app.posthog.com"},
|
||||
},
|
||||
geoip_disable=False,
|
||||
device_id=None,
|
||||
@@ -2045,7 +2045,7 @@ class TestClient(unittest.TestCase):
|
||||
)
|
||||
patch_flags.assert_called_with(
|
||||
"random_key",
|
||||
"http://app2.hanzo_insights.com",
|
||||
"http://app2.posthog.com",
|
||||
timeout=3,
|
||||
distinct_id="some_id",
|
||||
groups={},
|
||||
@@ -2107,7 +2107,7 @@ class TestClient(unittest.TestCase):
|
||||
expected_call["flag_keys_to_evaluate"] = expected_flag_keys
|
||||
|
||||
patch_flags.assert_called_with(
|
||||
"random_key", "https://us.i.hanzo_insights.com", timeout=3, **expected_call
|
||||
"random_key", "https://us.i.posthog.com", timeout=3, **expected_call
|
||||
)
|
||||
|
||||
@mock.patch("hanzo_insights.client.flags")
|
||||
@@ -2131,7 +2131,7 @@ class TestClient(unittest.TestCase):
|
||||
client.get_feature_flag("random_key", "some_id")
|
||||
patch_flags.assert_called_with(
|
||||
"random_key",
|
||||
"https://us.i.hanzo_insights.com",
|
||||
"https://us.i.posthog.com",
|
||||
timeout=3,
|
||||
distinct_id="some_id",
|
||||
groups={},
|
||||
@@ -2151,7 +2151,7 @@ class TestClient(unittest.TestCase):
|
||||
)
|
||||
patch_flags.assert_called_with(
|
||||
"random_key",
|
||||
"https://us.i.hanzo_insights.com",
|
||||
"https://us.i.posthog.com",
|
||||
timeout=3,
|
||||
distinct_id="some_id",
|
||||
groups={},
|
||||
|
||||
@@ -10,8 +10,8 @@ def test_excepthook(tmpdir):
|
||||
app.write(
|
||||
dedent(
|
||||
"""
|
||||
from posthog import Posthog
|
||||
posthog = Posthog('phc_x', host='https://eu.i.hanzo_insights.com', enable_exception_autocapture=True, debug=True, on_error=lambda e, batch: print('error handling batch: ', e, batch))
|
||||
from hanzo_insights import Posthog
|
||||
posthog = Posthog('phc_x', host='https://eu.i.posthog.com', enable_exception_autocapture=True, debug=True, on_error=lambda e, batch: print('error handling batch: ', e, batch))
|
||||
|
||||
# frame_value = "LOL"
|
||||
|
||||
@@ -27,7 +27,7 @@ def test_excepthook(tmpdir):
|
||||
|
||||
assert b"ZeroDivisionError" in output
|
||||
assert b"LOL" in output
|
||||
assert b"DEBUG:posthog:data uploaded successfully" in output
|
||||
assert b"DEBUG:hanzo_insights:data uploaded successfully" in output
|
||||
assert (
|
||||
b'"$exception_list": [{"mechanism": {"type": "generic", "handled": true}, "module": null, "type": "ZeroDivisionError", "value": "division by zero", "stacktrace": {"frames": [{"platform": "python", "filename": "app.py", "abs_path"'
|
||||
in output
|
||||
@@ -40,14 +40,14 @@ def test_code_variables_capture(tmpdir):
|
||||
dedent(
|
||||
"""
|
||||
import os
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Posthog
|
||||
|
||||
class UnserializableObject:
|
||||
pass
|
||||
|
||||
posthog = Posthog(
|
||||
'phc_x',
|
||||
host='https://eu.i.hanzo_insights.com',
|
||||
host='https://eu.i.posthog.com',
|
||||
debug=True,
|
||||
enable_exception_autocapture=True,
|
||||
capture_exception_code_variables=True,
|
||||
@@ -160,12 +160,12 @@ def test_code_variables_context_override(tmpdir):
|
||||
dedent(
|
||||
"""
|
||||
import os
|
||||
import posthog
|
||||
from posthog import Posthog
|
||||
import hanzo_insights
|
||||
from hanzo_insights import Posthog
|
||||
|
||||
posthog_client = Posthog(
|
||||
'phc_x',
|
||||
host='https://eu.i.hanzo_insights.com',
|
||||
host='https://eu.i.posthog.com',
|
||||
debug=True,
|
||||
enable_exception_autocapture=True,
|
||||
capture_exception_code_variables=False,
|
||||
@@ -205,11 +205,11 @@ def test_code_variables_size_limiter(tmpdir):
|
||||
dedent(
|
||||
"""
|
||||
import os
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Posthog
|
||||
|
||||
posthog = Posthog(
|
||||
'phc_x',
|
||||
host='https://eu.i.hanzo_insights.com',
|
||||
host='https://eu.i.posthog.com',
|
||||
debug=True,
|
||||
enable_exception_autocapture=True,
|
||||
capture_exception_code_variables=True,
|
||||
@@ -299,11 +299,11 @@ def test_code_variables_disabled_capture(tmpdir):
|
||||
dedent(
|
||||
"""
|
||||
import os
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Posthog
|
||||
|
||||
posthog = Posthog(
|
||||
'phc_x',
|
||||
host='https://eu.i.hanzo_insights.com',
|
||||
host='https://eu.i.posthog.com',
|
||||
debug=True,
|
||||
enable_exception_autocapture=True,
|
||||
capture_exception_code_variables=False,
|
||||
@@ -340,12 +340,12 @@ def test_code_variables_enabled_then_disabled_in_context(tmpdir):
|
||||
dedent(
|
||||
"""
|
||||
import os
|
||||
import posthog
|
||||
from posthog import Posthog
|
||||
import hanzo_insights
|
||||
from hanzo_insights import Posthog
|
||||
|
||||
posthog_client = Posthog(
|
||||
'phc_x',
|
||||
host='https://eu.i.hanzo_insights.com',
|
||||
host='https://eu.i.posthog.com',
|
||||
debug=True,
|
||||
enable_exception_autocapture=True,
|
||||
capture_exception_code_variables=True,
|
||||
@@ -388,7 +388,7 @@ def test_code_variables_repr_fallback(tmpdir):
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from fractions import Fraction
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Posthog
|
||||
|
||||
class CustomReprClass:
|
||||
def __repr__(self):
|
||||
@@ -396,7 +396,7 @@ def test_code_variables_repr_fallback(tmpdir):
|
||||
|
||||
posthog = Posthog(
|
||||
'phc_x',
|
||||
host='https://eu.i.hanzo_insights.com',
|
||||
host='https://eu.i.posthog.com',
|
||||
debug=True,
|
||||
enable_exception_autocapture=True,
|
||||
capture_exception_code_variables=True,
|
||||
@@ -458,11 +458,11 @@ def test_code_variables_too_long_string_value_replaced(tmpdir):
|
||||
dedent(
|
||||
"""
|
||||
import os
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Posthog
|
||||
|
||||
posthog = Posthog(
|
||||
'phc_x',
|
||||
host='https://eu.i.hanzo_insights.com',
|
||||
host='https://eu.i.posthog.com',
|
||||
debug=True,
|
||||
enable_exception_autocapture=True,
|
||||
capture_exception_code_variables=True,
|
||||
@@ -502,11 +502,11 @@ def test_code_variables_too_long_string_in_nested_dict(tmpdir):
|
||||
dedent(
|
||||
"""
|
||||
import os
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Posthog
|
||||
|
||||
posthog = Posthog(
|
||||
'phc_x',
|
||||
host='https://eu.i.hanzo_insights.com',
|
||||
host='https://eu.i.posthog.com',
|
||||
debug=True,
|
||||
enable_exception_autocapture=True,
|
||||
capture_exception_code_variables=True,
|
||||
|
||||
@@ -2544,7 +2544,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
client.load_feature_flags()
|
||||
self.assertEqual(
|
||||
logs.output[0],
|
||||
"ERROR:posthog:[FEATURE FLAGS] Error loading feature flags: To use feature flags, please set a valid personal_api_key. More information: https://hanzo_insights.com/docs/api/overview",
|
||||
"ERROR:hanzo_insights:[FEATURE FLAGS] Error loading feature flags: To use feature flags, please set a valid personal_api_key. More information: https://insights.hanzo.ai/docs/api/overview",
|
||||
)
|
||||
client.debug = True
|
||||
self.assertRaises(APIError, client.load_feature_flags)
|
||||
@@ -2775,7 +2775,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
{
|
||||
"key": "email",
|
||||
"type": "person",
|
||||
"value": "test@hanzo_insights.com",
|
||||
"value": "test@posthog.com",
|
||||
"operator": "exact",
|
||||
}
|
||||
],
|
||||
@@ -2810,7 +2810,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
client.get_feature_flag(
|
||||
"beta-feature",
|
||||
"test_id",
|
||||
person_properties={"email": "test@hanzo_insights.com"},
|
||||
person_properties={"email": "test@posthog.com"},
|
||||
),
|
||||
"second-variant",
|
||||
)
|
||||
@@ -2838,7 +2838,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
{
|
||||
"key": "email",
|
||||
"type": "person",
|
||||
"value": "test@hanzo_insights.com",
|
||||
"value": "test@posthog.com",
|
||||
"operator": "exact",
|
||||
}
|
||||
],
|
||||
@@ -2851,7 +2851,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
{
|
||||
"key": "email",
|
||||
"type": "person",
|
||||
"value": "test@hanzo_insights.com",
|
||||
"value": "test@posthog.com",
|
||||
"operator": "exact",
|
||||
}
|
||||
],
|
||||
@@ -2886,7 +2886,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
client.get_feature_flag(
|
||||
"beta-feature",
|
||||
"test_id",
|
||||
person_properties={"email": "test@hanzo_insights.com"},
|
||||
person_properties={"email": "test@posthog.com"},
|
||||
),
|
||||
"second-variant",
|
||||
)
|
||||
@@ -2894,7 +2894,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
client.get_feature_flag(
|
||||
"beta-feature",
|
||||
"example_id",
|
||||
person_properties={"email": "test@hanzo_insights.com"},
|
||||
person_properties={"email": "test@posthog.com"},
|
||||
),
|
||||
"second-variant",
|
||||
)
|
||||
@@ -2919,7 +2919,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
{
|
||||
"key": "email",
|
||||
"type": "person",
|
||||
"value": "test@hanzo_insights.com",
|
||||
"value": "test@posthog.com",
|
||||
"operator": "exact",
|
||||
}
|
||||
],
|
||||
@@ -2954,7 +2954,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
client.get_feature_flag(
|
||||
"beta-feature",
|
||||
"test_id",
|
||||
person_properties={"email": "test@hanzo_insights.com"},
|
||||
person_properties={"email": "test@posthog.com"},
|
||||
),
|
||||
"third-variant",
|
||||
)
|
||||
@@ -3109,7 +3109,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
{
|
||||
"key": "email",
|
||||
"type": "person",
|
||||
"value": "test@hanzo_insights.com",
|
||||
"value": "test@posthog.com",
|
||||
"operator": "exact",
|
||||
}
|
||||
],
|
||||
@@ -3149,7 +3149,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
self.client.get_feature_flag_payload(
|
||||
"beta-feature",
|
||||
"test_id",
|
||||
person_properties={"email": "test@hanzo_insights.com"},
|
||||
person_properties={"email": "test@posthog.com"},
|
||||
),
|
||||
{"a": "json"},
|
||||
)
|
||||
@@ -3158,7 +3158,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
"beta-feature",
|
||||
"test_id",
|
||||
match_value="third-variant",
|
||||
person_properties={"email": "test@hanzo_insights.com"},
|
||||
person_properties={"email": "test@posthog.com"},
|
||||
),
|
||||
{"a": "json"},
|
||||
)
|
||||
@@ -3169,7 +3169,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
||||
"beta-feature",
|
||||
"test_id",
|
||||
match_value="first-variant",
|
||||
person_properties={"email": "test@hanzo_insights.com"},
|
||||
person_properties={"email": "test@posthog.com"},
|
||||
),
|
||||
"some-payload",
|
||||
)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import unittest
|
||||
|
||||
from posthog import Posthog
|
||||
from hanzo_insights import Insights
|
||||
|
||||
|
||||
class TestModule(unittest.TestCase):
|
||||
posthog = None
|
||||
client = None
|
||||
|
||||
def _assert_enqueue_result(self, result):
|
||||
self.assertEqual(type(result[0]), str)
|
||||
@@ -14,19 +14,19 @@ class TestModule(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.failed = False
|
||||
self.posthog = Posthog(
|
||||
self.client = Insights(
|
||||
"testsecret", host="http://localhost:8000", on_error=self.failed
|
||||
)
|
||||
|
||||
def test_track(self):
|
||||
res = self.hanzo_insights.capture("python module event", distinct_id="distinct_id")
|
||||
res = self.client.capture("python module event", distinct_id="distinct_id")
|
||||
self._assert_enqueue_result(res)
|
||||
self.hanzo_insights.flush()
|
||||
self.client.flush()
|
||||
|
||||
def test_alias(self):
|
||||
res = self.hanzo_insights.alias("previousId", "distinct_id")
|
||||
res = self.client.alias("previousId", "distinct_id")
|
||||
self._assert_enqueue_result(res)
|
||||
self.hanzo_insights.flush()
|
||||
self.client.flush()
|
||||
|
||||
def test_flush(self):
|
||||
self.hanzo_insights.flush()
|
||||
self.client.flush()
|
||||
|
||||
@@ -72,12 +72,12 @@ class TestRequests(unittest.TestCase):
|
||||
|
||||
def test_invalid_request_error(self):
|
||||
self.assertRaises(
|
||||
Exception, batch_post, "testsecret", "https://t.hanzo_insights.com", False, "[{]"
|
||||
Exception, batch_post, "testsecret", "https://t.posthog.com", False, "[{]"
|
||||
)
|
||||
|
||||
def test_invalid_host(self):
|
||||
self.assertRaises(
|
||||
Exception, batch_post, "testsecret", "t.hanzo_insights.com/", batch=[]
|
||||
Exception, batch_post, "testsecret", "t.posthog.com/", batch=[]
|
||||
)
|
||||
|
||||
def test_datetime_serialization(self):
|
||||
@@ -286,7 +286,7 @@ class TestGet(unittest.TestCase):
|
||||
call_kwargs = mock_get.call_args[1]
|
||||
self.assertIn("User-Agent", call_kwargs["headers"])
|
||||
self.assertTrue(
|
||||
call_kwargs["headers"]["User-Agent"].startswith("posthog-python/")
|
||||
call_kwargs["headers"]["User-Agent"].startswith("hanzo-insights-python/")
|
||||
)
|
||||
|
||||
@mock.patch("hanzo_insights.request._session.get")
|
||||
@@ -332,20 +332,20 @@ class TestGet(unittest.TestCase):
|
||||
@pytest.mark.parametrize(
|
||||
"host, expected",
|
||||
[
|
||||
("https://t.hanzo_insights.com", "https://t.hanzo_insights.com"),
|
||||
("https://t.hanzo_insights.com/", "https://t.hanzo_insights.com/"),
|
||||
("t.hanzo_insights.com", "t.hanzo_insights.com"),
|
||||
("t.hanzo_insights.com/", "t.hanzo_insights.com/"),
|
||||
("https://us.hanzo_insights.com.rg.proxy.com", "https://us.hanzo_insights.com.rg.proxy.com"),
|
||||
("app.hanzo_insights.com", "app.hanzo_insights.com"),
|
||||
("eu.hanzo_insights.com", "eu.hanzo_insights.com"),
|
||||
("https://app.hanzo_insights.com", "https://us.i.hanzo_insights.com"),
|
||||
("https://eu.hanzo_insights.com", "https://eu.i.hanzo_insights.com"),
|
||||
("https://us.hanzo_insights.com", "https://us.i.hanzo_insights.com"),
|
||||
("https://app.hanzo_insights.com/", "https://us.i.hanzo_insights.com"),
|
||||
("https://eu.hanzo_insights.com/", "https://eu.i.hanzo_insights.com"),
|
||||
("https://us.hanzo_insights.com/", "https://us.i.hanzo_insights.com"),
|
||||
(None, "https://us.i.hanzo_insights.com"),
|
||||
("https://t.posthog.com", "https://t.posthog.com"),
|
||||
("https://t.posthog.com/", "https://t.posthog.com/"),
|
||||
("t.posthog.com", "t.posthog.com"),
|
||||
("t.posthog.com/", "t.posthog.com/"),
|
||||
("https://us.posthog.com.rg.proxy.com", "https://us.posthog.com.rg.proxy.com"),
|
||||
("app.posthog.com", "app.posthog.com"),
|
||||
("eu.posthog.com", "eu.posthog.com"),
|
||||
("https://app.posthog.com", "https://us.i.posthog.com"),
|
||||
("https://eu.posthog.com", "https://eu.i.posthog.com"),
|
||||
("https://us.posthog.com", "https://us.i.posthog.com"),
|
||||
("https://app.posthog.com/", "https://us.i.posthog.com"),
|
||||
("https://eu.posthog.com/", "https://eu.i.posthog.com"),
|
||||
("https://us.posthog.com/", "https://us.i.posthog.com"),
|
||||
(None, "https://us.i.posthog.com"),
|
||||
],
|
||||
)
|
||||
def test_routing_to_custom_host(host, expected):
|
||||
@@ -428,7 +428,7 @@ class TestFlagsSession(unittest.TestCase):
|
||||
mock_session.post.return_value = mock_response
|
||||
mock_get_flags_session.return_value = mock_session
|
||||
|
||||
result = flags("test-key", "https://test.hanzo_insights.com", distinct_id="user123")
|
||||
result = flags("test-key", "https://test.posthog.com", distinct_id="user123")
|
||||
|
||||
self.assertEqual(result["featureFlags"]["test-flag"], True)
|
||||
mock_get_flags_session.assert_called_once()
|
||||
@@ -453,7 +453,7 @@ class TestFlagsSession(unittest.TestCase):
|
||||
mock_get_flags_session.return_value = mock_session
|
||||
|
||||
with self.assertRaises(QuotaLimitError):
|
||||
flags("test-key", "https://test.hanzo_insights.com", distinct_id="user123")
|
||||
flags("test-key", "https://test.posthog.com", distinct_id="user123")
|
||||
|
||||
# QuotaLimitError is raised after response is received, not retried
|
||||
self.assertEqual(mock_session.post.call_count, 1)
|
||||
@@ -475,7 +475,7 @@ class TestFlagsSessionNetworkRetries(unittest.TestCase):
|
||||
session = _build_flags_session()
|
||||
|
||||
# Get the adapter for https://
|
||||
adapter = session.get_adapter("https://test.hanzo_insights.com")
|
||||
adapter = session.get_adapter("https://test.posthog.com")
|
||||
|
||||
# Verify retry configuration
|
||||
retry = adapter.max_retries
|
||||
@@ -494,7 +494,7 @@ class TestFlagsSessionNetworkRetries(unittest.TestCase):
|
||||
from hanzo_insights.request import _build_flags_session, RETRY_STATUS_FORCELIST
|
||||
|
||||
session = _build_flags_session()
|
||||
adapter = session.get_adapter("https://test.hanzo_insights.com")
|
||||
adapter = session.get_adapter("https://test.posthog.com")
|
||||
retry = adapter.max_retries
|
||||
|
||||
# Verify the status codes that trigger retries
|
||||
@@ -521,7 +521,7 @@ class TestFlagsSessionNetworkRetries(unittest.TestCase):
|
||||
from hanzo_insights.request import _build_flags_session
|
||||
|
||||
session = _build_flags_session()
|
||||
adapter = session.get_adapter("https://test.hanzo_insights.com")
|
||||
adapter = session.get_adapter("https://test.posthog.com")
|
||||
retry = adapter.max_retries
|
||||
|
||||
self.assertEqual(
|
||||
|
||||
@@ -2,7 +2,7 @@ import unittest
|
||||
|
||||
from parameterized import parameterized
|
||||
|
||||
from posthog import utils
|
||||
from hanzo_insights import utils
|
||||
|
||||
|
||||
class TestSizeLimitedDict(unittest.TestCase):
|
||||
|
||||
@@ -13,7 +13,7 @@ from parameterized import parameterized
|
||||
from pydantic import BaseModel
|
||||
from pydantic.v1 import BaseModel as BaseModelV1
|
||||
|
||||
from posthog import utils
|
||||
from hanzo_insights import utils
|
||||
from hanzo_insights.types import FeatureFlagResult
|
||||
|
||||
TEST_API_KEY = "kOOlRy2QlMY9jHZQv0bKz0FZyazBUoY8Arj0lFVNjs4"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Convenience re-export so `from insights import Insights` works.
|
||||
from hanzo_insights import * # noqa: F401, F403
|
||||
from hanzo_insights import Insights, Posthog, Client # noqa: F401
|
||||
@@ -125,5 +125,5 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
# PostHog settings for testing
|
||||
POSTHOG_API_KEY = "test-key"
|
||||
POSTHOG_HOST = "https://app.hanzo_insights.com"
|
||||
POSTHOG_HOST = "https://app.posthog.com"
|
||||
POSTHOG_MW_CAPTURE_EXCEPTIONS = True
|
||||
|
||||
@@ -91,6 +91,7 @@ packages = [
|
||||
"hanzo_insights.test.ai",
|
||||
"hanzo_insights.test.ai.openai_agents",
|
||||
"hanzo_insights.integrations",
|
||||
"insights",
|
||||
]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
|
||||
+2
-2
@@ -56,9 +56,9 @@ setup(
|
||||
# Basic fields for backward compatibility
|
||||
url="https://github.com/posthog/posthog-python",
|
||||
author="Posthog",
|
||||
author_email="hey@hanzo_insights.com",
|
||||
author_email="hey@hanzo.ai",
|
||||
maintainer="PostHog",
|
||||
maintainer_email="hey@hanzo_insights.com",
|
||||
maintainer_email="hey@hanzo.ai",
|
||||
license="MIT License",
|
||||
description="Integrate PostHog into any python application.",
|
||||
long_description=long_description,
|
||||
|
||||
Reference in New Issue
Block a user