letta-nightly 0.5.0.dev20241019104023__py3-none-any.whl → 0.5.0.dev20241021104213__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.
Potentially problematic release.
This version of letta-nightly might be problematic. Click here for more details.
- letta/agent.py +2 -1
- letta/llm_api/openai.py +12 -2
- letta/schemas/letta_message.py +8 -4
- letta/schemas/message.py +3 -0
- letta/server/rest_api/interface.py +15 -2
- letta/utils.py +3 -0
- {letta_nightly-0.5.0.dev20241019104023.dist-info → letta_nightly-0.5.0.dev20241021104213.dist-info}/METADATA +1 -1
- {letta_nightly-0.5.0.dev20241019104023.dist-info → letta_nightly-0.5.0.dev20241021104213.dist-info}/RECORD +11 -11
- {letta_nightly-0.5.0.dev20241019104023.dist-info → letta_nightly-0.5.0.dev20241021104213.dist-info}/LICENSE +0 -0
- {letta_nightly-0.5.0.dev20241019104023.dist-info → letta_nightly-0.5.0.dev20241021104213.dist-info}/WHEEL +0 -0
- {letta_nightly-0.5.0.dev20241019104023.dist-info → letta_nightly-0.5.0.dev20241021104213.dist-info}/entry_points.txt +0 -0
letta/agent.py
CHANGED
|
@@ -503,7 +503,7 @@ class Agent(BaseAgent):
|
|
|
503
503
|
def _handle_ai_response(
|
|
504
504
|
self,
|
|
505
505
|
response_message: ChatCompletionMessage, # TODO should we eventually move the Message creation outside of this function?
|
|
506
|
-
override_tool_call_id: bool =
|
|
506
|
+
override_tool_call_id: bool = False,
|
|
507
507
|
# If we are streaming, we needed to create a Message ID ahead of time,
|
|
508
508
|
# and now we want to use it in the creation of the Message object
|
|
509
509
|
# TODO figure out a cleaner way to do this
|
|
@@ -530,6 +530,7 @@ class Agent(BaseAgent):
|
|
|
530
530
|
|
|
531
531
|
# generate UUID for tool call
|
|
532
532
|
if override_tool_call_id or response_message.function_call:
|
|
533
|
+
warnings.warn("Overriding the tool call can result in inconsistent tool call IDs during streaming")
|
|
533
534
|
tool_call_id = get_tool_call_id() # needs to be a string for JSON
|
|
534
535
|
response_message.tool_calls[0].id = tool_call_id
|
|
535
536
|
else:
|
letta/llm_api/openai.py
CHANGED
|
@@ -41,7 +41,7 @@ from letta.streaming_interface import (
|
|
|
41
41
|
AgentChunkStreamingInterface,
|
|
42
42
|
AgentRefreshStreamingInterface,
|
|
43
43
|
)
|
|
44
|
-
from letta.utils import smart_urljoin
|
|
44
|
+
from letta.utils import get_tool_call_id, smart_urljoin
|
|
45
45
|
|
|
46
46
|
OPENAI_SSE_DONE = "[DONE]"
|
|
47
47
|
|
|
@@ -174,6 +174,7 @@ def openai_chat_completions_process_stream(
|
|
|
174
174
|
stream_interface: Optional[Union[AgentChunkStreamingInterface, AgentRefreshStreamingInterface]] = None,
|
|
175
175
|
create_message_id: bool = True,
|
|
176
176
|
create_message_datetime: bool = True,
|
|
177
|
+
override_tool_call_id: bool = True,
|
|
177
178
|
) -> ChatCompletionResponse:
|
|
178
179
|
"""Process a streaming completion response, and return a ChatCompletionRequest at the end.
|
|
179
180
|
|
|
@@ -244,6 +245,14 @@ def openai_chat_completions_process_stream(
|
|
|
244
245
|
):
|
|
245
246
|
assert isinstance(chat_completion_chunk, ChatCompletionChunkResponse), type(chat_completion_chunk)
|
|
246
247
|
|
|
248
|
+
# NOTE: this assumes that the tool call ID will only appear in one of the chunks during the stream
|
|
249
|
+
if override_tool_call_id:
|
|
250
|
+
for choice in chat_completion_chunk.choices:
|
|
251
|
+
if choice.delta.tool_calls and len(choice.delta.tool_calls) > 0:
|
|
252
|
+
for tool_call in choice.delta.tool_calls:
|
|
253
|
+
if tool_call.id is not None:
|
|
254
|
+
tool_call.id = get_tool_call_id()
|
|
255
|
+
|
|
247
256
|
if stream_interface:
|
|
248
257
|
if isinstance(stream_interface, AgentChunkStreamingInterface):
|
|
249
258
|
stream_interface.process_chunk(
|
|
@@ -290,6 +299,7 @@ def openai_chat_completions_process_stream(
|
|
|
290
299
|
else:
|
|
291
300
|
accum_message.content += content_delta
|
|
292
301
|
|
|
302
|
+
# TODO(charles) make sure this works for parallel tool calling?
|
|
293
303
|
if message_delta.tool_calls is not None:
|
|
294
304
|
tool_calls_delta = message_delta.tool_calls
|
|
295
305
|
|
|
@@ -340,7 +350,7 @@ def openai_chat_completions_process_stream(
|
|
|
340
350
|
assert all([c.finish_reason != TEMP_STREAM_FINISH_REASON for c in chat_completion_response.choices])
|
|
341
351
|
assert all(
|
|
342
352
|
[
|
|
343
|
-
all([tc != TEMP_STREAM_TOOL_CALL_ID for tc in c.message.tool_calls]) if c.message.tool_calls else True
|
|
353
|
+
all([tc.id != TEMP_STREAM_TOOL_CALL_ID for tc in c.message.tool_calls]) if c.message.tool_calls else True
|
|
344
354
|
for c in chat_completion_response.choices
|
|
345
355
|
]
|
|
346
356
|
)
|
letta/schemas/letta_message.py
CHANGED
|
@@ -78,12 +78,14 @@ class FunctionCall(BaseModel):
|
|
|
78
78
|
|
|
79
79
|
name: str
|
|
80
80
|
arguments: str
|
|
81
|
+
function_call_id: str
|
|
81
82
|
|
|
82
83
|
|
|
83
84
|
class FunctionCallDelta(BaseModel):
|
|
84
85
|
|
|
85
86
|
name: Optional[str]
|
|
86
87
|
arguments: Optional[str]
|
|
88
|
+
function_call_id: Optional[str]
|
|
87
89
|
|
|
88
90
|
# NOTE: this is a workaround to exclude None values from the JSON dump,
|
|
89
91
|
# since the OpenAI style of returning chunks doesn't include keys with null values
|
|
@@ -129,10 +131,10 @@ class FunctionCallMessage(LettaMessage):
|
|
|
129
131
|
@classmethod
|
|
130
132
|
def validate_function_call(cls, v):
|
|
131
133
|
if isinstance(v, dict):
|
|
132
|
-
if "name" in v and "arguments" in v:
|
|
133
|
-
return FunctionCall(name=v["name"], arguments=v["arguments"])
|
|
134
|
-
elif "name" in v or "arguments" in v:
|
|
135
|
-
return FunctionCallDelta(name=v.get("name"), arguments=v.get("arguments"))
|
|
134
|
+
if "name" in v and "arguments" in v and "function_call_id" in v:
|
|
135
|
+
return FunctionCall(name=v["name"], arguments=v["arguments"], function_call_id=v["function_call_id"])
|
|
136
|
+
elif "name" in v or "arguments" in v or "function_call_id" in v:
|
|
137
|
+
return FunctionCallDelta(name=v.get("name"), arguments=v.get("arguments"), function_call_id=v.get("function_call_id"))
|
|
136
138
|
else:
|
|
137
139
|
raise ValueError("function_call must contain either 'name' or 'arguments'")
|
|
138
140
|
return v
|
|
@@ -147,11 +149,13 @@ class FunctionReturn(LettaMessage):
|
|
|
147
149
|
status (Literal["success", "error"]): The status of the function call
|
|
148
150
|
id (str): The ID of the message
|
|
149
151
|
date (datetime): The date the message was created in ISO format
|
|
152
|
+
function_call_id (str): A unique identifier for the function call that generated this message
|
|
150
153
|
"""
|
|
151
154
|
|
|
152
155
|
message_type: Literal["function_return"] = "function_return"
|
|
153
156
|
function_return: str
|
|
154
157
|
status: Literal["success", "error"]
|
|
158
|
+
function_call_id: str
|
|
155
159
|
|
|
156
160
|
|
|
157
161
|
# Legacy Letta API had an additional type "assistant_message" and the "function_call" was a formatted string
|
letta/schemas/message.py
CHANGED
|
@@ -178,6 +178,7 @@ class Message(BaseMessage):
|
|
|
178
178
|
function_call=FunctionCall(
|
|
179
179
|
name=tool_call.function.name,
|
|
180
180
|
arguments=tool_call.function.arguments,
|
|
181
|
+
function_call_id=tool_call.id,
|
|
181
182
|
),
|
|
182
183
|
)
|
|
183
184
|
)
|
|
@@ -203,6 +204,7 @@ class Message(BaseMessage):
|
|
|
203
204
|
raise ValueError(f"Invalid status: {status}")
|
|
204
205
|
except json.JSONDecodeError:
|
|
205
206
|
raise ValueError(f"Failed to decode function return: {self.text}")
|
|
207
|
+
assert self.tool_call_id is not None
|
|
206
208
|
messages.append(
|
|
207
209
|
# TODO make sure this is what the API returns
|
|
208
210
|
# function_return may not match exactly...
|
|
@@ -211,6 +213,7 @@ class Message(BaseMessage):
|
|
|
211
213
|
date=self.created_at,
|
|
212
214
|
function_return=self.text,
|
|
213
215
|
status=status_enum,
|
|
216
|
+
function_call_id=self.tool_call_id,
|
|
214
217
|
)
|
|
215
218
|
)
|
|
216
219
|
elif self.role == MessageRole.user:
|
|
@@ -531,7 +531,11 @@ class StreamingServerInterface(AgentChunkStreamingInterface):
|
|
|
531
531
|
processed_chunk = FunctionCallMessage(
|
|
532
532
|
id=message_id,
|
|
533
533
|
date=message_date,
|
|
534
|
-
function_call=FunctionCallDelta(
|
|
534
|
+
function_call=FunctionCallDelta(
|
|
535
|
+
name=tool_call_delta.get("name"),
|
|
536
|
+
arguments=tool_call_delta.get("arguments"),
|
|
537
|
+
function_call_id=tool_call_delta.get("id"),
|
|
538
|
+
),
|
|
535
539
|
)
|
|
536
540
|
|
|
537
541
|
else:
|
|
@@ -548,7 +552,11 @@ class StreamingServerInterface(AgentChunkStreamingInterface):
|
|
|
548
552
|
processed_chunk = FunctionCallMessage(
|
|
549
553
|
id=message_id,
|
|
550
554
|
date=message_date,
|
|
551
|
-
function_call=FunctionCallDelta(
|
|
555
|
+
function_call=FunctionCallDelta(
|
|
556
|
+
name=tool_call_delta.get("name"),
|
|
557
|
+
arguments=tool_call_delta.get("arguments"),
|
|
558
|
+
function_call_id=tool_call_delta.get("id"),
|
|
559
|
+
),
|
|
552
560
|
)
|
|
553
561
|
|
|
554
562
|
elif choice.finish_reason is not None:
|
|
@@ -759,6 +767,7 @@ class StreamingServerInterface(AgentChunkStreamingInterface):
|
|
|
759
767
|
function_call=FunctionCall(
|
|
760
768
|
name=function_call.function.name,
|
|
761
769
|
arguments=function_call.function.arguments,
|
|
770
|
+
function_call_id=function_call.id,
|
|
762
771
|
),
|
|
763
772
|
)
|
|
764
773
|
|
|
@@ -786,21 +795,25 @@ class StreamingServerInterface(AgentChunkStreamingInterface):
|
|
|
786
795
|
elif msg.startswith("Success: "):
|
|
787
796
|
msg = msg.replace("Success: ", "")
|
|
788
797
|
# new_message = {"function_return": msg, "status": "success"}
|
|
798
|
+
assert msg_obj.tool_call_id is not None
|
|
789
799
|
new_message = FunctionReturn(
|
|
790
800
|
id=msg_obj.id,
|
|
791
801
|
date=msg_obj.created_at,
|
|
792
802
|
function_return=msg,
|
|
793
803
|
status="success",
|
|
804
|
+
function_call_id=msg_obj.tool_call_id,
|
|
794
805
|
)
|
|
795
806
|
|
|
796
807
|
elif msg.startswith("Error: "):
|
|
797
808
|
msg = msg.replace("Error: ", "")
|
|
798
809
|
# new_message = {"function_return": msg, "status": "error"}
|
|
810
|
+
assert msg_obj.tool_call_id is not None
|
|
799
811
|
new_message = FunctionReturn(
|
|
800
812
|
id=msg_obj.id,
|
|
801
813
|
date=msg_obj.created_at,
|
|
802
814
|
function_return=msg,
|
|
803
815
|
status="error",
|
|
816
|
+
function_call_id=msg_obj.tool_call_id,
|
|
804
817
|
)
|
|
805
818
|
|
|
806
819
|
else:
|
letta/utils.py
CHANGED
|
@@ -488,6 +488,9 @@ def is_utc_datetime(dt: datetime) -> bool:
|
|
|
488
488
|
|
|
489
489
|
|
|
490
490
|
def get_tool_call_id() -> str:
|
|
491
|
+
# TODO(sarah) make this a slug-style string?
|
|
492
|
+
# e.g. OpenAI: "call_xlIfzR1HqAW7xJPa3ExJSg3C"
|
|
493
|
+
# or similar to agents: "call-xlIfzR1HqAW7xJPa3ExJSg3C"
|
|
491
494
|
return str(uuid.uuid4())[:TOOL_CALL_ID_MAX_LEN]
|
|
492
495
|
|
|
493
496
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
letta/__init__.py,sha256=cwav47GUQB8F9w0sHIDPe1nZMf_WL00KovBa9dZvSj4,996
|
|
2
2
|
letta/__main__.py,sha256=6Hs2PV7EYc5Tid4g4OtcLXhqVHiNYTGzSBdoOnW2HXA,29
|
|
3
|
-
letta/agent.py,sha256=
|
|
3
|
+
letta/agent.py,sha256=PRMDj0vZu5TGj-k2apeWcWYzJnBR36prdMXTKWnRYc8,72997
|
|
4
4
|
letta/agent_store/chroma.py,sha256=upR5zGnGs6I6btulEYbiZdGG87BgKjxUJOQZ4Y-RQ_M,12492
|
|
5
5
|
letta/agent_store/db.py,sha256=54EpxQYX0lAWxrsO0iUKw2vibF8-62Khczns2vxIK-0,23307
|
|
6
6
|
letta/agent_store/lancedb.py,sha256=i63d4VZwj9UIOTNs5f0JZ_r5yZD-jKWz4FAH4RMpXOE,5104
|
|
@@ -44,7 +44,7 @@ letta/llm_api/google_ai.py,sha256=3xZ074nSOCC22c15yerA5ngWzh0ex4wxeI-6faNbHPE,17
|
|
|
44
44
|
letta/llm_api/helpers.py,sha256=8aG6LzB0T3NFlnab-RR2tj0ARUTMBHSd0icCur5-RCk,8813
|
|
45
45
|
letta/llm_api/llm_api_tools.py,sha256=GEBO7Dlt7xtAQud1sVsigKZKPpLOZOt2IWL8LwcNV4o,14869
|
|
46
46
|
letta/llm_api/mistral.py,sha256=fHdfD9ug-rQIk2qn8tRKay1U6w9maF11ryhKi91FfXM,1593
|
|
47
|
-
letta/llm_api/openai.py,sha256=
|
|
47
|
+
letta/llm_api/openai.py,sha256=faJLzgx94cxz32VSeSxLDHeeSiKkb5WCM3BA_MNylkI,22821
|
|
48
48
|
letta/local_llm/README.md,sha256=hFJyw5B0TU2jrh9nb0zGZMgdH-Ei1dSRfhvPQG_NSoU,168
|
|
49
49
|
letta/local_llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
50
|
letta/local_llm/chat_completion_proxy.py,sha256=SiohxsjGTku4vOryOZx7I0t0xoO_sUuhXgoe62fKq3c,12995
|
|
@@ -123,12 +123,12 @@ letta/schemas/file.py,sha256=Ns0V2Jp6_lmiCmLCnXsOAh_UNqTW-fstcLKjYI35VOA,1357
|
|
|
123
123
|
letta/schemas/health.py,sha256=zT6mYovvD17iJRuu2rcaQQzbEEYrkwvAE9TB7iU824c,139
|
|
124
124
|
letta/schemas/job.py,sha256=605TWjUdNy5Rgoc7en_DX3Giz-I7sVTXiSRZqxL__d8,1543
|
|
125
125
|
letta/schemas/letta_base.py,sha256=4QXFgyjCHqIagi8B6_4nmqb9eoJ52Y6aCxBxQpGX48M,2832
|
|
126
|
-
letta/schemas/letta_message.py,sha256=
|
|
126
|
+
letta/schemas/letta_message.py,sha256=RuVVtwFbi85yP3dXQxowofQ6cI2cO_CdGtgpHGQzgHc,6563
|
|
127
127
|
letta/schemas/letta_request.py,sha256=_oiDshc_AoFWIfXRk2VX5-AxO5vDlyN-9r-gnyLj_30,1890
|
|
128
128
|
letta/schemas/letta_response.py,sha256=_UJoO3UtC3F5DtQCHzdiGM1SHNPYPKvopIWqg8t5YZw,1564
|
|
129
129
|
letta/schemas/llm_config.py,sha256=eFA48vKBTO70qaob8pak2CWOH7TCQeqWuClkMBc2vbY,4172
|
|
130
130
|
letta/schemas/memory.py,sha256=rBbfCps6Oi1p3eYDx8_bY34PQGXx69-pha0Uj4B9678,11650
|
|
131
|
-
letta/schemas/message.py,sha256=
|
|
131
|
+
letta/schemas/message.py,sha256=DQxnRYrYgHXpTKfMzfS-bpCAe-BO_Rmcfc1Wf-4GHjw,33703
|
|
132
132
|
letta/schemas/openai/chat_completion_request.py,sha256=AOIwgbN3CZKVqkuXeMHeSa53u4h0wVq69t3T_LJ0vIE,3389
|
|
133
133
|
letta/schemas/openai/chat_completion_response.py,sha256=05FRfm1EsVivyeWo2aoJk34h3W4pAb4lBCPn1eujjcw,3916
|
|
134
134
|
letta/schemas/openai/chat_completions.py,sha256=V0ZPIIk-ds3O6MAkNHMz8zh1hqMFSPrTcYr88WDYzWE,3588
|
|
@@ -151,7 +151,7 @@ letta/server/rest_api/app.py,sha256=JNmDnvp9fP--hJPtPpEWgQT-14O1YOceZbWELr2vedA,
|
|
|
151
151
|
letta/server/rest_api/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
152
152
|
letta/server/rest_api/auth/index.py,sha256=fQBGyVylGSRfEMLQ17cZzrHd5Y1xiVylvPqH5Rl-lXQ,1378
|
|
153
153
|
letta/server/rest_api/auth_token.py,sha256=725EFEIiNj4dh70hrSd94UysmFD8vcJLrTRfNHkzxDo,774
|
|
154
|
-
letta/server/rest_api/interface.py,sha256=
|
|
154
|
+
letta/server/rest_api/interface.py,sha256=Mub9iOQFJh9HSwbc5X6OwHCdtwJYCBzhOjpSx9c5Lss,36181
|
|
155
155
|
letta/server/rest_api/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
156
156
|
letta/server/rest_api/routers/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
157
157
|
letta/server/rest_api/routers/openai/assistants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -188,9 +188,9 @@ letta/server/ws_api/server.py,sha256=C2Kv48PCwl46DQFb0ZP30s86KJLQ6dZk2AhWQEZn9pY
|
|
|
188
188
|
letta/settings.py,sha256=gNdH-Ty6f-Nfz2j9ZMZFRQHac2KzgsxLZNt5l_TiAyo,3301
|
|
189
189
|
letta/streaming_interface.py,sha256=_FPUWy58j50evHcpXyd7zB1wWqeCc71NCFeWh_TBvnw,15736
|
|
190
190
|
letta/system.py,sha256=buKYPqG5n2x41hVmWpu6JUpyd7vTWED9Km2_M7dLrvk,6960
|
|
191
|
-
letta/utils.py,sha256=
|
|
192
|
-
letta_nightly-0.5.0.
|
|
193
|
-
letta_nightly-0.5.0.
|
|
194
|
-
letta_nightly-0.5.0.
|
|
195
|
-
letta_nightly-0.5.0.
|
|
196
|
-
letta_nightly-0.5.0.
|
|
191
|
+
letta/utils.py,sha256=SXLEYhyp3gHyIjrxNIKNZZ5ittKo3KOj6zxgC_Trex0,31012
|
|
192
|
+
letta_nightly-0.5.0.dev20241021104213.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
|
|
193
|
+
letta_nightly-0.5.0.dev20241021104213.dist-info/METADATA,sha256=HzdXSUkW_tN8xukhNa0g1wcCtIoZAlc9S4vaAHbmdDs,10620
|
|
194
|
+
letta_nightly-0.5.0.dev20241021104213.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
195
|
+
letta_nightly-0.5.0.dev20241021104213.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
|
|
196
|
+
letta_nightly-0.5.0.dev20241021104213.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|