feat(web): show consult runs as a Lucide timeline with sliced compose

Keep provider thinking on a separate channel so process talk is not billed as the spoken reply (BUG-359).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-23 14:38:50 +08:00
co-authored by Cursor
parent 22010e81b7
commit 04463e9af3
29 changed files with 1410 additions and 201 deletions
+30 -4
View File
@@ -36,11 +36,14 @@ import { createServerSupabaseClient } from "@/lib/supabase/server";
import { streamTextResponse } from "@/lib/stream-text-response";
import { streamAgentResponse } from "@/lib/stream-agent-response";
import type { AgentExecutionReceipt, WorkflowReceipt } from "@/lib/consultation-agent-events";
import { consultationContinuePrompt, type PublicThinkingSection } from "@/lib/consultation-thinking-plan";
import { consultationContinuePrompt, consultationSectionPrompt, type PublicThinkingSection } from "@/lib/consultation-thinking-plan";
import {
AGENT_MAX_STEPS,
AGENT_TIMEOUT_MS,
AGENT_SLICE_MAX_STEPS,
consultationContinueGenerationSettings,
consultationGenerationSettings,
consultationSliceGenerationSettings,
createConsultationAgentContext,
createWindowConsultationAgentContext,
consultationModelStepTelemetry,
@@ -732,7 +735,10 @@ export async function POST(request: Request) {
...baseMessages,
{ role: "assistant" as const, content: output },
{ role: "user" as const, content: consultationContinuePrompt(output) },
], streamOptions);
], {
...streamOptions,
...consultationContinueGenerationSettings(selectedModel.model),
});
usages.push(continued.totalUsage);
return continued.fullStream;
};
@@ -831,7 +837,10 @@ export async function POST(request: Request) {
...baseMessages,
{ role: "assistant" as const, content: output },
{ role: "user" as const, content: consultationContinuePrompt(output) },
], streamOptions);
], {
...streamOptions,
...consultationContinueGenerationSettings(selectedModel.model),
});
usages.push(continued.totalUsage);
return continued.fullStream;
};
@@ -930,10 +939,26 @@ export async function POST(request: Request) {
...baseMessages,
{ role: "assistant" as const, content: output },
{ role: "user" as const, content: consultationContinuePrompt(output) },
], streamOptions);
], {
...streamOptions,
...consultationContinueGenerationSettings(selectedModel.model),
});
usages.push(continued.totalUsage);
return continued.fullStream;
};
const composeSection = async (heading: string, priorOutput: string) => {
const sliced = await agent.stream([
...baseMessages,
...(priorOutput.trim() ? [{ role: "assistant" as const, content: priorOutput }] : []),
{ role: "user" as const, content: consultationSectionPrompt(heading, priorOutput) },
], {
...streamOptions,
maxSteps: AGENT_SLICE_MAX_STEPS,
...consultationSliceGenerationSettings(selectedModel.model),
});
usages.push(sliced.totalUsage);
return sliced.fullStream;
};
const executionReceipt = (): AgentExecutionReceipt => ({
runId: requestId,
runtime: "mastra-agentic",
@@ -960,6 +985,7 @@ export async function POST(request: Request) {
retry,
retryForAnswer,
continueAfterLength,
composeSection,
continueAfterDisconnect: true,
transformText: (text) => createBirthTimeModeOutputGuard(
consultationMode,