latitude-sdk 0.1.0b4__tar.gz → 0.1.0b5__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.
Files changed (40) hide show
  1. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/PKG-INFO +1 -1
  2. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/pyproject.toml +1 -1
  3. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/sdk/types.py +11 -12
  4. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/evaluations/create_result_test.py +0 -2
  5. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/evaluations/trigger_test.py +1 -4
  6. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/logs/create_test.py +0 -4
  7. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/prompts/chat_test.py +0 -8
  8. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/prompts/get_or_create_test.py +0 -4
  9. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/prompts/run_test.py +0 -12
  10. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/utils/fixtures.py +227 -89
  11. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/utils/utils.py +10 -6
  12. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/uv.lock +1 -1
  13. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/.gitignore +0 -0
  14. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/.python-version +0 -0
  15. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/README.md +0 -0
  16. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/scripts/format.py +0 -0
  17. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/scripts/lint.py +0 -0
  18. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/scripts/test.py +0 -0
  19. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/__init__.py +0 -0
  20. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/client/__init__.py +0 -0
  21. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/client/client.py +0 -0
  22. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/client/payloads.py +0 -0
  23. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/client/router.py +0 -0
  24. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/env/__init__.py +0 -0
  25. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/env/env.py +0 -0
  26. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/py.typed +0 -0
  27. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/sdk/__init__.py +0 -0
  28. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/sdk/errors.py +0 -0
  29. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/sdk/evaluations.py +0 -0
  30. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/sdk/latitude.py +0 -0
  31. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/sdk/logs.py +0 -0
  32. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/sdk/prompts.py +0 -0
  33. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/util/__init__.py +0 -0
  34. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/src/latitude_sdk/util/utils.py +0 -0
  35. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/__init__.py +0 -0
  36. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/evaluations/__init__.py +0 -0
  37. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/logs/__init__.py +0 -0
  38. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/prompts/__init__.py +0 -0
  39. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/prompts/get_test.py +0 -0
  40. {latitude_sdk-0.1.0b4 → latitude_sdk-0.1.0b5}/tests/utils/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: latitude-sdk
3
- Version: 0.1.0b4
3
+ Version: 0.1.0b5
4
4
  Summary: Latitude SDK for Python
5
5
  Project-URL: repository, https://github.com/latitude-dev/latitude-llm/tree/main/packages/sdks/python
6
6
  Project-URL: homepage, https://github.com/latitude-dev/latitude-llm/tree/main/packages/sdks/python#readme
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "latitude-sdk"
3
- version = "0.1.0-beta.4"
3
+ version = "0.1.0-beta.5"
4
4
  description = "Latitude SDK for Python"
5
5
  authors = [{ name = "Latitude Data SL", email = "hello@latitude.so" }]
6
6
  maintainers = [{ name = "Latitude Data SL", email = "hello@latitude.so" }]
@@ -54,15 +54,15 @@ class FileContent(Model):
54
54
 
55
55
  class ToolCallContent(Model):
56
56
  type: Literal[ContentType.ToolCall] = ContentType.ToolCall
57
- tool_call_id: str = Field(alias=str("toolCallId"))
58
- tool_name: str = Field(alias=str("toolName"))
59
- tool_arguments: Dict[str, Any] = Field(alias=str("toolArguments"))
57
+ id: str = Field(alias=str("toolCallId"))
58
+ name: str = Field(alias=str("toolName"))
59
+ arguments: Dict[str, Any] = Field(alias=str("args"))
60
60
 
61
61
 
62
62
  class ToolResultContent(Model):
63
63
  type: Literal[ContentType.ToolResult] = ContentType.ToolResult
64
- tool_call_id: str = Field(alias=str("toolCallId"))
65
- tool_name: str = Field(alias=str("toolName"))
64
+ id: str = Field(alias=str("toolCallId"))
65
+ name: str = Field(alias=str("toolName"))
66
66
  result: str
67
67
  is_error: Optional[bool] = Field(default=None, alias=str("isError"))
68
68
 
@@ -95,16 +95,9 @@ class UserMessage(Model):
95
95
  name: Optional[str] = None
96
96
 
97
97
 
98
- class ToolCall(Model):
99
- id: str
100
- name: str
101
- arguments: Dict[str, Any]
102
-
103
-
104
98
  class AssistantMessage(Model):
105
99
  role: Literal[MessageRole.Assistant] = MessageRole.Assistant
106
100
  content: Union[str, List[Union[TextContent, ToolCallContent]]]
107
- tool_calls: Optional[List[ToolCall]] = Field(default=None, alias=str("toolCalls"))
108
101
 
109
102
 
110
103
  class ToolMessage(Model):
@@ -121,6 +114,12 @@ class ModelUsage(Model):
121
114
  total_tokens: int = Field(alias=str("totalTokens"))
122
115
 
123
116
 
