Initial import NDC_1C
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
import { Router } from "express";
|
||||
import type { AppServices } from "../serverContext";
|
||||
import { ApiError, created, ok } from "../utils/http";
|
||||
|
||||
const PREFIX = "/api/accounting-agent/v1";
|
||||
|
||||
export function buildAccountingAgentRouter(services: AppServices): Router {
|
||||
const router = Router();
|
||||
const runtime = services.runtimeAdapter;
|
||||
|
||||
router.post(`${PREFIX}/runs/start`, (req, res, next) => {
|
||||
try {
|
||||
const body = (req.body ?? {}) as Record<string, unknown>;
|
||||
const run = runtime.startRun({
|
||||
sessionId: body.sessionId ? String(body.sessionId) : undefined,
|
||||
initiator: body.initiator ? String(body.initiator) : "operator",
|
||||
source: body.source ? String(body.source) : "gui",
|
||||
metadata: (body.metadata ?? {}) as Record<string, unknown>,
|
||||
idempotencyKey: body.idempotencyKey ? String(body.idempotencyKey) : undefined
|
||||
});
|
||||
created(res, {
|
||||
ok: true,
|
||||
sessionId: run.sessionId,
|
||||
runId: run.runId,
|
||||
status: run.status,
|
||||
run
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.post(`${PREFIX}/runs/finish`, (req, res, next) => {
|
||||
try {
|
||||
const body = (req.body ?? {}) as Record<string, unknown>;
|
||||
const status = String(body.status ?? "DONE") as "DONE" | "ERROR" | "CANCELLED";
|
||||
if (!["DONE", "ERROR", "CANCELLED"].includes(status)) {
|
||||
throw new ApiError("INVALID_STATUS", `Invalid finish status: ${status}`, 400);
|
||||
}
|
||||
const run = runtime.finishRun({
|
||||
runId: String(body.runId ?? ""),
|
||||
status,
|
||||
source: body.source ? String(body.source) : "gui",
|
||||
reason: body.reason ? String(body.reason) : undefined,
|
||||
metadata: (body.metadata ?? {}) as Record<string, unknown>,
|
||||
idempotencyKey: body.idempotencyKey ? String(body.idempotencyKey) : undefined
|
||||
});
|
||||
ok(res, {
|
||||
ok: true,
|
||||
run
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.get(`${PREFIX}/runs`, (_req, res) => {
|
||||
ok(res, {
|
||||
ok: true,
|
||||
items: runtime.listRuns()
|
||||
});
|
||||
});
|
||||
|
||||
router.get(`${PREFIX}/runs/:runId`, (req, res, next) => {
|
||||
try {
|
||||
const run = runtime.getRun(String(req.params.runId));
|
||||
if (!run) {
|
||||
throw new ApiError("RUN_NOT_FOUND", `Run not found: ${req.params.runId}`, 404);
|
||||
}
|
||||
ok(res, {
|
||||
ok: true,
|
||||
run
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.post(`${PREFIX}/tasks/enqueue`, (req, res, next) => {
|
||||
try {
|
||||
const body = (req.body ?? {}) as Record<string, unknown>;
|
||||
const task = runtime.enqueueTask({
|
||||
runId: String(body.runId ?? ""),
|
||||
payload: (body.payload ?? {}) as Record<string, unknown>,
|
||||
source: body.source ? String(body.source) : "gui",
|
||||
idempotencyKey: body.idempotencyKey ? String(body.idempotencyKey) : undefined
|
||||
});
|
||||
created(res, {
|
||||
ok: true,
|
||||
task
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.post(`${PREFIX}/tasks/claim`, (_req, res) => {
|
||||
const task = runtime.claimTask();
|
||||
ok(res, {
|
||||
ok: true,
|
||||
task
|
||||
});
|
||||
});
|
||||
|
||||
router.post(`${PREFIX}/tasks/:taskId/complete`, (req, res, next) => {
|
||||
try {
|
||||
const body = (req.body ?? {}) as Record<string, unknown>;
|
||||
const task = runtime.completeTask({
|
||||
taskId: String(req.params.taskId),
|
||||
result: (body.result ?? {}) as Record<string, unknown>,
|
||||
source: body.source ? String(body.source) : "worker",
|
||||
idempotencyKey: body.idempotencyKey ? String(body.idempotencyKey) : undefined
|
||||
});
|
||||
ok(res, {
|
||||
ok: true,
|
||||
task
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.post(`${PREFIX}/tasks/:taskId/error`, (req, res, next) => {
|
||||
try {
|
||||
const body = (req.body ?? {}) as Record<string, unknown>;
|
||||
const task = runtime.failTask({
|
||||
taskId: String(req.params.taskId),
|
||||
error: {
|
||||
code: String(body.code ?? "TASK_ERROR"),
|
||||
message: String(body.message ?? "Task failed"),
|
||||
details: body.details
|
||||
},
|
||||
source: body.source ? String(body.source) : "worker",
|
||||
idempotencyKey: body.idempotencyKey ? String(body.idempotencyKey) : undefined
|
||||
});
|
||||
ok(res, {
|
||||
ok: true,
|
||||
task
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.get(`${PREFIX}/results`, (_req, res) => {
|
||||
ok(res, {
|
||||
ok: true,
|
||||
items: runtime.getResults()
|
||||
});
|
||||
});
|
||||
|
||||
router.get(`${PREFIX}/trace/run/:runId`, (req, res) => {
|
||||
ok(res, {
|
||||
ok: true,
|
||||
items: runtime.getRunTrace(String(req.params.runId))
|
||||
});
|
||||
});
|
||||
|
||||
router.get(`${PREFIX}/health`, (_req, res) => {
|
||||
ok(res, runtime.health());
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Router } from "express";
|
||||
import type { AppServices } from "../serverContext";
|
||||
import type { AssistantMessageRequestPayload } from "../types/assistant";
|
||||
import { ApiError, ok } from "../utils/http";
|
||||
|
||||
export function buildAssistantRouter(services: AppServices): Router {
|
||||
const router = Router();
|
||||
|
||||
router.post("/api/assistant/message", async (req, res, next) => {
|
||||
try {
|
||||
const payload = (req.body ?? {}) as Partial<AssistantMessageRequestPayload>;
|
||||
const userMessageSource =
|
||||
typeof payload.user_message === "string"
|
||||
? payload.user_message
|
||||
: typeof payload.message === "string"
|
||||
? payload.message
|
||||
: "";
|
||||
const userMessage = userMessageSource.trim();
|
||||
if (!userMessage) {
|
||||
throw new ApiError("INVALID_ASSISTANT_MESSAGE", "Field `user_message` or `message` is required.", 400);
|
||||
}
|
||||
|
||||
const response = await services.assistantService.handleMessage({
|
||||
...payload,
|
||||
user_message: userMessage,
|
||||
message: userMessage,
|
||||
mode: typeof payload.mode === "string" ? payload.mode : "assistant"
|
||||
});
|
||||
ok(res, response);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/api/assistant/session/:session_id", (req, res, next) => {
|
||||
try {
|
||||
const sessionId = String(req.params.session_id ?? "");
|
||||
const session = services.assistantService.getSession(sessionId);
|
||||
if (!session) {
|
||||
throw new ApiError("ASSISTANT_SESSION_NOT_FOUND", `Session not found: ${sessionId}`, 404);
|
||||
}
|
||||
ok(res, {
|
||||
ok: true,
|
||||
session
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Router } from "express";
|
||||
import type { AppServices } from "../serverContext";
|
||||
import { ok } from "../utils/http";
|
||||
import type { EvalRunMode, NormalizeRequestPayload } from "../types/normalizer";
|
||||
import type { EvalTarget } from "../types/assistantEval";
|
||||
|
||||
export function buildEvalRouter(services: AppServices): Router {
|
||||
const router = Router();
|
||||
|
||||
router.post("/api/eval/run", async (req, res, next) => {
|
||||
try {
|
||||
const body = (req.body ?? {}) as Record<string, unknown>;
|
||||
const report = await services.evalService.run({
|
||||
normalizeConfig: (body.normalizeConfig ?? {}) as Omit<NormalizeRequestPayload, "userQuestion" | "context">,
|
||||
caseIds: Array.isArray(body.caseIds) ? (body.caseIds as string[]) : undefined,
|
||||
useMock: Boolean(body.useMock),
|
||||
mode: (body.mode as EvalRunMode | undefined) ?? "standard",
|
||||
caseSetFile: typeof body.caseSetFile === "string" ? body.caseSetFile : undefined,
|
||||
rawQuestions: typeof body.rawQuestions === "string" ? body.rawQuestions : undefined,
|
||||
evalTarget: (body.eval_target as EvalTarget | undefined) ?? "normalizer",
|
||||
compareWithReportFile:
|
||||
typeof body.compare_with_report_file === "string"
|
||||
? body.compare_with_report_file
|
||||
: typeof body.comparisonBaselineReportFile === "string"
|
||||
? body.comparisonBaselineReportFile
|
||||
: undefined
|
||||
});
|
||||
ok(res, {
|
||||
ok: true,
|
||||
report
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Router } from "express";
|
||||
import { getTrace, listTraces } from "../services/traceLogger";
|
||||
import { ApiError, ok } from "../utils/http";
|
||||
|
||||
export function buildHistoryRouter(): Router {
|
||||
const router = Router();
|
||||
|
||||
router.get("/api/history", (_req, res) => {
|
||||
ok(res, {
|
||||
ok: true,
|
||||
items: listTraces(200)
|
||||
});
|
||||
});
|
||||
|
||||
router.get("/api/history/:trace_id", (req, res, next) => {
|
||||
try {
|
||||
const traceId = String(req.params.trace_id);
|
||||
const trace = getTrace(traceId);
|
||||
if (!trace) {
|
||||
throw new ApiError("TRACE_NOT_FOUND", `Trace not found: ${traceId}`, 404);
|
||||
}
|
||||
ok(res, {
|
||||
ok: true,
|
||||
trace
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Router } from "express";
|
||||
import { ok } from "../utils/http";
|
||||
import type { AppServices } from "../serverContext";
|
||||
import type { NormalizeRequestPayload } from "../types/normalizer";
|
||||
|
||||
export function buildNormalizeRouter(services: AppServices): Router {
|
||||
const router = Router();
|
||||
|
||||
router.post("/api/normalize", async (req, res, next) => {
|
||||
try {
|
||||
const payload = req.body as NormalizeRequestPayload;
|
||||
const result = await services.normalizerService.normalize(payload);
|
||||
ok(res, result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Router } from "express";
|
||||
import { nanoid } from "nanoid";
|
||||
import { DEFAULT_PROMPT_VERSION } from "../config";
|
||||
import { listBuiltinPromptPresets } from "../services/promptBuilder";
|
||||
import { listPresets, savePreset } from "../services/traceLogger";
|
||||
import type { PromptPreset } from "../types/preset";
|
||||
import { created, ok } from "../utils/http";
|
||||
|
||||
export function buildPresetsRouter(): Router {
|
||||
const router = Router();
|
||||
|
||||
router.get("/api/presets", (_req, res) => {
|
||||
const stored = listPresets();
|
||||
const builtin = listBuiltinPromptPresets();
|
||||
const combined = [...builtin, ...stored];
|
||||
ok(res, {
|
||||
ok: true,
|
||||
default_prompt_version: DEFAULT_PROMPT_VERSION,
|
||||
presets: combined
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/api/presets/save", (req, res, next) => {
|
||||
try {
|
||||
const body = (req.body ?? {}) as Partial<PromptPreset>;
|
||||
const now = new Date().toISOString();
|
||||
const preset: PromptPreset = {
|
||||
id: body.id ?? `preset-${nanoid(8)}`,
|
||||
name: body.name ?? "Пользовательский пресет",
|
||||
createdAt: body.createdAt ?? now,
|
||||
updatedAt: now,
|
||||
prompt_version: body.prompt_version ?? DEFAULT_PROMPT_VERSION,
|
||||
systemPrompt: body.systemPrompt ?? "",
|
||||
developerPrompt: body.developerPrompt ?? "",
|
||||
domainPrompt: body.domainPrompt ?? "",
|
||||
schemaNotes: body.schemaNotes ?? "",
|
||||
fewShotExamples: body.fewShotExamples ?? ""
|
||||
};
|
||||
savePreset(preset);
|
||||
created(res, {
|
||||
ok: true,
|
||||
preset
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Router } from "express";
|
||||
import { DEFAULT_MODEL, DEFAULT_OPENAI_BASE_URL } from "../config";
|
||||
import { OpenAIResponsesClient } from "../services/openaiResponsesClient";
|
||||
import { ok } from "../utils/http";
|
||||
|
||||
export function buildTestConnectionRouter(client: OpenAIResponsesClient): Router {
|
||||
const router = Router();
|
||||
|
||||
router.post("/api/openai/test-connection", async (req, res, next) => {
|
||||
try {
|
||||
const body = (req.body ?? {}) as Record<string, unknown>;
|
||||
const result = await client.testConnection({
|
||||
apiKey: String(body.apiKey ?? process.env.OPENAI_API_KEY ?? ""),
|
||||
model: String(body.model ?? DEFAULT_MODEL),
|
||||
baseUrl: String(body.baseUrl ?? DEFAULT_OPENAI_BASE_URL)
|
||||
});
|
||||
ok(res, {
|
||||
ok: true,
|
||||
model: result.model,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
Reference in New Issue
Block a user