Move-only (TASK-rectification-code-split-20260926 T2/T4). No behavior, API, copy, DB, Skill, billing or scoring change. - route.ts: 1077 -> 152 lines; POST 927 -> 114. It builds the Supabase clients (so the setup-failure mapping stays here) and assembles: agent-route-request.ts (auth / product / schema / flag / Case-Session binding), agent-route-typed-message.ts (declared-window reply, typed-answer preflight, unfocused classification), agent-route-structured-choice.ts, agent-route-agent-turn.ts (opening / read-only / typed agent stream and its exit gate), agent-route-billing.ts, agent-route-support.ts (schema, one-shot NDJSON reply, context types). - The four mutable preflight lets (expectedWrite, collectIntent, writeClassified, classifierDiagnostic) that crossed branches are one turnState object; values and flow unchanged. - Tests: whole-source contracts read tests/rectification-agent-route-surface.ts; the typed fast-path slice is rebuilt from the new files; billing, declared-window and structured-choice slices now call the handlers (billing in a child process because feature-pricing imports server-only), each with 原值/新值/原因. Route growth caps added. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
72 lines
2.5 KiB
TypeScript
72 lines
2.5 KiB
TypeScript
/**
|
|
* A verified route context for calling the branch handlers split out of
|
|
* POST /api/rectification/agent (TASK-rectification-code-split-20260926)
|
|
* directly, with a recording persistence client instead of Supabase.
|
|
*/
|
|
import type {
|
|
RectificationAgentRequest,
|
|
RectificationAgentRouteContext,
|
|
} from "../src/lib/rectification-agentic/v9/agent-route-support.ts";
|
|
|
|
export const ROUTE_CASE_ID = "44444444-4444-4444-8444-444444444444";
|
|
export const ROUTE_SESSION_ID = "33333333-3333-4333-8333-333333333333";
|
|
export const ROUTE_REQUEST_ID = "55555555-5555-4555-8555-555555555555";
|
|
export const ROUTE_TURN_ID = "66666666-6666-4666-8666-666666666666";
|
|
|
|
export type RecordedRpc = Readonly<{ fn: string; args: Record<string, unknown> }>;
|
|
|
|
export function routeContextFixture(
|
|
data: Partial<RectificationAgentRequest>,
|
|
rpcData: (fn: string) => unknown = () => ({ turn_id: ROUTE_TURN_ID, idempotent: false }),
|
|
) {
|
|
const rpcCalls: RecordedRpc[] = [];
|
|
const accounting = {
|
|
rpc: async (fn: string, args: Record<string, unknown> = {}) => {
|
|
rpcCalls.push({ fn, args });
|
|
return { data: rpcData(fn), error: null };
|
|
},
|
|
from: () => {
|
|
throw new Error("no table access expected");
|
|
},
|
|
};
|
|
const request: RectificationAgentRequest = {
|
|
caseId: ROUTE_CASE_ID,
|
|
sessionId: ROUTE_SESSION_ID,
|
|
requestId: ROUTE_REQUEST_ID,
|
|
action: "message",
|
|
...data,
|
|
};
|
|
const context = {
|
|
request: new Request("https://staging.jyotisha.chat/api/rectification/agent", { method: "POST" }),
|
|
turnStartedAt: Date.now(),
|
|
supabase: {},
|
|
accounting,
|
|
userId: "77777777-7777-4777-8777-777777777777",
|
|
parsed: { data: request },
|
|
caseId: request.caseId,
|
|
sessionId: request.sessionId,
|
|
requestId: request.requestId,
|
|
action: request.action,
|
|
isStructuredChoice: request.action === "answer_choice"
|
|
|| request.action === "stop_and_review"
|
|
|| request.action === "skip_probe",
|
|
caseStatus: "collecting_evidence",
|
|
skillVersion: "",
|
|
chatSession: {
|
|
id: request.sessionId,
|
|
session_type: "birth_time_rectification",
|
|
model_id: "model-a",
|
|
model_config_version: 1,
|
|
agentic_rectification_case_id: request.caseId,
|
|
},
|
|
} as unknown as RectificationAgentRouteContext;
|
|
return { context, rpcCalls };
|
|
}
|
|
|
|
export async function ndjsonEvents(response: Response): Promise<Array<Record<string, unknown>>> {
|
|
return (await response.text())
|
|
.split("\n")
|
|
.filter((line) => line.trim())
|
|
.map((line) => JSON.parse(line) as Record<string, unknown>);
|
|
}
|