"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InMemoryRuntimeAdapter = void 0; const nanoid_1 = require("nanoid"); const http_1 = require("../utils/http"); class InMemoryRuntimeAdapter { runs = []; tasks = []; traces = []; idempotencyCache = new Map(); now() { return new Date().toISOString(); } cacheKey(action, key) { if (!key || !key.trim()) return null; return `${action}:${key.trim()}`; } readIdempotency(action, idempotencyKey) { const cache = this.cacheKey(action, idempotencyKey); if (!cache) return null; return this.idempotencyCache.get(cache) ?? null; } writeIdempotency(action, idempotencyKey, value) { const cache = this.cacheKey(action, idempotencyKey); if (!cache) return; this.idempotencyCache.set(cache, value); } pushEvent(input) { this.traces.push({ timestamp: this.now(), level: input.level ?? "info", service: "llm_normalizer_backend", sessionId: input.sessionId, runId: input.runId, taskId: input.taskId ?? null, eventType: input.eventType, payload: input.payload }); } startRun(input) { const cached = this.readIdempotency("startRun", input.idempotencyKey); if (cached) return cached; const record = { sessionId: input.sessionId ?? `session_${(0, nanoid_1.nanoid)(8)}`, runId: `run_${(0, nanoid_1.nanoid)(10)}`, status: "RUNNING", initiator: input.initiator ?? "operator", source: input.source ?? "gui", createdAt: this.now(), updatedAt: this.now(), metadata: input.metadata ?? {} }; this.runs.unshift(record); this.pushEvent({ runId: record.runId, sessionId: record.sessionId, eventType: "RUN_STARTED", payload: record.metadata }); this.writeIdempotency("startRun", input.idempotencyKey, record); return record; } finishRun(input) { const cached = this.readIdempotency("finishRun", input.idempotencyKey); if (cached) return cached; const record = this.runs.find((item) => item.runId === input.runId); if (!record) { throw new http_1.ApiError("RUN_NOT_FOUND", `Run not found: ${input.runId}`, 404); } record.status = input.status; record.updatedAt = this.now(); record.source = input.source ?? record.source; record.metadata = { ...(record.metadata ?? {}), ...(input.metadata ?? {}), reason: input.reason ?? null }; this.pushEvent({ runId: record.runId, sessionId: record.sessionId, eventType: `RUN_FINISHED_${input.status}`, level: input.status === "ERROR" ? "error" : "info", payload: { reason: input.reason ?? null } }); this.writeIdempotency("finishRun", input.idempotencyKey, record); return record; } listRuns() { return [...this.runs]; } getRun(runId) { return this.runs.find((item) => item.runId === runId) ?? null; } enqueueTask(input) { const cached = this.readIdempotency("enqueueTask", input.idempotencyKey); if (cached) return cached; const run = this.getRun(input.runId); if (!run) { throw new http_1.ApiError("RUN_NOT_FOUND", `Run not found: ${input.runId}`, 404); } const task = { taskId: `task_${(0, nanoid_1.nanoid)(10)}`, runId: run.runId, status: "QUEUED", payload: input.payload, source: input.source ?? "gui", createdAt: this.now(), updatedAt: this.now() }; this.tasks.unshift(task); this.pushEvent({ runId: run.runId, sessionId: run.sessionId, taskId: task.taskId, eventType: "TASK_ENQUEUED", payload: task.payload }); this.writeIdempotency("enqueueTask", input.idempotencyKey, task); return task; } claimTask() { const task = this.tasks.find((item) => item.status === "QUEUED"); if (!task) { return null; } task.status = "RUNNING"; task.updatedAt = this.now(); const run = this.getRun(task.runId); if (run) { this.pushEvent({ runId: run.runId, sessionId: run.sessionId, taskId: task.taskId, eventType: "TASK_CLAIMED" }); } return task; } completeTask(input) { const cached = this.readIdempotency("completeTask", input.idempotencyKey); if (cached) return cached; const task = this.tasks.find((item) => item.taskId === input.taskId); if (!task) { throw new http_1.ApiError("TASK_NOT_FOUND", `Task not found: ${input.taskId}`, 404); } task.status = "DONE"; task.updatedAt = this.now(); task.result = input.result; task.source = input.source ?? task.source; const run = this.getRun(task.runId); if (run) { this.pushEvent({ runId: run.runId, sessionId: run.sessionId, taskId: task.taskId, eventType: "TASK_DONE", payload: input.result }); } this.writeIdempotency("completeTask", input.idempotencyKey, task); return task; } failTask(input) { const cached = this.readIdempotency("failTask", input.idempotencyKey); if (cached) return cached; const task = this.tasks.find((item) => item.taskId === input.taskId); if (!task) { throw new http_1.ApiError("TASK_NOT_FOUND", `Task not found: ${input.taskId}`, 404); } task.status = "ERROR"; task.updatedAt = this.now(); task.error = input.error; task.source = input.source ?? task.source; const run = this.getRun(task.runId); if (run) { this.pushEvent({ runId: run.runId, sessionId: run.sessionId, taskId: task.taskId, eventType: "TASK_ERROR", level: "error", payload: { errorCode: input.error.code, errorMessage: input.error.message } }); } this.writeIdempotency("failTask", input.idempotencyKey, task); return task; } getResults() { return this.tasks.filter((item) => item.status === "DONE" || item.status === "ERROR"); } getRunTrace(runId) { return this.traces.filter((item) => item.runId === runId); } health() { return { ok: true, queueDepth: this.tasks.filter((item) => item.status === "QUEUED").length, runsTotal: this.runs.length }; } } exports.InMemoryRuntimeAdapter = InMemoryRuntimeAdapter;