Initial import NDC_1C
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
"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;
|
||||
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
Reference in New Issue
Block a user