117
+ class ToolCall(Model):
118
+ id: str
119
+ name: str
120
+ arguments: Dict[str, Any]
121
+
122
+
124
123
  class StreamTypes(StrEnum):
125
124
  Text = "text"
126
125
  Object = "object"
@@ -26,7 +26,6 @@ class TestCreateEvaluationResult(TestCase):
26
26
  body={
27
27
  "result": options.result,
28
28
  "reason": options.reason,
29
- "__internal": {"source": "api"},
30
29
  },
31
30
  )
32
31
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -53,7 +52,6 @@ class TestCreateEvaluationResult(TestCase):
53
52
  body={
54
53
  "result": options.result,
55
54
  "reason": options.reason,
56
- "__internal": {"source": "api"},
57
55
  },
58
56
  )
59
57
  for request in requests
@@ -24,7 +24,6 @@ class TestTriggerEvaluation(TestCase):
24
24
  endpoint=endpoint,
25
25
  body={
26
26
  "evaluationUuids": options.evaluation_uuids,
27
- "__internal": {"source": "api"},
28
27
  },
29
28
  )
30
29
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -47,9 +46,7 @@ class TestTriggerEvaluation(TestCase):
47
46
  request,
48
47
  method="POST",
49
48
  endpoint=endpoint,
50
- body={
51
- "__internal": {"source": "api"},
52
- },
49
+ body={},
53
50
  )
54
51
  for request in requests
55
52
  ]
@@ -28,7 +28,6 @@ class TestCreateLog(TestCase):
28
28
  "path": path,
29
29
  "messages": [json.loads(message.model_dump_json()) for message in messages],
30
30
  "response": options.response,
31
- "__internal": {"source": "api"},
32
31
  },
33
32
  )
34
33
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -54,7 +53,6 @@ class TestCreateLog(TestCase):
54
53
  "path": path,
55
54
  "messages": [json.loads(message.model_dump_json()) for message in messages],
56
55
  "response": options.response,
57
- "__internal": {"source": "api"},
58
56
  },
59
57
  )
60
58
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -81,7 +79,6 @@ class TestCreateLog(TestCase):
81
79
  "path": path,
82
80
  "messages": [json.loads(message.model_dump_json()) for message in messages],
83
81
  "response": options.response,
84
- "__internal": {"source": "api"},
85
82
  },
86
83
  )
87
84
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -109,7 +106,6 @@ class TestCreateLog(TestCase):
109
106
  "path": path,
110
107
  "messages": [json.loads(message.model_dump_json()) for message in messages],
111
108
  "response": options.response,
112
- "__internal": {"source": "api"},
113
109
  },
114
110
  )
115
111
  for request in requests
@@ -36,7 +36,6 @@ class TestChatPromptSync(TestCase):
36
36
  body={
37
37
  "messages": [json.loads(message.model_dump_json()) for message in messages],
38
38
  "stream": options.stream,
39
- "__internal": {"source": "api"},
40
39
  },
41
40
  )
42
41
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -73,7 +72,6 @@ class TestChatPromptSync(TestCase):
73
72
  body={
74
73
  "messages": [json.loads(message.model_dump_json()) for message in messages],
75
74
  "stream": options.stream,
76
- "__internal": {"source": "api"},
77
75
  },
78
76
  )
79
77
  for request in requests
@@ -110,7 +108,6 @@ class TestChatPromptSync(TestCase):
110
108
  body={
111
109
  "messages": [json.loads(message.model_dump_json()) for message in messages],
112
110
  "stream": options.stream,
113
- "__internal": {"source": "api"},
114
111
  },
115
112
  )
116
113
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -144,7 +141,6 @@ class TestChatPromptSync(TestCase):
144
141
  body={
145
142
  "messages": [json.loads(message.model_dump_json()) for message in messages],
146
143
  "stream": options.stream,
147
- "__internal": {"source": "api"},
148
144
  },
149
145
  )
150
146
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -183,7 +179,6 @@ class TestChatPromptStream(TestCase):
183
179
  body={
184
180
  "messages": [json.loads(message.model_dump_json()) for message in messages],
185
181
  "stream": options.stream,
186
- "__internal": {"source": "api"},
187
182
  },
188
183
  )
189
184
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -221,7 +216,6 @@ class TestChatPromptStream(TestCase):
221
216
  body={
222
217
  "messages": [json.loads(message.model_dump_json()) for message in messages],
223
218
  "stream": options.stream,
224
- "__internal": {"source": "api"},
225
219
  },
226
220
  )
227
221
  for request in requests
@@ -258,7 +252,6 @@ class TestChatPromptStream(TestCase):
258
252
  body={
259
253
  "messages": [json.loads(message.model_dump_json()) for message in messages],
260
254
  "stream": options.stream,
261
- "__internal": {"source": "api"},
262
255
  },
263
256
  )
