24
24
from ddtrace .llmobs ._integrations .base import BaseLLMIntegration
25
25
from ddtrace .llmobs ._integrations .utils import update_proxy_workflow_input_output_value
26
26
from ddtrace .llmobs ._utils import _get_attr
27
- from ddtrace .llmobs .utils import ToolCall
27
+ from ddtrace .llmobs .utils import Message , ToolCall
28
28
from ddtrace .llmobs .utils import ToolDefinition
29
29
from ddtrace .llmobs .utils import ToolResult
30
30
from ddtrace .trace import Span
@@ -71,7 +71,7 @@ def _llmobs_set_tags(
71
71
system_prompt = kwargs .get ("system" )
72
72
input_messages = self ._extract_input_message (messages , system_prompt )
73
73
74
- output_messages = [{ " content" : "" } ]
74
+ output_messages : List [ Message ] = [Message ( content = "" ) ]
75
75
if not span .error and response is not None :
76
76
output_messages = self ._extract_output_message (response )
77
77
span_kind = "workflow" if span ._get_ctx_item (PROXY_REQUEST ) else "llm"
@@ -92,14 +92,14 @@ def _llmobs_set_tags(
92
92
)
93
93
update_proxy_workflow_input_output_value (span , span_kind )
94
94
95
- def _extract_input_message (self , messages , system_prompt : Optional [Union [str , List [Dict [str , Any ]]]] = None ):
95
+ def _extract_input_message (self , messages , system_prompt : Optional [Union [str , List [Dict [str , Any ]]]] = None ) -> List [ Message ] :
96
96
"""Extract input messages from the stored prompt.
97
97
Anthropic allows for messages and multiple texts in a message, which requires some special casing.
98
98
"""
99
99
if not isinstance (messages , Iterable ):
100
100
log .warning ("Anthropic input must be a list of messages." )
101
101
102
- input_messages = []
102
+ input_messages : List [ Message ] = []
103
103
if system_prompt is not None :
104
104
messages = [{"content" : system_prompt , "role" : "system" }] + messages
105
105
@@ -115,43 +115,43 @@ def _extract_input_message(self, messages, system_prompt: Optional[Union[str, Li
115
115
log .warning ("Anthropic input message must have content and role." )
116
116
117
117
if isinstance (content , str ):
118
- input_messages .append ({ " content" : content , " role" : role } )
118
+ input_messages .append (Message ( content = content , role = str ( role )) )
119
119
120
120
elif isinstance (content , list ):
121
121
for block in content :
122
122
if _get_attr (block , "type" , None ) == "text" :
123
- input_messages .append ({ " content" : _get_attr (block , "text" , "" ), " role" : role } )
123
+ input_messages .append (Message ( content = _get_attr (block , "text" , "" ), role = str ( role )) )
124
124
125
125
elif _get_attr (block , "type" , None ) == "image" :
126
126
# Store a placeholder for potentially enormous binary image data.
127
- input_messages .append ({ " content" : " ([IMAGE DETECTED])" , " role" : role } )
127
+ input_messages .append (Message ( content = " ([IMAGE DETECTED])" , role = str ( role )) )
128
128
129
129
elif _get_attr (block , "type" , None ) == "tool_use" :
130
130
text = _get_attr (block , "text" , None )
131
131
input_data = _get_attr (block , "input" , "" )
132
132
if isinstance (input_data , str ):
133
133
input_data = json .loads (input_data )
134
134
tool_call_info = ToolCall (
135
- name = _get_attr (block , "name" , "" ),
135
+ name = str ( _get_attr (block , "name" , "" ) ),
136
136
arguments = input_data ,
137
- tool_id = _get_attr (block , "id" , "" ),
138
- type = _get_attr (block , "type" , "" ),
137
+ tool_id = str ( _get_attr (block , "id" , "" ) ),
138
+ type = str ( _get_attr (block , "type" , "" ) ),
139
139
)
140
140
if text is None :
141
141
text = ""
142
- input_messages .append ({ " content" : text , " role" : role , " tool_calls" : [tool_call_info ]} )
142
+ input_messages .append (Message ( content = str ( text ), role = str ( role ), tool_calls = [tool_call_info ]) )
143
143
144
144
elif _get_attr (block , "type" , None ) == "tool_result" :
145
145
content = _get_attr (block , "content" , None )
146
146
formatted_content = self ._format_tool_result_content (content )
147
147
tool_result_info = ToolResult (
148
148
result = formatted_content ,
149
- tool_id = _get_attr (block , "tool_use_id" , "" ),
149
+ tool_id = str ( _get_attr (block , "tool_use_id" , "" ) ),
150
150
type = "tool_result" ,
151
151
)
152
- input_messages .append ({ " content" : "" , " role" : role , " tool_results" : [tool_result_info ]} )
152
+ input_messages .append (Message ( content = "" , role = str ( role ), tool_results = [tool_result_info ]) )
153
153
else :
154
- input_messages .append ({ " content" : str (block ), " role" : role } )
154
+ input_messages .append (Message ( content = str (block ), role = str ( role )) )
155
155
156
156
return input_messages
157
157
@@ -169,34 +169,34 @@ def _format_tool_result_content(self, content) -> str:
169
169
return "," .join (formatted_content )
170
170
return str (content )
171
171
172
- def _extract_output_message (self , response ):
172
+ def _extract_output_message (self , response ) -> List [ Message ] :
173
173
"""Extract output messages from the stored response."""
174
- output_messages = []
174
+ output_messages : List [ Message ] = []
175
175
content = _get_attr (response , "content" , "" )
176
176
role = _get_attr (response , "role" , "" )
177
177
178
178
if isinstance (content , str ):
179
- return [{ " content" : content , " role" : role } ]
179
+ return [Message ( content = content , role = str ( role )) ]
180
180
181
181
elif isinstance (content , list ):
182
182
for completion in content :
183
183
text = _get_attr (completion , "text" , None )
184
184
if isinstance (text , str ):
185
- output_messages .append ({ " content" : text , " role" : role } )
185
+ output_messages .append (Message ( content = text , role = str ( role )) )
186
186
else :
187
187
if _get_attr (completion , "type" , None ) == "tool_use" :
188
188
input_data = _get_attr (completion , "input" , "" )
189
189
if isinstance (input_data , str ):
190
190
input_data = json .loads (input_data )
191
191
tool_call_info = ToolCall (
192
- name = _get_attr (completion , "name" , "" ),
192
+ name = str ( _get_attr (completion , "name" , "" ) ),
193
193
arguments = input_data ,
194
- tool_id = _get_attr (completion , "id" , "" ),
195
- type = _get_attr (completion , "type" , "" ),
194
+ tool_id = str ( _get_attr (completion , "id" , "" ) ),
195
+ type = str ( _get_attr (completion , "type" , "" ) ),
196
196
)
197
197
if text is None :
198
198
text = ""
199
- output_messages .append ({ " content" : text , " role" : role , " tool_calls" : [tool_call_info ]} )
199
+ output_messages .append (Message ( content = str ( text ), role = str ( role ), tool_calls = [tool_call_info ]) )
200
200
return output_messages
201
201
202
202
def _extract_usage (self , span : Span , usage : Dict [str , Any ]):
0 commit comments