Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: rename internal monologue #2289

Merged
merged 3 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ def nb_print(messages):
def get_formatted_content(msg):
if msg.message_type == "internal_monologue":
return f'<div class="content"><span class="internal-monologue">{html.escape(msg.internal_monologue)}</span></div>'
elif msg.message_type == "reasoning_message":
return f'<div class="content"><span class="internal-monologue">{html.escape(msg.reasoning)}</span></div>'
elif msg.message_type == "function_call":
args = format_json(msg.function_call.arguments)
return f'<div class="content"><span class="function-name">{html.escape(msg.function_call.name)}</span>({args})</div>'
Expand Down
6 changes: 3 additions & 3 deletions letta/client/streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from letta.schemas.letta_message import (
ToolCallMessage,
ToolReturnMessage,
InternalMonologue,
ReasoningMessage,
)
from letta.schemas.letta_response import LettaStreamingResponse
from letta.schemas.usage import LettaUsageStatistics
Expand Down Expand Up @@ -53,8 +53,8 @@ def _sse_post(url: str, data: dict, headers: dict) -> Generator[LettaStreamingRe
yield MessageStreamStatus(sse.data)
else:
chunk_data = json.loads(sse.data)
if "internal_monologue" in chunk_data:
yield InternalMonologue(**chunk_data)
if "reasoning" in chunk_data:
yield ReasoningMessage(**chunk_data)
elif "tool_call" in chunk_data:
yield ToolCallMessage(**chunk_data)
elif "tool_return" in chunk_data:
Expand Down
28 changes: 21 additions & 7 deletions letta/schemas/letta_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,18 @@ class UserMessage(LettaMessage):
message: str


class InternalMonologue(LettaMessage):
class ReasoningMessage(LettaMessage):
"""
Representation of an agent's internal monologue.
Representation of an agent's internal reasoning.

Attributes:
internal_monologue (str): The internal monologue of the agent
reasoning (str): The internal reasoning of the agent
id (str): The ID of the message
date (datetime): The date the message was created in ISO format
"""

message_type: Literal["internal_monologue"] = "internal_monologue"
internal_monologue: str
message_type: Literal["reasoning_message"] = "reasoning_message"
reasoning: str


class ToolCall(BaseModel):
Expand Down Expand Up @@ -196,10 +196,24 @@ class LegacyFunctionReturn(LettaMessage):
stderr: Optional[List[str]] = None


LegacyLettaMessage = Union[InternalMonologue, AssistantMessage, LegacyFunctionCallMessage, LegacyFunctionReturn]
class LegacyInternalMonologue(LettaMessage):
"""
Representation of an agent's internal monologue.

Attributes:
internal_monologue (str): The internal monologue of the agent
id (str): The ID of the message
date (datetime): The date the message was created in ISO format
"""

message_type: Literal["internal_monologue"] = "internal_monologue"
internal_monologue: str


LegacyLettaMessage = Union[LegacyInternalMonologue, AssistantMessage, LegacyFunctionCallMessage, LegacyFunctionReturn]


LettaMessageUnion = Annotated[
Union[SystemMessage, UserMessage, InternalMonologue, ToolCallMessage, ToolReturnMessage, AssistantMessage],
Union[SystemMessage, UserMessage, ReasoningMessage, ToolCallMessage, ToolReturnMessage, AssistantMessage],
Field(discriminator="message_type"),
]
2 changes: 2 additions & 0 deletions letta/schemas/letta_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ def _repr_html_(self):
def get_formatted_content(msg):
if msg.message_type == "internal_monologue":
return f'<div class="content"><span class="internal-monologue">{html.escape(msg.internal_monologue)}</span></div>'
if msg.message_type == "reasoning_message":
return f'<div class="content"><span class="internal-monologue">{html.escape(msg.reasoning)}</span></div>'
elif msg.message_type == "function_call":
args = format_json(msg.function_call.arguments)
return f'<div class="content"><span class="function-name">{html.escape(msg.function_call.name)}</span>({args})</div>'
Expand Down
6 changes: 3 additions & 3 deletions letta/schemas/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
ToolCall as LettaToolCall,
ToolCallMessage,
ToolReturnMessage,
InternalMonologue,
ReasoningMessage,
LettaMessage,
SystemMessage,
UserMessage,
Expand Down Expand Up @@ -145,10 +145,10 @@ def to_letta_message(
if self.text is not None:
# This is type InnerThoughts
messages.append(
InternalMonologue(
ReasoningMessage(
id=self.id,
date=self.created_at,
internal_monologue=self.text,
reasoning=self.text,
)
)
if self.tool_calls is not None:
Expand Down
20 changes: 10 additions & 10 deletions letta/server/rest_api/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
ToolCallDelta,
ToolCallMessage,
ToolReturnMessage,
InternalMonologue,
ReasoningMessage,
LegacyFunctionCallMessage,
LegacyLettaMessage,
LettaMessage,
Expand Down Expand Up @@ -411,7 +411,7 @@ def clear():

def _process_chunk_to_letta_style(
self, chunk: ChatCompletionChunkResponse, message_id: str, message_date: datetime
) -> Optional[Union[InternalMonologue, ToolCallMessage, AssistantMessage]]:
) -> Optional[Union[ReasoningMessage, ToolCallMessage, AssistantMessage]]:
"""
Example data from non-streaming response looks like:

Expand All @@ -426,10 +426,10 @@ def _process_chunk_to_letta_style(

# inner thoughts
if message_delta.content is not None:
processed_chunk = InternalMonologue(
processed_chunk = ReasoningMessage(
id=message_id,
date=message_date,
internal_monologue=message_delta.content,
reasoning=message_delta.content,
)

# tool calls
Expand Down Expand Up @@ -518,10 +518,10 @@ def _process_chunk_to_letta_style(

# If we have inner thoughts, we should output them as a chunk
if updates_inner_thoughts:
processed_chunk = InternalMonologue(
processed_chunk = ReasoningMessage(
id=message_id,
date=message_date,
internal_monologue=updates_inner_thoughts,
reasoning=updates_inner_thoughts,
)
# Additionally inner thoughts may stream back with a chunk of main JSON
# In that case, since we can only return a chunk at a time, we should buffer it
Expand Down Expand Up @@ -680,13 +680,13 @@ def _process_chunk_to_letta_style(
# Once we get a complete key, check if the key matches

# If it does match, start processing the value (stringified-JSON string
# And with each new chunk, output it as a chunk of type InternalMonologue
# And with each new chunk, output it as a chunk of type ReasoningMessage

# If the key doesn't match, then flush the buffer as a single ToolCallMessage chunk

# If we're reading a value

# If we're reading the inner thoughts value, we output chunks of type InternalMonologue
# If we're reading the inner thoughts value, we output chunks of type ReasoningMessage

# Otherwise, do simple chunks of ToolCallMessage

Expand Down Expand Up @@ -823,10 +823,10 @@ def internal_monologue(self, msg: str, msg_obj: Optional[Message] = None):
# "id": str(msg_obj.id) if msg_obj is not None else None,
# }
assert msg_obj is not None, "Internal monologue requires msg_obj references for metadata"
processed_chunk = InternalMonologue(
processed_chunk = ReasoningMessage(
id=msg_obj.id,
date=msg_obj.created_at,
internal_monologue=msg,
reasoning=msg,
)

self._push_to_buffer(processed_chunk)
Expand Down
4 changes: 2 additions & 2 deletions tests/helpers/endpoints_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from letta.schemas.embedding_config import EmbeddingConfig
from letta.schemas.letta_message import (
ToolCallMessage,
InternalMonologue,
ReasoningMessage,
LettaMessage,
)
from letta.schemas.letta_response import LettaResponse
Expand Down Expand Up @@ -419,7 +419,7 @@ def assert_invoked_function_call(messages: List[LettaMessage], function_name: st

def assert_inner_monologue_is_present_and_valid(messages: List[LettaMessage]) -> None:
for message in messages:
if isinstance(message, InternalMonologue):
if isinstance(message, ReasoningMessage):
# Found it, do nothing
return

Expand Down
6 changes: 3 additions & 3 deletions tests/test_client_legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
AssistantMessage,
ToolCallMessage,
ToolReturnMessage,
InternalMonologue,
ReasoningMessage,
LettaMessage,
SystemMessage,
UserMessage,
Expand Down Expand Up @@ -171,7 +171,7 @@ def test_agent_interactions(mock_e2b_api_key_none, client: Union[LocalClient, RE
assert type(letta_message) in [
SystemMessage,
UserMessage,
InternalMonologue,
ReasoningMessage,
ToolCallMessage,
ToolReturnMessage,
AssistantMessage,
Expand Down Expand Up @@ -255,7 +255,7 @@ def test_streaming_send_message(mock_e2b_api_key_none, client: RESTClient, agent
assert response, "Sending message failed"
for chunk in response:
assert isinstance(chunk, LettaStreamingResponse)
if isinstance(chunk, InternalMonologue) and chunk.internal_monologue and chunk.internal_monologue != "":
if isinstance(chunk, ReasoningMessage) and chunk.reasoning and chunk.reasoning != "":
inner_thoughts_exist = True
inner_thoughts_count += 1
if isinstance(chunk, ToolCallMessage) and chunk.tool_call and chunk.tool_call.name == "send_message":
Expand Down
6 changes: 3 additions & 3 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from letta.schemas.letta_message import (
ToolCallMessage,
ToolReturnMessage,
InternalMonologue,
ReasoningMessage,
LettaMessage,
SystemMessage,
UserMessage,
Expand Down Expand Up @@ -691,14 +691,14 @@ def _test_get_messages_letta_format(
letta_message = letta_messages[letta_message_index]

if message.text:
assert isinstance(letta_message, InternalMonologue)
assert isinstance(letta_message, ReasoningMessage)
letta_message_index += 1
else:
assert message.tool_calls is not None

else: # Non-reverse handling
if message.text:
assert isinstance(letta_message, InternalMonologue)
assert isinstance(letta_message, ReasoningMessage)
letta_message_index += 1
if letta_message_index >= len(letta_messages):
break
Expand Down
Loading