feat(consult): split family into parents and children domains (engine still family)
parents (D12, 4/9 houses, Sun/Moon) and children (D7, 5th house, Jupiter, PK) are plan/card domains with Chinese labels and the brief's aliases. They send the family route contract to the engine and are rejected as a stored session theme, so neither Python nor the chat_sessions.theme CHECK changes. Methodology reports no strict checklist for them; must-use layers follow the plan domain. Tests with 原值/新值/原因 where assertions changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
75a1844cdf
commit
5c65834dda
@@ -5,7 +5,7 @@ import {
|
||||
type AgentExecutionReceipt,
|
||||
type WorkflowReceipt,
|
||||
} from "./consultation-agent-events.ts";
|
||||
import { consultationDomainSchema, type ConsultationDomain } from "./consultation-domain-registry.ts";
|
||||
import { consultationSessionThemeSchema, type ConsultationDomain } from "./consultation-domain-registry.ts";
|
||||
import { publicThinkingSectionSchema, type PublicThinkingSection } from "./consultation-thinking-plan.ts";
|
||||
|
||||
export const CHAT_SESSION_MAX_MESSAGES = 200;
|
||||
@@ -36,7 +36,7 @@ const chartBindingSchema = {
|
||||
|
||||
export const chatSessionMetadataPatchSchema = z.object({
|
||||
title: z.string().trim().min(1).max(160).optional(),
|
||||
theme: consultationDomainSchema.optional(),
|
||||
theme: consultationSessionThemeSchema.optional(),
|
||||
model_id: z.string().trim().min(1).max(64).optional(),
|
||||
pinned: z.boolean().optional(),
|
||||
...chartBindingSchema,
|
||||
@@ -52,7 +52,7 @@ export const chatSessionModelPatchSchema = z.object({
|
||||
export const chatSessionCreateSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
title: z.string().trim().min(1).max(160),
|
||||
theme: consultationDomainSchema,
|
||||
theme: consultationSessionThemeSchema,
|
||||
model_id: z.string().trim().min(1).max(64),
|
||||
// Former value: `.max(CHAT_SESSION_MAX_MESSAGES)` with transcript contents.
|
||||
// Create is no longer a history-import path; only an empty array is accepted.
|
||||
@@ -66,7 +66,7 @@ export const chatSessionCreateSchema = z.object({
|
||||
|
||||
const chatSessionLegacyWriteObjectSchema = z.object({
|
||||
title: z.string().trim().min(1).max(160),
|
||||
theme: consultationDomainSchema,
|
||||
theme: consultationSessionThemeSchema,
|
||||
model_id: z.string().trim().min(1).max(64),
|
||||
messages: z.array(chatMessageSchema).max(CHAT_SESSION_MAX_MESSAGES),
|
||||
session_type: z.enum(["consultation", "birth_time_rectification"]),
|
||||
|
||||
@@ -8,12 +8,41 @@ export const consultationDomainIds = [
|
||||
"education",
|
||||
"migration",
|
||||
"family",
|
||||
"parents",
|
||||
"children",
|
||||
"annual",
|
||||
"timing",
|
||||
"general",
|
||||
] as const;
|
||||
|
||||
export type ConsultationDomain = typeof consultationDomainIds[number];
|
||||
|
||||
/**
|
||||
* The themes the Python engine and the `chat_sessions.theme` CHECK know.
|
||||
*
|
||||
* `parents` and `children` split the engine's `family` theme only for what the
|
||||
* answer model is shown (the evidence card's domain section). They are sent to
|
||||
* the engine as `family` (`strictWorkflowRoute` / `workflowThemes`), and a
|
||||
* stored session theme stays one of these ten, so the split needs no Python or
|
||||
* database change.
|
||||
*/
|
||||
export const consultationEngineDomainIds = [
|
||||
"career",
|
||||
"marriage",
|
||||
"wealth",
|
||||
"health",
|
||||
"education",
|
||||
"migration",
|
||||
"family",
|
||||
"annual",
|
||||
"timing",
|
||||
"general",
|
||||
] as const satisfies readonly ConsultationDomain[];
|
||||
|
||||
export type ConsultationEngineDomain = typeof consultationEngineDomainIds[number];
|
||||
|
||||
/** The session-theme vocabulary (`chat_sessions.theme` CHECK). */
|
||||
export const consultationSessionThemeSchema = z.enum(consultationEngineDomainIds);
|
||||
export type ConsultationTheme = ConsultationDomain;
|
||||
|
||||
export const consultationDomainSchema = z.enum(consultationDomainIds);
|
||||
@@ -22,8 +51,9 @@ export type ConsultationDomainDefinition = Readonly<{
|
||||
id: ConsultationDomain;
|
||||
label: string;
|
||||
aliases: readonly string[];
|
||||
strictWorkflowRoute: ConsultationDomain;
|
||||
workflowThemes: readonly ConsultationDomain[];
|
||||
/** The engine route this domain runs as; `parents` / `children` run as `family`. */
|
||||
strictWorkflowRoute: ConsultationEngineDomain;
|
||||
workflowThemes: readonly ConsultationEngineDomain[];
|
||||
requiredLayers: readonly string[];
|
||||
claimBoundary: string;
|
||||
prompt: string;
|
||||
@@ -38,7 +68,9 @@ export const consultationDomainRegistry = [
|
||||
{ id: "health", label: "身心压力", aliases: ["health", "health-pressure", "health_pressure", "健康"], strictWorkflowRoute: "health", workflowThemes: ["health"], requiredLayers: ["D1", "D6", "D8", "6th/8th houses", "Dasha", "non-medical boundary"], claimBoundary: "wellbeing_pressure_patterns_not_medical_diagnosis", prompt: "我近期的身心压力模式和调节重点是什么?", evidencePreview: ["D1", "D6", "D8", "6/8宫", "Dasha"], confidenceCap: "low" },
|
||||
{ id: "education", label: "学习", aliases: ["education", "study", "教育", "学习"], strictWorkflowRoute: "education", workflowThemes: ["education"], requiredLayers: ["D1", "D24", "5th/9th houses", "Mercury/Jupiter", "Dasha"], claimBoundary: "learning_pattern_and_broad_timing_only", prompt: "我的学习优势、瓶颈和进阶方向是什么?", evidencePreview: ["D1", "D24", "5/9宫", "Mercury/Jupiter", "Dasha"], confidenceCap: "medium" },
|
||||
{ id: "migration", label: "迁居", aliases: ["migration", "home", "relocation", "foreign", "迁移", "海外"], strictWorkflowRoute: "migration", workflowThemes: ["migration"], requiredLayers: ["D1", "D4", "D12", "4th/12th houses", "Dasha", "Narayana"], claimBoundary: "migration_and_home_direction_broad_window_only", prompt: "迁居、置业或海外发展更适合怎样规划?", evidencePreview: ["D1", "D4", "D12", "4/12宫", "Dasha"], confidenceCap: "medium" },
|
||||
{ id: "family", label: "家庭", aliases: ["family", "children", "家庭", "子女"], strictWorkflowRoute: "family", workflowThemes: ["family"], requiredLayers: ["D1", "D7", "D12", "4th/5th/9th houses", "Dasha"], claimBoundary: "family_pattern_not_deterministic_event_claim", prompt: "我的家庭关系与责任边界该如何理解?", evidencePreview: ["D1", "D7", "D12", "4/5/9宫", "Dasha"], confidenceCap: "medium" },
|
||||
{ id: "family", label: "家庭", aliases: ["family", "家庭"], strictWorkflowRoute: "family", workflowThemes: ["family"], requiredLayers: ["D1", "D7", "D12", "4th/5th/9th houses", "Dasha"], claimBoundary: "family_pattern_not_deterministic_event_claim", prompt: "我的家庭关系与责任边界该如何理解?", evidencePreview: ["D1", "D7", "D12", "4/5/9宫", "Dasha"], confidenceCap: "medium" },
|
||||
{ id: "parents", label: "父母", aliases: ["parents", "父母", "父亲", "母亲", "爸爸", "妈妈", "爸妈"], strictWorkflowRoute: "family", workflowThemes: ["family"], requiredLayers: ["D1", "D12", "4th/9th houses/lords", "Sun/Moon", "Dasha", "Narayana"], claimBoundary: "family_pattern_not_deterministic_event_claim", prompt: "我和父母的关系该怎么理解?", evidencePreview: ["D1", "D12", "4/9宫", "太阳/月亮", "Dasha"], confidenceCap: "medium" },
|
||||
{ id: "children", label: "子女", aliases: ["children", "子女", "孩子", "儿子", "女儿"], strictWorkflowRoute: "family", workflowThemes: ["family"], requiredLayers: ["D1", "D7", "5th house/lord", "Jupiter", "PK", "Dasha", "Narayana"], claimBoundary: "family_pattern_not_deterministic_event_claim", prompt: "我和子女的缘分与相处该怎么看?", evidencePreview: ["D1", "D7", "5宫", "木星", "Dasha"], confidenceCap: "medium" },
|
||||
{ id: "annual", label: "年运", aliases: ["annual", "yearly", "varshaphala", "年度", "流年"], strictWorkflowRoute: "annual", workflowThemes: ["annual"], requiredLayers: ["D1", "Annual chart boundary", "Dasha", "Transit", "Tajika candidate"], claimBoundary: "annual_report_broad_periods_only", prompt: "未来一年的重点主题和阶段节奏是什么?", evidencePreview: ["D1", "Dasha", "Transit", "Annual chart boundary"], confidenceCap: "low" },
|
||||
{ id: "timing", label: "时运", aliases: ["timing"], strictWorkflowRoute: "timing", workflowThemes: ["timing"], requiredLayers: ["Vimshottari", "Narayana", "Transit", "Varga", "negative holdout gate"], claimBoundary: "candidate_day_month_window_only_until_holdout_passes", prompt: "未来哪些阶段值得把握?", evidencePreview: ["Dasha", "Narayana", "Transit", "Varga"], confidenceCap: "low" },
|
||||
{ id: "general", label: "综合", aliases: ["general"], strictWorkflowRoute: "general", workflowThemes: ["general"], requiredLayers: ["D1", "D9", "D10", "D2", "Dasha", "Narayana", "Transit", "Functional Benefic/Malefic"], claimBoundary: "multi_domain_summary_with_missing_layers_disclosed", prompt: "请综合说明我当前最值得关注的主题。", evidencePreview: ["D1", "D9", "D10", "D2", "Dasha", "Transit"], confidenceCap: "low" },
|
||||
@@ -87,3 +119,8 @@ export function consultationDomainDefinition(domain: ConsultationDomain): Consul
|
||||
if (!definition) throw new Error("consultation_domain_registry_incomplete");
|
||||
return definition;
|
||||
}
|
||||
|
||||
/** The engine theme a consultation domain is calculated as. */
|
||||
export function consultationEngineDomain(domain: ConsultationDomain): ConsultationEngineDomain {
|
||||
return consultationDomainDefinition(domain).strictWorkflowRoute;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ const domainMethodology: Readonly<Record<ConsultationDomain, { strictRoute: stri
|
||||
education: { strictRoute: null, eventJudgment: null },
|
||||
migration: { strictRoute: null, eventJudgment: null },
|
||||
family: { strictRoute: null, eventJudgment: null },
|
||||
// The router's shared baseline names D12 for family/ancestral themes and D7
|
||||
// for children; it declares no named strict checklist for either.
|
||||
parents: { strictRoute: null, eventJudgment: null },
|
||||
children: { strictRoute: null, eventJudgment: null },
|
||||
};
|
||||
|
||||
const ROUTER_FILE = "references/strict-workflow-router.md";
|
||||
|
||||
@@ -258,7 +258,7 @@ function queriesFromSection(section: PublicThinkingSection): string[] {
|
||||
}
|
||||
return uniqueLabels(section.steps
|
||||
.flatMap((step) => {
|
||||
const domainLabel = /^(事业|财富|关系|家庭)/.exec(step.label)?.[1];
|
||||
const domainLabel = /^(事业|财富|关系|家庭|父母|子女)/.exec(step.label)?.[1];
|
||||
return domainLabel ? [domainLabel] : [];
|
||||
})).slice(0, 8);
|
||||
}
|
||||
|
||||
@@ -38,12 +38,15 @@ export function projectConsultationWorkflowRequest(
|
||||
plan: ConsultationWorkflowPlanMetadata,
|
||||
) {
|
||||
const requirement = consultationDomainDefinition(theme);
|
||||
// The engine validates the route contract exactly (consultation_plan_contract.py),
|
||||
// so a card-only domain (parents, children) sends its engine route's contract.
|
||||
const engine = consultationDomainDefinition(requirement.strictWorkflowRoute);
|
||||
return {
|
||||
question,
|
||||
themes: requirement.workflowThemes,
|
||||
strictWorkflowRoute: requirement.strictWorkflowRoute,
|
||||
requiredLayers: requirement.requiredLayers,
|
||||
claimBoundary: requirement.claimBoundary,
|
||||
requiredLayers: engine.requiredLayers,
|
||||
claimBoundary: engine.claimBoundary,
|
||||
plan_version: plan.plan_version,
|
||||
depth: plan.depth,
|
||||
requested_domains: plan.requestedDomains,
|
||||
|
||||
@@ -31,6 +31,8 @@ const generalPromptByTheme: Partial<Record<ConsultationTheme, string>> = {
|
||||
education: "请帮我看看我更适合怎样学习,以及如何安排下一步。",
|
||||
migration: "请帮我分析现阶段是否适合迁居、置业或考虑海外发展。",
|
||||
family: "请帮我看看家庭关系中最需要处理的问题和责任边界。",
|
||||
parents: "请帮我看看我和父母之间最需要处理的问题。",
|
||||
children: "请帮我看看我和孩子相处时最需要留意的地方。",
|
||||
annual: "请帮我看看未来一年的主要趋势、机会和需要留意的阶段。",
|
||||
timing: "请帮我看看目前适合推进什么,哪些事情需要再等等。",
|
||||
general: "请结合我的情况,帮我找出现在最值得优先处理的三个问题。",
|
||||
|
||||
Reference in New Issue
Block a user