diff --git a/frontend/src/lib/consultation-workflow-request.ts b/frontend/src/lib/consultation-workflow-request.ts new file mode 100644 index 00000000..1f4d08d8 --- /dev/null +++ b/frontend/src/lib/consultation-workflow-request.ts @@ -0,0 +1,16 @@ +export const consultationThemeValues = ["career", "marriage", "wealth", "timing", "general"] as const; + +export type ConsultationTheme = typeof consultationThemeValues[number]; + +export function projectConsultationWorkflowRequest(question: string, theme: ConsultationTheme) { + switch (theme) { + case "career": + case "marriage": + case "wealth": + return { question, themes: [theme] } as const; + case "timing": + return { question: `应期与阶段问题:${question}`, themes: ["career"] } as const; + case "general": + return { question, themes: ["career", "marriage", "wealth"] } as const; + } +} diff --git a/frontend/src/mastra/index.ts b/frontend/src/mastra/index.ts index 53704e30..a1f3dc45 100644 --- a/frontend/src/mastra/index.ts +++ b/frontend/src/mastra/index.ts @@ -3,6 +3,7 @@ import { createTool } from "@mastra/core/tools"; import path from "node:path"; import { z } from "zod"; import { evidenceDraftModelOutputSchema } from "../lib/birth-time-guide-agent.ts"; +import { consultationThemeValues, projectConsultationWorkflowRequest } from "../lib/consultation-workflow-request.ts"; import type { ResolvedLanguageModel } from "./model"; export const consultationInputSchema = z.object({ @@ -16,7 +17,7 @@ export const consultationInputSchema = z.object({ tz: z.number().min(-12).max(14), city: z.string().trim().min(1).max(120), question: z.string().trim().min(1).max(500), - theme: z.enum(["career", "marriage", "wealth", "timing", "general"]), + theme: z.enum(consultationThemeValues), entryMode: z.enum(["direct_chart", "rectification"]).default("direct_chart"), }); @@ -54,15 +55,17 @@ const jyotishSkillPath = process.env.JYOTISH_SKILL_PATH?.trim() || path.resolve(process.cwd(), "..", "skills", "jyotish-vedic-astrology"); export async function runConsultationWorkflow(input: ConsultationInput) { - const { entryMode, ...workflowInput } = input; + const { entryMode, question, theme, ...workflowInput } = input; + const workflowRequest = projectConsultationWorkflowRequest(question, theme); const response = await fetch(`${apiBase}/api/consultation_workflow`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ ...workflowInput, entry_mode: entryMode, - question_text: input.question, - theme: input.theme === "general" ? ["career", "marriage", "wealth"] : [input.theme], + question: workflowRequest.question, + question_text: workflowRequest.question, + theme: workflowRequest.themes, }), signal: AbortSignal.timeout(45_000), }); diff --git a/frontend/tests/consultation-workflow-request.test.ts b/frontend/tests/consultation-workflow-request.test.ts new file mode 100644 index 00000000..eec94952 --- /dev/null +++ b/frontend/tests/consultation-workflow-request.test.ts @@ -0,0 +1,17 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { projectConsultationWorkflowRequest } from "../src/lib/consultation-workflow-request.ts"; + +test("timing questions use a legal report theme and preserve a timing route hint", () => { + // Given: a public timing consultation question. + const question = "未来哪些阶段值得把握?"; + + // When: its workflow request is projected for the Python service. + const request = projectConsultationWorkflowRequest(question, "timing"); + + // Then: the illegal public theme is converted to a legal report theme with a route hint. + assert.deepEqual(request, { + question: "应期与阶段问题:未来哪些阶段值得把握?", + themes: ["career"], + }); +});