diff --git a/apps/x/apps/renderer/src/App.tsx b/apps/x/apps/renderer/src/App.tsx index 39cc9c82..9848b286 100644 --- a/apps/x/apps/renderer/src/App.tsx +++ b/apps/x/apps/renderer/src/App.tsx @@ -918,14 +918,14 @@ function App() { try { let currentRunId = runId + let isNewRun = false if (!currentRunId) { const run = await window.ipc.invoke('runs:create', { agentId, }) currentRunId = run.id setRunId(currentRunId) - // Refresh runs list to include new run - loadRuns() + isNewRun = true } // Read mentioned file contents and format message with XML context @@ -955,6 +955,11 @@ function App() { runId: currentRunId, message: formattedMessage, }) + + // Refresh runs list after message is sent (so title is available) + if (isNewRun) { + loadRuns() + } } catch (error) { console.error('Failed to send message:', error) } @@ -1540,7 +1545,7 @@ function App() { handleAskHumanResponse(request.toolCallId, request.subflow, response)} + onResponse={(response) => handleAskHumanResponse(request.toolCallId, request.subflow, response)} isProcessing={isProcessing} /> ))} diff --git a/apps/x/apps/renderer/src/components/ai-elements/ask-human-request.tsx b/apps/x/apps/renderer/src/components/ai-elements/ask-human-request.tsx index 8c20f337..2e92e2ca 100644 --- a/apps/x/apps/renderer/src/components/ai-elements/ask-human-request.tsx +++ b/apps/x/apps/renderer/src/components/ai-elements/ask-human-request.tsx @@ -9,14 +9,14 @@ import { useState, useRef, useEffect } from "react"; export type AskHumanRequestProps = ComponentProps<"div"> & { query: string; - onSubmit: (response: string) => void; + onResponse: (response: string) => void; isProcessing?: boolean; }; export const AskHumanRequest = ({ className, query, - onSubmit, + onResponse, isProcessing = false, ...props }: AskHumanRequestProps) => { @@ -31,7 +31,7 @@ export const AskHumanRequest = ({ const handleSubmit = () => { const trimmed = response.trim(); if (trimmed && !isProcessing) { - onSubmit(trimmed); + onResponse(trimmed); setResponse(""); } }; diff --git a/apps/x/apps/renderer/src/components/chat-sidebar.tsx b/apps/x/apps/renderer/src/components/chat-sidebar.tsx index 2c462618..bbb2151f 100644 --- a/apps/x/apps/renderer/src/components/chat-sidebar.tsx +++ b/apps/x/apps/renderer/src/components/chat-sidebar.tsx @@ -511,7 +511,7 @@ export function ChatSidebar({ onAskHumanResponse(request.toolCallId, request.subflow, response)} + onResponse={(response) => onAskHumanResponse(request.toolCallId, request.subflow, response)} isProcessing={isProcessing} /> ))} diff --git a/apps/x/packages/core/src/runs/repo.ts b/apps/x/packages/core/src/runs/repo.ts index 20dd6389..3171d91e 100644 --- a/apps/x/packages/core/src/runs/repo.ts +++ b/apps/x/packages/core/src/runs/repo.ts @@ -14,6 +14,19 @@ export interface IRunsRepo { appendEvents(runId: string, events: z.infer[]): Promise; } +/** + * Strip attached-files XML from message content for title display (keeps @mentions) + */ +function cleanContentForTitle(content: string): string { + // Remove the entire attached-files block + let cleaned = content.replace(/\s*[\s\S]*?\s*<\/attached-files>/g, ''); + + // Clean up extra whitespace + cleaned = cleaned.replace(/\s+/g, ' ').trim(); + + return cleaned; +} + export class FSRunsRepo implements IRunsRepo { private idGenerator: IMonotonicallyIncreasingIdGenerator; constructor({ @@ -33,9 +46,10 @@ export class FSRunsRepo implements IRunsRepo { if (messageEvent.message.role === 'user') { const content = messageEvent.message.content; if (typeof content === 'string' && content.trim()) { - // Truncate to 100 chars for display - const truncated = content.trim(); - return truncated.length > 100 ? truncated.substring(0, 100) : truncated; + // Clean attached-files XML and @mentions, then truncate to 100 chars + const cleaned = cleanContentForTitle(content); + if (!cleaned) continue; // Skip if only attached files/mentions + return cleaned.length > 100 ? cleaned.substring(0, 100) : cleaned; } } } @@ -76,8 +90,11 @@ export class FSRunsRepo implements IRunsRepo { // Found first user message - use as title const content = msg.content; if (typeof content === 'string' && content.trim()) { - const truncated = content.trim(); - title = truncated.length > 100 ? truncated.substring(0, 100) : truncated; + // Clean attached-files XML and @mentions, then truncate + const cleaned = cleanContentForTitle(content); + if (cleaned) { + title = cleaned.length > 100 ? cleaned.substring(0, 100) : cleaned; + } } // Stop reading rl.close();