fix: restore birth-time rectification entry
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
||||
import type { RectificationNarrativeGenerator } from "../../../lib/conversational-rectification/narrative-agent.ts";
|
||||
import type { BirthTimeJourneyEngine, RectificationQuestionnaire } from "../../../lib/birth-time-journey-service.ts";
|
||||
import type { CandidateResult, LifeEvent } from "../../../lib/birth-time-evidence.ts";
|
||||
import type { CandidateDifferenceBuild } from "../../../lib/birth-time-dynamic-choice-internal.ts";
|
||||
import { conversationalRectificationCreationPolicyFromEnvironment } from "../../../lib/conversational-rectification/creation-policy.ts";
|
||||
import {
|
||||
conversationalRectificationLatencyBucket,
|
||||
@@ -449,6 +450,43 @@ function layerMetadata(scan: RectificationQuestionnaire, calculationVersion: str
|
||||
};
|
||||
}
|
||||
|
||||
function unavailableCandidateDifferences(
|
||||
caseId: string,
|
||||
range: { readonly startTime: string; readonly endTime: string },
|
||||
): CandidateDifferenceBuild {
|
||||
return {
|
||||
packet: {
|
||||
caseId,
|
||||
scoringVersion: "birth-time-choice-scoring-v2",
|
||||
currentRange: range,
|
||||
opportunities: [],
|
||||
askedQuestionFingerprints: [],
|
||||
candidatePartitionFingerprints: [],
|
||||
recentRangeHistory: [],
|
||||
},
|
||||
candidateModel: { version: "birth-time-choice-scoring-v2" },
|
||||
scoringPartitions: {},
|
||||
};
|
||||
}
|
||||
|
||||
function candidateDifferencesAreUnavailable(error: unknown): boolean {
|
||||
return error instanceof Error && [
|
||||
"AbortError",
|
||||
"TimeoutError",
|
||||
"BirthTimeJourneyEngineError",
|
||||
"BirthTimeJourneyEngineConfigurationError",
|
||||
].includes(error.name);
|
||||
}
|
||||
|
||||
function candidateDifferenceRangeIsTooWide(
|
||||
range: { readonly startTime: string; readonly endTime: string },
|
||||
): boolean {
|
||||
const start = minute(range.startTime);
|
||||
let end = minute(range.endTime);
|
||||
if (end < start) end += 1_440;
|
||||
return end - start > 360;
|
||||
}
|
||||
|
||||
function boundaryDistance(range: { readonly startTime: string; readonly endTime: string }, representative: string) {
|
||||
const start = minute(range.startTime);
|
||||
let end = minute(range.endTime);
|
||||
@@ -529,26 +567,35 @@ export async function buildProductionConversationalRectificationPacket(
|
||||
"merge_scans",
|
||||
() => mergeQuestionnaireScans(questionnaires, range),
|
||||
);
|
||||
const candidateDifferences = await rectificationPacketStage(
|
||||
"candidate_differences",
|
||||
() => engine.buildDifferencePacket({
|
||||
caseId: input.caseId,
|
||||
asOfDate: input.asOfDate,
|
||||
birthDate: input.declaredBirthInput.birthDate,
|
||||
startTime: range.startTime,
|
||||
endTime: range.endTime,
|
||||
lat: latitude,
|
||||
lon: longitude,
|
||||
tz: place.timezoneOffset,
|
||||
evidence: [],
|
||||
events,
|
||||
dismissedOpportunityIds: [],
|
||||
questionFingerprints: [],
|
||||
partitionFingerprints: [],
|
||||
recentRanges: [],
|
||||
candidateModel: null,
|
||||
}),
|
||||
);
|
||||
let candidateDifferences = unavailableCandidateDifferences(input.caseId, range);
|
||||
if (!candidateDifferenceRangeIsTooWide(range)) {
|
||||
try {
|
||||
candidateDifferences = await rectificationPacketStage(
|
||||
"candidate_differences",
|
||||
() => engine.buildDifferencePacket({
|
||||
caseId: input.caseId,
|
||||
asOfDate: input.asOfDate,
|
||||
birthDate: input.declaredBirthInput.birthDate,
|
||||
startTime: range.startTime,
|
||||
endTime: range.endTime,
|
||||
lat: latitude,
|
||||
lon: longitude,
|
||||
tz: place.timezoneOffset,
|
||||
evidence: [],
|
||||
events,
|
||||
dismissedOpportunityIds: [],
|
||||
questionFingerprints: [],
|
||||
partitionFingerprints: [],
|
||||
recentRanges: [],
|
||||
candidateModel: null,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
if (!candidateDifferencesAreUnavailable(error)) throw error;
|
||||
// Candidate partitions improve question ranking, but evidence collection can still
|
||||
// proceed from the server scan. Do not turn an optional slow dependency into a 503.
|
||||
}
|
||||
}
|
||||
const version = calculationVersion
|
||||
? `${candidateDifferences.packet.scoringVersion}+${calculationVersion}`
|
||||
: candidateDifferences.packet.scoringVersion;
|
||||
|
||||
@@ -161,7 +161,6 @@ button:disabled { cursor: default; opacity: .45; }
|
||||
.raw-evidence-receipt { margin: 0 var(--space-3) var(--space-3); border-top: 1px solid color-mix(in srgb, var(--color-border) 64%, transparent); padding-top: var(--space-2); }
|
||||
.raw-evidence-receipt summary { padding: var(--space-1) 0; color: var(--color-ink-tertiary); font-size: 12px; }
|
||||
.raw-evidence-receipt pre { max-height: 180px; overflow: auto; margin: var(--space-2) 0 0; padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-canvas); color: var(--color-ink-secondary); font-size: 11px; line-height: 1.5; }
|
||||
.report-download-button { margin-top: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas-soft); color: var(--color-ink-secondary); cursor: pointer; padding: 7px 10px; font-size: 12px; }
|
||||
.message-markdown p { margin: 0 0 14px; }
|
||||
.message-markdown ul, .message-markdown ol { margin: 10px 0 16px; padding-left: 24px; }
|
||||
.message-markdown li { margin: 6px 0; }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ChatMessageContent } from "@/components/chat-message-content";
|
||||
import type { ChatMessageView } from "@/lib/chat-message-view";
|
||||
import { consultationReportMarkdown, downloadMarkdownReport } from "@/lib/consultation-report-export";
|
||||
|
||||
export function AgentAvatar() {
|
||||
return <span className="agent-avatar" aria-hidden="true" />;
|
||||
@@ -24,7 +23,7 @@ export function ChatMessageRow({ message }: { readonly message: ChatMessageView
|
||||
{message.role === "assistant" ? (
|
||||
message.state === "thinking"
|
||||
? <div className="thinking"><i /><i /><i /></div>
|
||||
: <><ChatMessageContent text={message.text} /><button className="report-download-button" type="button" onClick={() => downloadMarkdownReport("Jyotisha 咨询报告", consultationReportMarkdown({ title: "Jyotisha 咨询报告", messages: [message] }))}>下载本次报告</button></>
|
||||
: <ChatMessageContent text={message.text} />
|
||||
) : <p>{message.text}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -240,13 +240,16 @@ function suggestedDomains(
|
||||
&& Boolean(values[index]?.length)
|
||||
&& value !== values[index]
|
||||
)).length;
|
||||
if (adjacentChanges === 0) return [];
|
||||
const observedRangeDifference = item.values.length > 1;
|
||||
if (adjacentChanges === 0 && !observedRangeDifference) return [];
|
||||
return [{
|
||||
domain,
|
||||
layer: item.layer,
|
||||
adjacentChanges,
|
||||
valueCount: item.values.length,
|
||||
reason: `${item.layer} 在相邻候选分钟中发生 ${adjacentChanges} 次实际切换,并呈现 ${item.values.join(" / ")} 差异,可用已发生的${domainLabels[domain]}事件区分。`,
|
||||
reason: adjacentChanges > 0
|
||||
? `${item.layer} 在相邻候选分钟中发生 ${adjacentChanges} 次实际切换,并呈现 ${item.values.join(" / ")} 差异,可用已发生的${domainLabels[domain]}事件区分。`
|
||||
: `${item.layer} 在候选范围内已扫描的时点呈现 ${item.values.join(" / ")} 差异,可用已发生的${domainLabels[domain]}事件继续区分;这不代表相邻分钟已经发生切换。`,
|
||||
}];
|
||||
}).sort((left, right) => right.adjacentChanges - left.adjacentChanges
|
||||
|| right.valueCount - left.valueCount
|
||||
|
||||
Reference in New Issue
Block a user