struct-sdk 0.2.11__tar.gz → 0.2.12__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: struct-sdk
3
- Version: 0.2.11
3
+ Version: 0.2.12
4
4
  Summary: Struct agent observability SDK — auto-instruments AI agent frameworks with OpenTelemetry
5
5
  Project-URL: Homepage, https://struct.ai
6
6
  Project-URL: Documentation, https://struct.ai/docs
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "struct-sdk"
7
- version = "0.2.11"
7
+ version = "0.2.12"
8
8
  description = "Struct agent observability SDK — auto-instruments AI agent frameworks with OpenTelemetry"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -333,6 +333,17 @@ def _set_response_attrs(span: trace.Span, sdk: StructSDK, response: Any, otel_lo
333
333
  # them and gets them re-added in struct_sdk.anthropic. Report as-is.
334
334
  span.set_attribute("gen_ai.usage.input_tokens", input_tokens)
335
335
  span.set_attribute("gen_ai.usage.output_tokens", output_tokens)
336
+ # Reasoning tokens are a SUBSET of ``output_tokens`` (chain-of-thought /
337
+ # extended thinking), not an additional bucket — surfaced here purely
338
+ # for observability, never for cost (``output_tokens`` already prices
339
+ # them at the output rate). ``gen_ai.usage.reasoning.output_tokens`` is
340
+ # the OTel GenAI semconv name; nested style matches ``cache_read`` below.
341
+ details_out = getattr(usage, "output_tokens_details", None)
342
+ reasoning_tokens = (
343
+ (getattr(details_out, "reasoning_tokens", 0) or 0) if details_out is not None else 0
344
+ )
345
+ if reasoning_tokens:
346
+ span.set_attribute("gen_ai.usage.reasoning.output_tokens", reasoning_tokens)
336
347
  if cache_read:
337
348
  # Nested-key naming (``cache_read.input_tokens``) matches the
338
349
  # Anthropic emitter — Struct's ingest views key on this exact
@@ -340,8 +351,11 @@ def _set_response_attrs(span: trace.Span, sdk: StructSDK, response: Any, otel_lo
340
351
  # ``gen_ai.usage.cache_read_input_tokens``: ingest compatibility
341
352
  # beats semconv purity here.
342
353
  span.set_attribute("gen_ai.usage.cache_read.input_tokens", cache_read)
343
- # The Responses API usage block has no cache-write counter, so
344
- # ``gen_ai.usage.cache_creation.input_tokens`` is never set here.
354
+ cache_write = (getattr(details, "cache_write_tokens", 0) or 0) if details is not None else 0
355
+ if cache_write:
356
+ # gpt-5.6 family charges for cache writes (1.25x input). Nested-key
357
+ # name matches the Anthropic emitter / Struct ingest views.
358
+ span.set_attribute("gen_ai.usage.cache_creation.input_tokens", cache_write)
345
359
 
346
360
  if getattr(response, "model", None):
347
361
  span.set_attribute("gen_ai.response.model", response.model)
File without changes
File without changes
File without changes