@hilbras/omninode 1.0.0 → 2.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/cli/index.js +257 -282
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +192 -36
- package/dist/index.js +284 -281
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// src/types/task.ts
|
|
2
|
+
var TERMINAL_TASK_STATUSES = [
|
|
3
|
+
"completed",
|
|
4
|
+
"failed",
|
|
5
|
+
"timed_out",
|
|
6
|
+
"cancelled",
|
|
7
|
+
"partially_completed"
|
|
8
|
+
];
|
|
9
|
+
|
|
1
10
|
// src/errors/index.ts
|
|
2
11
|
var OmniNodeError = class extends Error {
|
|
3
12
|
code;
|
|
@@ -804,7 +813,19 @@ var ProcessAgent = class {
|
|
|
804
813
|
new AgentError(
|
|
805
814
|
"AGENT_TIMEOUT",
|
|
806
815
|
`Agent "${this.config.name}" timed out after ${timeoutMs}ms and was killed.`,
|
|
807
|
-
{
|
|
816
|
+
{
|
|
817
|
+
details: {
|
|
818
|
+
operation: "agent.run",
|
|
819
|
+
agent: this.config.name,
|
|
820
|
+
durationMs: timeoutMs,
|
|
821
|
+
// The process was started and may have performed side
|
|
822
|
+
// effects before being killed — the outcome is unknown,
|
|
823
|
+
// not failed (roadmap §6.3).
|
|
824
|
+
dispatched: true,
|
|
825
|
+
stdout: stdout.slice(0, 4e3),
|
|
826
|
+
stderr: stderr.slice(0, 2e3)
|
|
827
|
+
}
|
|
828
|
+
}
|
|
808
829
|
)
|
|
809
830
|
);
|
|
810
831
|
return;
|
|
@@ -987,40 +1008,54 @@ function buildRoleRegistry(config) {
|
|
|
987
1008
|
return registry;
|
|
988
1009
|
}
|
|
989
1010
|
|
|
990
|
-
// src/
|
|
1011
|
+
// src/persistence/json-file-store.ts
|
|
991
1012
|
import { mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
992
1013
|
import { dirname } from "path";
|
|
993
|
-
var
|
|
1014
|
+
var JsonFileStore = class {
|
|
994
1015
|
filePath;
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
*/
|
|
1016
|
+
schemaVersion;
|
|
1017
|
+
onCorrupt;
|
|
1018
|
+
log;
|
|
999
1019
|
queue = Promise.resolve();
|
|
1000
|
-
constructor(
|
|
1001
|
-
this.filePath = `${directory}
|
|
1020
|
+
constructor(options) {
|
|
1021
|
+
this.filePath = `${options.directory ?? `${process.cwd()}/.omninode`}/${options.fileName}`;
|
|
1022
|
+
this.schemaVersion = options.schemaVersion ?? 1;
|
|
1023
|
+
this.onCorrupt = options.onCorrupt;
|
|
1024
|
+
this.log = logger.child({ component: "persistence", file: options.fileName });
|
|
1002
1025
|
}
|
|
1003
|
-
|
|
1004
|
-
return this.
|
|
1005
|
-
const tasks = await this.load();
|
|
1006
|
-
const index = tasks.findIndex((t) => t.id === task.id);
|
|
1007
|
-
if (index >= 0) tasks[index] = task;
|
|
1008
|
-
else tasks.push(task);
|
|
1009
|
-
await this.write(tasks);
|
|
1010
|
-
});
|
|
1026
|
+
get path() {
|
|
1027
|
+
return this.filePath;
|
|
1011
1028
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1029
|
+
/** All items, or [] when missing/corrupt. */
|
|
1030
|
+
async readAll() {
|
|
1031
|
+
let raw;
|
|
1032
|
+
try {
|
|
1033
|
+
raw = await readFile(this.filePath, "utf8");
|
|
1034
|
+
} catch {
|
|
1035
|
+
return [];
|
|
1036
|
+
}
|
|
1037
|
+
try {
|
|
1038
|
+
const parsed = JSON.parse(raw);
|
|
1039
|
+
if (Array.isArray(parsed)) return parsed;
|
|
1040
|
+
if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.items)) {
|
|
1041
|
+
return parsed.items;
|
|
1042
|
+
}
|
|
1043
|
+
throw new Error("persisted file has an unrecognized shape");
|
|
1044
|
+
} catch (error) {
|
|
1045
|
+
this.log.warn(`Treating ${this.filePath} as empty \u2014 it could not be parsed.`);
|
|
1046
|
+
this.onCorrupt?.(this.filePath, error);
|
|
1047
|
+
return [];
|
|
1048
|
+
}
|
|
1017
1049
|
}
|
|
1018
|
-
async
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
}
|
|
1050
|
+
async writeAll(items) {
|
|
1051
|
+
const document = { schemaVersion: this.schemaVersion, items };
|
|
1052
|
+
const tmp = `${this.filePath}.tmp`;
|
|
1053
|
+
await mkdir(dirname(this.filePath), { recursive: true });
|
|
1054
|
+
await writeFile(tmp, `${JSON.stringify(document, null, 2)}
|
|
1055
|
+
`, "utf8");
|
|
1056
|
+
await rename(tmp, this.filePath);
|
|
1023
1057
|
}
|
|
1058
|
+
/** Serializes an async operation against this file. */
|
|
1024
1059
|
synchronized(operation) {
|
|
1025
1060
|
const result = this.queue.then(operation, operation);
|
|
1026
1061
|
this.queue = result.then(
|
|
@@ -1029,21 +1064,37 @@ var FileTaskStore = class {
|
|
|
1029
1064
|
);
|
|
1030
1065
|
return result;
|
|
1031
1066
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
const
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
return
|
|
1039
|
-
}
|
|
1067
|
+
/** Read-modify-write helper: applies `mutate` to the current items. */
|
|
1068
|
+
async mutate(mutate) {
|
|
1069
|
+
return this.synchronized(async () => {
|
|
1070
|
+
const items = await this.readAll();
|
|
1071
|
+
const [next, result] = await mutate(items);
|
|
1072
|
+
await this.writeAll(next);
|
|
1073
|
+
return result;
|
|
1074
|
+
});
|
|
1040
1075
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1076
|
+
};
|
|
1077
|
+
|
|
1078
|
+
// src/tasks/store.ts
|
|
1079
|
+
var FileTaskStore = class extends JsonFileStore {
|
|
1080
|
+
constructor(directory) {
|
|
1081
|
+
super({ ...directory !== void 0 ? { directory } : {}, fileName: "tasks.json" });
|
|
1082
|
+
}
|
|
1083
|
+
save(task) {
|
|
1084
|
+
return this.mutate((tasks) => {
|
|
1085
|
+
const index = tasks.findIndex((t) => t.id === task.id);
|
|
1086
|
+
if (index >= 0) tasks[index] = task;
|
|
1087
|
+
else tasks.push(task);
|
|
1088
|
+
return [tasks, void 0];
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
async get(id) {
|
|
1092
|
+
const tasks = await this.readAll();
|
|
1093
|
+
return tasks.find((t) => t.id === id);
|
|
1094
|
+
}
|
|
1095
|
+
async list(filter = {}) {
|
|
1096
|
+
const tasks = await this.readAll();
|
|
1097
|
+
return tasks.filter((task) => filter.status ? task.status === filter.status : true).filter((task) => filter.project ? task.project === filter.project : true).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
1047
1098
|
}
|
|
1048
1099
|
};
|
|
1049
1100
|
|
|
@@ -1052,12 +1103,18 @@ import { randomBytes } from "crypto";
|
|
|
1052
1103
|
var ALLOWED_TRANSITIONS = {
|
|
1053
1104
|
created: ["queued", "running", "cancelled"],
|
|
1054
1105
|
queued: ["running", "cancelled"],
|
|
1055
|
-
running: ["completed", "failed", "cancelled"],
|
|
1106
|
+
running: ["completed", "failed", "timed_out", "unknown", "cancelled", "partially_completed"],
|
|
1056
1107
|
waiting: ["running", "cancelled"],
|
|
1057
1108
|
completed: [],
|
|
1058
|
-
failed:
|
|
1059
|
-
|
|
1109
|
+
// failed → running is the only re-entry: bounded automatic retry (§6.4).
|
|
1110
|
+
failed: ["running"],
|
|
1111
|
+
timed_out: [],
|
|
1112
|
+
cancelled: [],
|
|
1113
|
+
unknown: [],
|
|
1114
|
+
partially_completed: []
|
|
1060
1115
|
};
|
|
1116
|
+
var RETRYABLE_ERROR_CODES = ["AGENT_FAILED"];
|
|
1117
|
+
var EXECUTION_HISTORY_LIMIT = 10;
|
|
1061
1118
|
var TaskEngine = class {
|
|
1062
1119
|
constructor(options) {
|
|
1063
1120
|
this.options = options;
|
|
@@ -1089,6 +1146,7 @@ var TaskEngine = class {
|
|
|
1089
1146
|
id: generateTaskId(),
|
|
1090
1147
|
objective: input.objective.trim(),
|
|
1091
1148
|
status: "created",
|
|
1149
|
+
attempt: 0,
|
|
1092
1150
|
createdAt: now,
|
|
1093
1151
|
updatedAt: now,
|
|
1094
1152
|
...input.project !== void 0 ? { project: input.project } : {},
|
|
@@ -1105,8 +1163,10 @@ var TaskEngine = class {
|
|
|
1105
1163
|
const task = await this.mustGet(id);
|
|
1106
1164
|
return this.transition(task, "queued");
|
|
1107
1165
|
}
|
|
1108
|
-
/** Runs the task through its assigned agent and records the result.
|
|
1109
|
-
|
|
1166
|
+
/** Runs the task through its assigned agent and records the result.
|
|
1167
|
+
* `maxAttempts` enables bounded automatic retries of *retryable* errors
|
|
1168
|
+
* with linear backoff; unknown/timed_out outcomes are never auto-retried. */
|
|
1169
|
+
async run(id, options = {}) {
|
|
1110
1170
|
const task = await this.mustGet(id);
|
|
1111
1171
|
if (task.status !== "created" && task.status !== "queued") {
|
|
1112
1172
|
throw new TaskError("TASK_INVALID", `Task ${id} is "${task.status}" and cannot be run.`);
|
|
@@ -1119,49 +1179,84 @@ var TaskEngine = class {
|
|
|
1119
1179
|
throw new TaskError("TASK_INVALID", `Agent "${task.agent}" is not registered anymore.`);
|
|
1120
1180
|
}
|
|
1121
1181
|
const role = task.role ? this.options.roles.get(task.role) : void 0;
|
|
1122
|
-
const running = await this.transition(task, "running");
|
|
1123
1182
|
this.log.info(`Running task ${task.id} on agent "${task.agent}".`);
|
|
1124
|
-
let background =
|
|
1183
|
+
let background = task.context?.background;
|
|
1125
1184
|
if (this.options.memory) {
|
|
1126
1185
|
const memoryContext = await this.options.memory.gatherContext({
|
|
1127
|
-
objective:
|
|
1128
|
-
...
|
|
1129
|
-
...
|
|
1186
|
+
objective: task.objective,
|
|
1187
|
+
...task.role ? { role: task.role } : {},
|
|
1188
|
+
...task.project ? { project: task.project } : {}
|
|
1130
1189
|
});
|
|
1131
1190
|
if (memoryContext.length > 0) {
|
|
1132
1191
|
background = [memoryContext, background].filter((part) => part && part.length > 0).join("\n\n");
|
|
1133
1192
|
}
|
|
1134
1193
|
}
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
});
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1194
|
+
const maxAttempts = Math.max(1, options.maxAttempts ?? 1);
|
|
1195
|
+
const backoffMs = options.retryBackoffMs ?? 0;
|
|
1196
|
+
let current = task;
|
|
1197
|
+
for (let i = 0; i < maxAttempts; i += 1) {
|
|
1198
|
+
const attempt = current.attempt + 1;
|
|
1199
|
+
const executionId = `exec-${Date.now().toString(36)}-${randomBytes(3).toString("hex")}`;
|
|
1200
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1201
|
+
current = await this.transition(current, "running", { attempt });
|
|
1202
|
+
let output;
|
|
1203
|
+
let thrown;
|
|
1204
|
+
try {
|
|
1205
|
+
output = await agent.run({
|
|
1206
|
+
taskId: current.id,
|
|
1207
|
+
objective: current.objective,
|
|
1208
|
+
...role ? { role } : {},
|
|
1209
|
+
...background !== void 0 ? { context: background } : {}
|
|
1210
|
+
});
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
thrown = error;
|
|
1213
|
+
}
|
|
1214
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1215
|
+
if (thrown !== void 0 || output === void 0) {
|
|
1216
|
+
const outcome = classifyThrown(thrown);
|
|
1217
|
+
const message = thrown instanceof Error ? thrown.message : String(thrown);
|
|
1218
|
+
const retryable = outcome === "failed" && RETRYABLE_ERROR_CODES.includes(errorCode(thrown)) && i < maxAttempts - 1;
|
|
1219
|
+
current = await this.transition(current, outcome, {
|
|
1220
|
+
attempt,
|
|
1221
|
+
lastError: message,
|
|
1222
|
+
execution: {
|
|
1223
|
+
executionId,
|
|
1224
|
+
attempt,
|
|
1225
|
+
startedAt,
|
|
1226
|
+
finishedAt,
|
|
1227
|
+
outcome,
|
|
1228
|
+
error: message
|
|
1229
|
+
}
|
|
1230
|
+
});
|
|
1231
|
+
this.log.warn(`Task ${current.id} attempt ${attempt} \u2192 ${outcome}: ${message}`);
|
|
1232
|
+
if (retryable) {
|
|
1233
|
+
if (backoffMs > 0) await sleep(backoffMs * attempt);
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
if (this.options.memory) await this.options.memory.recordTaskOutcome(current);
|
|
1237
|
+
return current;
|
|
1238
|
+
}
|
|
1239
|
+
const result = {
|
|
1240
|
+
...output.summary !== void 0 ? { summary: output.summary } : {},
|
|
1241
|
+
...output.reports !== void 0 && output.reports.length > 0 ? { reports: output.reports } : {},
|
|
1242
|
+
// Keep the verbatim output (bounded) for report extraction and audit.
|
|
1243
|
+
...output.rawOutput !== void 0 && output.rawOutput.length > 0 ? { rawOutput: output.rawOutput.slice(0, 1e4) } : {},
|
|
1244
|
+
...output.error !== void 0 ? { error: output.error } : {},
|
|
1245
|
+
finishedAt
|
|
1246
|
+
};
|
|
1247
|
+
const finalStatus = output.status === "completed" ? "completed" : "failed";
|
|
1248
|
+
current = await this.transition(current, finalStatus, {
|
|
1249
|
+
attempt,
|
|
1250
|
+
result,
|
|
1251
|
+
execution: { executionId, attempt, startedAt, finishedAt, outcome: finalStatus }
|
|
1148
1252
|
});
|
|
1253
|
+
this.log.info(`Task ${current.id} finished: ${finalStatus}.`);
|
|
1254
|
+
break;
|
|
1149
1255
|
}
|
|
1150
|
-
const result = {
|
|
1151
|
-
...output.summary !== void 0 ? { summary: output.summary } : {},
|
|
1152
|
-
...output.reports !== void 0 && output.reports.length > 0 ? { reports: output.reports } : {},
|
|
1153
|
-
// Keep the verbatim output (bounded) for report extraction and audit.
|
|
1154
|
-
...output.rawOutput !== void 0 && output.rawOutput.length > 0 ? { rawOutput: output.rawOutput.slice(0, 1e4) } : {},
|
|
1155
|
-
...output.error !== void 0 ? { error: output.error } : {},
|
|
1156
|
-
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1157
|
-
};
|
|
1158
|
-
const finalStatus = output.status === "completed" ? "completed" : "failed";
|
|
1159
|
-
const finished = await this.transition(running, finalStatus, { result });
|
|
1160
|
-
this.log.info(`Task ${task.id} finished: ${finalStatus}.`);
|
|
1161
1256
|
if (this.options.memory) {
|
|
1162
|
-
await this.options.memory.recordTaskOutcome(
|
|
1257
|
+
await this.options.memory.recordTaskOutcome(current);
|
|
1163
1258
|
}
|
|
1164
|
-
return
|
|
1259
|
+
return current;
|
|
1165
1260
|
}
|
|
1166
1261
|
async cancel(id) {
|
|
1167
1262
|
const task = await this.mustGet(id);
|
|
@@ -1174,13 +1269,14 @@ var TaskEngine = class {
|
|
|
1174
1269
|
}
|
|
1175
1270
|
return this.transition(task, "cancelled");
|
|
1176
1271
|
}
|
|
1177
|
-
/** Error recovery
|
|
1272
|
+
/** Error recovery: reset a failed/cancelled/unknown/timed_out task so it can run again. */
|
|
1178
1273
|
async retry(id) {
|
|
1179
1274
|
const task = await this.mustGet(id);
|
|
1180
|
-
|
|
1275
|
+
const retryableStates = ["failed", "cancelled", "unknown", "timed_out"];
|
|
1276
|
+
if (!retryableStates.includes(task.status)) {
|
|
1181
1277
|
throw new TaskError(
|
|
1182
1278
|
"TASK_INVALID",
|
|
1183
|
-
`Only failed or cancelled tasks can be retried \u2014 task ${id} is "${task.status}".`
|
|
1279
|
+
`Only failed, timed out, unknown or cancelled tasks can be retried \u2014 task ${id} is "${task.status}".`
|
|
1184
1280
|
);
|
|
1185
1281
|
}
|
|
1186
1282
|
const { result: _discarded, ...rest } = task;
|
|
@@ -1212,10 +1308,14 @@ var TaskEngine = class {
|
|
|
1212
1308
|
if (!allowed.includes(to)) {
|
|
1213
1309
|
throw new TaskError("TASK_INVALID", `Task ${task.id} cannot move from "${task.status}" to "${to}".`);
|
|
1214
1310
|
}
|
|
1311
|
+
const executions = extra.execution ? [...task.executions ?? [], extra.execution].slice(-EXECUTION_HISTORY_LIMIT) : task.executions;
|
|
1215
1312
|
const updated = {
|
|
1216
1313
|
...task,
|
|
1217
1314
|
status: to,
|
|
1218
1315
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1316
|
+
...extra.attempt !== void 0 ? { attempt: extra.attempt } : {},
|
|
1317
|
+
...extra.lastError !== void 0 ? { lastError: extra.lastError } : {},
|
|
1318
|
+
...executions !== void 0 ? { executions } : {},
|
|
1219
1319
|
...extra.result !== void 0 ? { result: { ...task.result, ...extra.result } } : {}
|
|
1220
1320
|
};
|
|
1221
1321
|
await this.options.store.save(updated);
|
|
@@ -1236,6 +1336,19 @@ var TaskEngine = class {
|
|
|
1236
1336
|
function generateTaskId() {
|
|
1237
1337
|
return `task-${Date.now().toString(36)}-${randomBytes(3).toString("hex")}`;
|
|
1238
1338
|
}
|
|
1339
|
+
function errorCode(error) {
|
|
1340
|
+
return error?.code ?? "";
|
|
1341
|
+
}
|
|
1342
|
+
function classifyThrown(error) {
|
|
1343
|
+
if (error instanceof AgentError && error.code === "AGENT_TIMEOUT") {
|
|
1344
|
+
const dispatched = error.details?.dispatched;
|
|
1345
|
+
return dispatched === false ? "timed_out" : "unknown";
|
|
1346
|
+
}
|
|
1347
|
+
return "failed";
|
|
1348
|
+
}
|
|
1349
|
+
function sleep(ms) {
|
|
1350
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1351
|
+
}
|
|
1239
1352
|
|
|
1240
1353
|
// src/audit/index.ts
|
|
1241
1354
|
import { appendFile, mkdir as mkdir2 } from "fs/promises";
|
|
@@ -1260,10 +1373,10 @@ var FileAuditLog = class {
|
|
|
1260
1373
|
}
|
|
1261
1374
|
/** Recent events, oldest first; used by the CLI. */
|
|
1262
1375
|
async recent(limit = 20) {
|
|
1263
|
-
const { readFile:
|
|
1376
|
+
const { readFile: readFile2 } = await import("fs/promises");
|
|
1264
1377
|
let raw;
|
|
1265
1378
|
try {
|
|
1266
|
-
raw = await
|
|
1379
|
+
raw = await readFile2(this.filePath, "utf8");
|
|
1267
1380
|
} catch {
|
|
1268
1381
|
return [];
|
|
1269
1382
|
}
|
|
@@ -1279,8 +1392,6 @@ var FileAuditLog = class {
|
|
|
1279
1392
|
};
|
|
1280
1393
|
|
|
1281
1394
|
// src/memory/local.ts
|
|
1282
|
-
import { mkdir as mkdir3, readFile as readFile2, rename as rename2, writeFile as writeFile2 } from "fs/promises";
|
|
1283
|
-
import { dirname as dirname3 } from "path";
|
|
1284
1395
|
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
1285
1396
|
"the",
|
|
1286
1397
|
"and",
|
|
@@ -1337,29 +1448,24 @@ function relevanceScore(queryKeywords, entry) {
|
|
|
1337
1448
|
}
|
|
1338
1449
|
return overlap * 2 + tagMatches * 1.5;
|
|
1339
1450
|
}
|
|
1340
|
-
var LocalMemoryProvider = class {
|
|
1451
|
+
var LocalMemoryProvider = class extends JsonFileStore {
|
|
1341
1452
|
name = "local";
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
constructor(directory = `${process.cwd()}/.omninode`) {
|
|
1345
|
-
this.filePath = `${directory}/memory.json`;
|
|
1453
|
+
constructor(directory) {
|
|
1454
|
+
super({ ...directory !== void 0 ? { directory } : {}, fileName: "memory.json" });
|
|
1346
1455
|
}
|
|
1347
1456
|
async query(query) {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
return filtered.map((entry) => ({ entry, score: relevanceScore(queryKeywords, entry) })).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score).slice(0, query.limit ?? 10).map(({ entry }) => entry);
|
|
1358
|
-
});
|
|
1457
|
+
const entries = await this.readAll();
|
|
1458
|
+
const filtered = entries.filter((entry) => query.scope ? entry.scope === query.scope : true).filter(
|
|
1459
|
+
(entry) => query.tags && query.tags.length > 0 ? query.tags.every((tag) => (entry.tags ?? []).includes(tag)) : true
|
|
1460
|
+
);
|
|
1461
|
+
if (!query.text || query.text.trim().length === 0) {
|
|
1462
|
+
return filtered.sort((a, b) => (b.updatedAt ?? b.createdAt ?? "").localeCompare(a.updatedAt ?? a.createdAt ?? "")).slice(0, query.limit ?? 10);
|
|
1463
|
+
}
|
|
1464
|
+
const queryKeywords = keywords(query.text);
|
|
1465
|
+
return filtered.map((entry) => ({ entry, score: relevanceScore(queryKeywords, entry) })).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score).slice(0, query.limit ?? 10).map(({ entry }) => entry);
|
|
1359
1466
|
}
|
|
1360
|
-
|
|
1361
|
-
return this.
|
|
1362
|
-
const entries = await this.load();
|
|
1467
|
+
write(entry) {
|
|
1468
|
+
return this.mutate((entries) => {
|
|
1363
1469
|
const index = entries.findIndex((e) => e.key === entry.key);
|
|
1364
1470
|
const stamped = {
|
|
1365
1471
|
...entry,
|
|
@@ -1368,35 +1474,11 @@ var LocalMemoryProvider = class {
|
|
|
1368
1474
|
};
|
|
1369
1475
|
if (index >= 0) entries[index] = stamped;
|
|
1370
1476
|
else entries.push(stamped);
|
|
1371
|
-
|
|
1477
|
+
return [entries, void 0];
|
|
1372
1478
|
});
|
|
1373
1479
|
}
|
|
1374
1480
|
async count() {
|
|
1375
|
-
return (await this.
|
|
1376
|
-
}
|
|
1377
|
-
synchronized(operation) {
|
|
1378
|
-
const result = this.queue.then(operation, operation);
|
|
1379
|
-
this.queue = result.then(
|
|
1380
|
-
() => void 0,
|
|
1381
|
-
() => void 0
|
|
1382
|
-
);
|
|
1383
|
-
return result;
|
|
1384
|
-
}
|
|
1385
|
-
async load() {
|
|
1386
|
-
try {
|
|
1387
|
-
const raw = await readFile2(this.filePath, "utf8");
|
|
1388
|
-
const parsed = JSON.parse(raw);
|
|
1389
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
1390
|
-
} catch {
|
|
1391
|
-
return [];
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
async saveAll(entries) {
|
|
1395
|
-
const tmp = `${this.filePath}.tmp`;
|
|
1396
|
-
await mkdir3(dirname3(this.filePath), { recursive: true });
|
|
1397
|
-
await writeFile2(tmp, `${JSON.stringify(entries, null, 2)}
|
|
1398
|
-
`, "utf8");
|
|
1399
|
-
await rename2(tmp, this.filePath);
|
|
1481
|
+
return (await this.readAll()).length;
|
|
1400
1482
|
}
|
|
1401
1483
|
};
|
|
1402
1484
|
|
|
@@ -1975,7 +2057,7 @@ ${contribution}`);
|
|
|
1975
2057
|
}
|
|
1976
2058
|
const stepRun = {
|
|
1977
2059
|
stepId: step.id,
|
|
1978
|
-
status: outcome.status === "skipped" ? "cancelled" : outcome.status === "failed" ? "failed" : "completed",
|
|
2060
|
+
status: outcome.status === "skipped" ? "cancelled" : outcome.status === "failed" ? "failed" : outcome.status === "partial" ? "partially_completed" : "completed",
|
|
1979
2061
|
...outcome.taskIds.length > 0 ? { taskIds: outcome.taskIds } : {},
|
|
1980
2062
|
...outcome.planId !== void 0 ? { planId: outcome.planId } : {},
|
|
1981
2063
|
...outcome.error !== void 0 ? { error: outcome.error } : {}
|
|
@@ -1986,8 +2068,10 @@ ${contribution}`);
|
|
|
1986
2068
|
run.reports = [...allReports];
|
|
1987
2069
|
await this.options.store.save(run);
|
|
1988
2070
|
}
|
|
1989
|
-
const
|
|
1990
|
-
const
|
|
2071
|
+
const allOutcomes = [...outcomes.values()];
|
|
2072
|
+
const failed = allOutcomes.some((o) => o.status === "failed");
|
|
2073
|
+
const partial = !failed && allOutcomes.some((o) => o.status === "partial");
|
|
2074
|
+
const finalStatus = failed ? "failed" : partial ? "partial" : "completed";
|
|
1991
2075
|
const planId = [...outcomes.values()].find((o) => o.planId !== void 0)?.planId;
|
|
1992
2076
|
let resultSummary;
|
|
1993
2077
|
for (let i = def.steps.length - 1; i >= 0; i -= 1) {
|
|
@@ -2093,6 +2177,7 @@ ${contribution}`);
|
|
|
2093
2177
|
)
|
|
2094
2178
|
);
|
|
2095
2179
|
const results = await Promise.all(created.map((task) => this.options.tasks.run(task.id)));
|
|
2180
|
+
const completedTasks = results.filter((r) => r.status === "completed");
|
|
2096
2181
|
const failedTasks = results.filter((r) => r.status !== "completed");
|
|
2097
2182
|
const lines = results.map((result, index) => {
|
|
2098
2183
|
const agentName = agentNames[index] ?? "unknown";
|
|
@@ -2102,12 +2187,15 @@ ${contribution}`);
|
|
|
2102
2187
|
const reports = results.flatMap((r) => r.result?.reports ?? []);
|
|
2103
2188
|
const summary = lines.join("\n");
|
|
2104
2189
|
if (failedTasks.length > 0) {
|
|
2105
|
-
const firstError = failedTasks[0]?.result?.error ?? "unknown
|
|
2190
|
+
const firstError = failedTasks[0]?.result?.error ?? failedTasks[0]?.lastError ?? "unknown outcome";
|
|
2191
|
+
const states = failedTasks.map((r) => r.status).join(", ");
|
|
2106
2192
|
return {
|
|
2107
|
-
|
|
2193
|
+
// Some agents succeeded → the step produced usable but incomplete
|
|
2194
|
+
// intelligence: partial, not failed (roadmap §9.3).
|
|
2195
|
+
status: completedTasks.length > 0 ? "partial" : "failed",
|
|
2108
2196
|
summary,
|
|
2109
2197
|
taskIds: created.map((t) => t.id),
|
|
2110
|
-
error: `${failedTasks.length}/${results.length} task(s)
|
|
2198
|
+
error: `${failedTasks.length}/${results.length} task(s) incomplete (${states}) \u2014 ${firstError}`,
|
|
2111
2199
|
reports
|
|
2112
2200
|
};
|
|
2113
2201
|
}
|
|
@@ -2123,7 +2211,9 @@ ${contribution}`);
|
|
|
2123
2211
|
const result = await this.options.tasks.run(task.id);
|
|
2124
2212
|
if (result.status !== "completed") {
|
|
2125
2213
|
return {
|
|
2126
|
-
|
|
2214
|
+
// Unknown/timed_out outcomes are not failures — the work may have
|
|
2215
|
+
// happened remotely; the step is incomplete, not broken.
|
|
2216
|
+
status: result.status === "unknown" || result.status === "timed_out" ? "partial" : "failed",
|
|
2127
2217
|
summary: result.result?.summary ?? "",
|
|
2128
2218
|
taskIds: [task.id],
|
|
2129
2219
|
error: result.result?.error ?? `task ${task.id} did not complete`,
|
|
@@ -2239,114 +2329,44 @@ function createDefaultChatFn(providers) {
|
|
|
2239
2329
|
}
|
|
2240
2330
|
|
|
2241
2331
|
// src/pipelines/store.ts
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
filePath;
|
|
2246
|
-
queue = Promise.resolve();
|
|
2247
|
-
constructor(directory = `${process.cwd()}/.omninode`) {
|
|
2248
|
-
this.filePath = `${directory}/pipelines.json`;
|
|
2332
|
+
var FilePipelineRunStore = class extends JsonFileStore {
|
|
2333
|
+
constructor(directory) {
|
|
2334
|
+
super({ ...directory !== void 0 ? { directory } : {}, fileName: "pipelines.json" });
|
|
2249
2335
|
}
|
|
2250
|
-
|
|
2251
|
-
return this.
|
|
2252
|
-
const runs = await this.load();
|
|
2336
|
+
save(run) {
|
|
2337
|
+
return this.mutate((runs) => {
|
|
2253
2338
|
const index = runs.findIndex((r) => r.id === run.id);
|
|
2254
2339
|
if (index >= 0) runs[index] = run;
|
|
2255
2340
|
else runs.push(run);
|
|
2256
|
-
|
|
2341
|
+
return [runs, void 0];
|
|
2257
2342
|
});
|
|
2258
2343
|
}
|
|
2259
2344
|
async get(id) {
|
|
2260
|
-
return this.
|
|
2261
|
-
const runs = await this.load();
|
|
2262
|
-
return runs.find((r) => r.id === id);
|
|
2263
|
-
});
|
|
2345
|
+
return (await this.readAll()).find((r) => r.id === id);
|
|
2264
2346
|
}
|
|
2265
2347
|
async list(filter = {}) {
|
|
2266
|
-
return this.
|
|
2267
|
-
const runs = await this.load();
|
|
2268
|
-
return runs.filter((run) => filter.pipelineId ? run.pipelineId === filter.pipelineId : true).filter((run) => filter.status ? run.status === filter.status : true).sort((a, b) => (a.startedAt ?? "").localeCompare(b.startedAt ?? ""));
|
|
2269
|
-
});
|
|
2270
|
-
}
|
|
2271
|
-
synchronized(operation) {
|
|
2272
|
-
const result = this.queue.then(operation, operation);
|
|
2273
|
-
this.queue = result.then(
|
|
2274
|
-
() => void 0,
|
|
2275
|
-
() => void 0
|
|
2276
|
-
);
|
|
2277
|
-
return result;
|
|
2278
|
-
}
|
|
2279
|
-
async load() {
|
|
2280
|
-
try {
|
|
2281
|
-
const raw = await readFile3(this.filePath, "utf8");
|
|
2282
|
-
const parsed = JSON.parse(raw);
|
|
2283
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
2284
|
-
} catch {
|
|
2285
|
-
return [];
|
|
2286
|
-
}
|
|
2287
|
-
}
|
|
2288
|
-
async write(runs) {
|
|
2289
|
-
const tmp = `${this.filePath}.tmp`;
|
|
2290
|
-
await mkdir4(dirname4(this.filePath), { recursive: true });
|
|
2291
|
-
await writeFile3(tmp, `${JSON.stringify(runs, null, 2)}
|
|
2292
|
-
`, "utf8");
|
|
2293
|
-
await rename3(tmp, this.filePath);
|
|
2348
|
+
return (await this.readAll()).filter((run) => filter.pipelineId ? run.pipelineId === filter.pipelineId : true).filter((run) => filter.status ? run.status === filter.status : true).sort((a, b) => (a.startedAt ?? "").localeCompare(b.startedAt ?? ""));
|
|
2294
2349
|
}
|
|
2295
2350
|
};
|
|
2296
2351
|
|
|
2297
2352
|
// src/planner/store.ts
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
filePath;
|
|
2302
|
-
queue = Promise.resolve();
|
|
2303
|
-
constructor(directory = `${process.cwd()}/.omninode`) {
|
|
2304
|
-
this.filePath = `${directory}/plans.json`;
|
|
2353
|
+
var FilePlanStore = class extends JsonFileStore {
|
|
2354
|
+
constructor(directory) {
|
|
2355
|
+
super({ ...directory !== void 0 ? { directory } : {}, fileName: "plans.json" });
|
|
2305
2356
|
}
|
|
2306
|
-
|
|
2307
|
-
return this.
|
|
2308
|
-
const plans = await this.load();
|
|
2357
|
+
save(plan) {
|
|
2358
|
+
return this.mutate((plans) => {
|
|
2309
2359
|
const index = plans.findIndex((p) => p.id === plan.id);
|
|
2310
2360
|
if (index >= 0) plans[index] = plan;
|
|
2311
2361
|
else plans.push(plan);
|
|
2312
|
-
|
|
2362
|
+
return [plans, void 0];
|
|
2313
2363
|
});
|
|
2314
2364
|
}
|
|
2315
2365
|
async get(id) {
|
|
2316
|
-
return this.
|
|
2317
|
-
const plans = await this.load();
|
|
2318
|
-
return plans.find((p) => p.id === id);
|
|
2319
|
-
});
|
|
2366
|
+
return (await this.readAll()).find((p) => p.id === id);
|
|
2320
2367
|
}
|
|
2321
2368
|
async list(filter = {}) {
|
|
2322
|
-
return this.
|
|
2323
|
-
const plans = await this.load();
|
|
2324
|
-
return plans.filter((plan) => filter.pipelineRunId ? plan.pipelineRunId === filter.pipelineRunId : true).filter((plan) => filter.taskId ? plan.taskId === filter.taskId : true).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
2325
|
-
});
|
|
2326
|
-
}
|
|
2327
|
-
synchronized(operation) {
|
|
2328
|
-
const result = this.queue.then(operation, operation);
|
|
2329
|
-
this.queue = result.then(
|
|
2330
|
-
() => void 0,
|
|
2331
|
-
() => void 0
|
|
2332
|
-
);
|
|
2333
|
-
return result;
|
|
2334
|
-
}
|
|
2335
|
-
async load() {
|
|
2336
|
-
try {
|
|
2337
|
-
const raw = await readFile4(this.filePath, "utf8");
|
|
2338
|
-
const parsed = JSON.parse(raw);
|
|
2339
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
2340
|
-
} catch {
|
|
2341
|
-
return [];
|
|
2342
|
-
}
|
|
2343
|
-
}
|
|
2344
|
-
async write(plans) {
|
|
2345
|
-
const tmp = `${this.filePath}.tmp`;
|
|
2346
|
-
await mkdir5(dirname5(this.filePath), { recursive: true });
|
|
2347
|
-
await writeFile4(tmp, `${JSON.stringify(plans, null, 2)}
|
|
2348
|
-
`, "utf8");
|
|
2349
|
-
await rename4(tmp, this.filePath);
|
|
2369
|
+
return (await this.readAll()).filter((plan) => filter.pipelineRunId ? plan.pipelineRunId === filter.pipelineRunId : true).filter((plan) => filter.taskId ? plan.taskId === filter.taskId : true).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
2350
2370
|
}
|
|
2351
2371
|
};
|
|
2352
2372
|
|
|
@@ -2582,84 +2602,39 @@ var ReportService = class {
|
|
|
2582
2602
|
};
|
|
2583
2603
|
|
|
2584
2604
|
// src/reports/store.ts
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
filePath;
|
|
2589
|
-
queue = Promise.resolve();
|
|
2590
|
-
constructor(directory = `${process.cwd()}/.omninode`) {
|
|
2591
|
-
this.filePath = `${directory}/reports.json`;
|
|
2605
|
+
var FileReportStore = class extends JsonFileStore {
|
|
2606
|
+
constructor(directory) {
|
|
2607
|
+
super({ ...directory !== void 0 ? { directory } : {}, fileName: "reports.json" });
|
|
2592
2608
|
}
|
|
2593
2609
|
async saveReports(reports) {
|
|
2594
|
-
|
|
2595
|
-
const entries = await this.load();
|
|
2610
|
+
await this.mutate((entries) => {
|
|
2596
2611
|
for (const report of reports) {
|
|
2597
|
-
const index = entries.findIndex(
|
|
2598
|
-
(e) => e.kind === "report" && e.report.id === report.id
|
|
2599
|
-
);
|
|
2612
|
+
const index = entries.findIndex((e) => e.kind === "report" && e.report.id === report.id);
|
|
2600
2613
|
const entry = { kind: "report", report };
|
|
2601
2614
|
if (index >= 0) entries[index] = entry;
|
|
2602
2615
|
else entries.push(entry);
|
|
2603
2616
|
}
|
|
2604
|
-
|
|
2617
|
+
return [entries, void 0];
|
|
2605
2618
|
});
|
|
2606
2619
|
}
|
|
2607
2620
|
async listReports(filter = {}) {
|
|
2608
|
-
return this.
|
|
2609
|
-
const entries = await this.load();
|
|
2610
|
-
return entries.filter((e) => e.kind === "report").map((e) => e.report).filter((report) => filter.taskId ? report.taskId === filter.taskId : true).filter((report) => filter.agent ? report.agent === filter.agent : true).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
2611
|
-
});
|
|
2621
|
+
return (await this.readAll()).filter((e) => e.kind === "report").map((e) => e.report).filter((report) => filter.taskId ? report.taskId === filter.taskId : true).filter((report) => filter.agent ? report.agent === filter.agent : true).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
2612
2622
|
}
|
|
2613
2623
|
async saveCombined(combined) {
|
|
2614
|
-
|
|
2615
|
-
const
|
|
2616
|
-
const index = entries.findIndex(
|
|
2617
|
-
(e) => e.kind === "combined" && e.combined.id === combined.id
|
|
2618
|
-
);
|
|
2624
|
+
await this.mutate((entries) => {
|
|
2625
|
+
const index = entries.findIndex((e) => e.kind === "combined" && e.combined.id === combined.id);
|
|
2619
2626
|
const entry = { kind: "combined", combined };
|
|
2620
2627
|
if (index >= 0) entries[index] = entry;
|
|
2621
2628
|
else entries.push(entry);
|
|
2622
|
-
|
|
2629
|
+
return [entries, void 0];
|
|
2623
2630
|
});
|
|
2624
2631
|
}
|
|
2625
2632
|
async getCombined(id) {
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
const found = entries.find((e) => e.kind === "combined" && e.combined.id === id);
|
|
2629
|
-
return found?.kind === "combined" ? found.combined : void 0;
|
|
2630
|
-
});
|
|
2633
|
+
const found = (await this.readAll()).find((e) => e.kind === "combined" && e.combined.id === id);
|
|
2634
|
+
return found?.kind === "combined" ? found.combined : void 0;
|
|
2631
2635
|
}
|
|
2632
2636
|
async listCombined(filter = {}) {
|
|
2633
|
-
return this.
|
|
2634
|
-
const entries = await this.load();
|
|
2635
|
-
return entries.filter((e) => e.kind === "combined").map((e) => e.combined).filter(
|
|
2636
|
-
(combined) => filter.pipelineRunId ? combined.pipelineRunId === filter.pipelineRunId : true
|
|
2637
|
-
).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
2638
|
-
});
|
|
2639
|
-
}
|
|
2640
|
-
synchronized(operation) {
|
|
2641
|
-
const result = this.queue.then(operation, operation);
|
|
2642
|
-
this.queue = result.then(
|
|
2643
|
-
() => void 0,
|
|
2644
|
-
() => void 0
|
|
2645
|
-
);
|
|
2646
|
-
return result;
|
|
2647
|
-
}
|
|
2648
|
-
async load() {
|
|
2649
|
-
try {
|
|
2650
|
-
const raw = await readFile5(this.filePath, "utf8");
|
|
2651
|
-
const parsed = JSON.parse(raw);
|
|
2652
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
2653
|
-
} catch {
|
|
2654
|
-
return [];
|
|
2655
|
-
}
|
|
2656
|
-
}
|
|
2657
|
-
async write(entries) {
|
|
2658
|
-
const tmp = `${this.filePath}.tmp`;
|
|
2659
|
-
await mkdir6(dirname6(this.filePath), { recursive: true });
|
|
2660
|
-
await writeFile5(tmp, `${JSON.stringify(entries, null, 2)}
|
|
2661
|
-
`, "utf8");
|
|
2662
|
-
await rename5(tmp, this.filePath);
|
|
2637
|
+
return (await this.readAll()).filter((e) => e.kind === "combined").map((e) => e.combined).filter((combined) => filter.pipelineRunId ? combined.pipelineRunId === filter.pipelineRunId : true).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
2663
2638
|
}
|
|
2664
2639
|
};
|
|
2665
2640
|
|
|
@@ -2691,8 +2666,26 @@ function buildPipelineEngine(config, log = logger) {
|
|
|
2691
2666
|
});
|
|
2692
2667
|
}
|
|
2693
2668
|
|
|
2669
|
+
// src/persistence/index.ts
|
|
2670
|
+
var ProjectStores = class {
|
|
2671
|
+
tasks;
|
|
2672
|
+
pipelineRuns;
|
|
2673
|
+
reports;
|
|
2674
|
+
plans;
|
|
2675
|
+
memory;
|
|
2676
|
+
audit;
|
|
2677
|
+
constructor(directory = `${process.cwd()}/.omninode`) {
|
|
2678
|
+
this.tasks = new FileTaskStore(directory);
|
|
2679
|
+
this.pipelineRuns = new FilePipelineRunStore(directory);
|
|
2680
|
+
this.reports = new FileReportStore(directory);
|
|
2681
|
+
this.plans = new FilePlanStore(directory);
|
|
2682
|
+
this.memory = new LocalMemoryProvider(directory);
|
|
2683
|
+
this.audit = new FileAuditLog(directory);
|
|
2684
|
+
}
|
|
2685
|
+
};
|
|
2686
|
+
|
|
2694
2687
|
// src/version.ts
|
|
2695
|
-
var OMNINODE_VERSION = "
|
|
2688
|
+
var OMNINODE_VERSION = "2.0.0-alpha.2";
|
|
2696
2689
|
export {
|
|
2697
2690
|
AgentError,
|
|
2698
2691
|
AgentRegistry,
|
|
@@ -2700,12 +2693,16 @@ export {
|
|
|
2700
2693
|
ConsoleLogSink,
|
|
2701
2694
|
FileAuditLog,
|
|
2702
2695
|
FilePipelineRunStore,
|
|
2696
|
+
FilePlanStore,
|
|
2703
2697
|
FileReportStore,
|
|
2704
2698
|
FileTaskStore,
|
|
2699
|
+
HeuristicPlanner,
|
|
2700
|
+
JsonFileStore,
|
|
2705
2701
|
LocalMemoryProvider,
|
|
2706
2702
|
Logger,
|
|
2707
2703
|
MemoryError,
|
|
2708
2704
|
MemoryService,
|
|
2705
|
+
ModelPlanner,
|
|
2709
2706
|
ModelRegistry,
|
|
2710
2707
|
OMNINODE_VERSION,
|
|
2711
2708
|
OPENAI_COMPATIBLE_TYPES,
|
|
@@ -2716,11 +2713,13 @@ export {
|
|
|
2716
2713
|
PipelineError,
|
|
2717
2714
|
PlannerError,
|
|
2718
2715
|
ProcessAgent,
|
|
2716
|
+
ProjectStores,
|
|
2719
2717
|
ProtocolError,
|
|
2720
2718
|
ProviderError,
|
|
2721
2719
|
RememberaMemoryProvider,
|
|
2722
2720
|
ReportService,
|
|
2723
2721
|
RoleRegistry,
|
|
2722
|
+
TERMINAL_TASK_STATUSES,
|
|
2724
2723
|
TaskEngine,
|
|
2725
2724
|
TaskError,
|
|
2726
2725
|
agentConfigSchema,
|
|
@@ -2728,7 +2727,10 @@ export {
|
|
|
2728
2727
|
appConfigSchema,
|
|
2729
2728
|
authHeaders,
|
|
2730
2729
|
buildAgentRegistry,
|
|
2730
|
+
buildChildEnv,
|
|
2731
2731
|
buildPipelineEngine,
|
|
2732
|
+
buildPlanner,
|
|
2733
|
+
buildPlannerContext,
|
|
2732
2734
|
buildRoleRegistry,
|
|
2733
2735
|
composeTaskText,
|
|
2734
2736
|
createAgent,
|
|
@@ -2744,6 +2746,7 @@ export {
|
|
|
2744
2746
|
keywords,
|
|
2745
2747
|
loadConfig,
|
|
2746
2748
|
logger,
|
|
2749
|
+
parsePlanJson,
|
|
2747
2750
|
pipelineConfigSchema,
|
|
2748
2751
|
pipelineStepConfigSchema,
|
|
2749
2752
|
plannerConfigSchema,
|