33from __future__ import annotations
44
55from collections .abc import AsyncGenerator
6- from dataclasses import dataclass
76from typing import Any
87
8+ from pydantic import BaseModel , Field , computed_field
9+
910from agentle .generations .tracing .otel_client import GenerationContext , TraceContext
1011from agentle .generations .tracing .otel_client_type import OtelClientType
1112
1213
13- @dataclass
14- class TraceInputData :
14+ class TraceInputData (BaseModel ):
1515 """Structured input data for trace context."""
1616
1717 input : str | list [dict [str , Any ]] | None
@@ -26,34 +26,17 @@ class TraceInputData:
2626 max_output_tokens : int | None
2727 stream : bool
2828
29- def to_dict (self ) -> dict [str , Any ]:
30- """Convert to dictionary for API calls."""
31- return {
32- "input" : self .input ,
33- "model" : self .model ,
34- "has_tools" : self .has_tools ,
35- "tools_count" : self .tools_count ,
36- "has_structured_output" : self .has_structured_output ,
37- "reasoning_enabled" : self .reasoning_enabled ,
38- "reasoning_effort" : self .reasoning_effort ,
39- "temperature" : self .temperature ,
40- "top_p" : self .top_p ,
41- "max_output_tokens" : self .max_output_tokens ,
42- "stream" : self .stream ,
43- }
44-
4529
46- @dataclass
47- class TraceMetadata :
30+ class TraceMetadata (BaseModel ):
4831 """Metadata for trace context."""
4932
5033 model : str
5134 provider : str
5235 base_url : str
53- custom_metadata : dict [str , Any ]
36+ custom_metadata : dict [str , Any ] = Field ( default_factory = dict )
5437
55- def to_dict (self ) -> dict [str , Any ]:
56- """Convert to dictionary for API calls."""
38+ def to_api_dict (self ) -> dict [str , Any ]:
39+ """Convert to dictionary for API calls, merging custom_metadata ."""
5740 result = {
5841 "model" : self .model ,
5942 "provider" : self .provider ,
@@ -63,8 +46,7 @@ def to_dict(self) -> dict[str, Any]:
6346 return result
6447
6548
66- @dataclass
67- class UsageDetails :
49+ class UsageDetails (BaseModel ):
6850 """Token usage details from API response."""
6951
7052 input : int
@@ -73,21 +55,8 @@ class UsageDetails:
7355 unit : str
7456 reasoning_tokens : int | None = None
7557
76- def to_dict (self ) -> dict [str , Any ]:
77- """Convert to dictionary for API calls."""
78- result = {
79- "input" : self .input ,
80- "output" : self .output ,
81- "total" : self .total ,
82- "unit" : self .unit ,
83- }
84- if self .reasoning_tokens is not None and self .reasoning_tokens > 0 :
85- result ["reasoning_tokens" ] = self .reasoning_tokens
86- return result
87-
8858
89- @dataclass
90- class CostDetails :
59+ class CostDetails (BaseModel ):
9160 """Cost calculation details."""
9261
9362 input : float
@@ -97,28 +66,19 @@ class CostDetails:
9766 input_tokens : int
9867 output_tokens : int
9968
100- def to_dict (self ) -> dict [str , Any ]:
101- """Convert to dictionary for API calls."""
102- return {
103- "input" : self .input ,
104- "output" : self .output ,
105- "total" : self .total ,
106- "currency" : self .currency ,
107- "input_tokens" : self .input_tokens ,
108- "output_tokens" : self .output_tokens ,
109- }
11069
111-
112- @dataclass
113- class TracingContext :
70+ class TracingContext (BaseModel ):
11471 """Container for a single client's tracing contexts."""
11572
73+ model_config = {"arbitrary_types_allowed" : True }
74+
11675 client : OtelClientType
11776 trace_gen : AsyncGenerator [TraceContext | None , None ]
11877 trace_ctx : TraceContext | None
11978 generation_gen : AsyncGenerator [GenerationContext | None , None ]
12079 generation_ctx : GenerationContext | None
12180
81+ @computed_field
12282 @property
12383 def client_name (self ) -> str :
12484 """Get the client class name for logging."""
0 commit comments