Files
Jyotisha/frontend/tests/consultation-workflow-contract.test.ts

74 lines
3.7 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
const route = readFileSync(new URL("../src/app/api/consult/route.ts", import.meta.url), "utf8");
const reportsRoute = readFileSync(new URL("../src/app/api/reports/route.ts", import.meta.url), "utf8");
const mastra = readFileSync(new URL("../src/mastra/index.ts", import.meta.url), "utf8");
const tools = readFileSync(new URL("../src/mastra/consultation-tools.ts", import.meta.url), "utf8");
const workflow = readFileSync(new URL("../src/mastra/consultation-workflow.ts", import.meta.url), "utf8");
const stagingCompose = readFileSync(new URL("../../deploy/docker-compose.staging.yml", import.meta.url), "utf8");
test("personal consultation lets the Agent invoke the server-bound workflow tool", () => {
const agenticStart = route.indexOf("async function runAgenticConsultation");
const agenticBranch = route.slice(
agenticStart,
route.indexOf(" const { history } = parsed.data;", agenticStart),
);
assert.match(agenticBranch, /createConsultationAgentContext/);
assert.match(agenticBranch, /getJyotishAgent\(selectedModel, agentContext\)/);
assert.doesNotMatch(agenticBranch, /await runConsultationWorkflow/);
assert.doesNotMatch(agenticBranch, /JSON\.stringify\(toolInput\)/);
assert.match(tools, /\(ctx\.runWorkflow \?\? runConsultationWorkflow\)\(toolInput, \{/);
assert.match(tools, /return \{ "run-jyotish-consultation": consultationTool \};/);
assert.match(agenticBranch, /state\.workflowReceipt\?\.preciseTiming === "allowed"/);
});
test("defers optional external evidence only for foreground chat", () => {
assert.match(workflow, /defer_optional_external_evidence: options\?\.foreground === true/);
assert.match(reportsRoute, /runWorkflow: \(input\) => runConsultationWorkflow\(input\)/);
assert.doesNotMatch(reportsRoute, /foreground:\s*true/);
});
test("personal Agent owns the Skill and context-bound calculation tool", () => {
const personalFactory = mastra.slice(
mastra.indexOf("export function getJyotishAgent"),
mastra.indexOf("export function getLegacyJyotishAgent"),
);
assert.match(personalFactory, /getJyotishAgent\(model: ResolvedLanguageModel, context: ConsultationAgentContext\)/);
assert.match(personalFactory, /skills: \[jyotishSkillPath\]/);
assert.match(personalFactory, /tools: createConsultationTools\(context\)/);
assert.doesNotMatch(personalFactory, /server-computed-jyotish-workflow/);
});
test("validates and emits non-sensitive workflow and execution receipts", () => {
assert.match(workflow, /consultationWorkflowResponseSchema/);
assert.match(workflow, /safeParse\(data\)/);
assert.match(workflow, /consultationWorkflowReceipt/);
assert.match(route, /agentExecutionReceipt/);
assert.match(route, /streamAgentResponse/);
});
test("carries commercial technique truth into the model contract", () => {
assert.match(workflow, /technique_truth/);
assert.match(mastra, /deterministic_claims_forbidden_for/);
assert.match(mastra, /reference_only/);
assert.match(mastra, /Do not use a restricted technique/);
});
test("projects consultation themes through explicit strict workflow taxonomy", () => {
const projection = readFileSync(new URL("../src/lib/consultation-workflow-request.ts", import.meta.url), "utf8");
assert.match(projection, /strictWorkflowRoute/);
assert.match(projection, /claimBoundary/);
assert.match(projection, /requiredLayers/);
assert.match(projection, /negative holdout gate/);
});
test("staging enables the agentic consultation runtime without changing production compose", () => {
assert.match(stagingCompose, /CONSULTATION_AGENTIC_RUNTIME: enabled/);
assert.match(route, /CONSULTATION_AGENTIC_RUNTIME/);
assert.match(route, /legacy/);
assert.match(route, /canary/);
});