lmnr 0.7.12__tar.gz → 0.7.14__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.

Potentially problematic release.


This version of lmnr might be problematic. Click here for more details.

Files changed (103) hide show
  1. {lmnr-0.7.12 → lmnr-0.7.14}/PKG-INFO +47 -47
  2. {lmnr-0.7.12 → lmnr-0.7.14}/pyproject.toml +49 -50
  3. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/tracing/__init__.py +14 -10
  4. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +9 -0
  5. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/tracing/exporter.py +34 -8
  6. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/asynchronous/async_client.py +21 -3
  7. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/asynchronous/resources/evals.py +115 -18
  8. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/synchronous/resources/evals.py +71 -13
  9. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/synchronous/sync_client.py +20 -2
  10. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/laminar.py +17 -9
  11. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/types.py +40 -18
  12. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/utils.py +51 -0
  13. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/version.py +1 -1
  14. {lmnr-0.7.12 → lmnr-0.7.14}/README.md +0 -0
  15. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/__init__.py +0 -0
  16. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/cli.py +0 -0
  17. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/.flake8 +0 -0
  18. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/__init__.py +0 -0
  19. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/decorators/__init__.py +0 -0
  20. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/litellm/__init__.py +0 -0
  21. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/litellm/utils.py +0 -0
  22. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/__init__.py +0 -0
  23. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/config.py +0 -0
  24. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_emitter.py +0 -0
  25. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_models.py +0 -0
  26. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/span_utils.py +0 -0
  27. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/streaming.py +0 -0
  28. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/utils.py +0 -0
  29. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/version.py +0 -0
  30. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_agent/__init__.py +0 -0
  31. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_computer/__init__.py +0 -0
  32. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_computer/utils.py +0 -0
  33. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/__init__.py +0 -0
  34. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/config.py +0 -0
  35. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/schema_utils.py +0 -0
  36. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/utils.py +0 -0
  37. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/__init__.py +0 -0
  38. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/config.py +0 -0
  39. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_emitter.py +0 -0
  40. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_models.py +0 -0
  41. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/span_utils.py +0 -0
  42. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/utils.py +0 -0
  43. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/version.py +0 -0
  44. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/__init__.py +0 -0
  45. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/utils.py +0 -0
  46. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/__init__.py +0 -0
  47. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/__init__.py +0 -0
  48. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +0 -0
  49. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +0 -0
  50. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/config.py +0 -0
  51. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +0 -0
  52. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_emitter.py +0 -0
  53. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_models.py +0 -0
  54. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +0 -0
  55. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/utils.py +0 -0
  56. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v0/__init__.py +0 -0
  57. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/__init__.py +0 -0
  58. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +0 -0
  59. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +0 -0
  60. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +0 -0
  61. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/version.py +0 -0
  62. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openhands_ai/__init__.py +0 -0
  63. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/opentelemetry/__init__.py +0 -0
  64. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/skyvern/__init__.py +0 -0
  65. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/threading/__init__.py +0 -0
  66. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/tracing/attributes.py +0 -0
  67. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/tracing/context.py +0 -0
  68. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/tracing/instruments.py +0 -0
  69. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/tracing/processor.py +0 -0
  70. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/tracing/tracer.py +0 -0
  71. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/utils/__init__.py +0 -0
  72. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/utils/json_encoder.py +0 -0
  73. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/utils/package_check.py +0 -0
  74. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/opentelemetry_lib/utils/wrappers.py +0 -0
  75. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/py.typed +0 -0
  76. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/__init__.py +0 -0
  77. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/browser/__init__.py +0 -0
  78. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/browser/browser_use_cdp_otel.py +0 -0
  79. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/browser/browser_use_otel.py +0 -0
  80. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/browser/bubus_otel.py +0 -0
  81. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/browser/cdp_utils.py +0 -0
  82. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/browser/patchright_otel.py +0 -0
  83. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/browser/playwright_otel.py +0 -0
  84. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/browser/pw_utils.py +0 -0
  85. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/browser/recorder/record.umd.min.cjs +0 -0
  86. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/browser/utils.py +0 -0
  87. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/asynchronous/resources/__init__.py +0 -0
  88. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/asynchronous/resources/agent.py +0 -0
  89. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/asynchronous/resources/base.py +0 -0
  90. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/asynchronous/resources/browser_events.py +0 -0
  91. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/asynchronous/resources/evaluators.py +0 -0
  92. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/asynchronous/resources/tags.py +0 -0
  93. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/synchronous/resources/__init__.py +0 -0
  94. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/synchronous/resources/agent.py +0 -0
  95. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/synchronous/resources/base.py +0 -0
  96. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/synchronous/resources/browser_events.py +0 -0
  97. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/synchronous/resources/evaluators.py +0 -0
  98. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/client/synchronous/resources/tags.py +0 -0
  99. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/datasets.py +0 -0
  100. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/decorators.py +0 -0
  101. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/eval_control.py +0 -0
  102. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/evaluations.py +0 -0
  103. {lmnr-0.7.12 → lmnr-0.7.14}/src/lmnr/sdk/log.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lmnr
3
- Version: 0.7.12
3
+ Version: 0.7.14
4
4
  Summary: Python SDK for Laminar
5
5
  Author: lmnr.ai
6
6
  Author-email: lmnr.ai <founders@lmnr.ai>
