yaml-flow 2.8.0 → 3.0.0
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 +168 -3
- package/dist/{constants-BEbO2_OK.d.ts → constants-B_ftYTTE.d.ts} +36 -6
- package/dist/{constants-BNjeIlZ8.d.cts → constants-CiyHX8L-.d.cts} +36 -6
- package/dist/continuous-event-graph/index.cjs +399 -42
- package/dist/continuous-event-graph/index.cjs.map +1 -1
- package/dist/continuous-event-graph/index.d.cts +124 -5
- package/dist/continuous-event-graph/index.d.ts +124 -5
- package/dist/continuous-event-graph/index.js +396 -43
- package/dist/continuous-event-graph/index.js.map +1 -1
- package/dist/event-graph/index.cjs +6784 -44
- package/dist/event-graph/index.cjs.map +1 -1
- package/dist/event-graph/index.d.cts +5 -5
- package/dist/event-graph/index.d.ts +5 -5
- package/dist/event-graph/index.js +6777 -43
- package/dist/event-graph/index.js.map +1 -1
- package/dist/index.cjs +946 -91
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +938 -91
- package/dist/index.js.map +1 -1
- package/dist/inference/index.cjs +17 -8
- package/dist/inference/index.cjs.map +1 -1
- package/dist/inference/index.d.cts +2 -2
- package/dist/inference/index.d.ts +2 -2
- package/dist/inference/index.js +17 -8
- package/dist/inference/index.js.map +1 -1
- package/dist/step-machine/index.cjs +6600 -0
- package/dist/step-machine/index.cjs.map +1 -1
- package/dist/step-machine/index.d.cts +26 -1
- package/dist/step-machine/index.d.ts +26 -1
- package/dist/step-machine/index.js +6596 -1
- package/dist/step-machine/index.js.map +1 -1
- package/dist/{types-DAI_a2as.d.ts → types-BpWrH1sf.d.cts} +16 -7
- package/dist/{types-DAI_a2as.d.cts → types-BpWrH1sf.d.ts} +16 -7
- package/dist/{types-mS_pPftm.d.ts → types-BuEo3wVG.d.ts} +1 -1
- package/dist/{types-C2lOwquM.d.cts → types-CxJg9Jrt.d.cts} +1 -1
- package/package.json +1 -1
- package/schema/event-graph.schema.json +254 -0
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { execFile } from 'child_process';
|
|
2
1
|
import addFormats from 'ajv-formats';
|
|
2
|
+
import { existsSync, writeFileSync, appendFileSync, readFileSync } from 'fs';
|
|
3
|
+
import { execFile } from 'child_process';
|
|
3
4
|
|
|
4
5
|
var __create = Object.create;
|
|
5
6
|
var __defProp = Object.defineProperty;
|
|
@@ -3911,7 +3912,7 @@ var require_core = __commonJS({
|
|
|
3911
3912
|
uriResolver
|
|
3912
3913
|
};
|
|
3913
3914
|
}
|
|
3914
|
-
var
|
|
3915
|
+
var Ajv4 = class {
|
|
3915
3916
|
constructor(opts = {}) {
|
|
3916
3917
|
this.schemas = {};
|
|
3917
3918
|
this.refs = {};
|
|
@@ -4281,9 +4282,9 @@ var require_core = __commonJS({
|
|
|
4281
4282
|
}
|
|
4282
4283
|
}
|
|
4283
4284
|
};
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
exports$1.default =
|
|
4285
|
+
Ajv4.ValidationError = validation_error_1.default;
|
|
4286
|
+
Ajv4.MissingRefError = ref_error_1.default;
|
|
4287
|
+
exports$1.default = Ajv4;
|
|
4287
4288
|
function checkOptions(checkOpts, options, msg, log = "error") {
|
|
4288
4289
|
for (const key in checkOpts) {
|
|
4289
4290
|
const opt = key;
|
|
@@ -6354,7 +6355,7 @@ var require_ajv = __commonJS({
|
|
|
6354
6355
|
var draft7MetaSchema = require_json_schema_draft_07();
|
|
6355
6356
|
var META_SUPPORT_DATA = ["/properties"];
|
|
6356
6357
|
var META_SCHEMA_ID = "http://json-schema.org/draft-07/schema";
|
|
6357
|
-
var
|
|
6358
|
+
var Ajv4 = class extends core_1.default {
|
|
6358
6359
|
_addVocabularies() {
|
|
6359
6360
|
super._addVocabularies();
|
|
6360
6361
|
draft7_1.default.forEach((v) => this.addVocabulary(v));
|
|
@@ -6373,11 +6374,11 @@ var require_ajv = __commonJS({
|
|
|
6373
6374
|
return this.opts.defaultMeta = super.defaultMeta() || (this.getSchema(META_SCHEMA_ID) ? META_SCHEMA_ID : void 0);
|
|
6374
6375
|
}
|
|
6375
6376
|
};
|
|
6376
|
-
exports$1.Ajv =
|
|
6377
|
-
module.exports = exports$1 =
|
|
6378
|
-
module.exports.Ajv =
|
|
6377
|
+
exports$1.Ajv = Ajv4;
|
|
6378
|
+
module.exports = exports$1 = Ajv4;
|
|
6379
|
+
module.exports.Ajv = Ajv4;
|
|
6379
6380
|
Object.defineProperty(exports$1, "__esModule", { value: true });
|
|
6380
|
-
exports$1.default =
|
|
6381
|
+
exports$1.default = Ajv4;
|
|
6381
6382
|
var validate_1 = require_validate();
|
|
6382
6383
|
Object.defineProperty(exports$1, "KeywordCxt", { enumerable: true, get: function() {
|
|
6383
6384
|
return validate_1.KeywordCxt;
|
|
@@ -6911,6 +6912,188 @@ async function loadStepFlow(source) {
|
|
|
6911
6912
|
return flow;
|
|
6912
6913
|
}
|
|
6913
6914
|
|
|
6915
|
+
// schema/flow.schema.json
|
|
6916
|
+
var flow_schema_default = {
|
|
6917
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
6918
|
+
$id: "https://github.com/yaml-flow/schema/flow.json",
|
|
6919
|
+
title: "YamlFlow Configuration",
|
|
6920
|
+
description: "Schema for yaml-flow workflow definitions",
|
|
6921
|
+
type: "object",
|
|
6922
|
+
required: ["settings", "steps", "terminal_states"],
|
|
6923
|
+
properties: {
|
|
6924
|
+
id: {
|
|
6925
|
+
type: "string",
|
|
6926
|
+
description: "Optional flow identifier"
|
|
6927
|
+
},
|
|
6928
|
+
settings: {
|
|
6929
|
+
type: "object",
|
|
6930
|
+
description: "Flow-level settings",
|
|
6931
|
+
required: ["start_step"],
|
|
6932
|
+
properties: {
|
|
6933
|
+
start_step: {
|
|
6934
|
+
type: "string",
|
|
6935
|
+
description: "Step to start execution from"
|
|
6936
|
+
},
|
|
6937
|
+
max_total_steps: {
|
|
6938
|
+
type: "integer",
|
|
6939
|
+
minimum: 1,
|
|
6940
|
+
default: 100,
|
|
6941
|
+
description: "Maximum steps before forced termination"
|
|
6942
|
+
},
|
|
6943
|
+
timeout_ms: {
|
|
6944
|
+
type: "integer",
|
|
6945
|
+
minimum: 0,
|
|
6946
|
+
description: "Flow timeout in milliseconds"
|
|
6947
|
+
}
|
|
6948
|
+
},
|
|
6949
|
+
additionalProperties: false
|
|
6950
|
+
},
|
|
6951
|
+
steps: {
|
|
6952
|
+
type: "object",
|
|
6953
|
+
description: "Step definitions",
|
|
6954
|
+
minProperties: 1,
|
|
6955
|
+
additionalProperties: {
|
|
6956
|
+
$ref: "#/definitions/step"
|
|
6957
|
+
}
|
|
6958
|
+
},
|
|
6959
|
+
terminal_states: {
|
|
6960
|
+
type: "object",
|
|
6961
|
+
description: "Terminal state definitions",
|
|
6962
|
+
minProperties: 1,
|
|
6963
|
+
additionalProperties: {
|
|
6964
|
+
$ref: "#/definitions/terminal_state"
|
|
6965
|
+
}
|
|
6966
|
+
}
|
|
6967
|
+
},
|
|
6968
|
+
additionalProperties: false,
|
|
6969
|
+
definitions: {
|
|
6970
|
+
step: {
|
|
6971
|
+
type: "object",
|
|
6972
|
+
description: "Individual step configuration",
|
|
6973
|
+
required: ["transitions"],
|
|
6974
|
+
properties: {
|
|
6975
|
+
description: {
|
|
6976
|
+
type: "string",
|
|
6977
|
+
description: "Human-readable description"
|
|
6978
|
+
},
|
|
6979
|
+
expects_data: {
|
|
6980
|
+
type: "array",
|
|
6981
|
+
items: { type: "string" },
|
|
6982
|
+
description: "Data keys this step expects as input"
|
|
6983
|
+
},
|
|
6984
|
+
produces_data: {
|
|
6985
|
+
type: "array",
|
|
6986
|
+
items: { type: "string" },
|
|
6987
|
+
description: "Data keys this step produces as output"
|
|
6988
|
+
},
|
|
6989
|
+
transitions: {
|
|
6990
|
+
type: "object",
|
|
6991
|
+
description: "Mapping of result -> next step name",
|
|
6992
|
+
additionalProperties: { type: "string" },
|
|
6993
|
+
minProperties: 1
|
|
6994
|
+
},
|
|
6995
|
+
retry: {
|
|
6996
|
+
$ref: "#/definitions/retry_config"
|
|
6997
|
+
},
|
|
6998
|
+
circuit_breaker: {
|
|
6999
|
+
$ref: "#/definitions/circuit_breaker_config"
|
|
7000
|
+
}
|
|
7001
|
+
},
|
|
7002
|
+
additionalProperties: false
|
|
7003
|
+
},
|
|
7004
|
+
terminal_state: {
|
|
7005
|
+
type: "object",
|
|
7006
|
+
description: "Terminal state configuration",
|
|
7007
|
+
required: ["return_intent"],
|
|
7008
|
+
properties: {
|
|
7009
|
+
description: {
|
|
7010
|
+
type: "string",
|
|
7011
|
+
description: "Human-readable description"
|
|
7012
|
+
},
|
|
7013
|
+
return_intent: {
|
|
7014
|
+
type: "string",
|
|
7015
|
+
description: "Intent/status to return (e.g., 'success', 'error')"
|
|
7016
|
+
},
|
|
7017
|
+
return_artifacts: {
|
|
7018
|
+
oneOf: [
|
|
7019
|
+
{ type: "string" },
|
|
7020
|
+
{ type: "array", items: { type: "string" } },
|
|
7021
|
+
{ type: "boolean", const: false }
|
|
7022
|
+
],
|
|
7023
|
+
description: "Data key(s) to include in result, or false to exclude"
|
|
7024
|
+
},
|
|
7025
|
+
expects_data: {
|
|
7026
|
+
type: "array",
|
|
7027
|
+
items: { type: "string" },
|
|
7028
|
+
description: "Data keys this terminal state expects"
|
|
7029
|
+
}
|
|
7030
|
+
},
|
|
7031
|
+
additionalProperties: false
|
|
7032
|
+
},
|
|
7033
|
+
retry_config: {
|
|
7034
|
+
type: "object",
|
|
7035
|
+
description: "Retry configuration for step failures",
|
|
7036
|
+
required: ["max_attempts"],
|
|
7037
|
+
properties: {
|
|
7038
|
+
max_attempts: {
|
|
7039
|
+
type: "integer",
|
|
7040
|
+
minimum: 1,
|
|
7041
|
+
description: "Maximum retry attempts"
|
|
7042
|
+
},
|
|
7043
|
+
delay_ms: {
|
|
7044
|
+
type: "integer",
|
|
7045
|
+
minimum: 0,
|
|
7046
|
+
description: "Delay between retries in ms"
|
|
7047
|
+
},
|
|
7048
|
+
backoff_multiplier: {
|
|
7049
|
+
type: "number",
|
|
7050
|
+
minimum: 1,
|
|
7051
|
+
description: "Backoff multiplier (e.g., 2 for exponential)"
|
|
7052
|
+
}
|
|
7053
|
+
},
|
|
7054
|
+
additionalProperties: false
|
|
7055
|
+
},
|
|
7056
|
+
circuit_breaker_config: {
|
|
7057
|
+
type: "object",
|
|
7058
|
+
description: "Circuit breaker configuration for loops",
|
|
7059
|
+
required: ["max_iterations", "on_open"],
|
|
7060
|
+
properties: {
|
|
7061
|
+
max_iterations: {
|
|
7062
|
+
type: "integer",
|
|
7063
|
+
minimum: 1,
|
|
7064
|
+
description: "Maximum iterations before circuit opens"
|
|
7065
|
+
},
|
|
7066
|
+
on_open: {
|
|
7067
|
+
type: "string",
|
|
7068
|
+
description: "Step to transition to when circuit opens"
|
|
7069
|
+
}
|
|
7070
|
+
},
|
|
7071
|
+
additionalProperties: false
|
|
7072
|
+
}
|
|
7073
|
+
}
|
|
7074
|
+
};
|
|
7075
|
+
|
|
7076
|
+
// src/step-machine/schema-validator.ts
|
|
7077
|
+
var import_ajv = __toESM(require_ajv());
|
|
7078
|
+
var _compiled = null;
|
|
7079
|
+
function getValidator() {
|
|
7080
|
+
if (_compiled) return _compiled;
|
|
7081
|
+
const ajv = new import_ajv.default({ allErrors: true });
|
|
7082
|
+
addFormats(ajv);
|
|
7083
|
+
_compiled = ajv.compile(flow_schema_default);
|
|
7084
|
+
return _compiled;
|
|
7085
|
+
}
|
|
7086
|
+
function validateFlowSchema(config) {
|
|
7087
|
+
const validate = getValidator();
|
|
7088
|
+
const valid = validate(config);
|
|
7089
|
+
if (valid) return { ok: true, errors: [] };
|
|
7090
|
+
const errors = (validate.errors ?? []).map((e) => {
|
|
7091
|
+
const path = e.instancePath || "/";
|
|
7092
|
+
return `${path}: ${e.message ?? "unknown error"}`;
|
|
7093
|
+
});
|
|
7094
|
+
return { ok: false, errors };
|
|
7095
|
+
}
|
|
7096
|
+
|
|
6914
7097
|
// src/event-graph/constants.ts
|
|
6915
7098
|
var TASK_STATUS = {
|
|
6916
7099
|
NOT_STARTED: "not-started",
|
|
@@ -6987,15 +7170,14 @@ function isTaskCompleted(taskState) {
|
|
|
6987
7170
|
function isTaskRunning(taskState) {
|
|
6988
7171
|
return taskState?.status === TASK_STATUS.RUNNING;
|
|
6989
7172
|
}
|
|
6990
|
-
function
|
|
6991
|
-
return taskConfig.
|
|
7173
|
+
function getRefreshStrategy(taskConfig, graphSettings) {
|
|
7174
|
+
return taskConfig.refreshStrategy ?? graphSettings?.refreshStrategy ?? "data-changed";
|
|
6992
7175
|
}
|
|
6993
|
-
function
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
return void 0;
|
|
7176
|
+
function isRerunnable(taskConfig, graphSettings) {
|
|
7177
|
+
return getRefreshStrategy(taskConfig, graphSettings) !== "once";
|
|
7178
|
+
}
|
|
7179
|
+
function getMaxExecutions(taskConfig) {
|
|
7180
|
+
return taskConfig.maxExecutions;
|
|
6999
7181
|
}
|
|
7000
7182
|
function computeAvailableOutputs(graph, taskStates) {
|
|
7001
7183
|
const outputs = /* @__PURE__ */ new Set();
|
|
@@ -7427,48 +7609,88 @@ function getCandidateTasks(graph, state) {
|
|
|
7427
7609
|
const candidates = [];
|
|
7428
7610
|
for (const [taskName, taskConfig] of Object.entries(graphTasks)) {
|
|
7429
7611
|
const taskState = state.tasks[taskName];
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
}
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7612
|
+
const strategy = getRefreshStrategy(taskConfig, graph.settings);
|
|
7613
|
+
const rerunnable = strategy !== "once";
|
|
7614
|
+
if (taskState?.status === TASK_STATUS.RUNNING || isNonActiveTask(taskState)) {
|
|
7615
|
+
continue;
|
|
7616
|
+
}
|
|
7617
|
+
const maxExec = getMaxExecutions(taskConfig);
|
|
7618
|
+
if (maxExec !== void 0 && taskState && taskState.executionCount >= maxExec) {
|
|
7619
|
+
continue;
|
|
7620
|
+
}
|
|
7621
|
+
if (taskConfig.circuit_breaker && taskState && taskState.executionCount >= taskConfig.circuit_breaker.max_executions) {
|
|
7622
|
+
continue;
|
|
7623
|
+
}
|
|
7624
|
+
if (!rerunnable) {
|
|
7625
|
+
if (taskState?.status === TASK_STATUS.COMPLETED) {
|
|
7440
7626
|
continue;
|
|
7441
7627
|
}
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7628
|
+
}
|
|
7629
|
+
if (rerunnable && taskState?.status === TASK_STATUS.COMPLETED) {
|
|
7630
|
+
const requires2 = getRequires(taskConfig);
|
|
7631
|
+
switch (strategy) {
|
|
7632
|
+
case "data-changed": {
|
|
7633
|
+
if (requires2.length > 0) {
|
|
7634
|
+
const hasChangedData = requires2.some((req) => {
|
|
7635
|
+
for (const [otherName, otherConfig] of Object.entries(graphTasks)) {
|
|
7636
|
+
if (getProvides(otherConfig).includes(req)) {
|
|
7637
|
+
const otherState = state.tasks[otherName];
|
|
7638
|
+
if (!otherState) continue;
|
|
7639
|
+
const consumed = taskState.lastConsumedHashes?.[req];
|
|
7640
|
+
if (otherState.lastDataHash == null) {
|
|
7641
|
+
return otherState.executionCount > taskState.lastEpoch;
|
|
7642
|
+
}
|
|
7643
|
+
return otherState.lastDataHash !== consumed;
|
|
7644
|
+
}
|
|
7645
|
+
}
|
|
7646
|
+
return false;
|
|
7647
|
+
});
|
|
7648
|
+
if (!hasChangedData) continue;
|
|
7649
|
+
} else {
|
|
7650
|
+
continue;
|
|
7651
|
+
}
|
|
7652
|
+
break;
|
|
7445
7653
|
}
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
return true;
|
|
7654
|
+
case "epoch-changed": {
|
|
7655
|
+
if (requires2.length > 0) {
|
|
7656
|
+
const hasRefreshedInputs = requires2.some((req) => {
|
|
7657
|
+
for (const [otherName, otherConfig] of Object.entries(graphTasks)) {
|
|
7658
|
+
if (getProvides(otherConfig).includes(req)) {
|
|
7659
|
+
const otherState = state.tasks[otherName];
|
|
7660
|
+
if (otherState && otherState.executionCount > taskState.lastEpoch) {
|
|
7661
|
+
return true;
|
|
7662
|
+
}
|
|
7456
7663
|
}
|
|
7457
7664
|
}
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7665
|
+
return false;
|
|
7666
|
+
});
|
|
7667
|
+
if (!hasRefreshedInputs) continue;
|
|
7668
|
+
} else {
|
|
7669
|
+
continue;
|
|
7670
|
+
}
|
|
7671
|
+
break;
|
|
7672
|
+
}
|
|
7673
|
+
case "time-based": {
|
|
7674
|
+
const interval = taskConfig.refreshInterval ?? 0;
|
|
7675
|
+
if (interval <= 0) continue;
|
|
7676
|
+
const completedAt = taskState.completedAt;
|
|
7677
|
+
if (!completedAt) continue;
|
|
7678
|
+
const elapsedSec = (Date.now() - Date.parse(completedAt)) / 1e3;
|
|
7679
|
+
if (elapsedSec < interval) continue;
|
|
7680
|
+
break;
|
|
7681
|
+
}
|
|
7682
|
+
case "manual": {
|
|
7463
7683
|
continue;
|
|
7464
7684
|
}
|
|
7685
|
+
default:
|
|
7686
|
+
continue;
|
|
7465
7687
|
}
|
|
7466
7688
|
}
|
|
7467
7689
|
const requires = getRequires(taskConfig);
|
|
7468
7690
|
if (!requires.every((req) => availableOutputs.includes(req))) {
|
|
7469
7691
|
continue;
|
|
7470
7692
|
}
|
|
7471
|
-
if (!
|
|
7693
|
+
if (!rerunnable) {
|
|
7472
7694
|
const provides = getProvides(taskConfig);
|
|
7473
7695
|
const allAlreadyAvailable = provides.length > 0 && provides.every((output) => availableOutputs.includes(output));
|
|
7474
7696
|
if (allAlreadyAvailable) continue;
|
|
@@ -7552,7 +7774,7 @@ function applyTaskStart(state, taskName) {
|
|
|
7552
7774
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
7553
7775
|
};
|
|
7554
7776
|
}
|
|
7555
|
-
function applyTaskCompletion(state, graph, taskName, result) {
|
|
7777
|
+
function applyTaskCompletion(state, graph, taskName, result, dataHash) {
|
|
7556
7778
|
const existingTask = state.tasks[taskName] ?? createDefaultTaskState2();
|
|
7557
7779
|
const taskConfig = graph.tasks[taskName];
|
|
7558
7780
|
if (!taskConfig) {
|
|
@@ -7564,6 +7786,19 @@ function applyTaskCompletion(state, graph, taskName, result) {
|
|
|
7564
7786
|
} else {
|
|
7565
7787
|
outputTokens = getProvides(taskConfig);
|
|
7566
7788
|
}
|
|
7789
|
+
const lastConsumedHashes = { ...existingTask.lastConsumedHashes };
|
|
7790
|
+
const requires = taskConfig.requires ?? [];
|
|
7791
|
+
for (const token of requires) {
|
|
7792
|
+
for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {
|
|
7793
|
+
if (getProvides(otherConfig).includes(token)) {
|
|
7794
|
+
const otherState = state.tasks[otherName];
|
|
7795
|
+
if (otherState?.lastDataHash) {
|
|
7796
|
+
lastConsumedHashes[token] = otherState.lastDataHash;
|
|
7797
|
+
}
|
|
7798
|
+
break;
|
|
7799
|
+
}
|
|
7800
|
+
}
|
|
7801
|
+
}
|
|
7567
7802
|
const updatedTask = {
|
|
7568
7803
|
...existingTask,
|
|
7569
7804
|
status: "completed",
|
|
@@ -7571,11 +7806,10 @@ function applyTaskCompletion(state, graph, taskName, result) {
|
|
|
7571
7806
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7572
7807
|
executionCount: existingTask.executionCount + 1,
|
|
7573
7808
|
lastEpoch: existingTask.executionCount + 1,
|
|
7809
|
+
lastDataHash: dataHash,
|
|
7810
|
+
lastConsumedHashes,
|
|
7574
7811
|
error: void 0
|
|
7575
7812
|
};
|
|
7576
|
-
if (isRepeatableTask(taskConfig)) {
|
|
7577
|
-
updatedTask.status = "not-started";
|
|
7578
|
-
}
|
|
7579
7813
|
const newOutputs = [.../* @__PURE__ */ new Set([...state.availableOutputs, ...outputTokens])];
|
|
7580
7814
|
return {
|
|
7581
7815
|
...state,
|
|
@@ -7664,7 +7898,7 @@ function apply(state, event, graph) {
|
|
|
7664
7898
|
case "task-started":
|
|
7665
7899
|
return applyTaskStart(state, event.taskName);
|
|
7666
7900
|
case "task-completed":
|
|
7667
|
-
return applyTaskCompletion(state, graph, event.taskName, event.result);
|
|
7901
|
+
return applyTaskCompletion(state, graph, event.taskName, event.result, event.dataHash);
|
|
7668
7902
|
case "task-failed":
|
|
7669
7903
|
return applyTaskFailure(state, graph, event.taskName, event.error);
|
|
7670
7904
|
case "task-progress":
|
|
@@ -8354,6 +8588,276 @@ function buildResult(issues) {
|
|
|
8354
8588
|
};
|
|
8355
8589
|
}
|
|
8356
8590
|
|
|
8591
|
+
// schema/event-graph.schema.json
|
|
8592
|
+
var event_graph_schema_default = {
|
|
8593
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
8594
|
+
$id: "https://github.com/yaml-flow/schema/event-graph.json",
|
|
8595
|
+
title: "Event Graph Configuration",
|
|
8596
|
+
description: "Schema for stateless event-graph (DAG) workflow definitions in yaml-flow",
|
|
8597
|
+
type: "object",
|
|
8598
|
+
required: ["settings", "tasks"],
|
|
8599
|
+
additionalProperties: false,
|
|
8600
|
+
properties: {
|
|
8601
|
+
id: {
|
|
8602
|
+
type: "string",
|
|
8603
|
+
description: "Optional graph identifier"
|
|
8604
|
+
},
|
|
8605
|
+
settings: {
|
|
8606
|
+
$ref: "#/definitions/settings"
|
|
8607
|
+
},
|
|
8608
|
+
tasks: {
|
|
8609
|
+
type: "object",
|
|
8610
|
+
description: "Task definitions keyed by name",
|
|
8611
|
+
minProperties: 1,
|
|
8612
|
+
additionalProperties: {
|
|
8613
|
+
$ref: "#/definitions/task"
|
|
8614
|
+
}
|
|
8615
|
+
}
|
|
8616
|
+
},
|
|
8617
|
+
definitions: {
|
|
8618
|
+
settings: {
|
|
8619
|
+
type: "object",
|
|
8620
|
+
required: ["completion"],
|
|
8621
|
+
properties: {
|
|
8622
|
+
completion: {
|
|
8623
|
+
type: "string",
|
|
8624
|
+
enum: [
|
|
8625
|
+
"all-tasks-done",
|
|
8626
|
+
"all-outputs-done",
|
|
8627
|
+
"only-resolved",
|
|
8628
|
+
"goal-reached",
|
|
8629
|
+
"manual"
|
|
8630
|
+
],
|
|
8631
|
+
description: "Completion strategy"
|
|
8632
|
+
},
|
|
8633
|
+
conflict_strategy: {
|
|
8634
|
+
type: "string",
|
|
8635
|
+
enum: [
|
|
8636
|
+
"alphabetical",
|
|
8637
|
+
"priority-first",
|
|
8638
|
+
"duration-first",
|
|
8639
|
+
"cost-optimized",
|
|
8640
|
+
"resource-aware",
|
|
8641
|
+
"random-select",
|
|
8642
|
+
"user-choice",
|
|
8643
|
+
"parallel-all",
|
|
8644
|
+
"skip-conflicts",
|
|
8645
|
+
"round-robin"
|
|
8646
|
+
],
|
|
8647
|
+
description: "Conflict resolution strategy"
|
|
8648
|
+
},
|
|
8649
|
+
execution_mode: {
|
|
8650
|
+
type: "string",
|
|
8651
|
+
enum: ["dependency-mode", "eligibility-mode"],
|
|
8652
|
+
description: "Execution mode"
|
|
8653
|
+
},
|
|
8654
|
+
goal: {
|
|
8655
|
+
type: "array",
|
|
8656
|
+
items: { type: "string" },
|
|
8657
|
+
minItems: 1,
|
|
8658
|
+
description: "Goal outputs \u2014 required when completion is 'goal-reached'"
|
|
8659
|
+
},
|
|
8660
|
+
max_iterations: {
|
|
8661
|
+
type: "integer",
|
|
8662
|
+
minimum: 1,
|
|
8663
|
+
description: "Max scheduler iterations (safety limit, default: 1000)"
|
|
8664
|
+
},
|
|
8665
|
+
timeout_ms: {
|
|
8666
|
+
type: "integer",
|
|
8667
|
+
minimum: 0,
|
|
8668
|
+
description: "Timeout in ms (declared for drivers, not enforced by pure engine)"
|
|
8669
|
+
},
|
|
8670
|
+
refreshStrategy: {
|
|
8671
|
+
$ref: "#/definitions/refresh_strategy",
|
|
8672
|
+
description: "Default refresh strategy for all tasks (default: 'data-changed')"
|
|
8673
|
+
}
|
|
8674
|
+
},
|
|
8675
|
+
additionalProperties: false,
|
|
8676
|
+
if: {
|
|
8677
|
+
properties: { completion: { const: "goal-reached" } }
|
|
8678
|
+
},
|
|
8679
|
+
then: {
|
|
8680
|
+
required: ["completion", "goal"]
|
|
8681
|
+
}
|
|
8682
|
+
},
|
|
8683
|
+
task: {
|
|
8684
|
+
type: "object",
|
|
8685
|
+
required: ["provides"],
|
|
8686
|
+
properties: {
|
|
8687
|
+
requires: {
|
|
8688
|
+
type: "array",
|
|
8689
|
+
items: { type: "string" },
|
|
8690
|
+
description: "Tokens this task needs to become eligible"
|
|
8691
|
+
},
|
|
8692
|
+
provides: {
|
|
8693
|
+
type: "array",
|
|
8694
|
+
items: { type: "string" },
|
|
8695
|
+
description: "Tokens this task produces on successful completion"
|
|
8696
|
+
},
|
|
8697
|
+
on: {
|
|
8698
|
+
type: "object",
|
|
8699
|
+
description: "Conditional provides based on handler result key",
|
|
8700
|
+
additionalProperties: {
|
|
8701
|
+
type: "array",
|
|
8702
|
+
items: { type: "string" }
|
|
8703
|
+
}
|
|
8704
|
+
},
|
|
8705
|
+
on_failure: {
|
|
8706
|
+
type: "array",
|
|
8707
|
+
items: { type: "string" },
|
|
8708
|
+
description: "Tokens to inject when this task fails"
|
|
8709
|
+
},
|
|
8710
|
+
method: {
|
|
8711
|
+
type: "string",
|
|
8712
|
+
description: "Task execution method (informational \u2014 driver concern)"
|
|
8713
|
+
},
|
|
8714
|
+
config: {
|
|
8715
|
+
type: "object",
|
|
8716
|
+
description: "Arbitrary task configuration (driver concern)"
|
|
8717
|
+
},
|
|
8718
|
+
priority: {
|
|
8719
|
+
type: "number",
|
|
8720
|
+
description: "Higher = preferred in conflict resolution"
|
|
8721
|
+
},
|
|
8722
|
+
estimatedDuration: {
|
|
8723
|
+
type: "number",
|
|
8724
|
+
minimum: 0,
|
|
8725
|
+
description: "Estimated duration in ms (used by duration-first strategy)"
|
|
8726
|
+
},
|
|
8727
|
+
estimatedCost: {
|
|
8728
|
+
type: "number",
|
|
8729
|
+
minimum: 0,
|
|
8730
|
+
description: "Estimated cost (used by cost-optimized strategy)"
|
|
8731
|
+
},
|
|
8732
|
+
estimatedResources: {
|
|
8733
|
+
type: "object",
|
|
8734
|
+
additionalProperties: { type: "number" },
|
|
8735
|
+
description: "Resource requirements (used by resource-aware strategy)"
|
|
8736
|
+
},
|
|
8737
|
+
retry: {
|
|
8738
|
+
$ref: "#/definitions/task_retry"
|
|
8739
|
+
},
|
|
8740
|
+
refreshStrategy: {
|
|
8741
|
+
$ref: "#/definitions/refresh_strategy",
|
|
8742
|
+
description: "Task-level refresh strategy (overrides settings default)"
|
|
8743
|
+
},
|
|
8744
|
+
refreshInterval: {
|
|
8745
|
+
type: "number",
|
|
8746
|
+
minimum: 0,
|
|
8747
|
+
description: "Interval in seconds for time-based refresh strategy"
|
|
8748
|
+
},
|
|
8749
|
+
maxExecutions: {
|
|
8750
|
+
type: "integer",
|
|
8751
|
+
minimum: 1,
|
|
8752
|
+
description: "Maximum number of times this task can execute"
|
|
8753
|
+
},
|
|
8754
|
+
circuit_breaker: {
|
|
8755
|
+
$ref: "#/definitions/task_circuit_breaker"
|
|
8756
|
+
},
|
|
8757
|
+
description: {
|
|
8758
|
+
type: "string",
|
|
8759
|
+
description: "Human-readable description"
|
|
8760
|
+
},
|
|
8761
|
+
inference: {
|
|
8762
|
+
$ref: "#/definitions/inference_hints"
|
|
8763
|
+
}
|
|
8764
|
+
},
|
|
8765
|
+
additionalProperties: false
|
|
8766
|
+
},
|
|
8767
|
+
task_retry: {
|
|
8768
|
+
type: "object",
|
|
8769
|
+
required: ["max_attempts"],
|
|
8770
|
+
properties: {
|
|
8771
|
+
max_attempts: {
|
|
8772
|
+
type: "integer",
|
|
8773
|
+
minimum: 1,
|
|
8774
|
+
description: "Maximum retry attempts"
|
|
8775
|
+
},
|
|
8776
|
+
delay_ms: {
|
|
8777
|
+
type: "integer",
|
|
8778
|
+
minimum: 0,
|
|
8779
|
+
description: "Delay between retries in ms"
|
|
8780
|
+
},
|
|
8781
|
+
backoff_multiplier: {
|
|
8782
|
+
type: "number",
|
|
8783
|
+
minimum: 1,
|
|
8784
|
+
description: "Backoff multiplier (e.g., 2 for exponential)"
|
|
8785
|
+
}
|
|
8786
|
+
},
|
|
8787
|
+
additionalProperties: false
|
|
8788
|
+
},
|
|
8789
|
+
refresh_strategy: {
|
|
8790
|
+
type: "string",
|
|
8791
|
+
enum: ["data-changed", "epoch-changed", "time-based", "manual", "once"],
|
|
8792
|
+
description: "Strategy for determining when a completed task should re-run"
|
|
8793
|
+
},
|
|
8794
|
+
task_circuit_breaker: {
|
|
8795
|
+
type: "object",
|
|
8796
|
+
required: ["max_executions", "on_break"],
|
|
8797
|
+
properties: {
|
|
8798
|
+
max_executions: {
|
|
8799
|
+
type: "integer",
|
|
8800
|
+
minimum: 1,
|
|
8801
|
+
description: "Max executions before breaker trips"
|
|
8802
|
+
},
|
|
8803
|
+
on_break: {
|
|
8804
|
+
type: "array",
|
|
8805
|
+
items: { type: "string" },
|
|
8806
|
+
minItems: 1,
|
|
8807
|
+
description: "Tokens to inject when breaker trips"
|
|
8808
|
+
}
|
|
8809
|
+
},
|
|
8810
|
+
additionalProperties: false
|
|
8811
|
+
},
|
|
8812
|
+
inference_hints: {
|
|
8813
|
+
type: "object",
|
|
8814
|
+
description: "LLM inference hints \u2014 opt-in metadata for AI-assisted completion detection",
|
|
8815
|
+
properties: {
|
|
8816
|
+
criteria: {
|
|
8817
|
+
type: "string",
|
|
8818
|
+
description: "Human-readable completion criteria"
|
|
8819
|
+
},
|
|
8820
|
+
keywords: {
|
|
8821
|
+
type: "array",
|
|
8822
|
+
items: { type: "string" },
|
|
8823
|
+
description: "Keywords to help the LLM understand the domain"
|
|
8824
|
+
},
|
|
8825
|
+
suggestedChecks: {
|
|
8826
|
+
type: "array",
|
|
8827
|
+
items: { type: "string" },
|
|
8828
|
+
description: "Suggested checks for verification"
|
|
8829
|
+
},
|
|
8830
|
+
autoDetectable: {
|
|
8831
|
+
type: "boolean",
|
|
8832
|
+
description: "Whether the LLM should attempt to auto-detect completion (default: false)"
|
|
8833
|
+
}
|
|
8834
|
+
},
|
|
8835
|
+
additionalProperties: false
|
|
8836
|
+
}
|
|
8837
|
+
}
|
|
8838
|
+
};
|
|
8839
|
+
|
|
8840
|
+
// src/event-graph/schema-validator.ts
|
|
8841
|
+
var import_ajv2 = __toESM(require_ajv());
|
|
8842
|
+
var _compiled2 = null;
|
|
8843
|
+
function getValidator2() {
|
|
8844
|
+
if (_compiled2) return _compiled2;
|
|
8845
|
+
const ajv = new import_ajv2.default({ allErrors: true });
|
|
8846
|
+
addFormats(ajv);
|
|
8847
|
+
_compiled2 = ajv.compile(event_graph_schema_default);
|
|
8848
|
+
return _compiled2;
|
|
8849
|
+
}
|
|
8850
|
+
function validateGraphSchema(config) {
|
|
8851
|
+
const validate = getValidator2();
|
|
8852
|
+
const valid = validate(config);
|
|
8853
|
+
if (valid) return { ok: true, errors: [] };
|
|
8854
|
+
const errors = (validate.errors ?? []).map((e) => {
|
|
8855
|
+
const path = e.instancePath || "/";
|
|
8856
|
+
return `${path}: ${e.message ?? "unknown error"}`;
|
|
8857
|
+
});
|
|
8858
|
+
return { ok: false, errors };
|
|
8859
|
+
}
|
|
8860
|
+
|
|
8357
8861
|
// src/stores/localStorage.ts
|
|
8358
8862
|
var LocalStorageStore = class {
|
|
8359
8863
|
prefix;
|
|
@@ -8747,7 +9251,7 @@ function applyEvent(live, event) {
|
|
|
8747
9251
|
newState = applyTaskStart(state, event.taskName);
|
|
8748
9252
|
break;
|
|
8749
9253
|
case "task-completed":
|
|
8750
|
-
newState = applyTaskCompletion(state, config, event.taskName, event.result);
|
|
9254
|
+
newState = applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash);
|
|
8751
9255
|
break;
|
|
8752
9256
|
case "task-failed":
|
|
8753
9257
|
newState = applyTaskFailure(state, config, event.taskName, event.error);
|
|
@@ -8770,6 +9274,9 @@ function applyEvent(live, event) {
|
|
|
8770
9274
|
}
|
|
8771
9275
|
return { config, state: newState };
|
|
8772
9276
|
}
|
|
9277
|
+
function applyEvents(live, events) {
|
|
9278
|
+
return events.reduce((current, event) => applyEvent(current, event), live);
|
|
9279
|
+
}
|
|
8773
9280
|
function addNode(live, name, taskConfig) {
|
|
8774
9281
|
if (live.config.tasks[name]) return live;
|
|
8775
9282
|
return {
|
|
@@ -9014,38 +9521,84 @@ function schedule(live) {
|
|
|
9014
9521
|
const blocked = [];
|
|
9015
9522
|
for (const [taskName, taskConfig] of Object.entries(graphTasks)) {
|
|
9016
9523
|
const taskState = state.tasks[taskName];
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
}
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
|
|
9028
|
-
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9524
|
+
const strategy = getRefreshStrategy(taskConfig, config.settings);
|
|
9525
|
+
const rerunnable = strategy !== "once";
|
|
9526
|
+
if (taskState?.status === TASK_STATUS.RUNNING || isNonActiveTask(taskState)) {
|
|
9527
|
+
continue;
|
|
9528
|
+
}
|
|
9529
|
+
const maxExec = getMaxExecutions(taskConfig);
|
|
9530
|
+
if (maxExec !== void 0 && taskState && taskState.executionCount >= maxExec) {
|
|
9531
|
+
continue;
|
|
9532
|
+
}
|
|
9533
|
+
if (taskConfig.circuit_breaker && taskState && taskState.executionCount >= taskConfig.circuit_breaker.max_executions) {
|
|
9534
|
+
continue;
|
|
9535
|
+
}
|
|
9536
|
+
if (!rerunnable && taskState?.status === TASK_STATUS.COMPLETED) {
|
|
9537
|
+
continue;
|
|
9538
|
+
}
|
|
9539
|
+
if (rerunnable && taskState?.status === TASK_STATUS.COMPLETED) {
|
|
9540
|
+
const requires2 = getRequires(taskConfig);
|
|
9541
|
+
let shouldSkip = false;
|
|
9542
|
+
switch (strategy) {
|
|
9543
|
+
case "data-changed": {
|
|
9544
|
+
if (requires2.length > 0) {
|
|
9545
|
+
const hasChangedData = requires2.some((req) => {
|
|
9546
|
+
for (const [otherName, otherConfig] of Object.entries(graphTasks)) {
|
|
9547
|
+
if (getProvides(otherConfig).includes(req)) {
|
|
9548
|
+
const otherState = state.tasks[otherName];
|
|
9549
|
+
if (!otherState) continue;
|
|
9550
|
+
const consumed = taskState.lastConsumedHashes?.[req];
|
|
9551
|
+
if (otherState.lastDataHash == null) {
|
|
9552
|
+
return otherState.executionCount > taskState.lastEpoch;
|
|
9553
|
+
}
|
|
9554
|
+
return otherState.lastDataHash !== consumed;
|
|
9555
|
+
}
|
|
9040
9556
|
}
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
|
|
9046
|
-
|
|
9557
|
+
return false;
|
|
9558
|
+
});
|
|
9559
|
+
if (!hasChangedData) shouldSkip = true;
|
|
9560
|
+
} else {
|
|
9561
|
+
shouldSkip = true;
|
|
9562
|
+
}
|
|
9563
|
+
break;
|
|
9047
9564
|
}
|
|
9565
|
+
case "epoch-changed": {
|
|
9566
|
+
if (requires2.length > 0) {
|
|
9567
|
+
const hasRefreshed = requires2.some((req) => {
|
|
9568
|
+
for (const [otherName, otherConfig] of Object.entries(graphTasks)) {
|
|
9569
|
+
if (getProvides(otherConfig).includes(req)) {
|
|
9570
|
+
const otherState = state.tasks[otherName];
|
|
9571
|
+
if (otherState && otherState.executionCount > taskState.lastEpoch) return true;
|
|
9572
|
+
}
|
|
9573
|
+
}
|
|
9574
|
+
return false;
|
|
9575
|
+
});
|
|
9576
|
+
if (!hasRefreshed) shouldSkip = true;
|
|
9577
|
+
} else {
|
|
9578
|
+
shouldSkip = true;
|
|
9579
|
+
}
|
|
9580
|
+
break;
|
|
9581
|
+
}
|
|
9582
|
+
case "time-based": {
|
|
9583
|
+
const interval = taskConfig.refreshInterval ?? 0;
|
|
9584
|
+
if (interval <= 0) {
|
|
9585
|
+
shouldSkip = true;
|
|
9586
|
+
break;
|
|
9587
|
+
}
|
|
9588
|
+
const completedAt = taskState.completedAt;
|
|
9589
|
+
if (!completedAt) {
|
|
9590
|
+
shouldSkip = true;
|
|
9591
|
+
break;
|
|
9592
|
+
}
|
|
9593
|
+
const elapsedSec = (Date.now() - Date.parse(completedAt)) / 1e3;
|
|
9594
|
+
if (elapsedSec < interval) shouldSkip = true;
|
|
9595
|
+
break;
|
|
9596
|
+
}
|
|
9597
|
+
case "manual":
|
|
9598
|
+
shouldSkip = true;
|
|
9599
|
+
break;
|
|
9048
9600
|
}
|
|
9601
|
+
if (shouldSkip) continue;
|
|
9049
9602
|
}
|
|
9050
9603
|
const requires = getRequires(taskConfig);
|
|
9051
9604
|
if (requires.length === 0) {
|
|
@@ -9440,6 +9993,300 @@ function getDownstream(live, nodeName) {
|
|
|
9440
9993
|
}));
|
|
9441
9994
|
return { nodeName, nodes, tokens: [...tokenSet] };
|
|
9442
9995
|
}
|
|
9996
|
+
var MemoryJournal = class {
|
|
9997
|
+
buffer = [];
|
|
9998
|
+
append(event) {
|
|
9999
|
+
this.buffer.push(event);
|
|
10000
|
+
}
|
|
10001
|
+
drain() {
|
|
10002
|
+
const events = this.buffer;
|
|
10003
|
+
this.buffer = [];
|
|
10004
|
+
return events;
|
|
10005
|
+
}
|
|
10006
|
+
get size() {
|
|
10007
|
+
return this.buffer.length;
|
|
10008
|
+
}
|
|
10009
|
+
};
|
|
10010
|
+
var FileJournal = class {
|
|
10011
|
+
constructor(path) {
|
|
10012
|
+
this.path = path;
|
|
10013
|
+
if (!existsSync(path)) {
|
|
10014
|
+
writeFileSync(path, "", "utf-8");
|
|
10015
|
+
}
|
|
10016
|
+
}
|
|
10017
|
+
path;
|
|
10018
|
+
pending = 0;
|
|
10019
|
+
append(event) {
|
|
10020
|
+
appendFileSync(this.path, JSON.stringify(event) + "\n", "utf-8");
|
|
10021
|
+
this.pending++;
|
|
10022
|
+
}
|
|
10023
|
+
drain() {
|
|
10024
|
+
const content = readFileSync(this.path, "utf-8").trim();
|
|
10025
|
+
writeFileSync(this.path, "", "utf-8");
|
|
10026
|
+
this.pending = 0;
|
|
10027
|
+
if (!content) return [];
|
|
10028
|
+
return content.split("\n").map((line) => JSON.parse(line));
|
|
10029
|
+
}
|
|
10030
|
+
get size() {
|
|
10031
|
+
try {
|
|
10032
|
+
const content = readFileSync(this.path, "utf-8").trim();
|
|
10033
|
+
if (!content) return 0;
|
|
10034
|
+
return content.split("\n").length;
|
|
10035
|
+
} catch {
|
|
10036
|
+
return this.pending;
|
|
10037
|
+
}
|
|
10038
|
+
}
|
|
10039
|
+
};
|
|
10040
|
+
|
|
10041
|
+
// src/continuous-event-graph/reactive.ts
|
|
10042
|
+
function createReactiveGraph(config, options, executionId) {
|
|
10043
|
+
const {
|
|
10044
|
+
handlers: initialHandlers,
|
|
10045
|
+
maxDispatchRetries = 3,
|
|
10046
|
+
defaultTimeoutMs = 3e4,
|
|
10047
|
+
journal = new MemoryJournal(),
|
|
10048
|
+
onDispatchFailed,
|
|
10049
|
+
onAbandoned,
|
|
10050
|
+
onDrain
|
|
10051
|
+
} = options;
|
|
10052
|
+
let live = createLiveGraph(config, executionId);
|
|
10053
|
+
let disposed = false;
|
|
10054
|
+
const handlers = new Map(Object.entries(initialHandlers));
|
|
10055
|
+
const dispatched = /* @__PURE__ */ new Map();
|
|
10056
|
+
const timeoutTimers = /* @__PURE__ */ new Map();
|
|
10057
|
+
let draining = false;
|
|
10058
|
+
let drainQueued = false;
|
|
10059
|
+
function drain() {
|
|
10060
|
+
if (disposed) return;
|
|
10061
|
+
if (draining) {
|
|
10062
|
+
drainQueued = true;
|
|
10063
|
+
return;
|
|
10064
|
+
}
|
|
10065
|
+
draining = true;
|
|
10066
|
+
try {
|
|
10067
|
+
do {
|
|
10068
|
+
drainQueued = false;
|
|
10069
|
+
drainOnce();
|
|
10070
|
+
} while (drainQueued);
|
|
10071
|
+
} finally {
|
|
10072
|
+
draining = false;
|
|
10073
|
+
}
|
|
10074
|
+
}
|
|
10075
|
+
function drainOnce() {
|
|
10076
|
+
sweepTimeouts();
|
|
10077
|
+
const events = journal.drain();
|
|
10078
|
+
for (const event of events) {
|
|
10079
|
+
if (event.type === "task-completed" || event.type === "task-failed") {
|
|
10080
|
+
const taskName = event.taskName;
|
|
10081
|
+
dispatched.delete(taskName);
|
|
10082
|
+
clearTimeout(timeoutTimers.get(taskName));
|
|
10083
|
+
timeoutTimers.delete(taskName);
|
|
10084
|
+
}
|
|
10085
|
+
}
|
|
10086
|
+
if (events.length > 0) {
|
|
10087
|
+
live = applyEvents(live, events);
|
|
10088
|
+
}
|
|
10089
|
+
const result = schedule(live);
|
|
10090
|
+
if (onDrain && events.length > 0) {
|
|
10091
|
+
onDrain(events, live, result);
|
|
10092
|
+
}
|
|
10093
|
+
for (const taskName of result.eligible) {
|
|
10094
|
+
if (dispatched.has(taskName)) continue;
|
|
10095
|
+
dispatchTask(taskName);
|
|
10096
|
+
}
|
|
10097
|
+
for (const [taskName, entry] of dispatched) {
|
|
10098
|
+
if (entry.status === "retry-queued") {
|
|
10099
|
+
dispatchTask(taskName);
|
|
10100
|
+
}
|
|
10101
|
+
}
|
|
10102
|
+
}
|
|
10103
|
+
function dispatchTask(taskName) {
|
|
10104
|
+
const handler = handlers.get(taskName);
|
|
10105
|
+
if (!handler) {
|
|
10106
|
+
journal.append({
|
|
10107
|
+
type: "task-failed",
|
|
10108
|
+
taskName,
|
|
10109
|
+
error: `No handler registered for task "${taskName}"`,
|
|
10110
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10111
|
+
});
|
|
10112
|
+
drainQueued = true;
|
|
10113
|
+
return;
|
|
10114
|
+
}
|
|
10115
|
+
const existing = dispatched.get(taskName);
|
|
10116
|
+
const attempt = existing ? existing.dispatchAttempts + 1 : 1;
|
|
10117
|
+
if (attempt > maxDispatchRetries) {
|
|
10118
|
+
dispatched.set(taskName, {
|
|
10119
|
+
status: "abandoned",
|
|
10120
|
+
dispatchedAt: existing?.dispatchedAt ?? Date.now(),
|
|
10121
|
+
dispatchAttempts: attempt - 1,
|
|
10122
|
+
lastError: existing?.lastError
|
|
10123
|
+
});
|
|
10124
|
+
onAbandoned?.(taskName);
|
|
10125
|
+
journal.append({
|
|
10126
|
+
type: "task-failed",
|
|
10127
|
+
taskName,
|
|
10128
|
+
error: `dispatch-abandoned: handler unreachable after ${attempt - 1} attempts${existing?.lastError ? ` (${existing.lastError})` : ""}`,
|
|
10129
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10130
|
+
});
|
|
10131
|
+
drainQueued = true;
|
|
10132
|
+
return;
|
|
10133
|
+
}
|
|
10134
|
+
dispatched.set(taskName, {
|
|
10135
|
+
status: "initiated",
|
|
10136
|
+
dispatchedAt: Date.now(),
|
|
10137
|
+
dispatchAttempts: attempt
|
|
10138
|
+
});
|
|
10139
|
+
journal.append({
|
|
10140
|
+
type: "task-started",
|
|
10141
|
+
taskName,
|
|
10142
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10143
|
+
});
|
|
10144
|
+
if (defaultTimeoutMs > 0) {
|
|
10145
|
+
const timer = setTimeout(() => {
|
|
10146
|
+
if (disposed) return;
|
|
10147
|
+
const entry = dispatched.get(taskName);
|
|
10148
|
+
if (entry?.status === "initiated") {
|
|
10149
|
+
dispatched.set(taskName, {
|
|
10150
|
+
...entry,
|
|
10151
|
+
status: "timed-out"
|
|
10152
|
+
});
|
|
10153
|
+
dispatched.set(taskName, {
|
|
10154
|
+
...entry,
|
|
10155
|
+
status: entry.dispatchAttempts >= maxDispatchRetries ? "abandoned" : "retry-queued"
|
|
10156
|
+
});
|
|
10157
|
+
if (entry.dispatchAttempts >= maxDispatchRetries) {
|
|
10158
|
+
onAbandoned?.(taskName);
|
|
10159
|
+
journal.append({
|
|
10160
|
+
type: "task-failed",
|
|
10161
|
+
taskName,
|
|
10162
|
+
error: `dispatch-timeout: no callback after ${defaultTimeoutMs}ms (${entry.dispatchAttempts} attempts)`,
|
|
10163
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10164
|
+
});
|
|
10165
|
+
}
|
|
10166
|
+
drain();
|
|
10167
|
+
}
|
|
10168
|
+
}, defaultTimeoutMs);
|
|
10169
|
+
timeoutTimers.set(taskName, timer);
|
|
10170
|
+
}
|
|
10171
|
+
const ctx = {
|
|
10172
|
+
taskName,
|
|
10173
|
+
live,
|
|
10174
|
+
config: live.config.tasks[taskName]
|
|
10175
|
+
};
|
|
10176
|
+
try {
|
|
10177
|
+
const promise = handler(ctx);
|
|
10178
|
+
promise.then(
|
|
10179
|
+
(handlerResult) => {
|
|
10180
|
+
if (disposed) return;
|
|
10181
|
+
clearTimeout(timeoutTimers.get(taskName));
|
|
10182
|
+
timeoutTimers.delete(taskName);
|
|
10183
|
+
journal.append({
|
|
10184
|
+
type: "task-completed",
|
|
10185
|
+
taskName,
|
|
10186
|
+
result: handlerResult.result,
|
|
10187
|
+
data: handlerResult.data,
|
|
10188
|
+
dataHash: handlerResult.dataHash,
|
|
10189
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10190
|
+
});
|
|
10191
|
+
drain();
|
|
10192
|
+
},
|
|
10193
|
+
(error) => {
|
|
10194
|
+
if (disposed) return;
|
|
10195
|
+
clearTimeout(timeoutTimers.get(taskName));
|
|
10196
|
+
timeoutTimers.delete(taskName);
|
|
10197
|
+
journal.append({
|
|
10198
|
+
type: "task-failed",
|
|
10199
|
+
taskName,
|
|
10200
|
+
error: error.message ?? String(error),
|
|
10201
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10202
|
+
});
|
|
10203
|
+
drain();
|
|
10204
|
+
}
|
|
10205
|
+
);
|
|
10206
|
+
} catch (syncError) {
|
|
10207
|
+
const err = syncError instanceof Error ? syncError : new Error(String(syncError));
|
|
10208
|
+
dispatched.set(taskName, {
|
|
10209
|
+
status: "dispatch-failed",
|
|
10210
|
+
dispatchedAt: Date.now(),
|
|
10211
|
+
dispatchAttempts: attempt,
|
|
10212
|
+
lastError: err.message
|
|
10213
|
+
});
|
|
10214
|
+
onDispatchFailed?.(taskName, err, attempt);
|
|
10215
|
+
dispatched.set(taskName, {
|
|
10216
|
+
...dispatched.get(taskName),
|
|
10217
|
+
status: "retry-queued"
|
|
10218
|
+
});
|
|
10219
|
+
drainQueued = true;
|
|
10220
|
+
}
|
|
10221
|
+
}
|
|
10222
|
+
function sweepTimeouts() {
|
|
10223
|
+
const now = Date.now();
|
|
10224
|
+
for (const [taskName, entry] of dispatched) {
|
|
10225
|
+
if (entry.status !== "initiated") continue;
|
|
10226
|
+
if (defaultTimeoutMs <= 0) continue;
|
|
10227
|
+
if (now - entry.dispatchedAt >= defaultTimeoutMs) {
|
|
10228
|
+
dispatched.set(taskName, {
|
|
10229
|
+
...entry,
|
|
10230
|
+
status: entry.dispatchAttempts >= maxDispatchRetries ? "abandoned" : "retry-queued"
|
|
10231
|
+
});
|
|
10232
|
+
if (entry.dispatchAttempts >= maxDispatchRetries) {
|
|
10233
|
+
onAbandoned?.(taskName);
|
|
10234
|
+
journal.append({
|
|
10235
|
+
type: "task-failed",
|
|
10236
|
+
taskName,
|
|
10237
|
+
error: `dispatch-timeout: no callback after ${defaultTimeoutMs}ms (${entry.dispatchAttempts} attempts)`,
|
|
10238
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10239
|
+
});
|
|
10240
|
+
}
|
|
10241
|
+
clearTimeout(timeoutTimers.get(taskName));
|
|
10242
|
+
timeoutTimers.delete(taskName);
|
|
10243
|
+
}
|
|
10244
|
+
}
|
|
10245
|
+
}
|
|
10246
|
+
return {
|
|
10247
|
+
push(event) {
|
|
10248
|
+
if (disposed) return;
|
|
10249
|
+
live = applyEvent(live, event);
|
|
10250
|
+
drain();
|
|
10251
|
+
},
|
|
10252
|
+
pushAll(events) {
|
|
10253
|
+
if (disposed) return;
|
|
10254
|
+
if (events.length === 0) return;
|
|
10255
|
+
live = applyEvents(live, events);
|
|
10256
|
+
drain();
|
|
10257
|
+
},
|
|
10258
|
+
addNode(name, taskConfig, handler) {
|
|
10259
|
+
if (disposed) return;
|
|
10260
|
+
live = addNode(live, name, taskConfig);
|
|
10261
|
+
handlers.set(name, handler);
|
|
10262
|
+
drain();
|
|
10263
|
+
},
|
|
10264
|
+
removeNode(name) {
|
|
10265
|
+
if (disposed) return;
|
|
10266
|
+
live = removeNode(live, name);
|
|
10267
|
+
handlers.delete(name);
|
|
10268
|
+
dispatched.delete(name);
|
|
10269
|
+
clearTimeout(timeoutTimers.get(name));
|
|
10270
|
+
timeoutTimers.delete(name);
|
|
10271
|
+
},
|
|
10272
|
+
getState() {
|
|
10273
|
+
return live;
|
|
10274
|
+
},
|
|
10275
|
+
getSchedule() {
|
|
10276
|
+
return schedule(live);
|
|
10277
|
+
},
|
|
10278
|
+
getDispatchState() {
|
|
10279
|
+
return dispatched;
|
|
10280
|
+
},
|
|
10281
|
+
dispose() {
|
|
10282
|
+
disposed = true;
|
|
10283
|
+
for (const timer of timeoutTimers.values()) {
|
|
10284
|
+
clearTimeout(timer);
|
|
10285
|
+
}
|
|
10286
|
+
timeoutTimers.clear();
|
|
10287
|
+
}
|
|
10288
|
+
};
|
|
10289
|
+
}
|
|
9443
10290
|
|
|
9444
10291
|
// src/inference/core.ts
|
|
9445
10292
|
var DEFAULT_THRESHOLD = 0.5;
|
|
@@ -10005,17 +10852,17 @@ var live_cards_schema_default = {
|
|
|
10005
10852
|
};
|
|
10006
10853
|
|
|
10007
10854
|
// src/card-compute/schema-validator.ts
|
|
10008
|
-
var
|
|
10009
|
-
var
|
|
10010
|
-
function
|
|
10011
|
-
if (
|
|
10012
|
-
const ajv = new
|
|
10855
|
+
var import_ajv3 = __toESM(require_ajv());
|
|
10856
|
+
var _compiled3 = null;
|
|
10857
|
+
function getValidator3() {
|
|
10858
|
+
if (_compiled3) return _compiled3;
|
|
10859
|
+
const ajv = new import_ajv3.default({ allErrors: true });
|
|
10013
10860
|
addFormats(ajv);
|
|
10014
|
-
|
|
10015
|
-
return
|
|
10861
|
+
_compiled3 = ajv.compile(live_cards_schema_default);
|
|
10862
|
+
return _compiled3;
|
|
10016
10863
|
}
|
|
10017
10864
|
function validateLiveCardSchema(node) {
|
|
10018
|
-
const validate =
|
|
10865
|
+
const validate = getValidator3();
|
|
10019
10866
|
const valid = validate(node);
|
|
10020
10867
|
if (valid) return { ok: true, errors: [] };
|
|
10021
10868
|
const errors = (validate.errors ?? []).map((e) => {
|
|
@@ -10472,6 +11319,6 @@ var CardCompute = {
|
|
|
10472
11319
|
}
|
|
10473
11320
|
};
|
|
10474
11321
|
|
|
10475
|
-
export { COMPLETION_STRATEGIES, CONFLICT_STRATEGIES, CardCompute, DEFAULTS, EXECUTION_MODES, EXECUTION_STATUS, FileStore, StepMachine as FlowEngine, LocalStorageStore, MemoryStore, StepMachine, TASK_STATUS, addDynamicTask, addNode, addProvides, addRequires, apply, applyAll, applyEvent, applyInferences, applyStepResult, batch, buildInferencePrompt, checkCircuitBreaker, computeAvailableOutputs, computeStepInput, createCliAdapter, createDefaultTaskState, createStepMachine as createEngine, createHttpAdapter, createInitialExecutionState, createInitialState, createLiveGraph, createStepMachine, detectStuckState, disableNode, drainTokens, enableNode, exportGraphConfig, exportGraphConfigToFile, extractReturnData, flowToMermaid, getAllTasks, getCandidateTasks, getDownstream, getNode, getProvides, getRequires, getTask, getUnreachableNodes, getUnreachableTokens, getUpstream, graphToMermaid, hasTask, inferAndApply, inferCompletions, injectTokens, inspect, isExecutionComplete, isNonActiveTask,
|
|
11322
|
+
export { COMPLETION_STRATEGIES, CONFLICT_STRATEGIES, CardCompute, DEFAULTS, EXECUTION_MODES, EXECUTION_STATUS, FileJournal, FileStore, StepMachine as FlowEngine, LocalStorageStore, MemoryJournal, MemoryStore, StepMachine, TASK_STATUS, addDynamicTask, addNode, addProvides, addRequires, apply, applyAll, applyEvent, applyEvents, applyInferences, applyStepResult, batch, buildInferencePrompt, checkCircuitBreaker, computeAvailableOutputs, computeStepInput, createCliAdapter, createDefaultTaskState, createStepMachine as createEngine, createHttpAdapter, createInitialExecutionState, createInitialState, createLiveGraph, createReactiveGraph, createStepMachine, detectStuckState, disableNode, drainTokens, enableNode, exportGraphConfig, exportGraphConfigToFile, extractReturnData, flowToMermaid, getAllTasks, getCandidateTasks, getDownstream, getMaxExecutions, getNode, getProvides, getRefreshStrategy, getRequires, getTask, getUnreachableNodes, getUnreachableTokens, getUpstream, graphToMermaid, hasTask, inferAndApply, inferCompletions, injectTokens, inspect, isExecutionComplete, isNonActiveTask, isRerunnable, isTaskCompleted, isTaskRunning, loadGraphConfig, loadStepFlow, next, planExecution, removeNode, removeProvides, removeRequires, resetNode, resolveConfigTemplates, resolveVariables, restore, schedule, snapshot, validateFlowSchema, validateGraph, validateGraphConfig, validateGraphSchema, validateLiveCardSchema, validateStepFlowConfig };
|
|
10476
11323
|
//# sourceMappingURL=index.js.map
|
|
10477
11324
|
//# sourceMappingURL=index.js.map
|