diff --git a/letta/agent.py b/letta/agent.py index c68a0891..636b70ae 100644 --- a/letta/agent.py +++ b/letta/agent.py @@ -36,6 +36,7 @@ from letta.interface import AgentInterface from letta.llm_api.helpers import calculate_summarizer_cutoff, get_token_counts_for_messages, is_context_overflow_error from letta.llm_api.llm_api_tools import create from letta.llm_api.llm_client import LLMClient +from letta.local_llm.constants import INNER_THOUGHTS_KWARG from letta.local_llm.utils import num_tokens_from_functions, num_tokens_from_messages from letta.log import get_logger from letta.memory import summarize_messages @@ -548,8 +549,8 @@ class Agent(BaseAgent): return messages, False, True # force a heartbeat to allow agent to handle error # Check if inner thoughts is in the function call arguments (possible apparently if you are using Azure) - if "inner_thoughts" in function_args: - response_message.content = function_args.pop("inner_thoughts") + if INNER_THOUGHTS_KWARG in function_args: + response_message.content = function_args.pop(INNER_THOUGHTS_KWARG) # The content if then internal monologue, not chat if response_message.content and not nonnull_content: self.interface.internal_monologue(response_message.content, msg_obj=messages[-1], chunk_index=chunk_index) diff --git a/letta/local_llm/constants.py b/letta/local_llm/constants.py index 53f4e717..441bb4ae 100644 --- a/letta/local_llm/constants.py +++ b/letta/local_llm/constants.py @@ -25,7 +25,7 @@ DEFAULT_OLLAMA_MODEL = "dolphin2.2-mistral:7b-q6_K" DEFAULT_WRAPPER = ChatMLInnerMonologueWrapper DEFAULT_WRAPPER_NAME = "chatml" -INNER_THOUGHTS_KWARG = "inner_thoughts" +INNER_THOUGHTS_KWARG = "thinking" # used to be "inner_thoughts" INNER_THOUGHTS_KWARG_VERTEX = "thinking" INNER_THOUGHTS_KWARG_DESCRIPTION = "Deep inner monologue private to you only." INNER_THOUGHTS_KWARG_DESCRIPTION_GO_FIRST = f"Deep inner monologue private to you only. Think before you act, so always generate arg '{INNER_THOUGHTS_KWARG}' first before any other arg." diff --git a/letta/local_llm/json_parser.py b/letta/local_llm/json_parser.py index 16771d91..f721e557 100644 --- a/letta/local_llm/json_parser.py +++ b/letta/local_llm/json_parser.py @@ -1,5 +1,6 @@ import json import re +import warnings from letta.errors import LLMJSONParsingError from letta.helpers.json_helpers import json_loads @@ -77,10 +78,19 @@ def add_missing_heartbeat(llm_json): def clean_and_interpret_send_message_json(json_string): + from letta.local_llm.constants import INNER_THOUGHTS_KWARG + # If normal parsing fails, attempt to clean and extract manually cleaned_json_string = re.sub(r"[^\x00-\x7F]+", "", json_string) # Remove non-ASCII characters function_match = re.search(r'"function":\s*"send_message"', cleaned_json_string) - inner_thoughts_match = re.search(r'"inner_thoughts":\s*"([^"]+)"', cleaned_json_string) + if INNER_THOUGHTS_KWARG == "inner_thoughts": + inner_thoughts_match = re.search(r'"inner_thoughts":\s*"([^"]+)"', cleaned_json_string) + elif INNER_THOUGHTS_KWARG == "thinking": + inner_thoughts_match = re.search(r'"thinking":\s*"([^"]+)"', cleaned_json_string) + else: + warnings.warn(f"INNER_THOUGHTS_KWARG is not valid: {INNER_THOUGHTS_KWARG}") + inner_thoughts_match = re.search(r'"inner_thoughts":\s*"([^"]+)"', cleaned_json_string) + message_match = re.search(r'"message":\s*"([^"]+)"', cleaned_json_string) if function_match and inner_thoughts_match and message_match: diff --git a/letta/streaming_utils.py b/letta/streaming_utils.py index 485c2a7a..f1b84f2f 100644 --- a/letta/streaming_utils.py +++ b/letta/streaming_utils.py @@ -1,6 +1,7 @@ from typing import Optional, Tuple from letta.constants import DEFAULT_MESSAGE_TOOL_KWARG +from letta.local_llm.constants import INNER_THOUGHTS_KWARG class JSONInnerThoughtsExtractor: @@ -34,7 +35,7 @@ class JSONInnerThoughtsExtractor: """ - def __init__(self, inner_thoughts_key="inner_thoughts", wait_for_first_key=False): + def __init__(self, inner_thoughts_key=INNER_THOUGHTS_KWARG, wait_for_first_key=False): self.inner_thoughts_key = inner_thoughts_key self.wait_for_first_key = wait_for_first_key self.main_buffer = ""