264
257
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -292,7 +285,6 @@ class TestChatPromptStream(TestCase):
292
285
  body={
293
286
  "messages": [json.loads(message.model_dump_json()) for message in messages],
294
287
  "stream": options.stream,
295
- "__internal": {"source": "api"},
296
288
  },
297
289
  )
298
290
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -25,7 +25,6 @@ class TestGetOrCreatePrompt(TestCase):
25
25
  body={
26
26
  "path": path,
27
27
  "prompt": options.prompt,
28
- "__internal": {"source": "api"},
29
28
  },
30
29
  )
31
30
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -49,7 +48,6 @@ class TestGetOrCreatePrompt(TestCase):
49
48
  body={
50
49
  "path": path,
51
50
  "prompt": options.prompt,
52
- "__internal": {"source": "api"},
53
51
  },
54
52
  )
55
53
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -74,7 +72,6 @@ class TestGetOrCreatePrompt(TestCase):
74
72
  body={
75
73
  "path": path,
76
74
  "prompt": options.prompt,
77
- "__internal": {"source": "api"},
78
75
  },
79
76
  )
80
77
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -100,7 +97,6 @@ class TestGetOrCreatePrompt(TestCase):
100
97
  body={
101
98
  "path": path,
102
99
  "prompt": options.prompt,
103
- "__internal": {"source": "api"},
104
100
  },
105
101
  )
106
102
  for request in requests
@@ -38,7 +38,6 @@ class TestRunPromptSync(TestCase):
38
38
  "customIdentifier": options.custom_identifier,
39
39
  "parameters": options.parameters,
40
40
  "stream": options.stream,
41
- "__internal": {"source": "api"},
42
41
  },
43
42
  )
44
43
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -79,7 +78,6 @@ class TestRunPromptSync(TestCase):
79
78
  "customIdentifier": options.custom_identifier,
80
79
  "parameters": options.parameters,
81
80
  "stream": options.stream,
82
- "__internal": {"source": "api"},
83
81
  },
84
82
  )
85
83
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -119,7 +117,6 @@ class TestRunPromptSync(TestCase):
119
117
  "customIdentifier": options.custom_identifier,
120
118
  "parameters": options.parameters,
121
119
  "stream": options.stream,
122
- "__internal": {"source": "api"},
123
120
  },
124
121
  )
125
122
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -159,7 +156,6 @@ class TestRunPromptSync(TestCase):
159
156
  "customIdentifier": options.custom_identifier,
160
157
  "parameters": options.parameters,
161
158
  "stream": options.stream,
162
- "__internal": {"source": "api"},
163
159
  },
164
160
  )
165
161
  for request in requests
@@ -199,7 +195,6 @@ class TestRunPromptSync(TestCase):
199
195
  "customIdentifier": options.custom_identifier,
200
196
  "parameters": options.parameters,
201
197
  "stream": options.stream,
202
- "__internal": {"source": "api"},
203
198
  },
204
199
  )
205
200
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -236,7 +231,6 @@ class TestRunPromptSync(TestCase):
236
231
  "customIdentifier": options.custom_identifier,
237
232
  "parameters": options.parameters,
238
233
  "stream": options.stream,
239
- "__internal": {"source": "api"},
240
234
  },
241
235
  )
242
236
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -278,7 +272,6 @@ class TestRunPromptStream(TestCase):
278
272
  "customIdentifier": options.custom_identifier,
279
273
  "parameters": options.parameters,
280
274
  "stream": options.stream,
281
- "__internal": {"source": "api"},
282
275
  },
283
276
  )
284
277
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -321,7 +314,6 @@ class TestRunPromptStream(TestCase):
321
314
  "customIdentifier": options.custom_identifier,
322
315
  "parameters": options.parameters,
323
316
  "stream": options.stream,
324
- "__internal": {"source": "api"},
325
317
  },
326
318
  )
327
319
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -363,7 +355,6 @@ class TestRunPromptStream(TestCase):
363
355
  "customIdentifier": options.custom_identifier,
364
356
  "parameters": options.parameters,
365
357
  "stream": options.stream,
366
- "__internal": {"source": "api"},
367
358
  },
368
359
  )
369
360
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -404,7 +395,6 @@ class TestRunPromptStream(TestCase):
404
395
  "customIdentifier": options.custom_identifier,
405
396
  "parameters": options.parameters,
406
397
  "stream": options.stream,
407
- "__internal": {"source": "api"},
408
398
  },
409
399
  )
410
400
  for request in requests
@@ -444,7 +434,6 @@ class TestRunPromptStream(TestCase):
444
434
  "customIdentifier": options.custom_identifier,
445
435
  "parameters": options.parameters,
446
436
  "stream": options.stream,
447
- "__internal": {"source": "api"},
448
437
  },
449
438
  )
450
439
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -481,7 +470,6 @@ class TestRunPromptStream(TestCase):
481
470
  "customIdentifier": options.custom_identifier,
482
471
  "parameters": options.parameters,
483
472
  "stream": options.stream,
