fix(rectification): exhaustion exit, explain layer, range reading, unknown-time scan (BUG-565–568)
Keep askable cards after exhaustion, explain each probe, read the adopted credible range in reports and chat, and compare declared periods before the minute grid when the clock is unknown. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -57,6 +57,7 @@ import {
|
||||
} from "@/mastra/consultation-tools";
|
||||
import {
|
||||
applyBirthTimeModeToWorkflowContext,
|
||||
ACCEPTED_RANGE_READING_INSTRUCTION,
|
||||
consultationBirthTimeModeSchema,
|
||||
createBirthTimeModeOutputGuard,
|
||||
shouldRunBirthChartWorkflow,
|
||||
@@ -68,6 +69,7 @@ import {
|
||||
prepareConsultationRoute,
|
||||
type PreparedConsultationRoute,
|
||||
} from "@/lib/consultation-route-service";
|
||||
import { loadReportCandidateRange } from "@/lib/report-candidate-range";
|
||||
import {
|
||||
loadGeneralDailyPanchangaContext,
|
||||
type GeneralDailyPanchangaContext,
|
||||
@@ -209,7 +211,7 @@ function generalNoMinuteInstruction(hasPublicDaily: boolean) {
|
||||
}
|
||||
|
||||
function declaredWindowInstruction() {
|
||||
return "当前是声明出生窗口咨询,没有单一出生分钟。如需个人结构结论,必须调用 run-jyotish-window-consultation。探针时刻不是出生时间,不得把 00:00、时段中点、中午或任一探针写成出生分钟。只能根据稳定层作方向性回答;上升或宫位若在窗口内变化,列出可能星座,不得写成「你的上升是 X」。精确应期一律不可用。";
|
||||
return "当前是声明出生窗口咨询,没有单一出生分钟。如需个人结构结论,必须调用 run-jyotish-window-consultation。探针时刻不是出生时间,不得把 00:00、时段中点、中午或任一探针写成出生分钟。只能根据稳定层作方向性回答;上升或宫位若在窗口内变化,列出可能星座,不得写成「你的上升是 X」。精确应期一律不可用。这只是粗看。";
|
||||
}
|
||||
|
||||
function usesPublicDailyGeneralAgent(
|
||||
@@ -384,6 +386,7 @@ export async function POST(request: Request) {
|
||||
if (error || !data) throw new ConsultationProfileTruthError("profile_unavailable");
|
||||
return data;
|
||||
},
|
||||
loadCandidateRange: (profileUserId) => loadReportCandidateRange(accounting, { userId: profileUserId }),
|
||||
beforeReserve: ({ consultationMode }) => createConsultationPlan({
|
||||
userIntent: parsed.data.question,
|
||||
theme: consultationTheme,
|
||||
@@ -834,11 +837,17 @@ export async function POST(request: Request) {
|
||||
}
|
||||
};
|
||||
const cacheBoundary = cachedSystemMessage("【上下文缓存边界】后续内容为本轮请求输入。", selectedModel.model);
|
||||
const natalInstruction = "先加载 Jyotish Skill;如需新的个人星盘结论,必须调用服务器绑定的排盘工具。事业/财富/婚恋/家庭按 skill Level 2 模板写:原始结构、六步宫位、Yoga 表、时机、综合、文末技法审计表,然后才是现代生活措辞。不要复述内部 JSON 字段。";
|
||||
const adoptedRangeNote = consultationMode === "verified_chart"
|
||||
&& prepared.serverChart?.truth.birthTimeStatus === "accepted"
|
||||
&& prepared.serverChart.toolInput.candidate_range
|
||||
? ` ${ACCEPTED_RANGE_READING_INSTRUCTION}`
|
||||
: "";
|
||||
const modeInstruction = consultationMode === "general_no_birth_time" || (consultationMode === "declared_birth_window" && generalDailyContext)
|
||||
? generalNoMinuteInstruction(Boolean(generalDailyContext))
|
||||
: consultationMode === "declared_birth_window"
|
||||
? declaredWindowInstruction()
|
||||
: "先加载 Jyotish Skill;如需新的个人星盘结论,必须调用服务器绑定的排盘工具。事业/财富/婚恋/家庭按 skill Level 2 模板写:原始结构、六步宫位、Yoga 表、时机、综合、文末技法审计表,然后才是现代生活措辞。不要复述内部 JSON 字段。";
|
||||
: `${natalInstruction}${adoptedRangeNote}`;
|
||||
const consultationBaseMessages = (overflow: boolean) => {
|
||||
const tail = overflow ? lastConsultationPair(history) : history;
|
||||
const mapped = tail.map((message) => message.role === "user"
|
||||
@@ -1184,6 +1193,10 @@ export async function POST(request: Request) {
|
||||
transformText: (text) => createBirthTimeModeOutputGuard(
|
||||
consultationMode,
|
||||
state.workflowReceipt?.preciseTiming === "allowed",
|
||||
{
|
||||
currentTheme: consultationTheme,
|
||||
minuteSensitiveThemes: state.workflowReceipt?.minuteSensitiveThemes,
|
||||
},
|
||||
)(text),
|
||||
toolStatus: () => workflowStatus(state.workflowReceipt?.status),
|
||||
receipt: executionReceipt,
|
||||
@@ -1371,6 +1384,10 @@ export async function POST(request: Request) {
|
||||
transformText: createBirthTimeModeOutputGuard(
|
||||
consultationMode,
|
||||
workflowReceipt.preciseTiming !== "blocked",
|
||||
{
|
||||
currentTheme: consultationTheme,
|
||||
minuteSensitiveThemes: workflowReceipt.minuteSensitiveThemes,
|
||||
},
|
||||
),
|
||||
mode: "mastra",
|
||||
requestId,
|
||||
|
||||
@@ -75,6 +75,7 @@ function completedMessageResponse(
|
||||
"x-accel-buffering": "no",
|
||||
"x-ayanam-request-id": requestId,
|
||||
"x-rectification-case-id": caseId,
|
||||
...(turnId ? { "x-rectification-turn-id": turnId } : {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -675,6 +676,7 @@ export async function POST(request: Request) {
|
||||
userId,
|
||||
caseId,
|
||||
action,
|
||||
askedTurnId: immediateResponse.headers.get("x-rectification-turn-id"),
|
||||
}),
|
||||
);
|
||||
return response;
|
||||
|
||||
@@ -126,17 +126,13 @@ export async function POST(request: Request, context: RouteContext) {
|
||||
{ status: 409 },
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof RectificationToolServiceError) {
|
||||
return errorResponse(error);
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ error: "暂时无法采用该候选时间", code: "candidate_accept_failed" },
|
||||
{ status: 503 },
|
||||
);
|
||||
}
|
||||
const { adoptedCredibleRangePayload } = await import("@/lib/report-candidate-range");
|
||||
const credibleRange = adoptedCredibleRangePayload({
|
||||
startTime: decision.credibleRange?.[0],
|
||||
endTime: decision.credibleRange?.[1],
|
||||
representativeTime: decision.representativeTime,
|
||||
});
|
||||
|
||||
try {
|
||||
const { data, error } = await accounting.rpc(
|
||||
"accept_agentic_rectification_candidate_for_case_v2",
|
||||
{
|
||||
@@ -145,6 +141,7 @@ export async function POST(request: Request, context: RouteContext) {
|
||||
p_result_id: parsed.data.resultId,
|
||||
p_candidate_id: parsed.data.candidateId,
|
||||
p_request_id: parsed.data.requestId,
|
||||
...(credibleRange ? { p_credible_range: credibleRange } : {}),
|
||||
},
|
||||
);
|
||||
if (error) throw new RectificationToolServiceError(error.message);
|
||||
@@ -178,6 +175,12 @@ export async function POST(request: Request, context: RouteContext) {
|
||||
idempotent: result.idempotent === true,
|
||||
});
|
||||
} catch (error) {
|
||||
return errorResponse(error);
|
||||
if (error instanceof RectificationToolServiceError) {
|
||||
return errorResponse(error);
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ error: "暂时无法采用该候选时间", code: "candidate_accept_failed" },
|
||||
{ status: 503 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
type ConversationFocusList,
|
||||
type V9CaseDossier,
|
||||
} from "@/lib/rectification-agentic/v9/tool-service";
|
||||
import { choiceCardFromCaseDossier, decideFromDossier, overlayPublicDecision, nextUserActionFromDossier } from "@/lib/rectification-agentic/v9/interview-state";
|
||||
import { choiceCardFromCaseDossier, decideFromDossier, overlayPublicDecision, nextUserActionFromDossier, stepStateFromCaseDossier } from "@/lib/rectification-agentic/v9/interview-state";
|
||||
import { projectCurrentQuestion } from "@/lib/rectification-agentic/v9/turn-decision";
|
||||
import { attachQuestionsToTurns, attachOfferResultToTurns } from "@/lib/rectification-agentic/v9/turn-question";
|
||||
import { previousInferenceFromReceipt } from "@/lib/rectification-agentic/v9/inference-adapter";
|
||||
@@ -121,6 +121,7 @@ function dossierResponse(
|
||||
skill_identity_status: skillIdentity.status,
|
||||
requires_skill_adoption: skillIdentity.requiresSkillAdoption,
|
||||
candidate_range: dossier.case.candidateRange,
|
||||
stage: dossier.case.stage,
|
||||
accepted_time: dossier.case.acceptedTime,
|
||||
confirmed_time: dossier.case.confirmedTime,
|
||||
completed_at: dossier.case.completedAt,
|
||||
@@ -139,7 +140,9 @@ function dossierResponse(
|
||||
offer_result_id: turn.offer_result_id,
|
||||
})),
|
||||
evidence: dossier.evidence,
|
||||
latest_result: dossier.latestResult
|
||||
latest_result: dossier.case.stage === "block_scan" || decision.sessionOutcome === "compare_blocks"
|
||||
? null
|
||||
: dossier.latestResult
|
||||
? publicLatestResult(dossier.latestResult, decision, dossier, options.fullDetail === true)
|
||||
: null,
|
||||
interview: {
|
||||
@@ -148,6 +151,7 @@ function dossierResponse(
|
||||
},
|
||||
current_question: projectCurrentQuestion(dossier.conversationSummary.activeFocus),
|
||||
choice_card: choiceCardFromCaseDossier(dossier),
|
||||
step_state: stepStateFromCaseDossier(dossier),
|
||||
next_user_action: nextUserActionFromDossier(dossier),
|
||||
question_source: questionSourceFromFocusList(listed),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user