明说要校正时,第一步就能打开(BUG-1317)
本命和申报时段的第 0 步,校正工具挂上时可以排盘,也可以直接打开校正。还没看盘就顺口提议不算已经提议过。规则第一句写明 explicitRequest=true。定向测试 149 通过,类型检查和 lint 通过,隐私标记通过。名人生平回测未跑。 Co-Authored-By: Grok (agent loop)
This commit is contained in:
co-authored by
Grok (agent loop)
parent
0c04755560
commit
bccceff91f
@@ -25,8 +25,8 @@ Jyotisha 的可见文案是产品的一部分。正确性红线(真实性、
|
||||
|
||||
## 生时校正从对话进入(2026-10-07,BUG-1247~1251;2026-10-12,BUG-1306)
|
||||
|
||||
- **何时提议**:用户说推得不准时先分清读法问题和时间问题。只是不认同某个解释,按纠正规则认下、改读,不提校正。不承诺能收窄出生时间,不在对话里收集经历做校正。说出过去的具体事情和盘对不上、说出生时间是估的或记不准、但没有明确要做校正,才调用提议工具。同一次对话提议过、用户没接,不再主动提;用户自己再要求时传 `userAsked=true`。规则只定义在 `consultation-thinking-plan.ts` 的 `RECTIFICATION_OFFER_RULE`。不用关键词判断。
|
||||
- **明确要求则直接进入**:用户这一轮明确要做校正,由模型判断,不用关键词。服务端放行后直接打开校正:不先写解读,不用点卡。过渡只有一句「好,我们开始核对出生时间。」已经有一次没做完的,直接接着做那一次,不新开。开案还没成功时,回答下面仍是普通提议卡,不说「已经开始」;打开失败可以再点「开始核对出生时间」。开案并绑定来源之后才改成「已经开始」。
|
||||
- **何时提议**:校正就在这个对话里能开。用户说推得不准时先分清读法问题和时间问题。只是不认同某个解释,按改读规则认下、改读,不提校正。不承诺能收窄出生时间,不在对话里收集经历做校正。说出过去的具体事情和盘对不上、说出生时间是估的或记不准、但没有明确要做校正,要先看过盘再提议。同一次对话提议过、用户没接,不再主动提;用户自己再要求时传 `userAsked=true`。还没看盘就顺口提议,不算已经提议过。规则只定义在 `consultation-thinking-plan.ts` 的 `RECTIFICATION_OFFER_RULE`。不用关键词判断。
|
||||
- **明确要求则直接进入**:用户这一轮明确要做校正(校正、纠正、核对出生时间都算),由模型判断,不用关键词。第一步就可以打开,不用先排盘写解读。服务端放行后直接打开校正,不用点卡。过渡只有一句「好,我们开始核对出生时间。」已经有一次没做完的,直接接着做那一次,不新开。开案还没成功时,回答下面仍是普通提议卡,不说「已经开始」;打开失败可以再点「开始核对出生时间」。开案并绑定来源之后才改成「已经开始」。
|
||||
- **做不了必须说一句**:开关关着,或暂时没有价格,都说「出生时间核对这会儿还做不了。」不写内部原因,不写价格,不得沉默。家人档案说「给家人校正暂时还不支持」,不开案。有进行中的校正但这次打不开原来的会话,说「可在历史对话里接着做。」
|
||||
- **正文怎么提**(没有明确要求、只是时间可能不准):一句,放在最后一段(例:「如果想确认出生时间准不准,可以用下面的卡片,答几道过去经历的题核对一下。」),不写价格和题数——卡片上写。
|
||||
- **卡片**:「可以用几道过去经历的题,核对一下你的出生时间。大约 N 题,会用掉 M 点;开始答第一题时才扣。」按钮「开始核对出生时间」;已开始(开案并绑定来源之后,不是结算当时)「出生时间核对已经开始。」/「继续核对出生时间」。点数来自 `feature_pricing`,不写死。
|
||||
|
||||
@@ -1215,11 +1215,17 @@ export async function POST(request: Request) {
|
||||
};
|
||||
const natalStreamOptions = {
|
||||
...streamOptions,
|
||||
prepareStep: consultationNatalPrepareStep,
|
||||
prepareStep: (input: { stepNumber: number }) => consultationNatalPrepareStep({
|
||||
stepNumber: input.stepNumber,
|
||||
rectificationOffer: true,
|
||||
}),
|
||||
};
|
||||
const windowStreamOptions = {
|
||||
...streamOptions,
|
||||
prepareStep: consultationWindowPrepareStep,
|
||||
prepareStep: (input: { stepNumber: number }) => consultationWindowPrepareStep({
|
||||
stepNumber: input.stepNumber,
|
||||
rectificationOffer: true,
|
||||
}),
|
||||
};
|
||||
const answerPhaseSignal = runClock.answerSignal;
|
||||
const startAnswerPhase = () => {
|
||||
|
||||
@@ -459,7 +459,7 @@ export function natalAnswerShapeInstruction(): string {
|
||||
* Never decided from keywords. Defined here once; the offer tool names the
|
||||
* same parameters and does not restate this rule.
|
||||
*/
|
||||
export const RECTIFICATION_OFFER_RULE = "出生时间核对:用户说你推得不准时,先分清是读法问题还是时间问题。只是不认同某个解释,按纠正规则认下、改读,不提校正。不承诺能收窄出生时间,不在对话里收集经历做校正。用户这一轮明确要做校正,就在写回答之前调用 offer-birth-time-rectification 并传 explicitRequest=true;工具通过后只写那一句过渡,不写解读。用户说出过去某件具体的事和盘对不上、说自己的出生时间是估的或记不准、但没有明确要做校正,才在写回答之前调用 offer-birth-time-rectification,再按工具结果在正文里用一句话提一下(不写价格和题数,卡片上有)。同一次对话提议过、用户没接,就不再主动提;用户自己再要求时调用并传 userAsked=true。工具说不能提供时(比如问的是家人),照工具说明用一句话说清楚。";
|
||||
export const RECTIFICATION_OFFER_RULE = "校正就在这个对话里能开:用户这一轮明确要做出生时间校正(说法可能是校正、纠正、核对出生时间、看看出生时间准不准等),第一步就调用 offer-birth-time-rectification 并传 explicitRequest=true,不用先排盘,工具通过后只写那一句过渡,不写解读。用户说你推得不准时,先分清是读法问题还是时间问题。只是不认同某个解释,按改读规则认下、改读,不提校正。不承诺能收窄出生时间,不在对话里收集经历做校正。用户说出过去某件具体的事和盘对不上、说自己的出生时间是估的或记不准、但没有明确要做校正,才在看过盘之后调用 offer-birth-time-rectification,再按工具结果在正文里用一句话提一下(不写价格和题数,卡片上有)。同一次对话提议过、用户没接,就不再主动提;用户自己再要求时调用并传 userAsked=true。工具说不能提供时(比如问的是家人),照工具说明用一句话说清楚。";
|
||||
|
||||
/** D4 / BUG-1166: the user corrects an earlier reading; acknowledge it, never defend the reading. */
|
||||
export const FOLLOW_UP_CORRECTION_RULE = "用户纠正了前面的判断(比如说父亲其实不常在身边):先认下这件事,再只说盘上真正对得上的那几条、原来哪句读偏了;盘本身分不出的,直说「盘本身分不出这一点」,不把普通配置说成必然;不为原判断辩护。";
|
||||
|
||||
@@ -176,34 +176,41 @@ export const MAX_EVIDENCE_LOOKUPS_PER_TURN = 3;
|
||||
export const CONSULTATION_WINDOW_CALC_TOOL_ID = "run-jyotish-window-consultation";
|
||||
|
||||
/**
|
||||
* Step 0 exposes only the natal chart tool. Some thinking-mode providers
|
||||
* reject named and required toolChoice (BUG-282, BUG-937); the first step
|
||||
* therefore narrows with activeTools and leaves the choice as auto. Later
|
||||
* steps stay auto so the model can write after the request-scoped
|
||||
* calculation is in hand.
|
||||
* Step 0 narrows with activeTools and leaves toolChoice auto. Thinking-mode
|
||||
* providers reject named and required toolChoice (BUG-282, BUG-937).
|
||||
* When this turn mounted the rectification offer, that tool is available
|
||||
* beside the chart tool so an explicit request can open before a reading
|
||||
* (BUG-1317). Without it, step 0 is still only the chart tool (BUG-923).
|
||||
* Later steps stay auto.
|
||||
*
|
||||
* Window and general agents must not share this hook: they do not own this tool.
|
||||
* Window and general agents must not share the natal hook.
|
||||
*/
|
||||
export function consultationNatalPrepareStep(input: { stepNumber: number }) {
|
||||
return input.stepNumber === 0
|
||||
? {
|
||||
export function consultationNatalPrepareStep(input: { stepNumber: number; rectificationOffer?: boolean }) {
|
||||
if (input.stepNumber !== 0) return { toolChoice: "auto" as const };
|
||||
if (!input.rectificationOffer) {
|
||||
return {
|
||||
activeTools: [CONSULTATION_NATAL_CALC_TOOL_ID],
|
||||
toolChoice: "auto" as const,
|
||||
}
|
||||
: {
|
||||
toolChoice: "auto" as const,
|
||||
};
|
||||
}
|
||||
return {
|
||||
activeTools: [CONSULTATION_NATAL_CALC_TOOL_ID, RECTIFICATION_OFFER_TOOL_ID],
|
||||
toolChoice: "auto" as const,
|
||||
};
|
||||
}
|
||||
|
||||
export function consultationWindowPrepareStep(input: { stepNumber: number }) {
|
||||
return input.stepNumber === 0
|
||||
? {
|
||||
export function consultationWindowPrepareStep(input: { stepNumber: number; rectificationOffer?: boolean }) {
|
||||
if (input.stepNumber !== 0) return { toolChoice: "auto" as const };
|
||||
if (!input.rectificationOffer) {
|
||||
return {
|
||||
activeTools: [CONSULTATION_WINDOW_CALC_TOOL_ID],
|
||||
toolChoice: "auto" as const,
|
||||
}
|
||||
: {
|
||||
toolChoice: "auto" as const,
|
||||
};
|
||||
}
|
||||
return {
|
||||
activeTools: [CONSULTATION_WINDOW_CALC_TOOL_ID, RECTIFICATION_OFFER_TOOL_ID],
|
||||
toolChoice: "auto" as const,
|
||||
};
|
||||
}
|
||||
|
||||
const CONSULTATION_DOMAIN_DURATION_MS = 31_000;
|
||||
@@ -1174,6 +1181,12 @@ function createRectificationOfferTool(ctx: Readonly<{ state: ConsultationRuntime
|
||||
}
|
||||
return { offered: false as const, note: "已经在打开。不要再写解读。" };
|
||||
}
|
||||
if (input.explicitRequest !== true && !ctx.state.consultationToolCompleted) {
|
||||
return {
|
||||
offered: false as const,
|
||||
note: "先排盘,看过盘再决定要不要提。这次不算已经提议过。",
|
||||
};
|
||||
}
|
||||
if (hook.alreadyOffered && input.userAsked !== true && input.explicitRequest !== true) {
|
||||
return { offered: false as const, reason: "already_offered_in_session", note: "这次对话里已经提议过一次,用户没接。不再主动提校正,正常回答。" };
|
||||
}
|
||||
|
||||
@@ -679,26 +679,40 @@ test("guided-topic entrypoint ignores a model domain rewrite instead of executin
|
||||
|
||||
test("natal first step exposes only the chart calculation tool", () => {
|
||||
assert.equal(CONSULTATION_NATAL_CALC_TOOL_ID, "run-jyotish-consultation");
|
||||
// 原值: 第 0 步 toolChoice "required" / 新值: "auto"
|
||||
// 原因: BUG-282 供应商拒收 thinking 模式下的 required,BUG-937 撤回
|
||||
// 原值: 第 0 步 toolChoice "required",后来改为只有排盘工具且 toolChoice "auto"
|
||||
// 新值: 没挂校正工具时第 0 步仍只有排盘工具;挂了时是排盘工具和 offer-birth-time-rectification。toolChoice 仍是 "auto"。第 1 步不收窄。
|
||||
// 原因: BUG-937 保持 auto;BUG-1317 按产品选择,第 0 步在工具确实挂上时可以打开校正。
|
||||
assert.deepEqual(consultationNatalPrepareStep({ stepNumber: 0 }), {
|
||||
activeTools: ["run-jyotish-consultation"],
|
||||
toolChoice: "auto",
|
||||
});
|
||||
assert.deepEqual(consultationNatalPrepareStep({ stepNumber: 1 }), {
|
||||
assert.deepEqual(consultationNatalPrepareStep({ stepNumber: 0, rectificationOffer: false }), {
|
||||
activeTools: ["run-jyotish-consultation"],
|
||||
toolChoice: "auto",
|
||||
});
|
||||
assert.deepEqual(consultationNatalPrepareStep({ stepNumber: 0, rectificationOffer: true }), {
|
||||
activeTools: ["run-jyotish-consultation", "offer-birth-time-rectification"],
|
||||
toolChoice: "auto",
|
||||
});
|
||||
assert.deepEqual(consultationNatalPrepareStep({ stepNumber: 1, rectificationOffer: true }), {
|
||||
toolChoice: "auto",
|
||||
});
|
||||
});
|
||||
|
||||
test("window first step requires the window consultation tool", () => {
|
||||
assert.equal(CONSULTATION_WINDOW_CALC_TOOL_ID, "run-jyotish-window-consultation");
|
||||
// 原值: 第 0 步 toolChoice "required" / 新值: "auto"
|
||||
// 原因: BUG-282 供应商拒收 thinking 模式下的 required,BUG-937 撤回
|
||||
// 原值: 第 0 步 toolChoice "required",后来改为只有窗口排盘工具且 toolChoice "auto"
|
||||
// 新值: 没挂校正工具时第 0 步仍只有窗口排盘工具;挂了时再加上 offer-birth-time-rectification。toolChoice 仍是 "auto"。
|
||||
// 原因: 与本命同一条 BUG-1317 决定,申报时段也要能在第一步打开校正。
|
||||
assert.deepEqual(consultationWindowPrepareStep({ stepNumber: 0 }), {
|
||||
activeTools: ["run-jyotish-window-consultation"],
|
||||
toolChoice: "auto",
|
||||
});
|
||||
assert.deepEqual(consultationWindowPrepareStep({ stepNumber: 1 }), {
|
||||
assert.deepEqual(consultationWindowPrepareStep({ stepNumber: 0, rectificationOffer: true }), {
|
||||
activeTools: ["run-jyotish-window-consultation", "offer-birth-time-rectification"],
|
||||
toolChoice: "auto",
|
||||
});
|
||||
assert.deepEqual(consultationWindowPrepareStep({ stepNumber: 1, rectificationOffer: true }), {
|
||||
toolChoice: "auto",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -233,8 +233,12 @@ test("consult streams reserve an answer budget and keep provider thinking on a s
|
||||
route.indexOf("const natalStreamOptions = {"),
|
||||
);
|
||||
assert.doesNotMatch(sharedStreamOptions, /prepareStep/);
|
||||
assert.match(route, /prepareStep: consultationNatalPrepareStep/);
|
||||
assert.match(route, /prepareStep: consultationWindowPrepareStep/);
|
||||
// 原值:prepareStep: consultationNatalPrepareStep / consultationWindowPrepareStep,函数本身不知道校正工具在不在。
|
||||
// 新值:路由把 rectificationOffer: true 传进去,因为这两条路线都会挂上校正工具。
|
||||
// 原因:BUG-1317,第 0 步在工具挂上时要能打开校正;没传时函数仍只留排盘工具。
|
||||
assert.match(route, /prepareStep: \(input: \{ stepNumber: number \}\) => consultationNatalPrepareStep\(\{/);
|
||||
assert.match(route, /prepareStep: \(input: \{ stepNumber: number \}\) => consultationWindowPrepareStep\(\{/);
|
||||
assert.match(route, /rectificationOffer: true/);
|
||||
assert.match(route, /streamWithOverflowRetry\(agent, natalStreamOptions\)/);
|
||||
assert.match(route, /streamWithOverflowRetry\(agent, windowStreamOptions\)/);
|
||||
assert.match(
|
||||
|
||||
@@ -72,8 +72,14 @@ function offerTool(options: {
|
||||
alreadyOffered?: boolean;
|
||||
decide?: () => Promise<OfferDecision>;
|
||||
loadResumableSessionId?: () => Promise<string | null>;
|
||||
/** False only for a step-0 call that has not seen the chart yet. */
|
||||
chartReady?: boolean;
|
||||
} = {}) {
|
||||
const state = createConsultationRuntimeState();
|
||||
if (options.chartReady !== false) {
|
||||
state.consultationToolCompleted = true;
|
||||
state.consultationToolSuccessCount = 1;
|
||||
}
|
||||
let decisions = 0;
|
||||
let loads = 0;
|
||||
const tools = createConsultationTools({
|
||||
@@ -520,6 +526,111 @@ test("an ordinary consultation still retries once when the calculation never fin
|
||||
assert.equal(events.some((event) => event.type === "activity" && event.label === "正在补齐方法与计算步骤"), true);
|
||||
});
|
||||
|
||||
test("step 0 explicit request opens rectification without calculating a chart", async () => {
|
||||
const fresh = offerTool({ chartReady: false });
|
||||
const result = await fresh.tool.execute({ explicitRequest: true });
|
||||
assert.equal(result.directEntry, "new");
|
||||
assert.equal(fresh.state.consultationToolCallCount, 0);
|
||||
assert.equal(fresh.state.consultationToolCompleted, false);
|
||||
assert.equal(fresh.state.rectificationDirectEntry?.sentence, RECTIFICATION_DIRECT_NEW_COPY);
|
||||
let contractRetries = 0;
|
||||
const response = streamAgentResponse({
|
||||
runId: "run-step0-explicit",
|
||||
requestId: REQUEST_ID,
|
||||
state: fresh.state,
|
||||
requireTool: true,
|
||||
pass4Mode: "verified_chart",
|
||||
stepScopedAnswer: true,
|
||||
toolStatus: () => "ready",
|
||||
receipt: () => receipt(fresh.state),
|
||||
stream: (async function* () {
|
||||
yield { type: "text-delta", payload: { text: "我先看看盘,然后写一段解读。" } };
|
||||
yield STOP_FINISH;
|
||||
})(),
|
||||
retry: async () => {
|
||||
contractRetries += 1;
|
||||
return (async function* () { yield STOP_FINISH; })();
|
||||
},
|
||||
});
|
||||
const events = await readStream(response);
|
||||
assert.equal(contractRetries, 0);
|
||||
assert.equal(visibleAnswer(events), RECTIFICATION_DIRECT_NEW_COPY);
|
||||
assert.equal(events.some((event) => event.type === "run.completed" && event.responseKind === "smalltalk"), true);
|
||||
});
|
||||
|
||||
test("step 0 text without a tool still retries into a chart answer", async () => {
|
||||
const state = createConsultationRuntimeState();
|
||||
let contractRetries = 0;
|
||||
const response = streamAgentResponse({
|
||||
runId: "run-step0-empty",
|
||||
requestId: REQUEST_ID,
|
||||
state,
|
||||
requireTool: true,
|
||||
pass4Mode: "verified_chart",
|
||||
stepScopedAnswer: true,
|
||||
toolStatus: () => "ready",
|
||||
receipt: () => receipt(state),
|
||||
stream: (async function* () {
|
||||
yield { type: "text-delta", payload: { text: "还没排盘就想写。" } };
|
||||
yield STOP_FINISH;
|
||||
})(),
|
||||
retry: async () => {
|
||||
contractRetries += 1;
|
||||
state.consultationToolCompleted = true;
|
||||
state.consultationToolSuccessCount = 1;
|
||||
return (async function* () {
|
||||
yield { type: "text-delta", payload: { text: "事业方向可以看。" } };
|
||||
yield STOP_FINISH;
|
||||
})();
|
||||
},
|
||||
});
|
||||
const events = await readStream(response);
|
||||
assert.equal(contractRetries, 1);
|
||||
assert.equal(visibleAnswer(events), "事业方向可以看。");
|
||||
assert.equal(state.rectificationDirectEntry, undefined);
|
||||
assert.equal(events.some((event) => event.type === "activity" && event.label === "正在补齐方法与计算步骤"), true);
|
||||
});
|
||||
|
||||
test("a soft offer before the chart is not recorded, then a chart answer can still offer", async () => {
|
||||
const fresh = offerTool({ chartReady: false });
|
||||
const early = await fresh.tool.execute({});
|
||||
assert.equal(early.offered, false);
|
||||
assert.match(String(early.note), /先排盘,看过盘再决定要不要提/);
|
||||
// 记在局部上再断言。直接断言 state 上的字段会把它收成永远是空,排盘后再读就对不上类型。
|
||||
const offerBeforeChart = fresh.state.rectificationOffer;
|
||||
assert.equal(offerBeforeChart, undefined);
|
||||
assert.equal(fresh.state.rectificationDirectEntry, undefined);
|
||||
assert.equal(fresh.decisions(), 0);
|
||||
fresh.state.consultationToolCompleted = true;
|
||||
fresh.state.consultationToolSuccessCount = 1;
|
||||
const later = await fresh.tool.execute({});
|
||||
assert.equal(later.offered, true);
|
||||
const offerAfterChart = fresh.state.rectificationOffer;
|
||||
assert.equal(offerAfterChart?.status, "offered");
|
||||
assert.equal(offerAfterChart?.autoOpen, undefined);
|
||||
assert.equal(fresh.decisions(), 1);
|
||||
const response = streamAgentResponse({
|
||||
runId: "run-step0-soft",
|
||||
requestId: REQUEST_ID,
|
||||
state: fresh.state,
|
||||
requireTool: true,
|
||||
pass4Mode: "verified_chart",
|
||||
stepScopedAnswer: true,
|
||||
toolStatus: () => "ready",
|
||||
receipt: () => receipt(fresh.state),
|
||||
stream: (async function* () {
|
||||
yield { type: "text-delta", payload: { text: "事业方向可以看。" } };
|
||||
yield STOP_FINISH;
|
||||
})(),
|
||||
retry: async () => {
|
||||
throw new Error("chart contract should already be ready");
|
||||
},
|
||||
});
|
||||
const events = await readStream(response);
|
||||
assert.equal(visibleAnswer(events), "事业方向可以看。");
|
||||
assert.equal(visibleAnswer(events).includes(RECTIFICATION_DIRECT_NEW_COPY), false);
|
||||
});
|
||||
|
||||
test("the offer rule is defined once, and direct entry settles with the free completion", () => {
|
||||
const definitions = walkSources(fileURLToPath(new URL("../src/", import.meta.url))).filter((file) => (
|
||||
readFileSync(file, "utf8").includes("export const RECTIFICATION_OFFER_RULE")
|
||||
@@ -530,7 +641,12 @@ test("the offer rule is defined once, and direct entry settles with the free com
|
||||
assert.match(RECTIFICATION_OFFER_RULE, /不在对话里收集经历做校正/);
|
||||
assert.match(RECTIFICATION_OFFER_RULE, /explicitRequest=true/);
|
||||
assert.match(RECTIFICATION_OFFER_RULE, /只写那一句过渡,不写解读/);
|
||||
assert.match(RECTIFICATION_OFFER_RULE, /只是不认同某个解释,按纠正规则认下、改读,不提校正/);
|
||||
// 原值:规则以「用户说你推得不准时」开头,并写「按纠正规则认下」。
|
||||
// 新值:第一句就写 explicitRequest=true,并改称「改读规则」。全文不含「纠正规则」。
|
||||
// 原因:BUG-1317,「生时纠正」和「纠正解读」撞词,正向句被埋在禁止句中间。
|
||||
assert.match(RECTIFICATION_OFFER_RULE.split("。")[0] ?? "", /explicitRequest=true/);
|
||||
assert.match(RECTIFICATION_OFFER_RULE, /按改读规则认下、改读,不提校正/);
|
||||
assert.doesNotMatch(RECTIFICATION_OFFER_RULE, /纠正规则/);
|
||||
assert.match(RECTIFICATION_OFFER_RULE, /userAsked=true/);
|
||||
|
||||
const tools = src("../src/mastra/consultation-tools.ts");
|
||||
|
||||
@@ -117,6 +117,11 @@ test("the server decides whether a card may be shown: self, product on, no case
|
||||
|
||||
function offerTool(options: { alreadyOffered?: boolean; decide?: () => Promise<{ ok: true; creditCost: number; questionEstimate: number } | { ok: false; reason: "not_self" | "product_disabled" | "case_in_progress" | "pricing_unavailable" }> } = {}) {
|
||||
const state = createConsultationRuntimeState();
|
||||
// 原值:建出来还没排盘也能直接提议。
|
||||
// 新值:这些用例表示已经看过盘,所以先标计算完成。
|
||||
// 原因:BUG-1317,还没排盘的顺口提议不算已经提议过。
|
||||
state.consultationToolCompleted = true;
|
||||
state.consultationToolSuccessCount = 1;
|
||||
const tools = createConsultationTools({
|
||||
userId: "user-fictional",
|
||||
sessionId: SOURCE_SESSION,
|
||||
@@ -194,7 +199,10 @@ test("the C2 rule is defined once and reaches first turns, follow-ups and declar
|
||||
assert.ok(followUpAnswerShapeInstruction().includes(RECTIFICATION_OFFER_RULE));
|
||||
const route = readFileSync(new URL("../src/app/api/consult/route.ts", import.meta.url), "utf8");
|
||||
assert.match(route, /这只是粗看。" \+ RECTIFICATION_OFFER_RULE;/);
|
||||
assert.match(RECTIFICATION_OFFER_RULE, /只是不认同某个解释,按纠正规则认下、改读,不提校正/);
|
||||
// 原值:/按纠正规则认下、改读,不提校正/
|
||||
// 新值:/按改读规则认下、改读,不提校正/
|
||||
// 原因:BUG-1317,避免「生时纠正」被读成「用户在纠正解读」。
|
||||
assert.match(RECTIFICATION_OFFER_RULE, /只是不认同某个解释,按改读规则认下、改读,不提校正/);
|
||||
assert.match(RECTIFICATION_OFFER_RULE, /userAsked=true/);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user