lmnr 0.7.15__tar.gz → 0.7.17__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.
- {lmnr-0.7.15 → lmnr-0.7.17}/PKG-INFO +2 -1
- {lmnr-0.7.15 → lmnr-0.7.17}/pyproject.toml +3 -2
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/litellm/__init__.py +51 -4
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/__init__.py +19 -3
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/utils.py +50 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/version.py +1 -1
- {lmnr-0.7.15 → lmnr-0.7.17}/README.md +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/cli.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/.flake8 +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/decorators/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/litellm/utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/config.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_emitter.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_models.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/span_utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/streaming.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/version.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_agent/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_computer/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_computer/utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/config.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/schema_utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/config.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_emitter.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_models.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/span_utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/version.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/config.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_emitter.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_models.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v0/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/version.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openhands_ai/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/opentelemetry/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/skyvern/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/threading/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/tracing/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/tracing/attributes.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/tracing/context.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/tracing/exporter.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/tracing/instruments.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/tracing/processor.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/tracing/tracer.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/utils/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/utils/json_encoder.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/utils/package_check.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/utils/wrappers.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/py.typed +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/browser/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/browser/browser_use_cdp_otel.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/browser/browser_use_otel.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/browser/bubus_otel.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/browser/cdp_utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/browser/patchright_otel.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/browser/playwright_otel.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/browser/pw_utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/browser/recorder/record.umd.min.cjs +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/browser/utils.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/asynchronous/async_client.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/asynchronous/resources/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/asynchronous/resources/agent.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/asynchronous/resources/base.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/asynchronous/resources/browser_events.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/asynchronous/resources/evals.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/asynchronous/resources/evaluators.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/asynchronous/resources/tags.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/synchronous/resources/__init__.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/synchronous/resources/agent.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/synchronous/resources/base.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/synchronous/resources/browser_events.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/synchronous/resources/evals.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/synchronous/resources/evaluators.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/synchronous/resources/tags.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/client/synchronous/sync_client.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/datasets.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/decorators.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/eval_control.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/evaluations.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/laminar.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/log.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/types.py +0 -0
- {lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/sdk/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lmnr
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.17
|
|
4
4
|
Summary: Python SDK for Laminar
|
|
5
5
|
Author: lmnr.ai
|
|
6
6
|
Author-email: lmnr.ai <founders@lmnr.ai>
|
|
@@ -26,6 +26,7 @@ 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-threading>=0.57b0
|
|
29
30
|
Requires-Dist: opentelemetry-instrumentation-alephalpha>=0.47.1 ; extra == 'alephalpha'
|
|
30
31
|
Requires-Dist: opentelemetry-instrumentation-alephalpha>=0.47.1 ; extra == 'all'
|
|
31
32
|
Requires-Dist: opentelemetry-instrumentation-bedrock>=0.47.1 ; extra == 'all'
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "lmnr"
|
|
9
|
-
version = "0.7.
|
|
9
|
+
version = "0.7.17"
|
|
10
10
|
description = "Python SDK for Laminar"
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "lmnr.ai", email = "founders@lmnr.ai" }
|
|
@@ -39,6 +39,7 @@ dependencies = [
|
|
|
39
39
|
"httpx (>=0.24.0)",
|
|
40
40
|
"orjson (>=3.0.0)",
|
|
41
41
|
"packaging (>=22.0)",
|
|
42
|
+
"opentelemetry-instrumentation-threading>=0.57b0",
|
|
42
43
|
]
|
|
43
44
|
# poetry would auto-generate these based on requires-python, but other build
|
|
44
45
|
# systems don't, so we need to specify them manually.
|
|
@@ -145,4 +146,4 @@ build-backend = "uv_build"
|
|
|
145
146
|
members = ["examples/fastapi-app"]
|
|
146
147
|
|
|
147
148
|
[tool.ruff]
|
|
148
|
-
target-version = "py310"
|
|
149
|
+
target-version = "py310"
|
|
@@ -406,7 +406,15 @@ try:
|
|
|
406
406
|
details.get("cached_tokens"),
|
|
407
407
|
)
|
|
408
408
|
# TODO: add audio/image/text token details
|
|
409
|
-
|
|
409
|
+
if usage_dict.get("completion_tokens_details"):
|
|
410
|
+
details = usage_dict.get("completion_tokens_details", {})
|
|
411
|
+
details = model_as_dict(details)
|
|
412
|
+
if details.get("reasoning_tokens"):
|
|
413
|
+
set_span_attribute(
|
|
414
|
+
span,
|
|
415
|
+
"gen_ai.usage.reasoning_tokens",
|
|
416
|
+
details.get("reasoning_tokens"),
|
|
417
|
+
)
|
|
410
418
|
|
|
411
419
|
def _process_tool_calls(self, span, tool_calls, choice_index, is_response=True):
|
|
412
420
|
"""Process and set tool call attributes on the span"""
|
|
@@ -467,17 +475,56 @@ try:
|
|
|
467
475
|
content = message.get("content", "")
|
|
468
476
|
if content is None:
|
|
469
477
|
continue
|
|
478
|
+
reasoning_content = message.get("reasoning_content")
|
|
479
|
+
if reasoning_content:
|
|
480
|
+
if isinstance(reasoning_content, str):
|
|
481
|
+
reasoning_content = [
|
|
482
|
+
{
|
|
483
|
+
"type": "text",
|
|
484
|
+
"text": reasoning_content,
|
|
485
|
+
}
|
|
486
|
+
]
|
|
487
|
+
elif not isinstance(reasoning_content, list):
|
|
488
|
+
reasoning_content = [
|
|
489
|
+
{
|
|
490
|
+
"type": "text",
|
|
491
|
+
"text": str(reasoning_content),
|
|
492
|
+
}
|
|
493
|
+
]
|
|
494
|
+
else:
|
|
495
|
+
reasoning_content = []
|
|
470
496
|
if isinstance(content, str):
|
|
471
|
-
|
|
497
|
+
if reasoning_content:
|
|
498
|
+
set_span_attribute(
|
|
499
|
+
span,
|
|
500
|
+
f"gen_ai.completion.{i}.content",
|
|
501
|
+
json.dumps(
|
|
502
|
+
reasoning_content
|
|
503
|
+
+ [
|
|
504
|
+
{
|
|
505
|
+
"type": "text",
|
|
506
|
+
"text": content,
|
|
507
|
+
}
|
|
508
|
+
]
|
|
509
|
+
),
|
|
510
|
+
)
|
|
511
|
+
else:
|
|
512
|
+
set_span_attribute(
|
|
513
|
+
span,
|
|
514
|
+
f"gen_ai.completion.{i}.content",
|
|
515
|
+
content,
|
|
516
|
+
)
|
|
472
517
|
elif isinstance(content, list):
|
|
473
518
|
set_span_attribute(
|
|
474
|
-
span,
|
|
519
|
+
span,
|
|
520
|
+
f"gen_ai.completion.{i}.content",
|
|
521
|
+
json.dumps(reasoning_content + content),
|
|
475
522
|
)
|
|
476
523
|
else:
|
|
477
524
|
set_span_attribute(
|
|
478
525
|
span,
|
|
479
526
|
f"gen_ai.completion.{i}.content",
|
|
480
|
-
json.dumps(model_as_dict(content)),
|
|
527
|
+
json.dumps(reasoning_content + [model_as_dict(content)]),
|
|
481
528
|
)
|
|
482
529
|
|
|
483
530
|
def _process_content_part(self, content_part: dict) -> dict:
|
|
@@ -21,6 +21,7 @@ from .schema_utils import SchemaJSONEncoder, process_schema
|
|
|
21
21
|
from .utils import (
|
|
22
22
|
dont_throw,
|
|
23
23
|
get_content,
|
|
24
|
+
merge_text_parts,
|
|
24
25
|
process_content_union,
|
|
25
26
|
process_stream_chunk,
|
|
26
27
|
role_from_content_union,
|
|
@@ -272,6 +273,16 @@ def _set_response_attributes(span, response: types.GenerateContentResponse):
|
|
|
272
273
|
|
|
273
274
|
if response.usage_metadata:
|
|
274
275
|
usage_dict = to_dict(response.usage_metadata)
|
|
276
|
+
candidates_token_count = usage_dict.get("candidates_token_count")
|
|
277
|
+
# unlike OpenAI, and unlike input cached tokens, thinking tokens are
|
|
278
|
+
# not counted as part of candidates token count, so we need to add them
|
|
279
|
+
# separately for consistency with other instrumentations
|
|
280
|
+
thoughts_token_count = usage_dict.get("thoughts_token_count")
|
|
281
|
+
output_token_count = (
|
|
282
|
+
(candidates_token_count or 0) + (thoughts_token_count or 0)
|
|
283
|
+
if candidates_token_count is not None or thoughts_token_count is not None
|
|
284
|
+
else None
|
|
285
|
+
)
|
|
275
286
|
set_span_attribute(
|
|
276
287
|
span,
|
|
277
288
|
gen_ai_attributes.GEN_AI_USAGE_INPUT_TOKENS,
|
|
@@ -280,7 +291,7 @@ def _set_response_attributes(span, response: types.GenerateContentResponse):
|
|
|
280
291
|
set_span_attribute(
|
|
281
292
|
span,
|
|
282
293
|
gen_ai_attributes.GEN_AI_USAGE_OUTPUT_TOKENS,
|
|
283
|
-
|
|
294
|
+
output_token_count,
|
|
284
295
|
)
|
|
285
296
|
set_span_attribute(
|
|
286
297
|
span,
|
|
@@ -292,6 +303,11 @@ def _set_response_attributes(span, response: types.GenerateContentResponse):
|
|
|
292
303
|
SpanAttributes.LLM_USAGE_CACHE_READ_INPUT_TOKENS,
|
|
293
304
|
usage_dict.get("cached_content_token_count"),
|
|
294
305
|
)
|
|
306
|
+
set_span_attribute(
|
|
307
|
+
span,
|
|
308
|
+
SpanAttributes.LLM_USAGE_REASONING_TOKENS,
|
|
309
|
+
thoughts_token_count,
|
|
310
|
+
)
|
|
295
311
|
|
|
296
312
|
if should_send_prompts():
|
|
297
313
|
set_span_attribute(
|
|
@@ -388,7 +404,7 @@ def _build_from_streaming_response(
|
|
|
388
404
|
candidates=[
|
|
389
405
|
{
|
|
390
406
|
"content": {
|
|
391
|
-
"parts": final_parts,
|
|
407
|
+
"parts": merge_text_parts(final_parts),
|
|
392
408
|
"role": role,
|
|
393
409
|
},
|
|
394
410
|
}
|
|
@@ -438,7 +454,7 @@ async def _abuild_from_streaming_response(
|
|
|
438
454
|
candidates=[
|
|
439
455
|
{
|
|
440
456
|
"content": {
|
|
441
|
-
"parts": final_parts,
|
|
457
|
+
"parts": merge_text_parts(final_parts),
|
|
442
458
|
"role": role,
|
|
443
459
|
},
|
|
444
460
|
}
|
|
@@ -40,6 +40,56 @@ class ProcessChunkResult(TypedDict):
|
|
|
40
40
|
model_version: str | None
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
def merge_text_parts(
|
|
44
|
+
parts: list[types.PartDict | types.File | types.Part | str],
|
|
45
|
+
) -> list[types.Part]:
|
|
46
|
+
if not parts:
|
|
47
|
+
return []
|
|
48
|
+
|
|
49
|
+
merged_parts: list[types.Part] = []
|
|
50
|
+
accumulated_text = ""
|
|
51
|
+
|
|
52
|
+
for part in parts:
|
|
53
|
+
# Handle string input - treat as text
|
|
54
|
+
if isinstance(part, str):
|
|
55
|
+
accumulated_text += part
|
|
56
|
+
# Handle File objects - they are not text, so don't merge
|
|
57
|
+
elif isinstance(part, types.File):
|
|
58
|
+
# Flush any accumulated text first
|
|
59
|
+
if accumulated_text:
|
|
60
|
+
merged_parts.append(types.Part(text=accumulated_text))
|
|
61
|
+
accumulated_text = ""
|
|
62
|
+
# Add the File as-is (wrapped in a Part if needed)
|
|
63
|
+
# Note: File objects should be passed through as-is in the original part
|
|
64
|
+
merged_parts.append(part)
|
|
65
|
+
# Handle Part and PartDict (dicts)
|
|
66
|
+
else:
|
|
67
|
+
part_dict = to_dict(part)
|
|
68
|
+
|
|
69
|
+
# Check if this is a text part
|
|
70
|
+
if part_dict.get("text") is not None:
|
|
71
|
+
accumulated_text += part_dict.get("text")
|
|
72
|
+
else:
|
|
73
|
+
# Non-text part (inline_data, function_call, etc.)
|
|
74
|
+
# Flush any accumulated text first
|
|
75
|
+
if accumulated_text:
|
|
76
|
+
merged_parts.append(types.Part(text=accumulated_text))
|
|
77
|
+
accumulated_text = ""
|
|
78
|
+
|
|
79
|
+
# Add the non-text part as-is
|
|
80
|
+
if isinstance(part, types.Part):
|
|
81
|
+
merged_parts.append(part)
|
|
82
|
+
elif isinstance(part, dict):
|
|
83
|
+
# Convert dict to Part object
|
|
84
|
+
merged_parts.append(types.Part(**part_dict))
|
|
85
|
+
|
|
86
|
+
# Don't forget to add any remaining accumulated text
|
|
87
|
+
if accumulated_text:
|
|
88
|
+
merged_parts.append(types.Part(text=accumulated_text))
|
|
89
|
+
|
|
90
|
+
return merged_parts
|
|
91
|
+
|
|
92
|
+
|
|
43
93
|
def set_span_attribute(span: Span, name: str, value: Any):
|
|
44
94
|
if value is not None and value != "":
|
|
45
95
|
span.set_attribute(name, value)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/utils.py
RENAMED
|
File without changes
|
{lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/version.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lmnr-0.7.15 → lmnr-0.7.17}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|