Files
Jyotisha/frontend/src/lib/rectification-activity-labels.ts
T
Jesse_ChenandClaude Opus 5.5 8fc1a5bded fix(rectification): plain-word opening with examples in the stem, plain de-duplicated step receipt (BUG-1049, BUG-1050)
- BUG-1049 (recurrence of BUG-504): the opening stem carries six examples and
  an example answer again and is server-owned on the zero-evidence opening;
  the body is two plain sentences (no 大运/盘面/代表分钟/精确到秒, no year, no
  question). Stem de-dup compares whole sentences / near-equality instead of a
  12-char prefix, which had deleted the body's examples sentence since
  aa7ccb30 (BUG-604) + dd8f35f7 (BUG-648).
- BUG-1050: plain step labels; a finished step label shows once and
  「已完成 N 步」counts shown rows; failed rows read 「…未完成」 from the
  in-progress wording.
- Skill 10.0.30 -> 10.0.31 (OpeningPolicy); 10.0.30 kept as deprecated.
- VOICE / DESIGN / CHANGELOG / BUG_HISTORY / PROGRESS / real-device checklist
  and screenshots.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-26 22:04:56 +08:00

151 lines
6.5 KiB
TypeScript

import type { AgentActivityTraceItem } from "./agent-activity-trace.ts";
import { activityCompletedTrail } from "./chat-message-view.ts";
import type { PublicActivityPhase } from "./consultation-agent-events.ts";
import type { CompletedActivityReceiptView } from "./rectification-activity-receipt.ts";
import type {
PublicRectificationActivity,
PublicRectificationTool,
} from "./rectification-agentic/v9/public-receipt.ts";
import type { RectificationTurnProgressStage } from "./rectification-agentic/v9/turn-progress.ts";
import { RECTIFICATION_AGENT_ATTEMPT_TIMEOUT_MS as ATTEMPT_TIMEOUT_MS } from "./rectification-run-budget.ts";
export { RECTIFICATION_AGENT_ATTEMPT_TIMEOUT_MS } from "./rectification-run-budget.ts";
export const RECTIFICATION_TOOL_DONE_LABELS: Readonly<Record<PublicRectificationTool, string>> = {
"rectification-read-case": "看了你的资料",
"rectification-set-focus": "准备好下一个问题",
"rectification-resolve-focus": "记下你对这一问的回答",
"rectification-record-evidence-batch": "记下你说的事",
"rectification-propose-evidence": "记下你说的事",
"rectification-confirm-evidence": "核对好这件事",
"rectification-revise-evidence": "改好这件事",
"rectification-compare-candidates": "重新对照了盘面",
"rectification-read-diagnostics": "看了结果稳不稳",
"rectification-offer-candidates": "整理好可能的时间",
"rectification-accept-candidate": "用上你选的时间",
"rectification-confirm-birth-time": "确认好出生时间",
"rectification-stop-and-review": "先停下不再问",
"rectification-close-case": "结束这次校正",
};
export const RECTIFICATION_ACTIVITY_PROGRESS_LABELS: Readonly<Record<PublicRectificationActivity, string>> = {
reading_case: "正在看你的资料…",
recording_answer: "正在记下你的选择…",
updating_candidates: "正在重新对照盘面…",
checking_stability: "正在看结果稳不稳…",
preparing_question: "正在准备下一个问题…",
preparing_result: "正在准备结果…",
};
/**
* Stage lines for a typed answer (BUG-1047 D3). The first one shows the moment
* the reader sends; the server's `turn.progress` events move it forward. They
* live only on the live row and are never part of the saved reply.
*/
export const RECTIFICATION_TURN_PROGRESS_LABELS: Readonly<Record<RectificationTurnProgressStage, string>> = {
received: "收到,正在对照你的档案…",
recording: "正在记下这件事…",
rescoring: "正在重新对照盘面…",
preparing_question: "正在准备下一个问题…",
};
export function rectificationTurnProgressPhase(stage: RectificationTurnProgressStage): PublicActivityPhase {
if (stage === "received") return "loading-method";
if (stage === "rescoring") return "chart-calculation";
return "evidence-validation";
}
/** Live label between a completed tool and the next tool or spoken answer. */
export const RECTIFICATION_ANALYZING_LIVE_LABEL = "正在分析…";
export const RECTIFICATION_SLOW_STEP_MS = 45_000;
export const RECTIFICATION_TIMEOUT_WARN_BEFORE_MS = 20_000;
export function rectificationSlowProgressLabel(tool: PublicRectificationTool | string | null | undefined): string {
if (typeof tool === "string" && RECTIFICATION_TOOL_PROGRESS_LABELS[tool as PublicRectificationTool]) {
const doing = RECTIFICATION_TOOL_PROGRESS_LABELS[tool as PublicRectificationTool]
.replace(/^正在/, "")
.replace(/…$/, "");
return `还在${doing},可能需要一两分钟`;
}
return "这一步还在进行,可能需要一两分钟";
}
export function rectificationLiveProgressLabel(input: {
tool?: string | null;
baseLabel: string;
stepStartedAt: number;
runStartedAt: number;
now?: number;
}): string {
const now = input.now ?? Date.now();
if (now - input.runStartedAt >= ATTEMPT_TIMEOUT_MS - RECTIFICATION_TIMEOUT_WARN_BEFORE_MS) {
return "即将超时,会自动重试或提示";
}
if (now - input.stepStartedAt >= RECTIFICATION_SLOW_STEP_MS) {
return rectificationSlowProgressLabel(input.tool);
}
return input.baseLabel;
}
export const RECTIFICATION_TOOL_PROGRESS_LABELS: Readonly<Record<PublicRectificationTool, string>> = {
"rectification-read-case": "正在看你的资料…",
"rectification-set-focus": "正在准备下一个问题…",
"rectification-resolve-focus": "正在记下你对这一问的回答…",
"rectification-record-evidence-batch": "正在记下这件事…",
"rectification-propose-evidence": "正在记下这件事…",
"rectification-confirm-evidence": "正在核对这件事…",
"rectification-revise-evidence": "正在改这件事…",
"rectification-compare-candidates": "正在重新对照盘面…",
"rectification-read-diagnostics": "正在看结果稳不稳…",
"rectification-offer-candidates": "正在整理可能的时间…",
"rectification-accept-candidate": "正在用上你选的时间…",
"rectification-confirm-birth-time": "正在确认出生时间…",
"rectification-stop-and-review": "正在停下提问…",
"rectification-close-case": "正在结束这次校正…",
};
const COMPARE_TOOLS = new Set<PublicRectificationTool>([
"rectification-compare-candidates",
"rectification-read-diagnostics",
"rectification-offer-candidates",
]);
const LOAD_TOOLS = new Set<PublicRectificationTool>([
"rectification-read-case",
"rectification-set-focus",
"rectification-resolve-focus",
]);
/** Several tools share a plain label (BUG-1050); the trail names each once. */
export function rectificationCompletedTrail(steps: readonly PublicRectificationTool[]): string | undefined {
return activityCompletedTrail([...new Set(steps.map((tool) => RECTIFICATION_TOOL_DONE_LABELS[tool]))]);
}
export function activityTraceFromReceipt(
receipt: CompletedActivityReceiptView | null | undefined,
): readonly AgentActivityTraceItem[] {
if (!receipt?.steps.length) return [];
return receipt.steps.map((tool) => ({
id: `persisted-${tool}`,
kind: "activity" as const,
status: "done" as const,
label: RECTIFICATION_TOOL_DONE_LABELS[tool],
tool,
}));
}
export function rectificationToolActivityPhase(tool: PublicRectificationTool): PublicActivityPhase {
if (LOAD_TOOLS.has(tool)) return "loading-method";
if (COMPARE_TOOLS.has(tool)) return "chart-calculation";
if (
tool === "rectification-accept-candidate"
|| tool === "rectification-confirm-birth-time"
|| tool === "rectification-stop-and-review"
|| tool === "rectification-close-case"
) {
return "answer-composition";
}
return "evidence-validation";
}