langtrace-python-sdk 1.3.6__py3-none-any.whl → 2.0.0__py3-none-any.whl
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.
- examples/anthropic_example/completion.py +6 -6
- examples/cohere_example/chat.py +5 -4
- examples/cohere_example/chat_stream.py +2 -4
- examples/cohere_example/{embed_create.py → embed.py} +4 -3
- examples/cohere_example/rerank.py +31 -0
- examples/cohere_example/tools.py +40 -0
- examples/openai_example/chat_completion.py +41 -0
- examples/{openai → openai_example}/embeddings_create.py +3 -2
- examples/{openai → openai_example}/function_calling.py +3 -5
- examples/{openai → openai_example}/images_generate.py +1 -1
- examples/openai_example/tool_calling.py +67 -0
- examples/{openai → openai_example}/tool_calling_nonstreaming.py +2 -1
- langtrace_python_sdk/__init__.py +14 -1
- langtrace_python_sdk/constants/instrumentation/cohere.py +6 -1
- langtrace_python_sdk/instrumentation/anthropic/instrumentation.py +16 -4
- langtrace_python_sdk/instrumentation/anthropic/patch.py +26 -6
- langtrace_python_sdk/instrumentation/chroma/instrumentation.py +14 -2
- langtrace_python_sdk/instrumentation/chroma/patch.py +16 -4
- langtrace_python_sdk/instrumentation/cohere/instrumentation.py +24 -7
- langtrace_python_sdk/instrumentation/cohere/patch.py +295 -95
- langtrace_python_sdk/instrumentation/langchain/instrumentation.py +14 -3
- langtrace_python_sdk/instrumentation/langchain/patch.py +16 -4
- langtrace_python_sdk/instrumentation/langchain_community/instrumentation.py +15 -2
- langtrace_python_sdk/instrumentation/langchain_community/patch.py +20 -3
- langtrace_python_sdk/instrumentation/langchain_core/instrumentation.py +14 -4
- langtrace_python_sdk/instrumentation/langchain_core/patch.py +19 -7
- langtrace_python_sdk/instrumentation/llamaindex/instrumentation.py +15 -11
- langtrace_python_sdk/instrumentation/llamaindex/patch.py +20 -10
- langtrace_python_sdk/instrumentation/openai/instrumentation.py +20 -9
- langtrace_python_sdk/instrumentation/openai/patch.py +112 -78
- langtrace_python_sdk/instrumentation/pinecone/instrumentation.py +14 -3
- langtrace_python_sdk/instrumentation/pinecone/patch.py +17 -4
- langtrace_python_sdk/langtrace.py +40 -35
- langtrace_python_sdk/utils/llm.py +17 -4
- langtrace_python_sdk/utils/with_root_span.py +21 -5
- langtrace_python_sdk/version.py +1 -1
- {langtrace_python_sdk-1.3.6.dist-info → langtrace_python_sdk-2.0.0.dist-info}/METADATA +2 -2
- {langtrace_python_sdk-1.3.6.dist-info → langtrace_python_sdk-2.0.0.dist-info}/RECORD +53 -45
- tests/anthropic/cassettes/test_anthropic.yaml +85 -0
- tests/anthropic/cassettes/test_anthropic_streaming.yaml +456 -0
- tests/anthropic/cassettes/test_async_anthropic_streaming.yaml +328 -0
- tests/anthropic/conftest.py +38 -0
- tests/anthropic/test_anthropic.py +108 -72
- tests/conftest.py +17 -0
- tests/openai/conftest.py +5 -13
- tests/openai/test_chat_completion.py +21 -0
- tests/openai/test_image_generation.py +20 -8
- examples/openai/chat_completion.py +0 -58
- /examples/{openai → openai_example}/__init__.py +0 -0
- /examples/{openai → openai_example}/async_tool_calling_nonstreaming.py +0 -0
- /examples/{openai → openai_example}/async_tool_calling_streaming.py +0 -0
- /examples/{openai → openai_example}/tool_calling_streaming.py +0 -0
- {langtrace_python_sdk-1.3.6.dist-info → langtrace_python_sdk-2.0.0.dist-info}/WHEEL +0 -0
- {langtrace_python_sdk-1.3.6.dist-info → langtrace_python_sdk-2.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
interactions:
|
|
2
|
+
- request:
|
|
3
|
+
body: '{"max_tokens": 1024, "messages": [{"role": "user", "content": "How are
|
|
4
|
+
you today?"}], "model": "claude-3-opus-20240229", "stream": true}'
|
|
5
|
+
headers:
|
|
6
|
+
accept:
|
|
7
|
+
- application/json
|
|
8
|
+
accept-encoding:
|
|
9
|
+
- gzip, deflate
|
|
10
|
+
anthropic-version:
|
|
11
|
+
- '2023-06-01'
|
|
12
|
+
connection:
|
|
13
|
+
- keep-alive
|
|
14
|
+
content-length:
|
|
15
|
+
- '136'
|
|
16
|
+
content-type:
|
|
17
|
+
- application/json
|
|
18
|
+
host:
|
|
19
|
+
- api.anthropic.com
|
|
20
|
+
user-agent:
|
|
21
|
+
- AsyncAnthropic/Python 0.25.6
|
|
22
|
+
x-stainless-arch:
|
|
23
|
+
- arm64
|
|
24
|
+
x-stainless-async:
|
|
25
|
+
- async:asyncio
|
|
26
|
+
x-stainless-lang:
|
|
27
|
+
- python
|
|
28
|
+
x-stainless-os:
|
|
29
|
+
- MacOS
|
|
30
|
+
x-stainless-package-version:
|
|
31
|
+
- 0.25.6
|
|
32
|
+
x-stainless-runtime:
|
|
33
|
+
- CPython
|
|
34
|
+
x-stainless-runtime-version:
|
|
35
|
+
- 3.11.5
|
|
36
|
+
method: POST
|
|
37
|
+
uri: https://api.anthropic.com/v1/messages
|
|
38
|
+
response:
|
|
39
|
+
body:
|
|
40
|
+
string: 'event: message_start
|
|
41
|
+
|
|
42
|
+
data: {"type":"message_start","message":{"id":"msg_01WefXuaU9ctjjQqxDgV2v4r","type":"message","role":"assistant","model":"claude-3-opus-20240229","stop_sequence":null,"usage":{"input_tokens":12,"output_tokens":1},"content":[],"stop_reason":null}}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
event: content_block_start
|
|
46
|
+
|
|
47
|
+
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""} }
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
event: ping
|
|
51
|
+
|
|
52
|
+
data: {"type": "ping"}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
event: content_block_delta
|
|
56
|
+
|
|
57
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"As"} }
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
event: content_block_delta
|
|
61
|
+
|
|
62
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
63
|
+
an"} }
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
event: content_block_delta
|
|
67
|
+
|
|
68
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
69
|
+
AI"} }
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
event: content_block_delta
|
|
73
|
+
|
|
74
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
75
|
+
language"}}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
event: content_block_delta
|
|
79
|
+
|
|
80
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
81
|
+
model"} }
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
event: content_block_delta
|
|
85
|
+
|
|
86
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":","} }
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
event: content_block_delta
|
|
90
|
+
|
|
91
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
92
|
+
I"} }
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
event: content_block_delta
|
|
96
|
+
|
|
97
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
98
|
+
don"} }
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
event: content_block_delta
|
|
102
|
+
|
|
103
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"''t"} }
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
event: content_block_delta
|
|
107
|
+
|
|
108
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
109
|
+
have"}}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
event: content_block_delta
|
|
113
|
+
|
|
114
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
115
|
+
feelings"} }
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
event: content_block_delta
|
|
119
|
+
|
|
120
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":","} }
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
event: content_block_delta
|
|
124
|
+
|
|
125
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
126
|
+
but"} }
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
event: content_block_delta
|
|
130
|
+
|
|
131
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
132
|
+
I"} }
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
event: content_block_delta
|
|
136
|
+
|
|
137
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"''m"} }
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
event: content_block_delta
|
|
141
|
+
|
|
142
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
143
|
+
functioning"}}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
event: content_block_delta
|
|
147
|
+
|
|
148
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
149
|
+
well"} }
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
event: content_block_delta
|
|
153
|
+
|
|
154
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
155
|
+
an"} }
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
event: content_block_delta
|
|
159
|
+
|
|
160
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d
|
|
161
|
+
ready"} }
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
event: content_block_delta
|
|
165
|
+
|
|
166
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
167
|
+
to"} }
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
event: content_block_delta
|
|
171
|
+
|
|
172
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
173
|
+
assist"} }
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
event: content_block_delta
|
|
177
|
+
|
|
178
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
179
|
+
you"} }
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
event: content_block_delta
|
|
183
|
+
|
|
184
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
185
|
+
with"} }
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
event: content_block_delta
|
|
189
|
+
|
|
190
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
191
|
+
any"} }
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
event: content_block_delta
|
|
195
|
+
|
|
196
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
197
|
+
questions"} }
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
event: content_block_delta
|
|
201
|
+
|
|
202
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
203
|
+
or"}}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
event: content_block_delta
|
|
207
|
+
|
|
208
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
209
|
+
tasks"} }
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
event: content_block_delta
|
|
213
|
+
|
|
214
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
215
|
+
you"}}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
event: content_block_delta
|
|
219
|
+
|
|
220
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
221
|
+
may"} }
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
event: content_block_delta
|
|
225
|
+
|
|
226
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
227
|
+
have"} }
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
event: content_block_delta
|
|
231
|
+
|
|
232
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"."} }
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
event: content_block_delta
|
|
236
|
+
|
|
237
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
238
|
+
How"} }
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
event: content_block_delta
|
|
242
|
+
|
|
243
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
244
|
+
can"} }
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
event: content_block_delta
|
|
248
|
+
|
|
249
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
250
|
+
I"} }
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
event: content_block_delta
|
|
254
|
+
|
|
255
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
256
|
+
help"} }
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
event: content_block_delta
|
|
260
|
+
|
|
261
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
262
|
+
you"} }
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
event: content_block_delta
|
|
266
|
+
|
|
267
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"
|
|
268
|
+
today"} }
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
event: content_block_delta
|
|
272
|
+
|
|
273
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"?"} }
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
event: content_block_stop
|
|
277
|
+
|
|
278
|
+
data: {"type":"content_block_stop","index":0 }
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
event: message_delta
|
|
282
|
+
|
|
283
|
+
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":41} }
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
event: message_stop
|
|
287
|
+
|
|
288
|
+
data: {"type":"message_stop" }
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
'
|
|
292
|
+
headers:
|
|
293
|
+
CF-Cache-Status:
|
|
294
|
+
- DYNAMIC
|
|
295
|
+
CF-RAY:
|
|
296
|
+
- 87963ba7cab90d92-MRS
|
|
297
|
+
Cache-Control:
|
|
298
|
+
- no-cache
|
|
299
|
+
Connection:
|
|
300
|
+
- keep-alive
|
|
301
|
+
Content-Type:
|
|
302
|
+
- text/event-stream; charset=utf-8
|
|
303
|
+
Date:
|
|
304
|
+
- Wed, 24 Apr 2024 12:52:54 GMT
|
|
305
|
+
Server:
|
|
306
|
+
- cloudflare
|
|
307
|
+
Transfer-Encoding:
|
|
308
|
+
- chunked
|
|
309
|
+
anthropic-ratelimit-requests-limit:
|
|
310
|
+
- '50'
|
|
311
|
+
anthropic-ratelimit-requests-remaining:
|
|
312
|
+
- '49'
|
|
313
|
+
anthropic-ratelimit-requests-reset:
|
|
314
|
+
- '2024-04-24T12:53:29Z'
|
|
315
|
+
anthropic-ratelimit-tokens-limit:
|
|
316
|
+
- '20000'
|
|
317
|
+
anthropic-ratelimit-tokens-remaining:
|
|
318
|
+
- '19000'
|
|
319
|
+
anthropic-ratelimit-tokens-reset:
|
|
320
|
+
- '2024-04-24T12:53:29Z'
|
|
321
|
+
request-id:
|
|
322
|
+
- req_0165QboZpxrrNfD1oVun4cPB
|
|
323
|
+
via:
|
|
324
|
+
- 1.1 google
|
|
325
|
+
status:
|
|
326
|
+
code: 200
|
|
327
|
+
message: OK
|
|
328
|
+
version: 1
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Unit tests configuration module."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
import os
|
|
5
|
+
from anthropic import Anthropic, AsyncAnthropic
|
|
6
|
+
|
|
7
|
+
from langtrace_python_sdk.instrumentation.anthropic.instrumentation import (
|
|
8
|
+
AnthropicInstrumentation,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture(autouse=True)
|
|
13
|
+
def environment():
|
|
14
|
+
if not os.getenv("ANTHROPIC_API_KEY"):
|
|
15
|
+
os.environ["ANTHROPIC_API_KEY"] = "test_api_key"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture
|
|
19
|
+
def anthropic_client():
|
|
20
|
+
return Anthropic()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture
|
|
24
|
+
def async_anthropic_client():
|
|
25
|
+
return AsyncAnthropic()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.fixture(scope="module")
|
|
29
|
+
def vcr_config():
|
|
30
|
+
return {"filter_headers": ["authorization", "x-api-key"]}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.fixture(scope="session", autouse=True)
|
|
34
|
+
def instrument():
|
|
35
|
+
AnthropicInstrumentation().instrument()
|
|
36
|
+
|
|
37
|
+
yield
|
|
38
|
+
# exporter.shutdown()
|
|
@@ -1,73 +1,109 @@
|
|
|
1
|
-
import
|
|
2
|
-
from unittest.mock import MagicMock, call
|
|
3
|
-
from langtrace_python_sdk.instrumentation.anthropic.patch import messages_create
|
|
4
|
-
from opentelemetry.trace import SpanKind
|
|
5
|
-
import importlib.metadata
|
|
6
|
-
from langtrace_python_sdk.constants.instrumentation.anthropic import APIS
|
|
7
|
-
from opentelemetry.trace.status import Status, StatusCode
|
|
1
|
+
import pytest
|
|
8
2
|
import json
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
3
|
+
import importlib
|
|
4
|
+
from langtrace_python_sdk.constants.instrumentation.anthropic import APIS
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.mark.vcr()
|
|
8
|
+
def test_anthropic(anthropic_client, exporter):
|
|
9
|
+
llm_model_value = "claude-3-opus-20240229"
|
|
10
|
+
messages_value = [{"role": "user", "content": "How are you today?"}]
|
|
11
|
+
|
|
12
|
+
kwargs = {
|
|
13
|
+
"model": llm_model_value,
|
|
14
|
+
"messages": messages_value,
|
|
15
|
+
# "system": "Respond only in Yoda-speak.",
|
|
16
|
+
"stream": False,
|
|
17
|
+
"max_tokens": 1024,
|
|
18
|
+
}
|
|
19
|
+
response = anthropic_client.messages.create(**kwargs)
|
|
20
|
+
spans = exporter.get_finished_spans()
|
|
21
|
+
completion_span = spans[-1]
|
|
22
|
+
|
|
23
|
+
assert completion_span.name == "anthropic.messages.create"
|
|
24
|
+
attributes = completion_span.attributes
|
|
25
|
+
|
|
26
|
+
assert attributes.get("langtrace.sdk.name") == "langtrace-python-sdk"
|
|
27
|
+
assert attributes.get("langtrace.service.name") == "Anthropic"
|
|
28
|
+
assert attributes.get("langtrace.service.type") == "llm"
|
|
29
|
+
assert attributes.get("langtrace.service.version") == importlib.metadata.version(
|
|
30
|
+
"anthropic"
|
|
31
|
+
)
|
|
32
|
+
assert attributes.get("langtrace.version") == "1.0.0"
|
|
33
|
+
assert attributes.get("url.full") == "https://api.anthropic.com"
|
|
34
|
+
assert attributes.get("llm.api") == APIS["MESSAGES_CREATE"]["ENDPOINT"]
|
|
35
|
+
assert attributes.get("llm.model") == llm_model_value
|
|
36
|
+
assert attributes.get("llm.prompts") == json.dumps(messages_value)
|
|
37
|
+
assert attributes.get("llm.stream") is False
|
|
38
|
+
|
|
39
|
+
tokens = json.loads(attributes.get("llm.token.counts"))
|
|
40
|
+
output_tokens = tokens.get("output_tokens")
|
|
41
|
+
prompt_tokens = tokens.get("input_tokens")
|
|
42
|
+
total_tokens = tokens.get("total_tokens")
|
|
43
|
+
|
|
44
|
+
assert output_tokens and prompt_tokens and total_tokens
|
|
45
|
+
assert output_tokens + prompt_tokens == total_tokens
|
|
46
|
+
|
|
47
|
+
langtrace_responses = json.loads(attributes.get("llm.responses"))
|
|
48
|
+
assert isinstance(langtrace_responses, list)
|
|
49
|
+
for langtrace_response in langtrace_responses:
|
|
50
|
+
assert isinstance(langtrace_response, dict)
|
|
51
|
+
assert "role" in langtrace_response
|
|
52
|
+
assert "content" in langtrace_response
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.mark.vcr()
|
|
56
|
+
def test_anthropic_streaming(anthropic_client, exporter):
|
|
57
|
+
llm_model_value = "claude-3-opus-20240229"
|
|
58
|
+
messages_value = [{"role": "user", "content": "How are you today?"}]
|
|
59
|
+
|
|
60
|
+
kwargs = {
|
|
61
|
+
"model": llm_model_value,
|
|
62
|
+
"messages": messages_value,
|
|
63
|
+
# "system": "Respond only in Yoda-speak.",
|
|
64
|
+
"stream": True,
|
|
65
|
+
"max_tokens": 1024,
|
|
66
|
+
}
|
|
67
|
+
response = anthropic_client.messages.create(**kwargs)
|
|
68
|
+
chunk_count = 0
|
|
69
|
+
|
|
70
|
+
for chunk in response:
|
|
71
|
+
if chunk:
|
|
72
|
+
chunk_count += 1
|
|
73
|
+
|
|
74
|
+
spans = exporter.get_finished_spans()
|
|
75
|
+
streaming_span = spans[-1]
|
|
76
|
+
|
|
77
|
+
assert streaming_span.name == "anthropic.messages.create"
|
|
78
|
+
attributes = streaming_span.attributes
|
|
79
|
+
|
|
80
|
+
assert attributes.get("langtrace.sdk.name") == "langtrace-python-sdk"
|
|
81
|
+
assert attributes.get("langtrace.service.name") == "Anthropic"
|
|
82
|
+
assert attributes.get("langtrace.service.type") == "llm"
|
|
83
|
+
assert attributes.get("langtrace.service.version") == importlib.metadata.version(
|
|
84
|
+
"anthropic"
|
|
85
|
+
)
|
|
86
|
+
assert attributes.get("langtrace.version") == "1.0.0"
|
|
87
|
+
assert attributes.get("url.full") == "https://api.anthropic.com"
|
|
88
|
+
assert attributes.get("llm.api") == APIS["MESSAGES_CREATE"]["ENDPOINT"]
|
|
89
|
+
assert attributes.get("llm.model") == llm_model_value
|
|
90
|
+
assert attributes.get("llm.prompts") == json.dumps(messages_value)
|
|
91
|
+
assert attributes.get("llm.stream") is True
|
|
92
|
+
events = streaming_span.events
|
|
93
|
+
|
|
94
|
+
assert len(events) - 2 == chunk_count # -2 for start and end events
|
|
95
|
+
|
|
96
|
+
tokens = json.loads(attributes.get("llm.token.counts"))
|
|
97
|
+
output_tokens = tokens.get("output_tokens")
|
|
98
|
+
prompt_tokens = tokens.get("input_tokens")
|
|
99
|
+
total_tokens = tokens.get("total_tokens")
|
|
100
|
+
|
|
101
|
+
assert output_tokens and prompt_tokens and total_tokens
|
|
102
|
+
assert output_tokens + prompt_tokens == total_tokens
|
|
103
|
+
|
|
104
|
+
langtrace_responses = json.loads(attributes.get("llm.responses"))
|
|
105
|
+
assert isinstance(langtrace_responses, list)
|
|
106
|
+
for langtrace_response in langtrace_responses:
|
|
107
|
+
assert isinstance(langtrace_response, dict)
|
|
108
|
+
assert "role" in langtrace_response
|
|
109
|
+
assert "content" in langtrace_response
|
tests/conftest.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
3
|
+
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
|
|
4
|
+
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
|
|
5
|
+
from opentelemetry import trace
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.fixture(scope="session")
|
|
9
|
+
def exporter():
|
|
10
|
+
exporter = InMemorySpanExporter()
|
|
11
|
+
processor = SimpleSpanProcessor(exporter)
|
|
12
|
+
|
|
13
|
+
provider = TracerProvider()
|
|
14
|
+
provider.add_span_processor(processor)
|
|
15
|
+
trace.set_tracer_provider(provider)
|
|
16
|
+
|
|
17
|
+
return exporter
|
tests/openai/conftest.py
CHANGED
|
@@ -3,10 +3,6 @@
|
|
|
3
3
|
import pytest
|
|
4
4
|
import os
|
|
5
5
|
from openai import OpenAI, AsyncOpenAI
|
|
6
|
-
from opentelemetry.sdk.trace import TracerProvider
|
|
7
|
-
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
|
|
8
|
-
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
|
|
9
|
-
from opentelemetry import trace
|
|
10
6
|
from langtrace_python_sdk.instrumentation.openai.instrumentation import (
|
|
11
7
|
OpenAIInstrumentation,
|
|
12
8
|
)
|
|
@@ -33,13 +29,9 @@ def vcr_config():
|
|
|
33
29
|
return {"filter_headers": ["authorization", "api-key"]}
|
|
34
30
|
|
|
35
31
|
|
|
36
|
-
@pytest.fixture(scope="session")
|
|
37
|
-
def
|
|
38
|
-
exporter = InMemorySpanExporter()
|
|
39
|
-
processor = SimpleSpanProcessor(exporter)
|
|
40
|
-
|
|
41
|
-
provider = TracerProvider()
|
|
42
|
-
provider.add_span_processor(processor)
|
|
43
|
-
trace.set_tracer_provider(provider)
|
|
32
|
+
@pytest.fixture(scope="session", autouse=True)
|
|
33
|
+
def instrument():
|
|
44
34
|
OpenAIInstrumentation().instrument()
|
|
45
|
-
|
|
35
|
+
|
|
36
|
+
yield
|
|
37
|
+
# exporter.shutdown()
|
|
@@ -42,6 +42,13 @@ def test_chat_completion(exporter, openai_client):
|
|
|
42
42
|
assert output_tokens and prompt_tokens and total_tokens
|
|
43
43
|
assert output_tokens + prompt_tokens == total_tokens
|
|
44
44
|
|
|
45
|
+
langtrace_responses = json.loads(attributes.get("llm.responses"))
|
|
46
|
+
assert isinstance(langtrace_responses, list)
|
|
47
|
+
for langtrace_response in langtrace_responses:
|
|
48
|
+
assert isinstance(langtrace_response, dict)
|
|
49
|
+
assert "role" in langtrace_response
|
|
50
|
+
assert "content" in langtrace_response
|
|
51
|
+
|
|
45
52
|
|
|
46
53
|
@pytest.mark.vcr()
|
|
47
54
|
def test_chat_completion_streaming(exporter, openai_client):
|
|
@@ -91,6 +98,13 @@ def test_chat_completion_streaming(exporter, openai_client):
|
|
|
91
98
|
assert output_tokens and prompt_tokens and total_tokens
|
|
92
99
|
assert output_tokens + prompt_tokens == total_tokens
|
|
93
100
|
|
|
101
|
+
langtrace_responses = json.loads(attributes.get("llm.responses"))
|
|
102
|
+
assert isinstance(langtrace_responses, list)
|
|
103
|
+
for langtrace_response in langtrace_responses:
|
|
104
|
+
assert isinstance(langtrace_response, dict)
|
|
105
|
+
assert "role" in langtrace_response
|
|
106
|
+
assert "content" in langtrace_response
|
|
107
|
+
|
|
94
108
|
|
|
95
109
|
@pytest.mark.vcr()
|
|
96
110
|
@pytest.mark.asyncio()
|
|
@@ -140,3 +154,10 @@ async def test_async_chat_completion_streaming(exporter, async_openai_client):
|
|
|
140
154
|
|
|
141
155
|
assert output_tokens and prompt_tokens and total_tokens
|
|
142
156
|
assert output_tokens + prompt_tokens == total_tokens
|
|
157
|
+
|
|
158
|
+
langtrace_responses = json.loads(attributes.get("llm.responses"))
|
|
159
|
+
assert isinstance(langtrace_responses, list)
|
|
160
|
+
for langtrace_response in langtrace_responses:
|
|
161
|
+
assert isinstance(langtrace_response, dict)
|
|
162
|
+
assert "role" in langtrace_response
|
|
163
|
+
assert "content" in langtrace_response
|