posthoganalytics 6.9.1__tar.gz → 6.9.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. {posthoganalytics-6.9.1/posthoganalytics.egg-info → posthoganalytics-6.9.3}/PKG-INFO +1 -1
  2. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/__init__.py +9 -2
  3. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/langchain/callbacks.py +36 -9
  4. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/exception_utils.py +1 -1
  5. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/version.py +1 -1
  6. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3/posthoganalytics.egg-info}/PKG-INFO +1 -1
  7. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/LICENSE +0 -0
  8. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/MANIFEST.in +0 -0
  9. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/README.md +0 -0
  10. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/__init__.py +0 -0
  11. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/anthropic/__init__.py +0 -0
  12. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/anthropic/anthropic.py +0 -0
  13. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/anthropic/anthropic_async.py +0 -0
  14. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/anthropic/anthropic_converter.py +0 -0
  15. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/anthropic/anthropic_providers.py +0 -0
  16. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/gemini/__init__.py +0 -0
  17. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/gemini/gemini.py +0 -0
  18. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/gemini/gemini_converter.py +0 -0
  19. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/langchain/__init__.py +0 -0
  20. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/openai/__init__.py +0 -0
  21. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/openai/openai.py +0 -0
  22. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/openai/openai_async.py +0 -0
  23. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/openai/openai_converter.py +0 -0
  24. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/openai/openai_providers.py +0 -0
  25. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/sanitization.py +0 -0
  26. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/types.py +0 -0
  27. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/ai/utils.py +0 -0
  28. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/args.py +0 -0
  29. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/client.py +0 -0
  30. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/consumer.py +0 -0
  31. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/contexts.py +0 -0
  32. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/exception_capture.py +0 -0
  33. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/feature_flags.py +0 -0
  34. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/integrations/__init__.py +0 -0
  35. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/integrations/django.py +0 -0
  36. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/poller.py +0 -0
  37. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/py.typed +0 -0
  38. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/request.py +0 -0
  39. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/__init__.py +0 -0
  40. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_before_send.py +0 -0
  41. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_client.py +0 -0
  42. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_consumer.py +0 -0
  43. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_contexts.py +0 -0
  44. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_exception_capture.py +0 -0
  45. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_feature_flag.py +0 -0
  46. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_feature_flag_result.py +0 -0
  47. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_feature_flags.py +0 -0
  48. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_module.py +0 -0
  49. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_request.py +0 -0
  50. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_size_limited_dict.py +0 -0
  51. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_types.py +0 -0
  52. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/test/test_utils.py +0 -0
  53. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/types.py +0 -0
  54. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics/utils.py +0 -0
  55. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics.egg-info/SOURCES.txt +0 -0
  56. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics.egg-info/dependency_links.txt +0 -0
  57. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics.egg-info/requires.txt +0 -0
  58. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/posthoganalytics.egg-info/top_level.txt +0 -0
  59. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/pyproject.toml +0 -0
  60. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/setup.cfg +0 -0
  61. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/setup.py +0 -0
  62. {posthoganalytics-6.9.1 → posthoganalytics-6.9.3}/setup_analytics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: posthoganalytics
3
- Version: 6.9.1
3
+ Version: 6.9.3
4
4
  Summary: Integrate PostHog into any python application.
5
5
  Home-page: https://github.com/posthog/posthog-python
6
6
  Author: Posthog
@@ -18,8 +18,15 @@ from posthoganalytics.exception_utils import (
18
18
  DEFAULT_CODE_VARIABLES_IGNORE_PATTERNS,
19
19
  DEFAULT_CODE_VARIABLES_MASK_PATTERNS,
20
20
  )
21
- from posthoganalytics.feature_flags import InconclusiveMatchError, RequiresServerEvaluation
22
- from posthoganalytics.types import FeatureFlag, FlagsAndPayloads, FeatureFlagResult
21
+ from posthoganalytics.feature_flags import (
22
+ InconclusiveMatchError as InconclusiveMatchError,
23
+ RequiresServerEvaluation as RequiresServerEvaluation,
24
+ )
25
+ from posthoganalytics.types import (
26
+ FeatureFlag,
27
+ FlagsAndPayloads,
28
+ FeatureFlagResult as FeatureFlagResult,
29
+ )
23
30
  from posthoganalytics.version import VERSION
24
31
 
25
32
  __version__ = VERSION
@@ -79,6 +79,8 @@ class GenerationMetadata(SpanMetadata):
79
79
  """Base URL of the provider's API used in the run."""
80
80
  tools: Optional[List[Dict[str, Any]]] = None
81
81
  """Tools provided to the model."""
82
+ posthog_properties: Optional[Dict[str, Any]] = None
83
+ """PostHog properties of the run."""
82
84
 
83
85
 
84
86
  RunMetadata = Union[SpanMetadata, GenerationMetadata]
@@ -420,6 +422,8 @@ class CallbackHandler(BaseCallbackHandler):
420
422
  generation.model = model
421
423
  if provider := metadata.get("ls_provider"):
422
424
  generation.provider = provider
425
+
426
+ generation.posthog_properties = metadata.get("posthog_properties")
423
427
  try:
424
428
  base_url = serialized["kwargs"]["openai_api_base"]
425
429
  if base_url is not None:
@@ -566,6 +570,9 @@ class CallbackHandler(BaseCallbackHandler):
566
570
  "$ai_framework": "langchain",
567
571
  }
568
572
 
