feat(consult): add free model-classified smalltalk fast path
Independent Staging Quality Gate / validate (push) Successful in 9m35s
Independent Staging Quality Gate / publish (push) Successful in 3m52s

Keep full consultation tool contracts unchanged. Persist short replies and refund the original reservation atomically while recording actual model usage. Verify Linux frontend 3566/3566, database 40/40, Static home and gzip +0.0493%.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
jesse-ux
2026-09-20 12:58:34 +08:00
co-authored by Claude Code
parent 03cba4780a
commit 539d4daee4
33 changed files with 960 additions and 30 deletions
+9 -5
View File
@@ -53,7 +53,11 @@ export const ChatMessageRow = memo(function ChatMessageRow({
stoppedNotice?: string;
}>) {
const messageRow = useRef<HTMLElement>(null);
const assistantLabel = message.state === "thinking"
const smalltalk = message.responseKind === "smalltalk";
const awaitingClassification = message.state === "thinking" && !message.text && !message.activity
&& !message.thinkingText && message.timeline?.length === 0;
const quiet = smalltalk || awaitingClassification;
const assistantLabel = quiet ? "Jyotisha" : message.state === "thinking"
? "Jyotisha 正在分析"
: message.state === "streaming"
? "Jyotisha 正在回答"
@@ -69,11 +73,11 @@ export const ChatMessageRow = memo(function ChatMessageRow({
const activityLabel = message.activity?.label
?? (message.state === "thinking" ? "正在处理…" : undefined);
const hasAnswer = Boolean(message.text.trim());
const consultTimeline = message.timeline;
const consultTimeline = quiet ? undefined : message.timeline;
// Rows with a step timeline (every consultation and rectification reply) render
// `ConsultationRunTimeline`; the activity panel is the fallback for rows without one.
const showLiveActivity = showActivity && consultTimeline === undefined;
const showThinkingPanel = showLiveActivity || (consultTimeline === undefined && Boolean(message.thinkingText?.trim()));
const showLiveActivity = !quiet && showActivity && consultTimeline === undefined;
const showThinkingPanel = !quiet && (showLiveActivity || (consultTimeline === undefined && Boolean(message.thinkingText?.trim())));
const showSpokenAnswer = Boolean(message.text);
const stackedThinkingAndAnswer = showThinkingPanel && showSpokenAnswer;
@@ -119,7 +123,7 @@ export const ChatMessageRow = memo(function ChatMessageRow({
? (
<ChatMessageContent
text={message.text}
auditRows={message.agentExecutionReceipt?.techniqueAuditTable}
auditRows={smalltalk ? undefined : message.agentExecutionReceipt?.techniqueAuditTable}
streaming={message.state !== "settled"}
/>
)
@@ -42,6 +42,7 @@ export type ChatTranscriptProps = Readonly<{
streamingThinking?: string;
streamingSections?: readonly PublicThinkingSection[];
streamingTimeline?: readonly ConsultationTimelineRow[];
streamingResponseKind?: "smalltalk";
sessionId: string;
sessionType: "consultation" | "birth_time_rectification";
theme?: ConsultationDomain;
@@ -197,6 +198,7 @@ export const ChatTranscript = memo(function ChatTranscript({
streamingThinking,
streamingSections,
streamingTimeline,
streamingResponseKind,
sessionId,
sessionType,
theme,
@@ -214,6 +216,7 @@ export const ChatTranscript = memo(function ChatTranscript({
streamingThinking,
streamingSections,
streamingTimeline,
streamingResponseKind,
);
return (
@@ -260,6 +263,7 @@ export function UnsplitChatTranscript({
streamingThinking,
streamingSections,
streamingTimeline,
streamingResponseKind,
sessionId,
sessionType,
theme,
@@ -278,6 +282,7 @@ export function UnsplitChatTranscript({
streamingThinking,
streamingSections,
streamingTimeline,
streamingResponseKind,
);
return (
<>