484
- "__internal": {"source": "api"},
485
473
  },
486
474
  )
487
475
  self.assertEqual(endpoint_mock.call_count, 1)
@@ -24,6 +24,8 @@ from latitude_sdk import (
24
24
  StreamEvents,
25
25
  SystemMessage,
26
26
  TextContent,
27
+ ToolCall,
28
+ ToolCallContent,
27
29
  UserMessage,
28
30
  )
29
31
 
@@ -177,7 +179,7 @@ data: {json.dumps({
177
179
  "finishReason": "stop",
178
180
  "isContinued": False,
179
181
  "experimental_providerMetadata": {"openai": {"reasoningTokens": 0, "cachedPromptTokens": 0}},
180
- "response": {"timestamp": "2025-01-02T12:29:13.000Z", "modelId": "gpt-4o-mini-2024-07-18"},
182
+ "response": {"timestamp": "2025-01-02T12:29:13.000Z", "modelId": "gpt-4o-mini-latest"},
181
183
  "usage": {"promptTokens": 31, "completionTokens": 9, "totalTokens": 40},
182
184
  })}""",
183
185
  f"""
@@ -186,7 +188,7 @@ data: {json.dumps({
186
188
  "type": "finish",
187
189
  "finishReason": "stop",
188
190
  "experimental_providerMetadata": {"openai": {"reasoningTokens": 0, "cachedPromptTokens": 0}},
189
- "response": {"timestamp": "2025-01-02T12:29:13.000Z", "modelId": "gpt-4o-mini-2024-07-18"},
191
+ "response": {"timestamp": "2025-01-02T12:29:13.000Z", "modelId": "gpt-4o-mini-latest"},
190
192
  "usage": {"promptTokens": 31, "completionTokens": 9, "totalTokens": 40},
191
193
  })}""",
192
194
  f"""
@@ -199,32 +201,6 @@ data: {json.dumps({
199
201
  "text": "I should look at their decimals.",
200
202
  "toolCalls": [],
201
203
  "usage": {"promptTokens": 31, "completionTokens": 9, "totalTokens": 40},
202
- "documentLogUuid": "bf7b0b97-6a3a-4147-b058-2588517dd209",
203
- "providerLog": {
204
- "id": 248559,
205
- "workspaceId": 1,
206
- "uuid": "4ae2e019-52ef-4595-9610-b38423c175f5",
207
- "documentLogUuid": "bf7b0b97-6a3a-4147-b058-2588517dd209",
208
- "providerId": 1,
209
- "model": "gpt-4o-mini",
210
- "finishReason": "stop",
211
- "config": {"provider": "OpenAI", "model": "gpt-4o-mini"},
212
- "messages": [
213
- {"role": "system", "content": [{"type": "text", "text": "Reason before answering."}]},
214
- {"role": "user", "content": [{"type": "text", "text": "My question is: Is 9.9 greater than 9.11?"}]},
215
- ],
216
- "responseObject": None,
217
- "responseText": "I should look at their decimals.",
218
- "toolCalls": [],
219
- "tokens": 40,
220
- "costInMillicents": 9,
221
- "duration": 2,
222
- "source": "api",
223
- "apiKeyId": None,
224
- "generatedAt": "2025-01-02T12:29:16.085Z",
225
- "createdAt": "2025-01-02T12:29:16.086Z",
226
- "updatedAt": "2025-01-02T12:29:16.086Z",
227
- },
228
204
  },
229
205
  })}""",
230
206
  f"""