573
+ if isinstance(run.posthog_properties, dict):
574
+ event_properties.update(run.posthog_properties)
575
+
569
576
  if run.tools:
570
577
  event_properties["$ai_tools"] = run.tools
571
578
 
@@ -575,7 +582,7 @@ class CallbackHandler(BaseCallbackHandler):
575
582
  event_properties["$ai_is_error"] = True
576
583
  else:
577
584
  # Add usage
578
- usage = _parse_usage(output)
585
+ usage = _parse_usage(output, run.provider, run.model)
579
586
  event_properties["$ai_input_tokens"] = usage.input_tokens
580
587
  event_properties["$ai_output_tokens"] = usage.output_tokens
581
588
  event_properties["$ai_cache_creation_input_tokens"] = (
@@ -696,6 +703,8 @@ class ModelUsage:
696
703
 
697
704
  def _parse_usage_model(
698
705
  usage: Union[BaseModel, dict],
706
+ provider: Optional[str] = None,
707
+ model: Optional[str] = None,
699
708
  ) -> ModelUsage:
700
709
  if isinstance(usage, BaseModel):
701
710
  usage = usage.__dict__
@@ -764,16 +773,30 @@ def _parse_usage_model(
764
773
  for mapped_key, dataclass_key in field_mapping.items()
765
774
  },
766
775
  )
767
- # In LangChain, input_tokens is the sum of input and cache read tokens.
768
- # Our cost calculation expects them to be separate, for Anthropic.
769
- if normalized_usage.input_tokens and normalized_usage.cache_read_tokens:
776
+ # For Anthropic providers, LangChain reports input_tokens as the sum of input and cache read tokens.
777
+ # Our cost calculation expects them to be separate for Anthropic, so we subtract cache tokens.
778
+ # For other providers (OpenAI, etc.), input_tokens already includes cache tokens as expected.
779
+ # Match logic consistent with plugin-server: exact match on provider OR substring match on model
780
+ is_anthropic = False
781
+ if provider and provider.lower() == "anthropic":
782
+ is_anthropic = True
783
+ elif model and "anthropic" in model.lower():
784
+ is_anthropic = True
785
+
786
+ if (
787
+ is_anthropic
788
+ and normalized_usage.input_tokens
789
+ and normalized_usage.cache_read_tokens
790
+ ):
770
791
  normalized_usage.input_tokens = max(
771
792
  normalized_usage.input_tokens - normalized_usage.cache_read_tokens, 0
772
793
  )
773
794
  return normalized_usage
774
795
 
775
796
 
776
- def _parse_usage(response: LLMResult) -> ModelUsage:
797
+ def _parse_usage(
798
+ response: LLMResult, provider: Optional[str] = None, model: Optional[str] = None
799
+ ) -> ModelUsage:
777
800
  # langchain-anthropic uses the usage field
778
801
  llm_usage_keys = ["token_usage", "usage"]
779
802
  llm_usage: ModelUsage = ModelUsage(
@@ -787,13 +810,15 @@ def _parse_usage(response: LLMResult) -> ModelUsage:
787
810
  if response.llm_output is not None:
788
811
  for key in llm_usage_keys:
789
812
  if response.llm_output.get(key):
790
- llm_usage = _parse_usage_model(response.llm_output[key])
813
+ llm_usage = _parse_usage_model(
814
+ response.llm_output[key], provider, model
815
+ )
791
816
  break
792
817
 
793
818
  if hasattr(response, "generations"):
794
819
  for generation in response.generations:
795
820
  if "usage" in generation:
796
- llm_usage = _parse_usage_model(generation["usage"])
821
+ llm_usage = _parse_usage_model(generation["usage"], provider, model)
797
822
  break
798
823
 
799
824
  for generation_chunk in generation:
@@ -801,7 +826,9 @@ def _parse_usage(response: LLMResult) -> ModelUsage:
801
826
  "usage_metadata" in generation_chunk.generation_info
802
827
  ):
803
828
  llm_usage = _parse_usage_model(
804
- generation_chunk.generation_info["usage_metadata"]
829
+ generation_chunk.generation_info["usage_metadata"],
830
+ provider,
831
+ model,
805
832
  )
806
833
  break
807
834
 
@@ -828,7 +855,7 @@ def _parse_usage(response: LLMResult) -> ModelUsage:
828
855
  bedrock_anthropic_usage or bedrock_titan_usage or ollama_usage
829
856
  )
830
857
  if chunk_usage:
831
- llm_usage = _parse_usage_model(chunk_usage)
858
+ llm_usage = _parse_usage_model(chunk_usage, provider, model)
832
859
  break
833
860
 
834
861
  return llm_usage
@@ -929,7 +929,7 @@ def _compile_patterns(patterns):
929
929
  for pattern in patterns:
930
930
  try:
931
931
  compiled.append(re.compile(pattern))
932
- except:
932
+ except Exception:
933
933
  pass
934
934
  return compiled
935
935
 
@@ -1,4 +1,4 @@
1
- VERSION = "6.9.1"
1
+ VERSION = "6.9.3"
2
2
 
3
3
  if __name__ == "__main__":
4
4
  print(VERSION, end="") # noqa: T201
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: posthoganalytics
3
- Version: 6.9.1
3
+ Version: 6.9.3
4
4
  Summary: Integrate PostHog into any python application.
5
5
  Home-page: https://github.com/posthog/posthog-python
6
6
  Author: Posthog