diff --git a/src/app/api/conversations/[threadId]/runs/[runId]/stream/route.ts b/src/app/api/conversations/[threadId]/runs/[runId]/stream/route.ts index edb2321..e04c55c 100644 --- a/src/app/api/conversations/[threadId]/runs/[runId]/stream/route.ts +++ b/src/app/api/conversations/[threadId]/runs/[runId]/stream/route.ts @@ -27,7 +27,7 @@ export async function GET(request: NextRequest, context: RouteContext) { signal: request.signal, cancelOnDisconnect: false, lastEventId, - streamMode: ["messages", "updates", "values", "tasks"], + streamMode: ["messages", "updates", "values", "tasks", "custom"], }); const stream = new ReadableStream({ async start(controller) { diff --git a/src/app/api/conversations/[threadId]/runs/route.ts b/src/app/api/conversations/[threadId]/runs/route.ts index 6966074..cf555d6 100644 --- a/src/app/api/conversations/[threadId]/runs/route.ts +++ b/src/app/api/conversations/[threadId]/runs/route.ts @@ -281,6 +281,9 @@ export async function POST(request: NextRequest, context: RouteContext) { metadata, config, multitaskStrategy: "enqueue", + // langgraph dev only buffers the stream modes declared at run + // creation; joinStream subscribers receive nothing outside them. + streamMode: ["messages", "updates", "values", "tasks", "custom"], } ); } catch (error) { diff --git a/src/app/components/ChatInterface.tsx b/src/app/components/ChatInterface.tsx index 9da167b..6d3f6a9 100644 --- a/src/app/components/ChatInterface.tsx +++ b/src/app/components/ChatInterface.tsx @@ -36,6 +36,8 @@ import { import { ChatMessage } from "@/app/components/ChatMessage"; import { ActionGroup } from "@/app/components/ActionGroup"; import { CompactionSummary } from "@/app/components/CompactionSummary"; +import { ContextUsageIndicator } from "@/app/components/ContextUsageIndicator"; +import { extractMeasuredInputTokens } from "@/lib/contextUsage"; import { ResearchDashboard } from "@/app/components/ResearchDashboard"; import { isSummarizationMessage } from "@/lib/summarization"; import { useCollapseAgentActions } from "@/lib/uiSettings"; @@ -509,6 +511,7 @@ export const ChatInterface = React.memo( subAgentActivity, asyncTasks, summarizationEvent, + contextUsage, modelSelection, setModelSelection, } = useChatContext(); @@ -771,6 +774,14 @@ export const ChatInterface = React.memo( [selectableModels, modelSelection] ); + // Provider-measured prompt size of the most recent model call — the + // truthful numerator for the ctx pill (the middleware's stream event + // only estimates message text + fixed reserves). + const measuredInputTokens = useMemo( + () => extractMeasuredInputTokens(messages), + [messages] + ); + // Bind captured sub-agent activity (keyed by subgraph namespace) to each task // tool call → its live steps. B': match a finished sub-agent to a task by its // final text == the task's result; assign still-running sub-agents to the @@ -1811,11 +1822,21 @@ export const ChatInterface = React.memo( )} ( )} {askUserQuestions && reviewMode !== "full" && ( @@ -2326,6 +2356,12 @@ export const ChatInterface = React.memo( }} /> )} + {threadId && ( + + )} {threadId && (