@hilbras/omninode 2.0.0-alpha.1 → 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 +1 -1
- package/dist/cli/index.js +140 -49
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +46 -7
- package/dist/index.js +140 -48
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -229,7 +229,27 @@ interface ModelInfo {
|
|
|
229
229
|
|
|
230
230
|
/** Task system: every operation becomes a Task (§13). */
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
/**
|
|
233
|
+
* Execution states (v2 Phase 2, roadmap §6.1).
|
|
234
|
+
*
|
|
235
|
+
* The crucial distinction: `unknown` means "we cannot prove the outcome" —
|
|
236
|
+
* e.g. a process timeout after the agent may already have performed side
|
|
237
|
+
* effects. It is deliberately NOT `failed`: retrying blindly could duplicate
|
|
238
|
+
* work, and reporting failure would be a lie. Resolve it explicitly with
|
|
239
|
+
* `task retry` (which starts a fresh execution) or by inspecting artifacts.
|
|
240
|
+
*/
|
|
241
|
+
type TaskStatus = "created" | "queued" | "running" | "waiting" | "completed" | "failed" | "timed_out" | "cancelled" | "unknown" | "partially_completed";
|
|
242
|
+
/** States from which no further automatic transition happens. */
|
|
243
|
+
declare const TERMINAL_TASK_STATUSES: readonly TaskStatus[];
|
|
244
|
+
/** One execution attempt (roadmap §6.5 identity: task + attempt + execution id). */
|
|
245
|
+
interface ExecutionRecord {
|
|
246
|
+
executionId: string;
|
|
247
|
+
attempt: number;
|
|
248
|
+
startedAt: string;
|
|
249
|
+
finishedAt: string;
|
|
250
|
+
outcome: "completed" | "failed" | "timed_out" | "unknown" | "cancelled";
|
|
251
|
+
error?: string;
|
|
252
|
+
}
|
|
233
253
|
interface TaskContext {
|
|
234
254
|
project?: string;
|
|
235
255
|
/** Paths or globs relevant to the task. */
|
|
@@ -262,6 +282,12 @@ interface Task {
|
|
|
262
282
|
status: TaskStatus;
|
|
263
283
|
createdAt: string;
|
|
264
284
|
updatedAt: string;
|
|
285
|
+
/** Number of engine.run attempts so far (0 = never executed). */
|
|
286
|
+
attempt: number;
|
|
287
|
+
/** Error from the most recent failed/unknown attempt. */
|
|
288
|
+
lastError?: string;
|
|
289
|
+
/** Recent execution attempts, newest last, bounded in length. */
|
|
290
|
+
executions?: ExecutionRecord[];
|
|
265
291
|
result?: TaskResult;
|
|
266
292
|
}
|
|
267
293
|
|
|
@@ -292,7 +318,12 @@ interface PipelineDefinition {
|
|
|
292
318
|
role?: string;
|
|
293
319
|
steps: PipelineStep[];
|
|
294
320
|
}
|
|
295
|
-
|
|
321
|
+
/**
|
|
322
|
+
* Run status. "partial" means the run finished but some step outcome was
|
|
323
|
+
* incomplete or unprovable (partial fan-out, unknown task state) — the
|
|
324
|
+
* authoritative detail always lives in `stepRuns`/`taskRuns`.
|
|
325
|
+
*/
|
|
326
|
+
type PipelineRunStatus = "pending" | "running" | "completed" | "failed" | "partial" | "cancelled";
|
|
296
327
|
interface PipelineStepRun {
|
|
297
328
|
stepId: string;
|
|
298
329
|
status: TaskStatus;
|
|
@@ -1823,6 +1854,12 @@ interface CreateTaskInput {
|
|
|
1823
1854
|
agent?: string;
|
|
1824
1855
|
context?: TaskContext;
|
|
1825
1856
|
}
|
|
1857
|
+
interface RunTaskOptions {
|
|
1858
|
+
/** Total attempts (1 = no automatic retry). Retries apply to retryable errors only. */
|
|
1859
|
+
maxAttempts?: number;
|
|
1860
|
+
/** Linear backoff base in ms: waits backoffMs × attempt between attempts. */
|
|
1861
|
+
retryBackoffMs?: number;
|
|
1862
|
+
}
|
|
1826
1863
|
interface TaskEngineOptions {
|
|
1827
1864
|
agents: AgentRegistry;
|
|
1828
1865
|
roles: RoleRegistry;
|
|
@@ -1840,10 +1877,12 @@ declare class TaskEngine {
|
|
|
1840
1877
|
get store(): TaskStore;
|
|
1841
1878
|
create(input: CreateTaskInput): Promise<Task>;
|
|
1842
1879
|
queue(id: string): Promise<Task>;
|
|
1843
|
-
/** Runs the task through its assigned agent and records the result.
|
|
1844
|
-
|
|
1880
|
+
/** Runs the task through its assigned agent and records the result.
|
|
1881
|
+
* `maxAttempts` enables bounded automatic retries of *retryable* errors
|
|
1882
|
+
* with linear backoff; unknown/timed_out outcomes are never auto-retried. */
|
|
1883
|
+
run(id: string, options?: RunTaskOptions): Promise<Task>;
|
|
1845
1884
|
cancel(id: string): Promise<Task>;
|
|
1846
|
-
/** Error recovery
|
|
1885
|
+
/** Error recovery: reset a failed/cancelled/unknown/timed_out task so it can run again. */
|
|
1847
1886
|
retry(id: string): Promise<Task>;
|
|
1848
1887
|
get(id: string): Promise<Task | undefined>;
|
|
1849
1888
|
list(filter?: TaskStoreFilter): Promise<Task[]>;
|
|
@@ -2111,6 +2150,6 @@ declare class ProjectStores {
|
|
|
2111
2150
|
constructor(directory?: string);
|
|
2112
2151
|
}
|
|
2113
2152
|
|
|
2114
|
-
declare const OMNINODE_VERSION = "2.0.0-alpha.
|
|
2153
|
+
declare const OMNINODE_VERSION = "2.0.0-alpha.2";
|
|
2115
2154
|
|
|
2116
|
-
export { type AgentConfig, type AgentConfigYaml, AgentError, type AgentInfo, type AgentInputMode, type AgentIntegrationType, AgentRegistry, type AgentStatus, type AgentTaskInput, type AgentTaskOutput, type AgentToNodeMessage, type AggregateOptions, type AggregatedFinding, type AggregatedRecommendation, type AppConfig, type AppConfigYaml, type AuditAction, type AuditEvent, type AuditSink, type ChatFn, type ChatMessage, type ChatRequest, type ChatResponse, type ChatRole, type ChatUsage, type CombinedMeta, type CombinedReport, type CombinedReportFilter, type Confidence, ConfigError, ConsoleLogSink, type CreateTaskInput, type DiscoveryResult, type EnvelopeMeta, type ExtractionMeta, FileAuditLog, FilePipelineRunStore, FilePlanStore, FileReportStore, FileTaskStore, type Finding, type FindingSeverity, type FindingSource, HeuristicPlanner, type HttpRequestOptions, type HttpResponse, type IAgent, type IChatProvider, type IMemoryProvider, type IPlanner, type IProvider, type JsonDocument, JsonFileStore, type JsonFileStoreOptions, type LoadConfigOptions, LocalMemoryProvider, type LogLevel, type LogSink, Logger, type LoggerOptions, type MemoryContextQuery, type MemoryEntry, MemoryError, type MemoryProviderConfig, type MemoryQuery, type MemoryScope, MemoryService, type MessageEnvelope, type ModelCapabilities, type ModelFilter, type ModelInfo, ModelPlanner, ModelRegistry, type ModelStatus, type NodeToAgentMessage, OMNINODE_VERSION, OPENAI_COMPATIBLE_TYPES, type OmniHilbrasConnectionResult, OmniHilbrasProvider, OmniNodeError, type OmniNodeErrorCode, type OmniNodeErrorOptions, OpenAICompatibleProvider, type PipelineConfigYaml, type PipelineDefinition, PipelineEngine, type PipelineEngineOptions, PipelineError, type PipelineRun, type PipelineRunFilter, type PipelineRunStatus, type PipelineRunStore, type PipelineStep, type PipelineStepCondition, type PipelineStepConfigYaml, type PipelineStepKind, type PipelineStepRun, type Plan, type PlanFilter, type PlanRequest, type PlanStep, type PlanStore, type PlannerConfigYaml, PlannerError, ProcessAgent, type Project, type ProjectConfigYaml, ProjectStores, ProtocolError, type ProviderConfig, type ProviderConfigYaml, ProviderError, type ProviderHealth, type ProviderStatus, type ProviderType, type RememberaConfig, RememberaMemoryProvider, type Report, type ReportFilter, ReportService, type ReportStore, type RoleConfigYaml, type RoleDefinition, RoleRegistry, type RunPipelineOptions, type Task, type TaskContext, TaskEngine, type TaskEngineOptions, TaskError, type TaskResult, type TaskStatus, type TaskStore, type TaskStoreFilter, type WritableLike, agentConfigSchema, aggregateReports, appConfigSchema, authHeaders, buildAgentRegistry, buildChildEnv, buildPipelineEngine, buildPlanner, buildPlannerContext, buildRoleRegistry, composeTaskText, createAgent, createDefaultChatFn, createMemoryProvider, createProvider, createTaskEngine, defaultProjectConfigYaml, expandEnvRefs, extractReportFromText, findConfigFile, isOmniNodeError, keywords, loadConfig, logger, parsePlanJson, pipelineConfigSchema, pipelineStepConfigSchema, plannerConfigSchema, projectConfigSchema, providerConfigSchema, registryKey, requestJson, resolveApiKey, roleConfigSchema, similar };
|
|
2155
|
+
export { type AgentConfig, type AgentConfigYaml, AgentError, type AgentInfo, type AgentInputMode, type AgentIntegrationType, AgentRegistry, type AgentStatus, type AgentTaskInput, type AgentTaskOutput, type AgentToNodeMessage, type AggregateOptions, type AggregatedFinding, type AggregatedRecommendation, type AppConfig, type AppConfigYaml, type AuditAction, type AuditEvent, type AuditSink, type ChatFn, type ChatMessage, type ChatRequest, type ChatResponse, type ChatRole, type ChatUsage, type CombinedMeta, type CombinedReport, type CombinedReportFilter, type Confidence, ConfigError, ConsoleLogSink, type CreateTaskInput, type DiscoveryResult, type EnvelopeMeta, type ExecutionRecord, type ExtractionMeta, FileAuditLog, FilePipelineRunStore, FilePlanStore, FileReportStore, FileTaskStore, type Finding, type FindingSeverity, type FindingSource, HeuristicPlanner, type HttpRequestOptions, type HttpResponse, type IAgent, type IChatProvider, type IMemoryProvider, type IPlanner, type IProvider, type JsonDocument, JsonFileStore, type JsonFileStoreOptions, type LoadConfigOptions, LocalMemoryProvider, type LogLevel, type LogSink, Logger, type LoggerOptions, type MemoryContextQuery, type MemoryEntry, MemoryError, type MemoryProviderConfig, type MemoryQuery, type MemoryScope, MemoryService, type MessageEnvelope, type ModelCapabilities, type ModelFilter, type ModelInfo, ModelPlanner, ModelRegistry, type ModelStatus, type NodeToAgentMessage, OMNINODE_VERSION, OPENAI_COMPATIBLE_TYPES, type OmniHilbrasConnectionResult, OmniHilbrasProvider, OmniNodeError, type OmniNodeErrorCode, type OmniNodeErrorOptions, OpenAICompatibleProvider, type PipelineConfigYaml, type PipelineDefinition, PipelineEngine, type PipelineEngineOptions, PipelineError, type PipelineRun, type PipelineRunFilter, type PipelineRunStatus, type PipelineRunStore, type PipelineStep, type PipelineStepCondition, type PipelineStepConfigYaml, type PipelineStepKind, type PipelineStepRun, type Plan, type PlanFilter, type PlanRequest, type PlanStep, type PlanStore, type PlannerConfigYaml, PlannerError, ProcessAgent, type Project, type ProjectConfigYaml, ProjectStores, ProtocolError, type ProviderConfig, type ProviderConfigYaml, ProviderError, type ProviderHealth, type ProviderStatus, type ProviderType, type RememberaConfig, RememberaMemoryProvider, type Report, type ReportFilter, ReportService, type ReportStore, type RoleConfigYaml, type RoleDefinition, RoleRegistry, type RunPipelineOptions, TERMINAL_TASK_STATUSES, type Task, type TaskContext, TaskEngine, type TaskEngineOptions, TaskError, type TaskResult, type TaskStatus, type TaskStore, type TaskStoreFilter, type WritableLike, agentConfigSchema, aggregateReports, appConfigSchema, authHeaders, buildAgentRegistry, buildChildEnv, buildPipelineEngine, buildPlanner, buildPlannerContext, buildRoleRegistry, composeTaskText, createAgent, createDefaultChatFn, createMemoryProvider, createProvider, createTaskEngine, defaultProjectConfigYaml, expandEnvRefs, extractReportFromText, findConfigFile, isOmniNodeError, keywords, loadConfig, logger, parsePlanJson, pipelineConfigSchema, pipelineStepConfigSchema, plannerConfigSchema, projectConfigSchema, providerConfigSchema, registryKey, requestJson, resolveApiKey, roleConfigSchema, similar };
|
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;
|
|
@@ -1082,12 +1103,18 @@ import { randomBytes } from "crypto";
|
|
|
1082
1103
|
var ALLOWED_TRANSITIONS = {
|
|
1083
1104
|
created: ["queued", "running", "cancelled"],
|
|
1084
1105
|
queued: ["running", "cancelled"],
|
|
1085
|
-
running: ["completed", "failed", "cancelled"],
|
|
1106
|
+
running: ["completed", "failed", "timed_out", "unknown", "cancelled", "partially_completed"],
|
|
1086
1107
|
waiting: ["running", "cancelled"],
|
|
1087
1108
|
completed: [],
|
|
1088
|
-
failed:
|
|
1089
|
-
|
|
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: []
|
|
1090
1115
|
};
|
|
1116
|
+
var RETRYABLE_ERROR_CODES = ["AGENT_FAILED"];
|
|
1117
|
+
var EXECUTION_HISTORY_LIMIT = 10;
|
|
1091
1118
|
var TaskEngine = class {
|
|
1092
1119
|
constructor(options) {
|
|
1093
1120
|
this.options = options;
|
|
@@ -1119,6 +1146,7 @@ var TaskEngine = class {
|
|
|
1119
1146
|
id: generateTaskId(),
|
|
1120
1147
|
objective: input.objective.trim(),
|
|
1121
1148
|
status: "created",
|
|
1149
|
+
attempt: 0,
|
|
1122
1150
|
createdAt: now,
|
|
1123
1151
|
updatedAt: now,
|
|
1124
1152
|
...input.project !== void 0 ? { project: input.project } : {},
|
|
@@ -1135,8 +1163,10 @@ var TaskEngine = class {
|
|
|
1135
1163
|
const task = await this.mustGet(id);
|
|
1136
1164
|
return this.transition(task, "queued");
|
|
1137
1165
|
}
|
|
1138
|
-
/** Runs the task through its assigned agent and records the result.
|
|
1139
|
-
|
|
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 = {}) {
|
|
1140
1170
|
const task = await this.mustGet(id);
|
|
1141
1171
|
if (task.status !== "created" && task.status !== "queued") {
|
|
1142
1172
|
throw new TaskError("TASK_INVALID", `Task ${id} is "${task.status}" and cannot be run.`);
|
|
@@ -1149,49 +1179,84 @@ var TaskEngine = class {
|
|
|
1149
1179
|
throw new TaskError("TASK_INVALID", `Agent "${task.agent}" is not registered anymore.`);
|
|
1150
1180
|
}
|
|
1151
1181
|
const role = task.role ? this.options.roles.get(task.role) : void 0;
|
|
1152
|
-
const running = await this.transition(task, "running");
|
|
1153
1182
|
this.log.info(`Running task ${task.id} on agent "${task.agent}".`);
|
|
1154
|
-
let background =
|
|
1183
|
+
let background = task.context?.background;
|
|
1155
1184
|
if (this.options.memory) {
|
|
1156
1185
|
const memoryContext = await this.options.memory.gatherContext({
|
|
1157
|
-
objective:
|
|
1158
|
-
...
|
|
1159
|
-
...
|
|
1186
|
+
objective: task.objective,
|
|
1187
|
+
...task.role ? { role: task.role } : {},
|
|
1188
|
+
...task.project ? { project: task.project } : {}
|
|
1160
1189
|
});
|
|
1161
1190
|
if (memoryContext.length > 0) {
|
|
1162
1191
|
background = [memoryContext, background].filter((part) => part && part.length > 0).join("\n\n");
|
|
1163
1192
|
}
|
|
1164
1193
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
});
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
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 }
|
|
1178
1252
|
});
|
|
1253
|
+
this.log.info(`Task ${current.id} finished: ${finalStatus}.`);
|
|
1254
|
+
break;
|
|
1179
1255
|
}
|
|
1180
|
-
const result = {
|
|
1181
|
-
...output.summary !== void 0 ? { summary: output.summary } : {},
|
|
1182
|
-
...output.reports !== void 0 && output.reports.length > 0 ? { reports: output.reports } : {},
|
|
1183
|
-
// Keep the verbatim output (bounded) for report extraction and audit.
|
|
1184
|
-
...output.rawOutput !== void 0 && output.rawOutput.length > 0 ? { rawOutput: output.rawOutput.slice(0, 1e4) } : {},
|
|
1185
|
-
...output.error !== void 0 ? { error: output.error } : {},
|
|
1186
|
-
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1187
|
-
};
|
|
1188
|
-
const finalStatus = output.status === "completed" ? "completed" : "failed";
|
|
1189
|
-
const finished = await this.transition(running, finalStatus, { result });
|
|
1190
|
-
this.log.info(`Task ${task.id} finished: ${finalStatus}.`);
|
|
1191
1256
|
if (this.options.memory) {
|
|
1192
|
-
await this.options.memory.recordTaskOutcome(
|
|
1257
|
+
await this.options.memory.recordTaskOutcome(current);
|
|
1193
1258
|
}
|
|
1194
|
-
return
|
|
1259
|
+
return current;
|
|
1195
1260
|
}
|
|
1196
1261
|
async cancel(id) {
|
|
1197
1262
|
const task = await this.mustGet(id);
|
|
@@ -1204,13 +1269,14 @@ var TaskEngine = class {
|
|
|
1204
1269
|
}
|
|
1205
1270
|
return this.transition(task, "cancelled");
|
|
1206
1271
|
}
|
|
1207
|
-
/** Error recovery
|
|
1272
|
+
/** Error recovery: reset a failed/cancelled/unknown/timed_out task so it can run again. */
|
|
1208
1273
|
async retry(id) {
|
|
1209
1274
|
const task = await this.mustGet(id);
|
|
1210
|
-
|
|
1275
|
+
const retryableStates = ["failed", "cancelled", "unknown", "timed_out"];
|
|
1276
|
+
if (!retryableStates.includes(task.status)) {
|
|
1211
1277
|
throw new TaskError(
|
|
1212
1278
|
"TASK_INVALID",
|
|
1213
|
-
`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}".`
|
|
1214
1280
|
);
|
|
1215
1281
|
}
|
|
1216
1282
|
const { result: _discarded, ...rest } = task;
|
|
@@ -1242,10 +1308,14 @@ var TaskEngine = class {
|
|
|
1242
1308
|
if (!allowed.includes(to)) {
|
|
1243
1309
|
throw new TaskError("TASK_INVALID", `Task ${task.id} cannot move from "${task.status}" to "${to}".`);
|
|
1244
1310
|
}
|
|
1311
|
+
const executions = extra.execution ? [...task.executions ?? [], extra.execution].slice(-EXECUTION_HISTORY_LIMIT) : task.executions;
|
|
1245
1312
|
const updated = {
|
|
1246
1313
|
...task,
|
|
1247
1314
|
status: to,
|
|
1248
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 } : {},
|
|
1249
1319
|
...extra.result !== void 0 ? { result: { ...task.result, ...extra.result } } : {}
|
|
1250
1320
|
};
|
|
1251
1321
|
await this.options.store.save(updated);
|
|
@@ -1266,6 +1336,19 @@ var TaskEngine = class {
|
|
|
1266
1336
|
function generateTaskId() {
|
|
1267
1337
|
return `task-${Date.now().toString(36)}-${randomBytes(3).toString("hex")}`;
|
|
1268
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
|
+
}
|
|
1269
1352
|
|
|
1270
1353
|
// src/audit/index.ts
|
|
1271
1354
|
import { appendFile, mkdir as mkdir2 } from "fs/promises";
|
|
@@ -1974,7 +2057,7 @@ ${contribution}`);
|
|
|
1974
2057
|
}
|
|
1975
2058
|
const stepRun = {
|
|
1976
2059
|
stepId: step.id,
|
|
1977
|
-
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",
|
|
1978
2061
|
...outcome.taskIds.length > 0 ? { taskIds: outcome.taskIds } : {},
|
|
1979
2062
|
...outcome.planId !== void 0 ? { planId: outcome.planId } : {},
|
|
1980
2063
|
...outcome.error !== void 0 ? { error: outcome.error } : {}
|
|
@@ -1985,8 +2068,10 @@ ${contribution}`);
|
|
|
1985
2068
|
run.reports = [...allReports];
|
|
1986
2069
|
await this.options.store.save(run);
|
|
1987
2070
|
}
|
|
1988
|
-
const
|
|
1989
|
-
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";
|
|
1990
2075
|
const planId = [...outcomes.values()].find((o) => o.planId !== void 0)?.planId;
|
|
1991
2076
|
let resultSummary;
|
|
1992
2077
|
for (let i = def.steps.length - 1; i >= 0; i -= 1) {
|
|
@@ -2092,6 +2177,7 @@ ${contribution}`);
|
|
|
2092
2177
|
)
|
|
2093
2178
|
);
|
|
2094
2179
|
const results = await Promise.all(created.map((task) => this.options.tasks.run(task.id)));
|
|
2180
|
+
const completedTasks = results.filter((r) => r.status === "completed");
|
|
2095
2181
|
const failedTasks = results.filter((r) => r.status !== "completed");
|
|
2096
2182
|
const lines = results.map((result, index) => {
|
|
2097
2183
|
const agentName = agentNames[index] ?? "unknown";
|
|
@@ -2101,12 +2187,15 @@ ${contribution}`);
|
|
|
2101
2187
|
const reports = results.flatMap((r) => r.result?.reports ?? []);
|
|
2102
2188
|
const summary = lines.join("\n");
|
|
2103
2189
|
if (failedTasks.length > 0) {
|
|
2104
|
-
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(", ");
|
|
2105
2192
|
return {
|
|
2106
|
-
|
|
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",
|
|
2107
2196
|
summary,
|
|
2108
2197
|
taskIds: created.map((t) => t.id),
|
|
2109
|
-
error: `${failedTasks.length}/${results.length} task(s)
|
|
2198
|
+
error: `${failedTasks.length}/${results.length} task(s) incomplete (${states}) \u2014 ${firstError}`,
|
|
2110
2199
|
reports
|
|
2111
2200
|
};
|
|
2112
2201
|
}
|
|
@@ -2122,7 +2211,9 @@ ${contribution}`);
|
|
|
2122
2211
|
const result = await this.options.tasks.run(task.id);
|
|
2123
2212
|
if (result.status !== "completed") {
|
|
2124
2213
|
return {
|
|
2125
|
-
|
|
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",
|
|
2126
2217
|
summary: result.result?.summary ?? "",
|
|
2127
2218
|
taskIds: [task.id],
|
|
2128
2219
|
error: result.result?.error ?? `task ${task.id} did not complete`,
|
|
@@ -2594,7 +2685,7 @@ var ProjectStores = class {
|
|
|
2594
2685
|
};
|
|
2595
2686
|
|
|
2596
2687
|
// src/version.ts
|
|
2597
|
-
var OMNINODE_VERSION = "2.0.0-alpha.
|
|
2688
|
+
var OMNINODE_VERSION = "2.0.0-alpha.2";
|
|
2598
2689
|
export {
|
|
2599
2690
|
AgentError,
|
|
2600
2691
|
AgentRegistry,
|
|
@@ -2628,6 +2719,7 @@ export {
|
|
|
2628
2719
|
RememberaMemoryProvider,
|
|
2629
2720
|
ReportService,
|
|
2630
2721
|
RoleRegistry,
|
|
2722
|
+
TERMINAL_TASK_STATUSES,
|
|
2631
2723
|
TaskEngine,
|
|
2632
2724
|
TaskError,
|
|
2633
2725
|
agentConfigSchema,
|