Files
Jyotisha/frontend/tests/agent-activity-progress.test.ts
T
Jesse_Chen 04463e9af3 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>
2026-08-23 14:38:50 +08:00

104 lines
4.5 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { agentGenerationSettings, AGENT_MAX_OUTPUT_TOKENS } from "../src/lib/agent-generation-settings.ts";
import {
activityCompletedSteps,
activityCompletedTrail,
activityElapsedLabel,
nextActivityView,
} from "../src/lib/chat-message-view.ts";
import {
chartCalculationProgressLabel,
CONSULTATION_CHART_CALCULATION_LABEL,
} from "../src/lib/consultation-activity-labels.ts";
import {
RECTIFICATION_TOOL_PROGRESS_LABELS,
rectificationCompletedTrail,
rectificationToolActivityPhase,
} from "../src/lib/rectification-activity-labels.ts";
test("generation settings reserve spoken-answer tokens and disable thinking by default", () => {
const settings = agentGenerationSettings({ providerId: "deepseek" });
assert.equal(AGENT_MAX_OUTPUT_TOKENS, 16_384);
assert.equal(settings.modelSettings.maxOutputTokens, 16_384);
assert.deepEqual(settings.providerOptions.openai, { thinking: { type: "disabled" } });
assert.deepEqual(settings.providerOptions.deepseek, { thinking: { type: "disabled" } });
});
test("callers can enable a separate thinking channel without pinching the answer budget", () => {
const settings = agentGenerationSettings({ providerId: "deepseek" }, { thinking: "enabled" });
assert.equal(settings.modelSettings.maxOutputTokens, 16_384 + 8_192);
assert.deepEqual(settings.providerOptions.openai, { thinking: { type: "enabled" } });
assert.deepEqual(settings.providerOptions.deepseek, { thinking: { type: "enabled" } });
});
test("activity elapsed copy stays hidden until eight seconds", () => {
assert.equal(activityElapsedLabel(1_000, 8_999), null);
assert.equal(activityElapsedLabel(1_000, 9_000), "已用时 8 秒");
assert.equal(activityElapsedLabel(1_000, 25_000), "已用时 24 秒");
});
test("the same activity label keeps its start time", () => {
const first = nextActivityView(undefined, {
phase: "chart-calculation",
label: "正在比较候选时间…",
}, 10);
const same = nextActivityView(first, {
phase: "chart-calculation",
label: "正在比较候选时间…",
}, 40);
const next = nextActivityView(same, {
phase: "answer-composition",
label: "正在组织回答…",
}, 50);
assert.equal(first.startedAt, 10);
assert.equal(same.startedAt, 10);
assert.equal(next.startedAt, 50);
});
test("completed-step trail stays short and drops while composing", () => {
assert.equal(activityCompletedTrail([]), undefined);
assert.equal(
activityCompletedTrail(["读取校正记录", "整理事件证据"]),
"已完成:读取校正记录 · 整理事件证据",
);
assert.equal(
activityCompletedTrail(["一", "二", "三", "四"]),
"已完成:二 · 三 · 四",
);
const waiting = nextActivityView(undefined, {
phase: "chart-calculation",
label: "正在比较候选时间…",
completedTrail: activityCompletedTrail(["读取校正记录", "整理事件证据"]),
}, 10);
assert.equal(waiting.completedTrail, "已完成:读取校正记录 · 整理事件证据");
const composing = nextActivityView(waiting, {
phase: "answer-composition",
label: "正在组织回答…",
}, 20);
assert.equal(composing.completedTrail, undefined);
assert.deepEqual(
activityCompletedSteps("已完成:读取分析方法 · 计算本命盘"),
["读取分析方法", "计算本命盘"],
);
});
test("live rectification labels name the actual public tool", () => {
assert.equal(RECTIFICATION_TOOL_PROGRESS_LABELS["rectification-read-case"], "正在读取校正记录…");
assert.equal(RECTIFICATION_TOOL_PROGRESS_LABELS["rectification-compare-candidates"], "正在比较候选时间…");
assert.equal(rectificationToolActivityPhase("rectification-read-case"), "loading-method");
assert.equal(rectificationToolActivityPhase("rectification-compare-candidates"), "chart-calculation");
assert.equal(rectificationToolActivityPhase("rectification-propose-evidence"), "evidence-validation");
assert.equal(
rectificationCompletedTrail(["rectification-read-case", "rectification-propose-evidence"]),
"已完成:读取校正记录 · 整理事件证据",
);
});
test("multi-domain chart calculation names the current item without domain ids", () => {
assert.equal(chartCalculationProgressLabel(1, 1), CONSULTATION_CHART_CALCULATION_LABEL);
assert.equal(chartCalculationProgressLabel(2, 3), "正在计算本命盘(第 2/3 项)…");
assert.doesNotMatch(chartCalculationProgressLabel(2, 3), /career|wealth|timing|marriage/);
});