@@ -26,52 +26,52 @@ Requires-Dist: grpcio>=1
26
26
  Requires-Dist: httpx>=0.24.0
27
27
  Requires-Dist: orjson>=3.0.0
28
28
  Requires-Dist: packaging>=22.0
29
- Requires-Dist: opentelemetry-instrumentation-alephalpha>=0.46.2 ; extra == 'alephalpha'
30
- Requires-Dist: opentelemetry-instrumentation-alephalpha>=0.46.2 ; extra == 'all'
31
- Requires-Dist: opentelemetry-instrumentation-bedrock>=0.46.2 ; extra == 'all'
32
- Requires-Dist: opentelemetry-instrumentation-chromadb>=0.46.2 ; extra == 'all'
33
- Requires-Dist: opentelemetry-instrumentation-cohere>=0.46.2 ; extra == 'all'
34
- Requires-Dist: opentelemetry-instrumentation-crewai>=0.46.2 ; extra == 'all'
35
- Requires-Dist: opentelemetry-instrumentation-haystack>=0.46.2 ; extra == 'all'
36
- Requires-Dist: opentelemetry-instrumentation-lancedb>=0.46.2 ; extra == 'all'
37
- Requires-Dist: opentelemetry-instrumentation-langchain>=0.46.2 ; extra == 'all'
38
- Requires-Dist: opentelemetry-instrumentation-llamaindex>=0.46.2 ; extra == 'all'
39
- Requires-Dist: opentelemetry-instrumentation-marqo>=0.46.2 ; extra == 'all'
40
- Requires-Dist: opentelemetry-instrumentation-mcp>=0.46.2 ; extra == 'all'
41
- Requires-Dist: opentelemetry-instrumentation-milvus>=0.46.2 ; extra == 'all'
42
- Requires-Dist: opentelemetry-instrumentation-mistralai>=0.46.2 ; extra == 'all'
43
- Requires-Dist: opentelemetry-instrumentation-ollama>=0.46.2 ; extra == 'all'
44
- Requires-Dist: opentelemetry-instrumentation-pinecone>=0.46.2 ; extra == 'all'
45
- Requires-Dist: opentelemetry-instrumentation-qdrant>=0.46.2 ; extra == 'all'
46
- Requires-Dist: opentelemetry-instrumentation-replicate>=0.46.2 ; extra == 'all'
47
- Requires-Dist: opentelemetry-instrumentation-sagemaker>=0.46.2 ; extra == 'all'
48
- Requires-Dist: opentelemetry-instrumentation-together>=0.46.2 ; extra == 'all'
49
- Requires-Dist: opentelemetry-instrumentation-transformers>=0.46.2 ; extra == 'all'
50
- Requires-Dist: opentelemetry-instrumentation-vertexai>=0.46.2 ; extra == 'all'
51
- Requires-Dist: opentelemetry-instrumentation-watsonx>=0.46.2 ; extra == 'all'
52
- Requires-Dist: opentelemetry-instrumentation-weaviate>=0.46.2 ; extra == 'all'
53
- Requires-Dist: opentelemetry-instrumentation-bedrock>=0.46.2 ; extra == 'bedrock'
54
- Requires-Dist: opentelemetry-instrumentation-chromadb>=0.46.2 ; extra == 'chromadb'
55
- Requires-Dist: opentelemetry-instrumentation-cohere>=0.46.2 ; extra == 'cohere'
56
- Requires-Dist: opentelemetry-instrumentation-crewai>=0.46.2 ; extra == 'crewai'
57
- Requires-Dist: opentelemetry-instrumentation-haystack>=0.46.2 ; extra == 'haystack'
58
- Requires-Dist: opentelemetry-instrumentation-lancedb>=0.46.2 ; extra == 'lancedb'
59
- Requires-Dist: opentelemetry-instrumentation-langchain>=0.46.2 ; extra == 'langchain'
60
- Requires-Dist: opentelemetry-instrumentation-llamaindex>=0.46.2 ; extra == 'llamaindex'
61
- Requires-Dist: opentelemetry-instrumentation-marqo>=0.46.2 ; extra == 'marqo'
62
- Requires-Dist: opentelemetry-instrumentation-mcp>=0.46.2 ; extra == 'mcp'
63
- Requires-Dist: opentelemetry-instrumentation-milvus>=0.46.2 ; extra == 'milvus'
64
- Requires-Dist: opentelemetry-instrumentation-mistralai>=0.46.2 ; extra == 'mistralai'
65
- Requires-Dist: opentelemetry-instrumentation-ollama>=0.46.2 ; extra == 'ollama'
66
- Requires-Dist: opentelemetry-instrumentation-pinecone>=0.46.2 ; extra == 'pinecone'
67
- Requires-Dist: opentelemetry-instrumentation-qdrant>=0.46.2 ; extra == 'qdrant'
68
- Requires-Dist: opentelemetry-instrumentation-replicate>=0.46.2 ; extra == 'replicate'
69
- Requires-Dist: opentelemetry-instrumentation-sagemaker>=0.46.2 ; extra == 'sagemaker'
70
- Requires-Dist: opentelemetry-instrumentation-together>=0.46.2 ; extra == 'together'
71
- Requires-Dist: opentelemetry-instrumentation-transformers>=0.46.2 ; extra == 'transformers'
72
- Requires-Dist: opentelemetry-instrumentation-vertexai>=0.46.2 ; extra == 'vertexai'
73
- Requires-Dist: opentelemetry-instrumentation-watsonx>=0.46.2 ; extra == 'watsonx'
74
- Requires-Dist: opentelemetry-instrumentation-weaviate>=0.46.2 ; extra == 'weaviate'
29
+ Requires-Dist: opentelemetry-instrumentation-alephalpha>=0.47.1 ; extra == 'alephalpha'
30
+ Requires-Dist: opentelemetry-instrumentation-alephalpha>=0.47.1 ; extra == 'all'
31
+ Requires-Dist: opentelemetry-instrumentation-bedrock>=0.47.1 ; extra == 'all'
32
+ Requires-Dist: opentelemetry-instrumentation-chromadb>=0.47.1 ; extra == 'all'
33
+ Requires-Dist: opentelemetry-instrumentation-cohere>=0.47.1 ; extra == 'all'
34
+ Requires-Dist: opentelemetry-instrumentation-crewai>=0.47.1 ; extra == 'all'
35
+ Requires-Dist: opentelemetry-instrumentation-haystack>=0.47.1 ; extra == 'all'
36
+ Requires-Dist: opentelemetry-instrumentation-lancedb>=0.47.1 ; extra == 'all'
37
+ Requires-Dist: opentelemetry-instrumentation-langchain>=0.47.1 ; extra == 'all'
38
+ Requires-Dist: opentelemetry-instrumentation-llamaindex>=0.47.1 ; extra == 'all'
39
+ Requires-Dist: opentelemetry-instrumentation-marqo>=0.47.1 ; extra == 'all'
40
+ Requires-Dist: opentelemetry-instrumentation-mcp>=0.47.1 ; extra == 'all'
41
+ Requires-Dist: opentelemetry-instrumentation-milvus>=0.47.1 ; extra == 'all'
42
+ Requires-Dist: opentelemetry-instrumentation-mistralai>=0.47.1 ; extra == 'all'
43
+ Requires-Dist: opentelemetry-instrumentation-ollama>=0.47.1 ; extra == 'all'
44
+ Requires-Dist: opentelemetry-instrumentation-pinecone>=0.47.1 ; extra == 'all'
45
+ Requires-Dist: opentelemetry-instrumentation-qdrant>=0.47.1 ; extra == 'all'
46
+ Requires-Dist: opentelemetry-instrumentation-replicate>=0.47.1 ; extra == 'all'
47
+ Requires-Dist: opentelemetry-instrumentation-sagemaker>=0.47.1 ; extra == 'all'
48
+ Requires-Dist: opentelemetry-instrumentation-together>=0.47.1 ; extra == 'all'
49
+ Requires-Dist: opentelemetry-instrumentation-transformers>=0.47.1 ; extra == 'all'
50
+ Requires-Dist: opentelemetry-instrumentation-vertexai>=0.47.1 ; extra == 'all'
51
+ Requires-Dist: opentelemetry-instrumentation-watsonx>=0.47.1 ; extra == 'all'
52
+ Requires-Dist: opentelemetry-instrumentation-weaviate>=0.47.1 ; extra == 'all'
53
+ Requires-Dist: opentelemetry-instrumentation-bedrock>=0.47.1 ; extra == 'bedrock'
54
+ Requires-Dist: opentelemetry-instrumentation-chromadb>=0.47.1 ; extra == 'chromadb'
55
+ Requires-Dist: opentelemetry-instrumentation-cohere>=0.47.1 ; extra == 'cohere'
56
+ Requires-Dist: opentelemetry-instrumentation-crewai>=0.47.1 ; extra == 'crewai'
57
+ Requires-Dist: opentelemetry-instrumentation-haystack>=0.47.1 ; extra == 'haystack'
58
+ Requires-Dist: opentelemetry-instrumentation-lancedb>=0.47.1 ; extra == 'lancedb'
59
+ Requires-Dist: opentelemetry-instrumentation-langchain>=0.47.1 ; extra == 'langchain'
60
+ Requires-Dist: opentelemetry-instrumentation-llamaindex>=0.47.1 ; extra == 'llamaindex'
61
+ Requires-Dist: opentelemetry-instrumentation-marqo>=0.47.1 ; extra == 'marqo'
62
+ Requires-Dist: opentelemetry-instrumentation-mcp>=0.47.1 ; extra == 'mcp'
63
+ Requires-Dist: opentelemetry-instrumentation-milvus>=0.47.1 ; extra == 'milvus'
64
+ Requires-Dist: opentelemetry-instrumentation-mistralai>=0.47.1 ; extra == 'mistralai'
65
+ Requires-Dist: opentelemetry-instrumentation-ollama>=0.47.1 ; extra == 'ollama'
66
+ Requires-Dist: opentelemetry-instrumentation-pinecone>=0.47.1 ; extra == 'pinecone'
67
+ Requires-Dist: opentelemetry-instrumentation-qdrant>=0.47.1 ; extra == 'qdrant'
68
+ Requires-Dist: opentelemetry-instrumentation-replicate>=0.47.1 ; extra == 'replicate'
69
+ Requires-Dist: opentelemetry-instrumentation-sagemaker>=0.47.1 ; extra == 'sagemaker'
70
+ Requires-Dist: opentelemetry-instrumentation-together>=0.47.1 ; extra == 'together'
71
+ Requires-Dist: opentelemetry-instrumentation-transformers>=0.47.1 ; extra == 'transformers'
72
+ Requires-Dist: opentelemetry-instrumentation-vertexai>=0.47.1 ; extra == 'vertexai'
73
+ Requires-Dist: opentelemetry-instrumentation-watsonx>=0.47.1 ; extra == 'watsonx'
74
+ Requires-Dist: opentelemetry-instrumentation-weaviate>=0.47.1 ; extra == 'weaviate'
75
75
  Requires-Python: >=3.10, <4