@@ -233,7 +209,26 @@ data: {json.dumps({
233
209
  "type": "chain-step",
234
210
  "uuid": "bf7b0b97-6a3a-4147-b058-2588517dd209",
235
211
  "isLastStep": True,
236
- "config": {"provider": "OpenAI", "model": "gpt-4o-mini"},
212
+ "config": {
213
+ "provider": "OpenAI",
214
+ "model": "gpt-4o-mini",
215
+ "tools": {
216
+ "calculator": {
217
+ "description": "Calculates an expression.",
218
+ "parameters": {
219
+ "type": "object",
220
+ "properties": {
221
+ "expression": {
222
+ "type": "string",
223
+ "description": "The expression to calculate, e.g., '1 + 1'.",
224
+ }
225
+ },
226
+ "required": ["expression"],
227
+ "additionalProperties": False,
228
+ },
229
+ },
230
+ },
231
+ },
237
232
  "messages": [
238
233
  {"role": "assistant", "content": [{"type": "text", "text": "I should look at their decimals."}]},
239
234
  {"role": "system", "content": [{"type": "text", "text": "Now answer succinctly."}]},
@@ -244,25 +239,33 @@ data: {json.dumps({
244
239
  event: provider-event
245
240
  data: {json.dumps({
246
241
  "type": "text-delta",
247
- "textDelta": "Yes, 9.9 is greater than 9.11.",
242
+ "textDelta": "Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
243
+ })}""",
244
+ f"""
245
+ event: provider-event
246
+ data: {json.dumps({
247
+ "type": "tool-call",
248
+ "toolCallId": "toolu_01ARatRfRidTDshkg1UuQhW2",
249
+ "toolName": "calculator",
250
+ "args": {"expression": "9.9 > 9.11 ?"},
248
251
  })}""",
249
252
  f"""
250
253
  event: provider-event
251
254
  data: {json.dumps({
252
255
  "type": "step-finish",
253
- "finishReason": "stop",
256
+ "finishReason": "tool-calls",
254
257
  "isContinued": False,
255
258
  "experimental_providerMetadata": {"openai": {"reasoningTokens": 0, "cachedPromptTokens": 0}},
256
- "response": {"timestamp": "2025-01-02T12:29:16.000Z", "modelId": "gpt-4o-mini-2024-07-18"},
259
+ "response": {"timestamp": "2025-01-02T12:29:16.000Z", "modelId": "gpt-4o-mini-latest"},
257
260
  "usage": {"promptTokens": 61, "completionTokens": 9, "totalTokens": 70},
258
261
  })}""",
259
262
  f"""
260
263
  event: provider-event
261
264
  data: {json.dumps({
262
265
  "type": "finish",
263
- "finishReason": "stop",
266
+ "finishReason": "tool-calls",
264
267
  "experimental_providerMetadata": {"openai": {"reasoningTokens": 0, "cachedPromptTokens": 0}},
265
- "response": {"timestamp": "2025-01-02T12:29:16.000Z", "modelId": "gpt-4o-mini-2024-07-18"},
268
+ "response": {"timestamp": "2025-01-02T12:29:16.000Z", "modelId": "gpt-4o-mini-latest"},
266
269
  "usage": {"promptTokens": 61, "completionTokens": 9, "totalTokens": 70},
267
270
  })}""",
268
271
  f"""
@@ -272,38 +275,15 @@ data: {json.dumps({
272
275
  "uuid": "bf7b0b97-6a3a-4147-b058-2588517dd209",
273
276
  "response": {
274
277
  "streamType": "text",
275
- "text": "Yes, 9.9 is greater than 9.11.",
276
- "toolCalls": [],
278
+ "text": "Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
279
+ "toolCalls": [
280
+ {
281
+ "id": "toolu_01ARatRfRidTDshkg1UuQhW2",
282
+ "name": "calculator",
283
+ "arguments": {"expression": "9.9 > 9.11 ?"},
284
+ },
285
+ ],
277
286
  "usage": {"promptTokens": 61, "completionTokens": 9, "totalTokens": 70},
278
- "documentLogUuid": "bf7b0b97-6a3a-4147-b058-2588517dd209",
279
- "providerLog": {
280
- "id": 248560,
281
- "workspaceId": 1,
282
- "uuid": "5b7c7d44-c99b-4764-af9b-f2c4adf16b42",
283
- "documentLogUuid": "bf7b0b97-6a3a-4147-b058-2588517dd209",
284
- "providerId": 1,
285
- "model": "gpt-4o-mini",
286
- "finishReason": "stop",
287
- "config": {"provider": "OpenAI", "model": "gpt-4o-mini"},
288
- "messages": [
289
- {"role": "system", "content": [{"type": "text", "text": "Reason before answering."}]},
290
- {"role": "user", "content": [{"type": "text", "text": "My question is: Is 9.9 greater than 9.11?"}]},
291
- {"role": "assistant", "content": [{"type": "text", "text": "I should look at their decimals."}]},
292
- {"role": "system", "content": [{"type": "text", "text": "Now answer succinctly."}]},
293
- {"role": "user", "content": [{"type": "text", "text": "My question was: Is 9.9 greater than 9.11?"}]},
294
- ],
295
- "responseObject": None,
296
- "responseText": "Yes, 9.9 is greater than 9.11.",
297
- "toolCalls": [],
298
- "tokens": 70,
299
- "costInMillicents": 9,
300
- "duration": 2,
301
- "source": "api",
302
- "apiKeyId": None,
303
- "generatedAt": "2025-01-02T12:29:16.607Z",
304
- "createdAt": "2025-01-02T12:29:16.608Z",
305
- "updatedAt": "2025-01-02T12:29:16.608Z",
306
- },
307
287
  },
308
288
  })}""",
309
289
  f"""
@@ -311,14 +291,60 @@ event: latitude-event
311
291
  data: {json.dumps({
312
292
  "type": "chain-complete",
313
293
  "uuid": "bf7b0b97-6a3a-4147-b058-2588517dd209",
314
- "config": {"provider": "OpenAI", "model": "gpt-4o-mini"},
294
+ "config": {
295
+ "provider": "OpenAI",
296
+ "model": "gpt-4o-mini",
297
+ "tools": {
298
+ "calculator": {
299
+ "description": "Calculates an expression.",
300
+ "parameters": {
301
+ "type": "object",
302
+ "properties": {
303
+ "expression": {
304
+ "type": "string",
305
+ "description": "The expression to calculate, e.g., '1 + 1'.",
306
+ }
307
+ },
308
+ "required": ["expression"],
309
+ "additionalProperties": False,
310
+ },
311
+ },
312
+ },
313
+ },
315
314
  "messages": [
316
- {"role": "assistant", "content": "Yes, 9.9 is greater than 9.11.", "toolCalls": []},
315
+ {
316
+ "role": "assistant",
317
+ "content": [
318
+ {
319
+ "type": "text",
320
+ "text": "Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
321
+ },
322
+ {
323
+ "type": "tool-call",
324
+ "toolCallId": "toolu_01ARatRfRidTDshkg1UuQhW2",
325
+ "toolName": "calculator",
326
+ "args": {"expression": "9.9 > 9.11 ?"},
327
+ },
328
+ ],
329
+ "toolCalls": [
330
+ {
331
+ "id": "toolu_01ARatRfRidTDshkg1UuQhW2",
332
+ "name": "calculator",
333
+ "arguments": {"expression": "9.9 > 9.11 ?"},
334
+ },
335
+ ],
336
+ },
317
337
  ],
318
338
  "response": {
319
339
  "streamType": "text",
320
- "text": "Yes, 9.9 is greater than 9.11.",
321
- "toolCalls": [],
340
+ "text": "Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
341
+ "toolCalls": [
342
+ {
343
+ "id": "toolu_01ARatRfRidTDshkg1UuQhW2",
344
+ "name": "calculator",
345
+ "arguments": {"expression": "9.9 > 9.11 ?"},
346
+ },
347
+ ],
322
348
  "usage": {"promptTokens": 61, "completionTokens": 9, "totalTokens": 70},
323
349
  },
324
350
  })}""",
@@ -351,7 +377,7 @@ CONVERSATION_EVENTS: List[StreamEvent] = [
351
377
  "finishReason": "stop",
352
378
  "isContinued": False,
353
379
  "experimental_providerMetadata": {"openai": {"reasoningTokens": 0, "cachedPromptTokens": 0}},
354
- "response": {"timestamp": "2025-01-02T12:29:13.000Z", "modelId": "gpt-4o-mini-2024-07-18"},
380
+ "response": {"timestamp": "2025-01-02T12:29:13.000Z", "modelId": "gpt-4o-mini-latest"},
355
381
  "usage": {"promptTokens": 31, "completionTokens": 9, "totalTokens": 40},
356
382
  },
357
383
  {
@@ -359,7 +385,7 @@ CONVERSATION_EVENTS: List[StreamEvent] = [
359
385
  "type": "finish",
360
386
  "finishReason": "stop",
361
387
  "experimental_providerMetadata": {"openai": {"reasoningTokens": 0, "cachedPromptTokens": 0}},
362
- "response": {"timestamp": "2025-01-02T12:29:13.000Z", "modelId": "gpt-4o-mini-2024-07-18"},
388
+ "response": {"timestamp": "2025-01-02T12:29:13.000Z", "modelId": "gpt-4o-mini-latest"},
363
389
  "usage": {"promptTokens": 31, "completionTokens": 9, "totalTokens": 40},
364
390
  },
365
391
  ChainEventStepCompleted(
@@ -373,7 +399,26 @@ CONVERSATION_EVENTS: List[StreamEvent] = [
373
399
  ChainEventStep(
374
400
  uuid="bf7b0b97-6a3a-4147-b058-2588517dd209",
375
401
  is_last_step=True,
376
- config={"provider": "OpenAI", "model": "gpt-4o-mini"},
402
+ config={
403
+ "provider": "OpenAI",
404
+ "model": "gpt-4o-mini",
405
+ "tools": {
406
+ "calculator": {
407
+ "description": "Calculates an expression.",
408
+ "parameters": {
409
+ "type": "object",
410
+ "properties": {
411
+ "expression": {
412
+ "type": "string",
413
+ "description": "The expression to calculate, e.g., '1 + 1'.",
414
+ }
415
+ },
416
+ "required": ["expression"],
417
+ "additionalProperties": False,
418
+ },
419
+ },
420
+ },
421
+ },
377
422
  messages=[
378
423
  AssistantMessage(content=[TextContent(text="I should look at their decimals.")]),
379
424
  SystemMessage(content=[TextContent(text="Now answer succinctly.")]),
@@ -383,43 +428,92 @@ CONVERSATION_EVENTS: List[StreamEvent] = [
383
428
  {
384
429
  "event": StreamEvents.Provider,
385
430
  "type": "text-delta",
386
- "textDelta": "Yes, 9.9 is greater than 9.11.",
431
+ "textDelta": "Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
432
+ },
433
+ {
434
+ "event": StreamEvents.Provider,
435
+ "type": "tool-call",
436
+ "toolCallId": "toolu_01ARatRfRidTDshkg1UuQhW2",
437
+ "toolName": "calculator",
438
+ "args": {"expression": "9.9 > 9.11 ?"},
387
439
  },
388
440
  {
389
441
  "event": StreamEvents.Provider,
390
442
  "type": "step-finish",
391
- "finishReason": "stop",
443
+ "finishReason": "tool-calls",
392
444
  "isContinued": False,
393
445
  "experimental_providerMetadata": {"openai": {"reasoningTokens": 0, "cachedPromptTokens": 0}},
394
- "response": {"timestamp": "2025-01-02T12:29:16.000Z", "modelId": "gpt-4o-mini-2024-07-18"},
446
+ "response": {"timestamp": "2025-01-02T12:29:16.000Z", "modelId": "gpt-4o-mini-latest"},
395
447
  "usage": {"promptTokens": 61, "completionTokens": 9, "totalTokens": 70},
396
448
  },
397
449
  {
398
450
  "event": StreamEvents.Provider,
399
451
  "type": "finish",
400
- "finishReason": "stop",
452
+ "finishReason": "tool-calls",
401
453
  "experimental_providerMetadata": {"openai": {"reasoningTokens": 0, "cachedPromptTokens": 0}},
402
- "response": {"timestamp": "2025-01-02T12:29:16.000Z", "modelId": "gpt-4o-mini-2024-07-18"},
454
+ "response": {"timestamp": "2025-01-02T12:29:16.000Z", "modelId": "gpt-4o-mini-latest"},
403
455
  "usage": {"promptTokens": 61, "completionTokens": 9, "totalTokens": 70},
404
456
  },
405
457
  ChainEventStepCompleted(
406
458
  uuid="bf7b0b97-6a3a-4147-b058-2588517dd209",
407
459
  response=ChainTextResponse(
408
- text="Yes, 9.9 is greater than 9.11.",
409
- tool_calls=[],
460
+ text="Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
461
+ tool_calls=[
462
+ ToolCall(
463
+ id="toolu_01ARatRfRidTDshkg1UuQhW2",
464
+ name="calculator",
465
+ arguments={"expression": "9.9 > 9.11 ?"},
466
+ )
467
+ ],
410
468
  usage=ModelUsage(prompt_tokens=61, completion_tokens=9, total_tokens=70),
411
469
  ),
412
470
  ),
413
471
  ChainEventCompleted(
414
472
  uuid="bf7b0b97-6a3a-4147-b058-2588517dd209",
415
- config={"provider": "OpenAI", "model": "gpt-4o-mini"},
473
+ config={
474
+ "provider": "OpenAI",
475
+ "model": "gpt-4o-mini",
476
+ "tools": {
477
+ "calculator": {
478
+ "description": "Calculates an expression.",
479
+ "parameters": {
480
+ "type": "object",
481
+ "properties": {
482
+ "expression": {
483
+ "type": "string",
484
+ "description": "The expression to calculate, e.g., '1 + 1'.",
485
+ }
486
+ },
487
+ "required": ["expression"],
488
+ "additionalProperties": False,
489
+ },
490
+ },
491
+ },
492
+ },
416
493
  messages=[
417
- AssistantMessage(content="Yes, 9.9 is greater than 9.11.", tool_calls=[]),
494
+ AssistantMessage(
495
+ content=[
496
+ TextContent(
497
+ text="Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
498
+ ),
499
+ ToolCallContent(
500
+ id="toolu_01ARatRfRidTDshkg1UuQhW2",
501
+ name="calculator",
502
+ arguments={"expression": "9.9 > 9.11 ?"},
503
+ ),
504
+ ]
505
+ ),
418
506
  ],
419
507
  object=None,
420
508
  response=ChainTextResponse(
421
- text="Yes, 9.9 is greater than 9.11.",
422
- tool_calls=[],
509
+ text="Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
510
+ tool_calls=[
511
+ ToolCall(
512
+ id="toolu_01ARatRfRidTDshkg1UuQhW2",
513
+ name="calculator",
514
+ arguments={"expression": "9.9 > 9.11 ?"},
515
+ )
516
+ ],
423
517
  usage=ModelUsage(prompt_tokens=61, completion_tokens=9, total_tokens=70),
424
518
  ),
425
519
  ),
@@ -469,12 +563,39 @@ CONVERSATION_FINISHED_EVENT_RESPONSE: Dict[str, Any] = {
469
563
  {"role": "assistant", "content": [{"type": "text", "text": "I should look at their decimals."}]},
470
564
  {"role": "system", "content": [{"type": "text", "text": "Now answer succinctly."}]},
471
565
  {"role": "user", "content": [{"type": "text", "text": "My question was: Is 9.9 greater than 9.11?"}]},
472
- {"role": "assistant", "content": "Yes, 9.9 is greater than 9.11.", "toolCalls": []},
566
+ {
567
+ "role": "assistant",
568
+ "content": [
569
+ {
570
+ "type": "text",
571
+ "text": "Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
572
+ },
573
+ {
574
+ "type": "tool-call",
575
+ "toolCallId": "toolu_01ARatRfRidTDshkg1UuQhW2",
576
+ "toolName": "calculator",
577
+ "args": {"expression": "9.9 > 9.11 ?"},
578
+ },
579
+ ],
580
+ "toolCalls": [
581
+ {
582
+ "id": "toolu_01ARatRfRidTDshkg1UuQhW2",
583
+ "name": "calculator",
584
+ "arguments": {"expression": "9.9 > 9.11 ?"},
585
+ },
586
+ ],
587
+ },
473
588
  ],
474
589
  "response": {
475
590
  "streamType": "text",
476
- "text": "Yes, 9.9 is greater than 9.11.",
477
- "toolCalls": [],
591
+ "text": "Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
592
+ "toolCalls": [
593
+ {
594
+ "id": "toolu_01ARatRfRidTDshkg1UuQhW2",
595
+ "name": "calculator",
596
+ "arguments": {"expression": "9.9 > 9.11 ?"},
597
+ },
598
+ ],
478
599
  "usage": {"promptTokens": 61, "completionTokens": 9, "totalTokens": 70},
479
600
  },
480
601
  }
@@ -487,11 +608,28 @@ CONVERSATION_FINISHED_EVENT = FinishedEvent(
487
608
  AssistantMessage(content=[TextContent(text="I should look at their decimals.")]),
488
609
  SystemMessage(content=[TextContent(text="Now answer succinctly.")]),
489
610
  UserMessage(content=[TextContent(text="My question was: Is 9.9 greater than 9.11?")]),
490
- AssistantMessage(content="Yes, 9.9 is greater than 9.11.", tool_calls=[]),
611
+ AssistantMessage(
612
+ content=[
613
+ TextContent(
614
+ text="Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
615
+ ),
616
+ ToolCallContent(
617
+ id="toolu_01ARatRfRidTDshkg1UuQhW2",
618
+ name="calculator",
619
+ arguments={"expression": "9.9 > 9.11 ?"},
620
+ ),
621
+ ]
622
+ ),
491
623
  ],
492
624
  response=ChainTextResponse(
493
- text="Yes, 9.9 is greater than 9.11.",
494
- tool_calls=[],
625
+ text="Yes, 9.9 is greater than 9.11. Use the calculator if you don't believe me.",
626
+ tool_calls=[
627
+ ToolCall(
628
+ id="toolu_01ARatRfRidTDshkg1UuQhW2",
629
+ name="calculator",
630
+ arguments={"expression": "9.9 > 9.11 ?"},
631
+ )
632
+ ],
495
633
  usage=ModelUsage(prompt_tokens=61, completion_tokens=9, total_tokens=70),
496
634
  ),
497
635
  )
@@ -13,6 +13,7 @@ from latitude_sdk import (
13
13
  InternalOptions,
14
14
  Latitude,
15
15
  LatitudeOptions,
16
+ LogSources,
16
17
  Message,
17
18
  SystemMessage,
18
19
  TextContent,
@@ -81,7 +82,10 @@ class TestCase(IsolatedAsyncioTestCase):
81
82
  dict(request.headers),
82
83
  )
83
84
  try:
84
- self.assertEqual(json.loads(request.content), body or {})
85
+ self.assertEqual(
86
+ json.loads(request.content),
87
+ {**{"__internal": {"source": LogSources.Api}}, **(body or {})},
88
+ )
85
89
  except json.JSONDecodeError:
86
90
  self.assertEqual(None, body)
87
91
 
@@ -100,17 +104,17 @@ class TestCase(IsolatedAsyncioTestCase):
100
104
  content=[
101
105
  TextContent(text="assistant message"),
102
106
  ToolCallContent(
103
- tool_call_id="tool call id",
104
- tool_name="tool name",
105
- tool_arguments={"argument_1": "value 1", "argument_2": "value 2"},
107
+ id="tool id",
108
+ name="tool name",
109
+ arguments={"argument_1": "value 1", "argument_2": "value 2"},
106
110
  ),
107
111
  ],
108
112
  ),
109
113
  ToolMessage(
110
114
  content=[
111
115
  ToolResultContent(
112
- tool_call_id="tool call id",
113
- tool_name="tool name",
116
+ id="tool id",
117
+ name="tool name",
114
118
  result="tool result",
115
119
  is_error=False,
116
120
  ),
@@ -158,7 +158,7 @@ wheels = [
158
158
 
159
159
  [[package]]
160
160
  name = "latitude-sdk"
161
- version = "0.1.0b4"
161
+ version = "0.1.0b5"
162
162
  source = { editable = "." }
163
163
  dependencies = [
164
164
  { name = "httpx" },
File without changes