diff --git a/backend/functions/letta_agents.py b/backend/functions/letta_agents.py
index 580c12b51..d63993c7a 100644
--- a/backend/functions/letta_agents.py
+++ b/backend/functions/letta_agents.py
@@ -141,12 +141,17 @@ class Pipe:
return "".join(content_parts) if content_parts else "No response"
def _stream_response(self, client, agent_id: str, messages: list) -> Generator:
- """Stream response from Letta agent with tool call support."""
+ """Stream response from Letta agent with tool call and reasoning support."""
import html
+ import time
# Track tool calls: {tool_call_id: {"name": str, "arguments": str}}
tool_calls = {}
+ # Track reasoning: accumulate content and emit when complete
+ reasoning_content = ""
+ reasoning_start = None
+
with client.agents.messages.stream(
agent_id=agent_id,
messages=messages,
@@ -155,7 +160,23 @@ class Pipe:
for chunk in stream:
msg_type = getattr(chunk, 'message_type', None)
- if msg_type == 'tool_call_message':
+ # Emit accumulated reasoning when transitioning to non-reasoning message
+ if reasoning_content and msg_type != 'reasoning_message':
+ duration = int(time.time() - reasoning_start) if reasoning_start else 0
+ yield f'\n'
+ yield f'{html.escape(reasoning_content)}\n'
+ yield ' \n\n'
+ reasoning_content = ""
+ reasoning_start = None
+
+ if msg_type == 'reasoning_message':
+ reasoning = getattr(chunk, 'reasoning', '')
+ if reasoning:
+ if reasoning_start is None:
+ reasoning_start = time.time()
+ reasoning_content += reasoning
+
+ elif msg_type == 'tool_call_message':
# Handle tool call chunks - accumulate but don't emit yet
tool_call = getattr(chunk, 'tool_call', None)
if tool_call:
@@ -200,3 +221,10 @@ class Pipe:
# Stream assistant content
if hasattr(chunk, 'content') and chunk.content:
yield chunk.content
+
+ # Handle case where reasoning was the last message
+ if reasoning_content:
+ duration = int(time.time() - reasoning_start) if reasoning_start else 0
+ yield f'\n'
+ yield f'{html.escape(reasoning_content)}\n'
+ yield ' \n\n'
diff --git a/src/lib/components/common/Collapsible.svelte b/src/lib/components/common/Collapsible.svelte
index 8f788c6d8..4df06fa33 100644
--- a/src/lib/components/common/Collapsible.svelte
+++ b/src/lib/components/common/Collapsible.svelte
@@ -246,18 +246,18 @@
{#if attributes?.type === 'reasoning'}
{#if attributes?.done === 'true' && attributes?.duration}
{#if attributes.duration < 1}
- {$i18n.t('Thought for less than a second')}
+ {$i18n.t('Reasoned for less than a second')}
{:else if attributes.duration < 60}
- {$i18n.t('Thought for {{DURATION}} seconds', {
+ {$i18n.t('Reasoned for {{DURATION}} seconds', {
DURATION: attributes.duration
})}
{:else}
- {$i18n.t('Thought for {{DURATION}}', {
+ {$i18n.t('Reasoned for {{DURATION}}', {
DURATION: dayjs.duration(attributes.duration, 'seconds').humanize()
})}
{/if}
{:else}
- {$i18n.t('Thinking...')}
+ {$i18n.t('Reasoning...')}
{/if}
{:else if attributes?.type === 'code_interpreter'}
{#if attributes?.done === 'true'}