76
76
  Provides-Extra: alephalpha
77
77
  Provides-Extra: all
@@ -6,7 +6,7 @@
6
6
 
7
7
  [project]
8
8
  name = "lmnr"
9
- version = "0.7.12"
9
+ version = "0.7.14"
10
10
  description = "Python SDK for Laminar"
11
11
  authors = [
12
12
  { name = "lmnr.ai", email = "founders@lmnr.ai" }
@@ -62,57 +62,57 @@ lmnr = "lmnr.cli:cli"
62
62
  # `uv add lmnr --extra anthropic --extra groq`
63
63
  # `poetry add 'lmnr[anthropic,groq]'`
64
64
 
65
- alephalpha=["opentelemetry-instrumentation-alephalpha>=0.46.2"]
66
- bedrock=["opentelemetry-instrumentation-bedrock>=0.46.2"]
67
- chromadb=["opentelemetry-instrumentation-chromadb>=0.46.2"]
68
- cohere=["opentelemetry-instrumentation-cohere>=0.46.2"]
69
- crewai=["opentelemetry-instrumentation-crewai>=0.46.2"]
70
- haystack=["opentelemetry-instrumentation-haystack>=0.46.2"]
71
- lancedb=["opentelemetry-instrumentation-lancedb>=0.46.2"]
72
- langchain=["opentelemetry-instrumentation-langchain>=0.46.2"]
73
- llamaindex=["opentelemetry-instrumentation-llamaindex>=0.46.2"]
74
- marqo=["opentelemetry-instrumentation-marqo>=0.46.2"]
75
- mcp=["opentelemetry-instrumentation-mcp>=0.46.2"]
76
- milvus=["opentelemetry-instrumentation-milvus>=0.46.2"]
77
- mistralai=["opentelemetry-instrumentation-mistralai>=0.46.2"]
78
- ollama=["opentelemetry-instrumentation-ollama>=0.46.2"]
79
- pinecone=["opentelemetry-instrumentation-pinecone>=0.46.2"]
80
- qdrant=["opentelemetry-instrumentation-qdrant>=0.46.2"]
81
- replicate=["opentelemetry-instrumentation-replicate>=0.46.2"]
82
- sagemaker=["opentelemetry-instrumentation-sagemaker>=0.46.2"]
83
- together=["opentelemetry-instrumentation-together>=0.46.2"]
84
- transformers=["opentelemetry-instrumentation-transformers>=0.46.2"]
85
- vertexai=["opentelemetry-instrumentation-vertexai>=0.46.2"]
86
- watsonx=["opentelemetry-instrumentation-watsonx>=0.46.2"]
87
- weaviate=["opentelemetry-instrumentation-weaviate>=0.46.2"]
65
+ alephalpha=["opentelemetry-instrumentation-alephalpha>=0.47.1"]
66
+ bedrock=["opentelemetry-instrumentation-bedrock>=0.47.1"]
67
+ chromadb=["opentelemetry-instrumentation-chromadb>=0.47.1"]
68
+ cohere=["opentelemetry-instrumentation-cohere>=0.47.1"]
69
+ crewai=["opentelemetry-instrumentation-crewai>=0.47.1"]
70
+ haystack=["opentelemetry-instrumentation-haystack>=0.47.1"]
71
+ lancedb=["opentelemetry-instrumentation-lancedb>=0.47.1"]
72
+ langchain=["opentelemetry-instrumentation-langchain>=0.47.1"]
73
+ llamaindex=["opentelemetry-instrumentation-llamaindex>=0.47.1"]
74
+ marqo=["opentelemetry-instrumentation-marqo>=0.47.1"]
75
+ mcp=["opentelemetry-instrumentation-mcp>=0.47.1"]
76
+ milvus=["opentelemetry-instrumentation-milvus>=0.47.1"]
77
+ mistralai=["opentelemetry-instrumentation-mistralai>=0.47.1"]
78
+ ollama=["opentelemetry-instrumentation-ollama>=0.47.1"]
79
+ pinecone=["opentelemetry-instrumentation-pinecone>=0.47.1"]
80
+ qdrant=["opentelemetry-instrumentation-qdrant>=0.47.1"]
81
+ replicate=["opentelemetry-instrumentation-replicate>=0.47.1"]
82
+ sagemaker=["opentelemetry-instrumentation-sagemaker>=0.47.1"]
83
+ together=["opentelemetry-instrumentation-together>=0.47.1"]
84
+ transformers=["opentelemetry-instrumentation-transformers>=0.47.1"]
85
+ vertexai=["opentelemetry-instrumentation-vertexai>=0.47.1"]
86
+ watsonx=["opentelemetry-instrumentation-watsonx>=0.47.1"]
87
+ weaviate=["opentelemetry-instrumentation-weaviate>=0.47.1"]
88
88
  # `all` is the group added for convenience, if you want to install all
89
89
  # the instrumentations.
90
90
  # we suggest using package-manager-specific commands instead,
91
91
  # like `uv add lmnr --all-extras`
92
92
  all = [
93
- "opentelemetry-instrumentation-alephalpha>=0.46.2",
94
- "opentelemetry-instrumentation-bedrock>=0.46.2",
95
- "opentelemetry-instrumentation-chromadb>=0.46.2",
96
- "opentelemetry-instrumentation-cohere>=0.46.2",
97
- "opentelemetry-instrumentation-crewai>=0.46.2",
98
- "opentelemetry-instrumentation-haystack>=0.46.2",
99
- "opentelemetry-instrumentation-lancedb>=0.46.2",
100
- "opentelemetry-instrumentation-langchain>=0.46.2",
101
- "opentelemetry-instrumentation-llamaindex>=0.46.2",
102
- "opentelemetry-instrumentation-marqo>=0.46.2",
103
- "opentelemetry-instrumentation-mcp>=0.46.2",
104
- "opentelemetry-instrumentation-milvus>=0.46.2",
105
- "opentelemetry-instrumentation-mistralai>=0.46.2",
106
- "opentelemetry-instrumentation-ollama>=0.46.2",
107
- "opentelemetry-instrumentation-pinecone>=0.46.2",
108
- "opentelemetry-instrumentation-qdrant>=0.46.2",
109
- "opentelemetry-instrumentation-replicate>=0.46.2",
110
- "opentelemetry-instrumentation-sagemaker>=0.46.2",
111
- "opentelemetry-instrumentation-together>=0.46.2",
112
- "opentelemetry-instrumentation-transformers>=0.46.2",
113
- "opentelemetry-instrumentation-vertexai>=0.46.2",
114
- "opentelemetry-instrumentation-watsonx>=0.46.2",
115
- "opentelemetry-instrumentation-weaviate>=0.46.2"
93
+ "opentelemetry-instrumentation-alephalpha>=0.47.1",
94
+ "opentelemetry-instrumentation-bedrock>=0.47.1",
95
+ "opentelemetry-instrumentation-chromadb>=0.47.1",
96
+ "opentelemetry-instrumentation-cohere>=0.47.1",
97
+ "opentelemetry-instrumentation-crewai>=0.47.1",
98
+ "opentelemetry-instrumentation-haystack>=0.47.1",
99
+ "opentelemetry-instrumentation-lancedb>=0.47.1",
100
+ "opentelemetry-instrumentation-langchain>=0.47.1",
101
+ "opentelemetry-instrumentation-llamaindex>=0.47.1",
102
+ "opentelemetry-instrumentation-marqo>=0.47.1",
103
+ "opentelemetry-instrumentation-mcp>=0.47.1",
104
+ "opentelemetry-instrumentation-milvus>=0.47.1",
105
+ "opentelemetry-instrumentation-mistralai>=0.47.1",
106
+ "opentelemetry-instrumentation-ollama>=0.47.1",
107
+ "opentelemetry-instrumentation-pinecone>=0.47.1",
108
+ "opentelemetry-instrumentation-qdrant>=0.47.1",
109
+ "opentelemetry-instrumentation-replicate>=0.47.1",
110
+ "opentelemetry-instrumentation-sagemaker>=0.47.1",
111
+ "opentelemetry-instrumentation-together>=0.47.1",
112
+ "opentelemetry-instrumentation-transformers>=0.47.1",
113
+ "opentelemetry-instrumentation-vertexai>=0.47.1",
114
+ "opentelemetry-instrumentation-watsonx>=0.47.1",
115
+ "opentelemetry-instrumentation-weaviate>=0.47.1"
116
116
  ]
117
117
 
118
118
  [dependency-groups]
@@ -124,15 +124,14 @@ dev = [
124
124
  "pytest-asyncio>=1.1.0",
125
125
  "playwright>=1.52.0",
126
126
  "vcrpy>=7.0.0",
127
- # litellm breaks with openai>=1.100.0 (as of litellm 1.75.8)
128
- "openai>=1.99.7,<1.100.0",
127
+ "openai>=1.107.0",
129
128
  "pytest-recording>=0.13.4",
130
129
  "patchright>=1.52.3",
131
130
  "google-genai>=1.31.0",
132
131
  "langgraph>=0.4.8",
133
132
  "langchain-core>=0.3.75",
134
133
  "langchain>=0.3.27",
135
- "litellm>=1.75.8",
134
+ "litellm>=1.77.0",
136
135
  "groq>=0.30.0",
137
136
  "anthropic[bedrock]>=0.60.0",
138
137
  "langchain-openai>=0.3.32",
@@ -55,7 +55,7 @@ class TracerWrapper(object):
55
55
  exporter: SpanExporter | None = None,
56
56
  instruments: set[Instruments] | None = None,
57
57
  block_instruments: set[Instruments] | None = None,
58
- base_url: str = "https://api.lmnr.ai",
58
+ base_url: str | None = None,
59
59
  port: int = 8443,
60
60
  http_port: int = 443,
61
61
  project_api_key: str | None = None,
@@ -69,7 +69,7 @@ class TracerWrapper(object):
69
69
  # Silence some opentelemetry warnings
70
70
  logging.getLogger("opentelemetry.trace").setLevel(otel_logger_level)
71
71
 
72
- base_http_url = f"{base_url}:{http_port}"
72
+ base_http_url = f"{base_url}:{http_port}" if base_url else None
73
73
  with cls._lock:
74
74
  if not hasattr(cls, "instance"):
75
75
  cls._initialize_logger(cls)
@@ -78,14 +78,18 @@ class TracerWrapper(object):
78
78
  # Store session recording options
79
79
  cls.session_recording_options = session_recording_options or {}
80
80
 
81
- obj._client = LaminarClient(
82
- base_url=base_http_url,
83
- project_api_key=project_api_key,
84
- )
85
- obj._async_client = AsyncLaminarClient(
86
- base_url=base_http_url,
87
- project_api_key=project_api_key,
88
- )
81
+ if project_api_key:
82
+ obj._client = LaminarClient(
83
+ base_url=base_http_url or "https://api.lmnr.ai",
84
+ project_api_key=project_api_key,
85
+ )
86
+ obj._async_client = AsyncLaminarClient(
87
+ base_url=base_http_url or "https://api.lmnr.ai",
88
+ project_api_key=project_api_key,
89
+ )
90
+ else:
91
+ obj._client = None
92
+ obj._async_client = None
89
93
 
90
94
  obj._resource = Resource(attributes=TracerWrapper.resource_attributes)
91
95
 
@@ -91,6 +91,9 @@ class BrowserUseSessionInstrumentorInitializer(InstrumentorInitializer):
91
91
  if version and parse(version) >= parse("0.6.0rc1"):
92
92
  from lmnr.sdk.browser.browser_use_cdp_otel import BrowserUseInstrumentor
93
93
 
94
+ if async_client is None:
95
+ return None
96
+
94
97
  return BrowserUseInstrumentor(async_client)
95
98
 
96
99
  return None
@@ -348,6 +351,9 @@ class PatchrightInstrumentorInitializer(InstrumentorInitializer):
348
351
 
349
352
  from lmnr.sdk.browser.patchright_otel import PatchrightInstrumentor
350
353
 
354
+ if client is None and async_client is None:
355
+ return None
356
+
351
357
  return PatchrightInstrumentor(client, async_client)
352
358
 
353
359
 
@@ -372,6 +378,9 @@ class PlaywrightInstrumentorInitializer(InstrumentorInitializer):
372
378
 
373
379
  from lmnr.sdk.browser.playwright_otel import PlaywrightInstrumentor
374
380
 
381
+ if client is None and async_client is None:
382
+ return None
383
+
375
384
  return PlaywrightInstrumentor(client, async_client)
376
385
 
377
386
 
@@ -10,7 +10,10 @@ from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
10
10
  OTLPSpanExporter as HTTPOTLPSpanExporter,
11
11
  )
12
12
 
13
- from lmnr.sdk.utils import from_env
13
+ from lmnr.sdk.log import get_default_logger
14
+ from lmnr.sdk.utils import from_env, get_otel_env_var, parse_otel_headers
15
+
16
+ logger = get_default_logger(__name__)
14
17
 
15
18
 
16
19
  class LaminarSpanExporter(SpanExporter):
@@ -39,16 +42,39 @@ class LaminarSpanExporter(SpanExporter):
39
42
  final_url = f"{url}:{port or 443}"
40
43
  api_key = api_key or from_env("LMNR_PROJECT_API_KEY")
41
44
  self.endpoint = final_url
42
- self.headers = (
43
- {"Authorization": f"Bearer {api_key}"}
44
- if force_http
45
- else {"authorization": f"Bearer {api_key}"}
46
- )
45
+ if api_key:
46
+ self.headers = (
47
+ {"Authorization": f"Bearer {api_key}"}
48
+ if force_http
49
+ else {"authorization": f"Bearer {api_key}"}
50
+ )
51
+ elif get_otel_env_var("HEADERS"):
52
+ self.headers = parse_otel_headers(get_otel_env_var("HEADERS"))
53
+ else:
54
+ self.headers = {}
47
55
  self.timeout = timeout_seconds
48
56
  self.force_http = force_http
49
- self._init_instance()
57
+ if get_otel_env_var("ENDPOINT"):
58
+ if not base_url:
59
+ self.endpoint = get_otel_env_var("ENDPOINT")
60
+ else:
61
+ logger.warning(
62
+ "OTEL_ENDPOINT is set, but Laminar base URL is also set. Ignoring OTEL_ENDPOINT."
63
+ )
64
+ protocol = get_otel_env_var("PROTOCOL") or "grpc/protobuf"
65
+ exporter_type = from_env("OTEL_EXPORTER") or "otlp_grpc"
66
+ self.force_http = (
67
+ protocol in ("http/protobuf", "http/json")
68
+ or exporter_type == "otlp_http"
69
+ )
70
+ if not self.endpoint:
71
+ raise ValueError(
72
+ "Laminar base URL is not set and OTEL_ENDPOINT is not set. Please either\n"
73
+ "- set the LMNR_BASE_URL environment variable\n"
74
+ "- set the OTEL_ENDPOINT environment variable\n"
75
+ "- pass the base_url parameter to Laminar.initialize"
76
+ )
50
77
 
51
- def _init_instance(self):
52
78
  if self.force_http:
53
79
  self.instance = HTTPOTLPSpanExporter(
54
80
  endpoint=self.endpoint,
@@ -12,7 +12,7 @@ from lmnr.sdk.client.asynchronous.resources import (
12
12
  AsyncBrowserEvents,
13
13
  AsyncEvals,
14
14
  AsyncTags,
15
- AsyncEvaluators
15
+ AsyncEvaluators,
16
16
  )
17
17
  from lmnr.sdk.utils import from_env
18
18
 
@@ -66,6 +66,26 @@ class AsyncLaminarClient:
66
66
  self.__client = httpx.AsyncClient(
67
67
  headers=self._headers(),
68
68
  timeout=timeout,
69
+ # Context: If the server responds with a 413, the connection becomes
70
+ # poisoned and freezes on subsequent requests, and there is no way
71
+ # to recover or recycle such connection.
72
+ # Setting max_keepalive_connections to 0 will resolve this, but is
73
+ # less efficient, as it will create a new connection
74
+ # (not client, so still better) for each request.
75
+ #
76
+ # Note: from my experiments with a simple python server, forcing the
77
+ # server to read/consume the request payload from the socket seems
78
+ # to resolve this, but I haven't figured out how to do that in our
79
+ # real actix-web backend server and whether it makes sense to do so.
80
+ #
81
+ # TODO: investigate if there are better ways to fix this rather than
82
+ # setting keepalive_expiry to 0. Other alternative: migrate to
83
+ # requests + aiohttp.
84
+ #
85
+ # limits=httpx.Limits(
86
+ # max_keepalive_connections=0,
87
+ # keepalive_expiry=0,
88
+ # ),
69
89
  )
70
90
 
71
91
  # Initialize resource objects
@@ -157,5 +177,3 @@ class AsyncLaminarClient:
157
177
  "Content-Type": "application/json",
158
178
  "Accept": "application/json",
159
179
  }
160
-
161
-
@@ -1,21 +1,31 @@
1
1
  """Evals resource for interacting with Laminar evaluations API."""
2
2
 
3
- from typing import Any
3
+ import urllib
4
4
  import uuid
5
+ from typing import Any
5
6
 
6
7
  from lmnr.sdk.client.asynchronous.resources.base import BaseAsyncResource
8
+ from lmnr.sdk.log import get_default_logger
7
9
  from lmnr.sdk.types import (
10
+ GetDatapointsResponse,
8
11
  InitEvaluationResponse,
9
12
  EvaluationResultDatapoint,
10
13
  PartialEvaluationDatapoint,
11
14
  )
15
+ from lmnr.sdk.utils import serialize
16
+
17
+ INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16_000_000 # 16MB
18
+ logger = get_default_logger(__name__)
12
19
 
13
20
 
14
21
  class AsyncEvals(BaseAsyncResource):
15
22
  """Resource for interacting with Laminar evaluations API."""
16
23
 
17
24
  async def init(
18
- self, name: str | None = None, group_name: str | None = None, metadata: dict[str, Any] | None = None
25
+ self,
26
+ name: str | None = None,
27
+ group_name: str | None = None,
28
+ metadata: dict[str, Any] | None = None,
19
29
  ) -> InitEvaluationResponse:
20
30
  """Initialize a new evaluation.
21
31
 
@@ -51,7 +61,7 @@ class AsyncEvals(BaseAsyncResource):
51
61
  ) -> uuid.UUID:
52
62
  """
53
63
  Create a new evaluation and return its ID.
54
-
64
+
55
65
  Parameters:
56
66
  name (str | None, optional): Optional name of the evaluation.
57
67
  group_name (str | None, optional): An identifier to group evaluations.
@@ -60,7 +70,9 @@ class AsyncEvals(BaseAsyncResource):
60
70
  Returns:
61
71
  uuid.UUID: The evaluation ID.
62
72
  """
63
- evaluation = await self.init(name=name, group_name=group_name, metadata=metadata)
73
+ evaluation = await self.init(
74
+ name=name, group_name=group_name, metadata=metadata
75
+ )
64
76
  return evaluation.id
65
77
 
66
78
  async def create_datapoint(
@@ -74,7 +86,7 @@ class AsyncEvals(BaseAsyncResource):
74
86
  ) -> uuid.UUID:
75
87
  """
76
88
  Create a datapoint for an evaluation.
77
-
89
+
78
90
  Parameters:
79
91
  eval_id (uuid.UUID): The evaluation ID.
80
92
  data: The input data for the executor.
@@ -82,13 +94,13 @@ class AsyncEvals(BaseAsyncResource):
82
94
  metadata (dict[str, Any] | None, optional): Optional metadata.
83
95
  index (int | None, optional): Optional index of the datapoint.
84
96
  trace_id (uuid.UUID | None, optional): Optional trace ID.
85
-
97
+
86
98
  Returns:
87
99
  uuid.UUID: The datapoint ID.
88
100
  """
89
-
101
+
90
102
  datapoint_id = uuid.uuid4()
91
-
103
+
92
104
  # Create a minimal datapoint first
93
105
  partial_datapoint = PartialEvaluationDatapoint(
94
106
  id=datapoint_id,
@@ -99,7 +111,7 @@ class AsyncEvals(BaseAsyncResource):
99
111
  executor_span_id=uuid.uuid4(), # Will be updated when executor runs
100
112
  metadata=metadata,
101
113
  )
102
-
114
+
103
115
  await self.save_datapoints(eval_id, [partial_datapoint])
104
116
  return datapoint_id
105
117
 
@@ -119,18 +131,61 @@ class AsyncEvals(BaseAsyncResource):
119
131
  Raises:
120
132
  ValueError: If there's an error saving the datapoints.
121
133
  """
134
+ length = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH
135
+ points = [datapoint.to_dict(max_data_length=length) for datapoint in datapoints]
122
136
  response = await self._client.post(
123
137
  self._base_url + f"/v1/evals/{eval_id}/datapoints",
124
138
  json={
125
- "points": [datapoint.to_dict() for datapoint in datapoints],
139
+ "points": points,
126
140
  "groupName": group_name,
127
141
  },
128
142
  headers=self._headers(),
129
143
  )
144
+ if response.status_code == 413:
145
+ await self._retry_save_datapoints(eval_id, datapoints, group_name)
146
+ return
147
+
130
148
  if response.status_code != 200:
131
- raise ValueError(f"Error saving evaluation datapoints: {response.text}")
132
-
133
-
149
+ raise ValueError(
150
+ f"Error saving evaluation datapoints: [{response.status_code}] {response.text}"
151
+ )
152
+
153
+ async def get_datapoints(
154
+ self,
155
+ dataset_name: str,
156
+ offset: int,
157
+ limit: int,
158
+ ) -> GetDatapointsResponse:
159
+ """Get datapoints from a dataset.
160
+
161
+ Args:
162
+ dataset_name (str): The name of the dataset.
163
+ offset (int): The offset to start from.
164
+ limit (int): The maximum number of datapoints to return.
165
+
166
+ Returns:
167
+ GetDatapointsResponse: The response containing the datapoints.
168
+
169
+ Raises:
170
+ ValueError: If there's an error fetching the datapoints.
171
+ """
172
+ params = {"name": dataset_name, "offset": offset, "limit": limit}
173
+ url = (
174
+ self._base_url + "/v1/datasets/datapoints?" + urllib.parse.urlencode(params)
175
+ )
176
+ response = await self._client.get(url, headers=self._headers())
177
+ if response.status_code != 200:
178
+ try:
179
+ resp_json = response.json()
180
+ raise ValueError(
181
+ f"Error fetching datapoints: [{response.status_code}] {resp_json}"
182
+ )
183
+ except Exception:
184
+ raise ValueError(
185
+ f"Error fetching datapoints: [{response.status_code}] {response.text}"
186
+ )
187
+ return GetDatapointsResponse.model_validate(response.json())
188
+
134
189
  async def update_datapoint(
135
190
  self,
136
191
  eval_id: uuid.UUID,
@@ -146,17 +201,59 @@ class AsyncEvals(BaseAsyncResource):
146
201
  executor_output (Any): The executor output.
147
202
  scores (dict[str, float | int] | None, optional): The scores. Defaults to None.
148
203
  """
149
-
204
+
150
205
  response = await self._client.post(
151
206
  self._base_url + f"/v1/evals/{eval_id}/datapoints/{datapoint_id}",
152
207
  json={
153
- "executorOutput": executor_output,
208
+ "executorOutput": (
209
+ str(serialize(executor_output))[
210
+ :INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH
211
+ ]
212
+ if executor_output is not None
213
+ else None
214
+ ),
154
215
  "scores": scores,
155
216
  },
156
217
  headers=self._headers(),
157
218
  )
158
219
 
159
220
  if response.status_code != 200:
160
- raise ValueError(f"Error updating evaluation datapoint: {response.text}")
161
-
162
-
221
+ raise ValueError(
222
+ f"Error updating evaluation datapoint: [{response.status_code}] {response.text}"
223
+ )
224
+
225
+ async def _retry_save_datapoints(
226
+ self,
227
+ eval_id: uuid.UUID,
228
+ datapoints: list[EvaluationResultDatapoint | PartialEvaluationDatapoint],
229
+ group_name: str | None = None,
230
+ initial_length: int = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,
231
+ max_retries: int = 20,
232
+ ):
233
+ retry = 0
234
+ length = initial_length
235
+ while retry < max_retries:
236
+ retry += 1
237
+ length = length // 2
238
+ logger.debug(
239
+ f"Retrying save datapoints: {retry} of {max_retries}, length: {length}"
240
+ )
241
+ if length == 0:
242
+ raise ValueError("Error saving evaluation datapoints")
243
+ points = [
244
+ datapoint.to_dict(max_data_length=length) for datapoint in datapoints
245
+ ]
246
+ response = await self._client.post(
247
+ self._base_url + f"/v1/evals/{eval_id}/datapoints",
248
+ json={
249
+ "points": points,
250
+ "groupName": group_name,
251
+ },
252
+ headers=self._headers(),
253
+ )
254
+ if response.status_code != 413:
255
+ break
256
+ if response.status_code != 200:
257
+ raise ValueError(
258
+ f"Error saving evaluation datapoints: [{response.status_code}] {response.text}"
259
+ )