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.cjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var child_process = require('child_process');
|
|
4
3
|
var addFormats = require('ajv-formats');
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var child_process = require('child_process');
|
|
5
6
|
|
|
6
7
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
8
|
|
|
@@ -3917,7 +3918,7 @@ var require_core = __commonJS({
|
|
|
3917
3918
|
uriResolver
|
|
3918
3919
|
};
|
|
3919
3920
|
}
|
|
3920
|
-
var
|
|
3921
|
+
var Ajv4 = class {
|
|
3921
3922
|
constructor(opts = {}) {
|
|
3922
3923
|
this.schemas = {};
|
|
3923
3924
|
this.refs = {};
|
|
@@ -4287,9 +4288,9 @@ var require_core = __commonJS({
|
|
|
4287
4288
|
}
|
|
4288
4289
|
}
|
|
4289
4290
|
};
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
exports$1.default =
|
|
4291
|
+
Ajv4.ValidationError = validation_error_1.default;
|
|
4292
|
+
Ajv4.MissingRefError = ref_error_1.default;
|
|
4293
|
+
exports$1.default = Ajv4;
|
|
4293
4294
|
function checkOptions(checkOpts, options, msg, log = "error") {
|
|
4294
4295
|
for (const key in checkOpts) {
|
|
4295
4296
|
const opt = key;
|
|
@@ -6360,7 +6361,7 @@ var require_ajv = __commonJS({
|
|
|
6360
6361
|
var draft7MetaSchema = require_json_schema_draft_07();
|
|
6361
6362
|
var META_SUPPORT_DATA = ["/properties"];
|
|
6362
6363
|
var META_SCHEMA_ID = "http://json-schema.org/draft-07/schema";
|
|
6363
|
-
var
|
|
6364
|
+
var Ajv4 = class extends core_1.default {
|
|
6364
6365
|
_addVocabularies() {
|
|
6365
6366
|
super._addVocabularies();
|
|
6366
6367
|
draft7_1.default.forEach((v) => this.addVocabulary(v));
|
|
@@ -6379,11 +6380,11 @@ var require_ajv = __commonJS({
|
|
|
6379
6380
|
return this.opts.defaultMeta = super.defaultMeta() || (this.getSchema(META_SCHEMA_ID) ? META_SCHEMA_ID : void 0);
|
|
6380
6381
|
}
|
|
6381
6382
|
};
|
|
6382
|
-
exports$1.Ajv =
|
|
6383
|
-
module.exports = exports$1 =
|
|
6384
|
-
module.exports.Ajv =
|
|
6383
|
+
exports$1.Ajv = Ajv4;
|
|
6384
|
+
module.exports = exports$1 = Ajv4;
|
|
6385
|
+
module.exports.Ajv = Ajv4;
|
|
6385
6386
|
Object.defineProperty(exports$1, "__esModule", { value: true });
|
|
6386
|
-
exports$1.default =
|
|
6387
|
+
exports$1.default = Ajv4;
|
|
6387
6388
|
var validate_1 = require_validate();
|
|
6388
6389
|
Object.defineProperty(exports$1, "KeywordCxt", { enumerable: true, get: function() {
|
|
6389
6390
|
return validate_1.KeywordCxt;
|
|
@@ -6917,6 +6918,188 @@ async function loadStepFlow(source) {
|
|
|
6917
6918
|
return flow;
|
|
6918
6919
|
}
|
|
6919
6920
|
|
|
6921
|
+
// schema/flow.schema.json
|
|
6922
|
+
var flow_schema_default = {
|
|
6923
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
6924
|
+
$id: "https://github.com/yaml-flow/schema/flow.json",
|
|
6925
|
+
title: "YamlFlow Configuration",
|
|
6926
|
+
description: "Schema for yaml-flow workflow definitions",
|
|
6927
|
+
type: "object",
|
|
6928
|
+
required: ["settings", "steps", "terminal_states"],
|
|
6929
|
+
properties: {
|
|
6930
|
+
id: {
|
|
6931
|
+
type: "string",
|
|
6932
|
+
description: "Optional flow identifier"
|
|
6933
|
+
},
|
|
6934
|
+
settings: {
|
|
6935
|
+
type: "object",
|
|
6936
|
+
description: "Flow-level settings",
|
|
6937
|
+
required: ["start_step"],
|
|
6938
|
+
properties: {
|
|
6939
|
+
start_step: {
|
|
6940
|
+
type: "string",
|
|
6941
|
+
description: "Step to start execution from"
|
|
6942
|
+
},
|
|
6943
|
+
max_total_steps: {
|
|
6944
|
+
type: "integer",
|
|
6945
|
+
minimum: 1,
|
|
6946
|
+
default: 100,
|
|
6947
|
+
description: "Maximum steps before forced termination"
|
|
6948
|
+
},
|
|
6949
|
+
timeout_ms: {
|
|
6950
|
+
type: "integer",
|
|
6951
|
+
minimum: 0,
|
|
6952
|
+
description: "Flow timeout in milliseconds"
|
|
6953
|
+
}
|
|
6954
|
+
},
|
|
6955
|
+
additionalProperties: false
|
|
6956
|
+
},
|
|
6957
|
+
steps: {
|
|
6958
|
+
type: "object",
|
|
6959
|
+
description: "Step definitions",
|
|
6960
|
+
minProperties: 1,
|
|
6961
|
+
additionalProperties: {
|
|
6962
|
+
$ref: "#/definitions/step"
|
|
6963
|
+
}
|
|
6964
|
+
},
|
|
6965
|
+
terminal_states: {
|
|
6966
|
+
type: "object",
|
|
6967
|
+
description: "Terminal state definitions",
|
|
6968
|
+
minProperties: 1,
|
|
6969
|
+
additionalProperties: {
|
|
6970
|
+
$ref: "#/definitions/terminal_state"
|
|
6971
|
+
}
|
|
6972
|
+
}
|
|
6973
|
+
},
|
|
6974
|
+
additionalProperties: false,
|
|
6975
|
+
definitions: {
|
|
6976
|
+
step: {
|
|
6977
|
+
type: "object",
|
|
6978
|
+
description: "Individual step configuration",
|
|
6979
|
+
required: ["transitions"],
|
|
6980
|
+
properties: {
|
|
6981
|
+
description: {
|
|
6982
|
+
type: "string",
|
|
6983
|
+
description: "Human-readable description"
|
|
6984
|
+
},
|
|
6985
|
+
expects_data: {
|
|
6986
|
+
type: "array",
|
|
6987
|
+
items: { type: "string" },
|
|
6988
|
+
description: "Data keys this step expects as input"
|
|
6989
|
+
},
|
|
6990
|
+
produces_data: {
|
|
6991
|
+
type: "array",
|
|
6992
|
+
items: { type: "string" },
|
|
6993
|
+
description: "Data keys this step produces as output"
|
|
6994
|
+
},
|
|
6995
|
+
transitions: {
|
|
6996
|
+
type: "object",
|
|
6997
|
+
description: "Mapping of result -> next step name",
|
|
6998
|
+
additionalProperties: { type: "string" },
|
|
6999
|
+
minProperties: 1
|
|
7000
|
+
},
|
|
7001
|
+
retry: {
|
|
7002
|
+
$ref: "#/definitions/retry_config"
|
|
7003
|
+
},
|
|
7004
|
+
circuit_breaker: {
|
|
7005
|
+
$ref: "#/definitions/circuit_breaker_config"
|
|
7006
|
+
}
|
|
7007
|
+
},
|
|
7008
|
+
additionalProperties: false
|
|
7009
|
+
},
|
|
7010
|
+
terminal_state: {
|
|
7011
|
+
type: "object",
|
|
7012
|
+
description: "Terminal state configuration",
|
|
7013
|
+
required: ["return_intent"],
|
|
7014
|
+
properties: {
|
|
7015
|
+
description: {
|
|
7016
|
+
type: "string",
|
|
7017
|
+
description: "Human-readable description"
|
|
7018
|
+
},
|
|
7019
|
+
return_intent: {
|
|
7020
|
+
type: "string",
|
|
7021
|
+
description: "Intent/status to return (e.g., 'success', 'error')"
|
|
7022
|
+
},
|
|
7023
|
+
return_artifacts: {
|
|
7024
|
+
oneOf: [
|
|
7025
|
+
{ type: "string" },
|
|
7026
|
+
{ type: "array", items: { type: "string" } },
|
|
7027
|
+
{ type: "boolean", const: false }
|
|
7028
|
+
],
|
|
7029
|
+
description: "Data key(s) to include in result, or false to exclude"
|
|
7030
|
+
},
|
|
7031
|
+
expects_data: {
|
|
7032
|
+
type: "array",
|
|
7033
|
+
items: { type: "string" },
|
|
7034
|
+
description: "Data keys this terminal state expects"
|
|
7035
|
+
}
|
|
7036
|
+
},
|
|
7037
|
+
additionalProperties: false
|
|
7038
|
+
},
|
|
7039
|
+
retry_config: {
|
|
7040
|
+
type: "object",
|
|
7041
|
+
description: "Retry configuration for step failures",
|
|
7042
|
+
required: ["max_attempts"],
|
|
7043
|
+
properties: {
|
|
7044
|
+
max_attempts: {
|
|
7045
|
+
type: "integer",
|
|
7046
|
+
minimum: 1,
|
|
7047
|
+
description: "Maximum retry attempts"
|
|
7048
|
+
},
|
|
7049
|
+
delay_ms: {
|
|
7050
|
+
type: "integer",
|
|
7051
|
+
minimum: 0,
|
|
7052
|
+
description: "Delay between retries in ms"
|
|
7053
|
+
},
|
|
7054
|
+
backoff_multiplier: {
|
|
7055
|
+
type: "number",
|
|
7056
|
+
minimum: 1,
|
|
7057
|
+
description: "Backoff multiplier (e.g., 2 for exponential)"
|
|
7058
|
+
}
|
|
7059
|
+
},
|
|
7060
|
+
additionalProperties: false
|
|
7061
|
+
},
|
|
7062
|
+
circuit_breaker_config: {
|
|
7063
|
+
type: "object",
|
|
7064
|
+
description: "Circuit breaker configuration for loops",
|
|
7065
|
+
required: ["max_iterations", "on_open"],
|
|
7066
|
+
properties: {
|
|
7067
|
+
max_iterations: {
|
|
7068
|
+
type: "integer",
|
|
7069
|
+
minimum: 1,
|
|
7070
|
+
description: "Maximum iterations before circuit opens"
|
|
7071
|
+
},
|
|
7072
|
+
on_open: {
|
|
7073
|
+
type: "string",
|
|
7074
|
+
description: "Step to transition to when circuit opens"
|
|
7075
|
+
}
|
|
7076
|
+
},
|
|
7077
|
+
additionalProperties: false
|
|
7078
|
+
}
|
|
7079
|
+
}
|
|
7080
|
+
};
|
|
7081
|
+
|
|
7082
|
+
// src/step-machine/schema-validator.ts
|
|
7083
|
+
var import_ajv = __toESM(require_ajv());
|
|
7084
|
+
var _compiled = null;
|
|
7085
|
+
function getValidator() {
|
|
7086
|
+
if (_compiled) return _compiled;
|
|
7087
|
+
const ajv = new import_ajv.default({ allErrors: true });
|
|
7088
|
+
addFormats__default.default(ajv);
|
|
7089
|
+
_compiled = ajv.compile(flow_schema_default);
|
|
7090
|
+
return _compiled;
|
|
7091
|
+
}
|
|
7092
|
+
function validateFlowSchema(config) {
|
|
7093
|
+
const validate = getValidator();
|
|
7094
|
+
const valid = validate(config);
|
|
7095
|
+
if (valid) return { ok: true, errors: [] };
|
|
7096
|
+
const errors = (validate.errors ?? []).map((e) => {
|
|
7097
|
+
const path = e.instancePath || "/";
|
|
7098
|
+
return `${path}: ${e.message ?? "unknown error"}`;
|
|
7099
|
+
});
|
|
7100
|
+
return { ok: false, errors };
|
|
7101
|
+
}
|
|
7102
|
+
|
|
6920
7103
|
// src/event-graph/constants.ts
|
|
6921
7104
|
var TASK_STATUS = {
|
|
6922
7105
|
NOT_STARTED: "not-started",
|
|
@@ -6993,15 +7176,14 @@ function isTaskCompleted(taskState) {
|
|
|
6993
7176
|
function isTaskRunning(taskState) {
|
|
6994
7177
|
return taskState?.status === TASK_STATUS.RUNNING;
|
|
6995
7178
|
}
|
|
6996
|
-
function
|
|
6997
|
-
return taskConfig.
|
|
7179
|
+
function getRefreshStrategy(taskConfig, graphSettings) {
|
|
7180
|
+
return taskConfig.refreshStrategy ?? graphSettings?.refreshStrategy ?? "data-changed";
|
|
6998
7181
|
}
|
|
6999
|
-
function
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
return void 0;
|
|
7182
|
+
function isRerunnable(taskConfig, graphSettings) {
|
|
7183
|
+
return getRefreshStrategy(taskConfig, graphSettings) !== "once";
|
|
7184
|
+
}
|
|
7185
|
+
function getMaxExecutions(taskConfig) {
|
|
7186
|
+
return taskConfig.maxExecutions;
|
|
7005
7187
|
}
|
|
7006
7188
|
function computeAvailableOutputs(graph, taskStates) {
|
|
7007
7189
|
const outputs = /* @__PURE__ */ new Set();
|
|
@@ -7433,48 +7615,88 @@ function getCandidateTasks(graph, state) {
|
|
|
7433
7615
|
const candidates = [];
|
|
7434
7616
|
for (const [taskName, taskConfig] of Object.entries(graphTasks)) {
|
|
7435
7617
|
const taskState = state.tasks[taskName];
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
}
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7618
|
+
const strategy = getRefreshStrategy(taskConfig, graph.settings);
|
|
7619
|
+
const rerunnable = strategy !== "once";
|
|
7620
|
+
if (taskState?.status === TASK_STATUS.RUNNING || isNonActiveTask(taskState)) {
|
|
7621
|
+
continue;
|
|
7622
|
+
}
|
|
7623
|
+
const maxExec = getMaxExecutions(taskConfig);
|
|
7624
|
+
if (maxExec !== void 0 && taskState && taskState.executionCount >= maxExec) {
|
|
7625
|
+
continue;
|
|
7626
|
+
}
|
|
7627
|
+
if (taskConfig.circuit_breaker && taskState && taskState.executionCount >= taskConfig.circuit_breaker.max_executions) {
|
|
7628
|
+
continue;
|
|
7629
|
+
}
|
|
7630
|
+
if (!rerunnable) {
|
|
7631
|
+
if (taskState?.status === TASK_STATUS.COMPLETED) {
|
|
7446
7632
|
continue;
|
|
7447
7633
|
}
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7634
|
+
}
|
|
7635
|
+
if (rerunnable && taskState?.status === TASK_STATUS.COMPLETED) {
|
|
7636
|
+
const requires2 = getRequires(taskConfig);
|
|
7637
|
+
switch (strategy) {
|
|
7638
|
+
case "data-changed": {
|
|
7639
|
+
if (requires2.length > 0) {
|
|
7640
|
+
const hasChangedData = requires2.some((req) => {
|
|
7641
|
+
for (const [otherName, otherConfig] of Object.entries(graphTasks)) {
|
|
7642
|
+
if (getProvides(otherConfig).includes(req)) {
|
|
7643
|
+
const otherState = state.tasks[otherName];
|
|
7644
|
+
if (!otherState) continue;
|
|
7645
|
+
const consumed = taskState.lastConsumedHashes?.[req];
|
|
7646
|
+
if (otherState.lastDataHash == null) {
|
|
7647
|
+
return otherState.executionCount > taskState.lastEpoch;
|
|
7648
|
+
}
|
|
7649
|
+
return otherState.lastDataHash !== consumed;
|
|
7650
|
+
}
|
|
7651
|
+
}
|
|
7652
|
+
return false;
|
|
7653
|
+
});
|
|
7654
|
+
if (!hasChangedData) continue;
|
|
7655
|
+
} else {
|
|
7656
|
+
continue;
|
|
7657
|
+
}
|
|
7658
|
+
break;
|
|
7451
7659
|
}
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
return true;
|
|
7660
|
+
case "epoch-changed": {
|
|
7661
|
+
if (requires2.length > 0) {
|
|
7662
|
+
const hasRefreshedInputs = requires2.some((req) => {
|
|
7663
|
+
for (const [otherName, otherConfig] of Object.entries(graphTasks)) {
|
|
7664
|
+
if (getProvides(otherConfig).includes(req)) {
|
|
7665
|
+
const otherState = state.tasks[otherName];
|
|
7666
|
+
if (otherState && otherState.executionCount > taskState.lastEpoch) {
|
|
7667
|
+
return true;
|
|
7668
|
+
}
|
|
7462
7669
|
}
|
|
7463
7670
|
}
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7671
|
+
return false;
|
|
7672
|
+
});
|
|
7673
|
+
if (!hasRefreshedInputs) continue;
|
|
7674
|
+
} else {
|
|
7675
|
+
continue;
|
|
7676
|
+
}
|
|
7677
|
+
break;
|
|
7678
|
+
}
|
|
7679
|
+
case "time-based": {
|
|
7680
|
+
const interval = taskConfig.refreshInterval ?? 0;
|
|
7681
|
+
if (interval <= 0) continue;
|
|
7682
|
+
const completedAt = taskState.completedAt;
|
|
7683
|
+
if (!completedAt) continue;
|
|
7684
|
+
const elapsedSec = (Date.now() - Date.parse(completedAt)) / 1e3;
|
|
7685
|
+
if (elapsedSec < interval) continue;
|
|
7686
|
+
break;
|
|
7687
|
+
}
|
|
7688
|
+
case "manual": {
|
|
7469
7689
|
continue;
|
|
7470
7690
|
}
|
|
7691
|
+
default:
|
|
7692
|
+
continue;
|
|
7471
7693
|
}
|
|
7472
7694
|
}
|
|
7473
7695
|
const requires = getRequires(taskConfig);
|
|
7474
7696
|
if (!requires.every((req) => availableOutputs.includes(req))) {
|
|
7475
7697
|
continue;
|
|
7476
7698
|
}
|
|
7477
|
-
if (!
|
|
7699
|
+
if (!rerunnable) {
|
|
7478
7700
|
const provides = getProvides(taskConfig);
|
|
7479
7701
|
const allAlreadyAvailable = provides.length > 0 && provides.every((output) => availableOutputs.includes(output));
|
|
7480
7702
|
if (allAlreadyAvailable) continue;
|
|
@@ -7558,7 +7780,7 @@ function applyTaskStart(state, taskName) {
|
|
|
7558
7780
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
7559
7781
|
};
|
|
7560
7782
|
}
|
|
7561
|
-
function applyTaskCompletion(state, graph, taskName, result) {
|
|
7783
|
+
function applyTaskCompletion(state, graph, taskName, result, dataHash) {
|
|
7562
7784
|
const existingTask = state.tasks[taskName] ?? createDefaultTaskState2();
|
|
7563
7785
|
const taskConfig = graph.tasks[taskName];
|
|
7564
7786
|
if (!taskConfig) {
|
|
@@ -7570,6 +7792,19 @@ function applyTaskCompletion(state, graph, taskName, result) {
|
|
|
7570
7792
|
} else {
|
|
7571
7793
|
outputTokens = getProvides(taskConfig);
|
|
7572
7794
|
}
|
|
7795
|
+
const lastConsumedHashes = { ...existingTask.lastConsumedHashes };
|
|
7796
|
+
const requires = taskConfig.requires ?? [];
|
|
7797
|
+
for (const token of requires) {
|
|
7798
|
+
for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {
|
|
7799
|
+
if (getProvides(otherConfig).includes(token)) {
|
|
7800
|
+
const otherState = state.tasks[otherName];
|
|
7801
|
+
if (otherState?.lastDataHash) {
|
|
7802
|
+
lastConsumedHashes[token] = otherState.lastDataHash;
|
|
7803
|
+
}
|
|
7804
|
+
break;
|
|
7805
|
+
}
|
|
7806
|
+
}
|
|
7807
|
+
}
|
|
7573
7808
|
const updatedTask = {
|
|
7574
7809
|
...existingTask,
|
|
7575
7810
|
status: "completed",
|
|
@@ -7577,11 +7812,10 @@ function applyTaskCompletion(state, graph, taskName, result) {
|
|
|
7577
7812
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7578
7813
|
executionCount: existingTask.executionCount + 1,
|
|
7579
7814
|
lastEpoch: existingTask.executionCount + 1,
|
|
7815
|
+
lastDataHash: dataHash,
|
|
7816
|
+
lastConsumedHashes,
|
|
7580
7817
|
error: void 0
|
|
7581
7818
|
};
|
|
7582
|
-
if (isRepeatableTask(taskConfig)) {
|
|
7583
|
-
updatedTask.status = "not-started";
|
|
7584
|
-
}
|
|
7585
7819
|
const newOutputs = [.../* @__PURE__ */ new Set([...state.availableOutputs, ...outputTokens])];
|
|
7586
7820
|
return {
|
|
7587
7821
|
...state,
|
|
@@ -7670,7 +7904,7 @@ function apply(state, event, graph) {
|
|
|
7670
7904
|
case "task-started":
|
|
7671
7905
|
return applyTaskStart(state, event.taskName);
|
|
7672
7906
|
case "task-completed":
|
|
7673
|
-
return applyTaskCompletion(state, graph, event.taskName, event.result);
|
|
7907
|
+
return applyTaskCompletion(state, graph, event.taskName, event.result, event.dataHash);
|
|
7674
7908
|
case "task-failed":
|
|
7675
7909
|
return applyTaskFailure(state, graph, event.taskName, event.error);
|
|
7676
7910
|
case "task-progress":
|
|
@@ -8360,6 +8594,276 @@ function buildResult(issues) {
|
|
|
8360
8594
|
};
|
|
8361
8595
|
}
|
|
8362
8596
|
|
|
8597
|
+
// schema/event-graph.schema.json
|
|
8598
|
+
var event_graph_schema_default = {
|
|
8599
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
8600
|
+
$id: "https://github.com/yaml-flow/schema/event-graph.json",
|
|
8601
|
+
title: "Event Graph Configuration",
|
|
8602
|
+
description: "Schema for stateless event-graph (DAG) workflow definitions in yaml-flow",
|
|
8603
|
+
type: "object",
|
|
8604
|
+
required: ["settings", "tasks"],
|
|
8605
|
+
additionalProperties: false,
|
|
8606
|
+
properties: {
|
|
8607
|
+
id: {
|
|
8608
|
+
type: "string",
|
|
8609
|
+
description: "Optional graph identifier"
|
|
8610
|
+
},
|
|
8611
|
+
settings: {
|
|
8612
|
+
$ref: "#/definitions/settings"
|
|
8613
|
+
},
|
|
8614
|
+
tasks: {
|
|
8615
|
+
type: "object",
|
|
8616
|
+
description: "Task definitions keyed by name",
|
|
8617
|
+
minProperties: 1,
|
|
8618
|
+
additionalProperties: {
|
|
8619
|
+
$ref: "#/definitions/task"
|
|
8620
|
+
}
|
|
8621
|
+
}
|
|
8622
|
+
},
|
|
8623
|
+
definitions: {
|
|
8624
|
+
settings: {
|
|
8625
|
+
type: "object",
|
|
8626
|
+
required: ["completion"],
|
|
8627
|
+
properties: {
|
|
8628
|
+
completion: {
|
|
8629
|
+
type: "string",
|
|
8630
|
+
enum: [
|
|
8631
|
+
"all-tasks-done",
|
|
8632
|
+
"all-outputs-done",
|
|
8633
|
+
"only-resolved",
|
|
8634
|
+
"goal-reached",
|
|
8635
|
+
"manual"
|
|
8636
|
+
],
|
|
8637
|
+
description: "Completion strategy"
|
|
8638
|
+
},
|
|
8639
|
+
conflict_strategy: {
|
|
8640
|
+
type: "string",
|
|
8641
|
+
enum: [
|
|
8642
|
+
"alphabetical",
|
|
8643
|
+
"priority-first",
|
|
8644
|
+
"duration-first",
|
|
8645
|
+
"cost-optimized",
|
|
8646
|
+
"resource-aware",
|
|
8647
|
+
"random-select",
|
|
8648
|
+
"user-choice",
|
|
8649
|
+
"parallel-all",
|
|
8650
|
+
"skip-conflicts",
|
|
8651
|
+
"round-robin"
|
|
8652
|
+
],
|
|
8653
|
+
description: "Conflict resolution strategy"
|
|
8654
|
+
},
|
|
8655
|
+
execution_mode: {
|
|
8656
|
+
type: "string",
|
|
8657
|
+
enum: ["dependency-mode", "eligibility-mode"],
|
|
8658
|
+
description: "Execution mode"
|
|
8659
|
+
},
|
|
8660
|
+
goal: {
|
|
8661
|
+
type: "array",
|
|
8662
|
+
items: { type: "string" },
|
|
8663
|
+
minItems: 1,
|
|
8664
|
+
description: "Goal outputs \u2014 required when completion is 'goal-reached'"
|
|
8665
|
+
},
|
|
8666
|
+
max_iterations: {
|
|
8667
|
+
type: "integer",
|
|
8668
|
+
minimum: 1,
|
|
8669
|
+
description: "Max scheduler iterations (safety limit, default: 1000)"
|
|
8670
|
+
},
|
|
8671
|
+
timeout_ms: {
|
|
8672
|
+
type: "integer",
|
|
8673
|
+
minimum: 0,
|
|
8674
|
+
description: "Timeout in ms (declared for drivers, not enforced by pure engine)"
|
|
8675
|
+
},
|
|
8676
|
+
refreshStrategy: {
|
|
8677
|
+
$ref: "#/definitions/refresh_strategy",
|
|
8678
|
+
description: "Default refresh strategy for all tasks (default: 'data-changed')"
|
|
8679
|
+
}
|
|
8680
|
+
},
|
|
8681
|
+
additionalProperties: false,
|
|
8682
|
+
if: {
|
|
8683
|
+
properties: { completion: { const: "goal-reached" } }
|
|
8684
|
+
},
|
|
8685
|
+
then: {
|
|
8686
|
+
required: ["completion", "goal"]
|
|
8687
|
+
}
|
|
8688
|
+
},
|
|
8689
|
+
task: {
|
|
8690
|
+
type: "object",
|
|
8691
|
+
required: ["provides"],
|
|
8692
|
+
properties: {
|
|
8693
|
+
requires: {
|
|
8694
|
+
type: "array",
|
|
8695
|
+
items: { type: "string" },
|
|
8696
|
+
description: "Tokens this task needs to become eligible"
|
|
8697
|
+
},
|
|
8698
|
+
provides: {
|
|
8699
|
+
type: "array",
|
|
8700
|
+
items: { type: "string" },
|
|
8701
|
+
description: "Tokens this task produces on successful completion"
|
|
8702
|
+
},
|
|
8703
|
+
on: {
|
|
8704
|
+
type: "object",
|
|
8705
|
+
description: "Conditional provides based on handler result key",
|
|
8706
|
+
additionalProperties: {
|
|
8707
|
+
type: "array",
|
|
8708
|
+
items: { type: "string" }
|
|
8709
|
+
}
|
|
8710
|
+
},
|
|
8711
|
+
on_failure: {
|
|
8712
|
+
type: "array",
|
|
8713
|
+
items: { type: "string" },
|
|
8714
|
+
description: "Tokens to inject when this task fails"
|
|
8715
|
+
},
|
|
8716
|
+
method: {
|
|
8717
|
+
type: "string",
|
|
8718
|
+
description: "Task execution method (informational \u2014 driver concern)"
|
|
8719
|
+
},
|
|
8720
|
+
config: {
|
|
8721
|
+
type: "object",
|
|
8722
|
+
description: "Arbitrary task configuration (driver concern)"
|
|
8723
|
+
},
|
|
8724
|
+
priority: {
|
|
8725
|
+
type: "number",
|
|
8726
|
+
description: "Higher = preferred in conflict resolution"
|
|
8727
|
+
},
|
|
8728
|
+
estimatedDuration: {
|
|
8729
|
+
type: "number",
|
|
8730
|
+
minimum: 0,
|
|
8731
|
+
description: "Estimated duration in ms (used by duration-first strategy)"
|
|
8732
|
+
},
|
|
8733
|
+
estimatedCost: {
|
|
8734
|
+
type: "number",
|
|
8735
|
+
minimum: 0,
|
|
8736
|
+
description: "Estimated cost (used by cost-optimized strategy)"
|
|
8737
|
+
},
|
|
8738
|
+
estimatedResources: {
|
|
8739
|
+
type: "object",
|
|
8740
|
+
additionalProperties: { type: "number" },
|
|
8741
|
+
description: "Resource requirements (used by resource-aware strategy)"
|
|
8742
|
+
},
|
|
8743
|
+
retry: {
|
|
8744
|
+
$ref: "#/definitions/task_retry"
|
|
8745
|
+
},
|
|
8746
|
+
refreshStrategy: {
|
|
8747
|
+
$ref: "#/definitions/refresh_strategy",
|
|
8748
|
+
description: "Task-level refresh strategy (overrides settings default)"
|
|
8749
|
+
},
|
|
8750
|
+
refreshInterval: {
|
|
8751
|
+
type: "number",
|
|
8752
|
+
minimum: 0,
|
|
8753
|
+
description: "Interval in seconds for time-based refresh strategy"
|
|
8754
|
+
},
|
|
8755
|
+
maxExecutions: {
|
|
8756
|
+
type: "integer",
|
|
8757
|
+
minimum: 1,
|
|
8758
|
+
description: "Maximum number of times this task can execute"
|
|
8759
|
+
},
|
|
8760
|
+
circuit_breaker: {
|
|
8761
|
+
$ref: "#/definitions/task_circuit_breaker"
|
|
8762
|
+
},
|
|
8763
|
+
description: {
|
|
8764
|
+
type: "string",
|
|
8765
|
+
description: "Human-readable description"
|
|
8766
|
+
},
|
|
8767
|
+
inference: {
|
|
8768
|
+
$ref: "#/definitions/inference_hints"
|
|
8769
|
+
}
|
|
8770
|
+
},
|
|
8771
|
+
additionalProperties: false
|
|
8772
|
+
},
|
|
8773
|
+
task_retry: {
|
|
8774
|
+
type: "object",
|
|
8775
|
+
required: ["max_attempts"],
|
|
8776
|
+
properties: {
|
|
8777
|
+
max_attempts: {
|
|
8778
|
+
type: "integer",
|
|
8779
|
+
minimum: 1,
|
|
8780
|
+
description: "Maximum retry attempts"
|
|
8781
|
+
},
|
|
8782
|
+
delay_ms: {
|
|
8783
|
+
type: "integer",
|
|
8784
|
+
minimum: 0,
|
|
8785
|
+
description: "Delay between retries in ms"
|
|
8786
|
+
},
|
|
8787
|
+
backoff_multiplier: {
|
|
8788
|
+
type: "number",
|
|
8789
|
+
minimum: 1,
|
|
8790
|
+
description: "Backoff multiplier (e.g., 2 for exponential)"
|
|
8791
|
+
}
|
|
8792
|
+
},
|
|
8793
|
+
additionalProperties: false
|
|
8794
|
+
},
|
|
8795
|
+
refresh_strategy: {
|
|
8796
|
+
type: "string",
|
|
8797
|
+
enum: ["data-changed", "epoch-changed", "time-based", "manual", "once"],
|
|
8798
|
+
description: "Strategy for determining when a completed task should re-run"
|
|
8799
|
+
},
|
|
8800
|
+
task_circuit_breaker: {
|
|
8801
|
+
type: "object",
|
|
8802
|
+
required: ["max_executions", "on_break"],
|
|
8803
|
+
properties: {
|
|
8804
|
+
max_executions: {
|
|
8805
|
+
type: "integer",
|
|
8806
|
+
minimum: 1,
|
|
8807
|
+
description: "Max executions before breaker trips"
|
|
8808
|
+
},
|
|
8809
|
+
on_break: {
|
|
8810
|
+
type: "array",
|
|
8811
|
+
items: { type: "string" },
|
|
8812
|
+
minItems: 1,
|
|
8813
|
+
description: "Tokens to inject when breaker trips"
|
|
8814
|
+
}
|
|
8815
|
+
},
|
|
8816
|
+
additionalProperties: false
|
|
8817
|
+
},
|
|
8818
|
+
inference_hints: {
|
|
8819
|
+
type: "object",
|
|
8820
|
+
description: "LLM inference hints \u2014 opt-in metadata for AI-assisted completion detection",
|
|
8821
|
+
properties: {
|
|
8822
|
+
criteria: {
|
|
8823
|
+
type: "string",
|
|
8824
|
+
description: "Human-readable completion criteria"
|
|
8825
|
+
},
|
|
8826
|
+
keywords: {
|
|
8827
|
+
type: "array",
|
|
8828
|
+
items: { type: "string" },
|
|
8829
|
+
description: "Keywords to help the LLM understand the domain"
|
|
8830
|
+
},
|
|
8831
|
+
suggestedChecks: {
|
|
8832
|
+
type: "array",
|
|
8833
|
+
items: { type: "string" },
|
|
8834
|
+
description: "Suggested checks for verification"
|
|
8835
|
+
},
|
|
8836
|
+
autoDetectable: {
|
|
8837
|
+
type: "boolean",
|
|
8838
|
+
description: "Whether the LLM should attempt to auto-detect completion (default: false)"
|
|
8839
|
+
}
|
|
8840
|
+
},
|
|
8841
|
+
additionalProperties: false
|
|
8842
|
+
}
|
|
8843
|
+
}
|
|
8844
|
+
};
|
|
8845
|
+
|
|
8846
|
+
// src/event-graph/schema-validator.ts
|
|
8847
|
+
var import_ajv2 = __toESM(require_ajv());
|
|
8848
|
+
var _compiled2 = null;
|
|
8849
|
+
function getValidator2() {
|
|
8850
|
+
if (_compiled2) return _compiled2;
|
|
8851
|
+
const ajv = new import_ajv2.default({ allErrors: true });
|
|
8852
|
+
addFormats__default.default(ajv);
|
|
8853
|
+
_compiled2 = ajv.compile(event_graph_schema_default);
|
|
8854
|
+
return _compiled2;
|
|
8855
|
+
}
|
|
8856
|
+
function validateGraphSchema(config) {
|
|
8857
|
+
const validate = getValidator2();
|
|
8858
|
+
const valid = validate(config);
|
|
8859
|
+
if (valid) return { ok: true, errors: [] };
|
|
8860
|
+
const errors = (validate.errors ?? []).map((e) => {
|
|
8861
|
+
const path = e.instancePath || "/";
|
|
8862
|
+
return `${path}: ${e.message ?? "unknown error"}`;
|
|
8863
|
+
});
|
|
8864
|
+
return { ok: false, errors };
|
|
8865
|
+
}
|
|
8866
|
+
|
|
8363
8867
|
// src/stores/localStorage.ts
|
|
8364
8868
|
var LocalStorageStore = class {
|
|
8365
8869
|
prefix;
|
|
@@ -8753,7 +9257,7 @@ function applyEvent(live, event) {
|
|
|
8753
9257
|
newState = applyTaskStart(state, event.taskName);
|
|
8754
9258
|
break;
|
|
8755
9259
|
case "task-completed":
|
|
8756
|
-
newState = applyTaskCompletion(state, config, event.taskName, event.result);
|
|
9260
|
+
newState = applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash);
|
|
8757
9261
|
break;
|
|
8758
9262
|
case "task-failed":
|
|
8759
9263
|
newState = applyTaskFailure(state, config, event.taskName, event.error);
|
|
@@ -8776,6 +9280,9 @@ function applyEvent(live, event) {
|
|
|
8776
9280
|
}
|
|
8777
9281
|
return { config, state: newState };
|
|
8778
9282
|
}
|
|
9283
|
+
function applyEvents(live, events) {
|
|
9284
|
+
return events.reduce((current, event) => applyEvent(current, event), live);
|
|
9285
|
+
}
|
|
8779
9286
|
function addNode(live, name, taskConfig) {
|
|
8780
9287
|
if (live.config.tasks[name]) return live;
|
|
8781
9288
|
return {
|
|
@@ -9020,38 +9527,84 @@ function schedule(live) {
|
|
|
9020
9527
|
const blocked = [];
|
|
9021
9528
|
for (const [taskName, taskConfig] of Object.entries(graphTasks)) {
|
|
9022
9529
|
const taskState = state.tasks[taskName];
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
}
|
|
9028
|
-
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
|
|
9530
|
+
const strategy = getRefreshStrategy(taskConfig, config.settings);
|
|
9531
|
+
const rerunnable = strategy !== "once";
|
|
9532
|
+
if (taskState?.status === TASK_STATUS.RUNNING || isNonActiveTask(taskState)) {
|
|
9533
|
+
continue;
|
|
9534
|
+
}
|
|
9535
|
+
const maxExec = getMaxExecutions(taskConfig);
|
|
9536
|
+
if (maxExec !== void 0 && taskState && taskState.executionCount >= maxExec) {
|
|
9537
|
+
continue;
|
|
9538
|
+
}
|
|
9539
|
+
if (taskConfig.circuit_breaker && taskState && taskState.executionCount >= taskConfig.circuit_breaker.max_executions) {
|
|
9540
|
+
continue;
|
|
9541
|
+
}
|
|
9542
|
+
if (!rerunnable && taskState?.status === TASK_STATUS.COMPLETED) {
|
|
9543
|
+
continue;
|
|
9544
|
+
}
|
|
9545
|
+
if (rerunnable && taskState?.status === TASK_STATUS.COMPLETED) {
|
|
9546
|
+
const requires2 = getRequires(taskConfig);
|
|
9547
|
+
let shouldSkip = false;
|
|
9548
|
+
switch (strategy) {
|
|
9549
|
+
case "data-changed": {
|
|
9550
|
+
if (requires2.length > 0) {
|
|
9551
|
+
const hasChangedData = requires2.some((req) => {
|
|
9552
|
+
for (const [otherName, otherConfig] of Object.entries(graphTasks)) {
|
|
9553
|
+
if (getProvides(otherConfig).includes(req)) {
|
|
9554
|
+
const otherState = state.tasks[otherName];
|
|
9555
|
+
if (!otherState) continue;
|
|
9556
|
+
const consumed = taskState.lastConsumedHashes?.[req];
|
|
9557
|
+
if (otherState.lastDataHash == null) {
|
|
9558
|
+
return otherState.executionCount > taskState.lastEpoch;
|
|
9559
|
+
}
|
|
9560
|
+
return otherState.lastDataHash !== consumed;
|
|
9561
|
+
}
|
|
9046
9562
|
}
|
|
9047
|
-
|
|
9048
|
-
|
|
9049
|
-
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9563
|
+
return false;
|
|
9564
|
+
});
|
|
9565
|
+
if (!hasChangedData) shouldSkip = true;
|
|
9566
|
+
} else {
|
|
9567
|
+
shouldSkip = true;
|
|
9568
|
+
}
|
|
9569
|
+
break;
|
|
9053
9570
|
}
|
|
9571
|
+
case "epoch-changed": {
|
|
9572
|
+
if (requires2.length > 0) {
|
|
9573
|
+
const hasRefreshed = requires2.some((req) => {
|
|
9574
|
+
for (const [otherName, otherConfig] of Object.entries(graphTasks)) {
|
|
9575
|
+
if (getProvides(otherConfig).includes(req)) {
|
|
9576
|
+
const otherState = state.tasks[otherName];
|
|
9577
|
+
if (otherState && otherState.executionCount > taskState.lastEpoch) return true;
|
|
9578
|
+
}
|
|
9579
|
+
}
|
|
9580
|
+
return false;
|
|
9581
|
+
});
|
|
9582
|
+
if (!hasRefreshed) shouldSkip = true;
|
|
9583
|
+
} else {
|
|
9584
|
+
shouldSkip = true;
|
|
9585
|
+
}
|
|
9586
|
+
break;
|
|
9587
|
+
}
|
|
9588
|
+
case "time-based": {
|
|
9589
|
+
const interval = taskConfig.refreshInterval ?? 0;
|
|
9590
|
+
if (interval <= 0) {
|
|
9591
|
+
shouldSkip = true;
|
|
9592
|
+
break;
|
|
9593
|
+
}
|
|
9594
|
+
const completedAt = taskState.completedAt;
|
|
9595
|
+
if (!completedAt) {
|
|
9596
|
+
shouldSkip = true;
|
|
9597
|
+
break;
|
|
9598
|
+
}
|
|
9599
|
+
const elapsedSec = (Date.now() - Date.parse(completedAt)) / 1e3;
|
|
9600
|
+
if (elapsedSec < interval) shouldSkip = true;
|
|
9601
|
+
break;
|
|
9602
|
+
}
|
|
9603
|
+
case "manual":
|
|
9604
|
+
shouldSkip = true;
|
|
9605
|
+
break;
|
|
9054
9606
|
}
|
|
9607
|
+
if (shouldSkip) continue;
|
|
9055
9608
|
}
|
|
9056
9609
|
const requires = getRequires(taskConfig);
|
|
9057
9610
|
if (requires.length === 0) {
|
|
@@ -9446,6 +9999,300 @@ function getDownstream(live, nodeName) {
|
|
|
9446
9999
|
}));
|
|
9447
10000
|
return { nodeName, nodes, tokens: [...tokenSet] };
|
|
9448
10001
|
}
|
|
10002
|
+
var MemoryJournal = class {
|
|
10003
|
+
buffer = [];
|
|
10004
|
+
append(event) {
|
|
10005
|
+
this.buffer.push(event);
|
|
10006
|
+
}
|
|
10007
|
+
drain() {
|
|
10008
|
+
const events = this.buffer;
|
|
10009
|
+
this.buffer = [];
|
|
10010
|
+
return events;
|
|
10011
|
+
}
|
|
10012
|
+
get size() {
|
|
10013
|
+
return this.buffer.length;
|
|
10014
|
+
}
|
|
10015
|
+
};
|
|
10016
|
+
var FileJournal = class {
|
|
10017
|
+
constructor(path) {
|
|
10018
|
+
this.path = path;
|
|
10019
|
+
if (!fs.existsSync(path)) {
|
|
10020
|
+
fs.writeFileSync(path, "", "utf-8");
|
|
10021
|
+
}
|
|
10022
|
+
}
|
|
10023
|
+
path;
|
|
10024
|
+
pending = 0;
|
|
10025
|
+
append(event) {
|
|
10026
|
+
fs.appendFileSync(this.path, JSON.stringify(event) + "\n", "utf-8");
|
|
10027
|
+
this.pending++;
|
|
10028
|
+
}
|
|
10029
|
+
drain() {
|
|
10030
|
+
const content = fs.readFileSync(this.path, "utf-8").trim();
|
|
10031
|
+
fs.writeFileSync(this.path, "", "utf-8");
|
|
10032
|
+
this.pending = 0;
|
|
10033
|
+
if (!content) return [];
|
|
10034
|
+
return content.split("\n").map((line) => JSON.parse(line));
|
|
10035
|
+
}
|
|
10036
|
+
get size() {
|
|
10037
|
+
try {
|
|
10038
|
+
const content = fs.readFileSync(this.path, "utf-8").trim();
|
|
10039
|
+
if (!content) return 0;
|
|
10040
|
+
return content.split("\n").length;
|
|
10041
|
+
} catch {
|
|
10042
|
+
return this.pending;
|
|
10043
|
+
}
|
|
10044
|
+
}
|
|
10045
|
+
};
|
|
10046
|
+
|
|
10047
|
+
// src/continuous-event-graph/reactive.ts
|
|
10048
|
+
function createReactiveGraph(config, options, executionId) {
|
|
10049
|
+
const {
|
|
10050
|
+
handlers: initialHandlers,
|
|
10051
|
+
maxDispatchRetries = 3,
|
|
10052
|
+
defaultTimeoutMs = 3e4,
|
|
10053
|
+
journal = new MemoryJournal(),
|
|
10054
|
+
onDispatchFailed,
|
|
10055
|
+
onAbandoned,
|
|
10056
|
+
onDrain
|
|
10057
|
+
} = options;
|
|
10058
|
+
let live = createLiveGraph(config, executionId);
|
|
10059
|
+
let disposed = false;
|
|
10060
|
+
const handlers = new Map(Object.entries(initialHandlers));
|
|
10061
|
+
const dispatched = /* @__PURE__ */ new Map();
|
|
10062
|
+
const timeoutTimers = /* @__PURE__ */ new Map();
|
|
10063
|
+
let draining = false;
|
|
10064
|
+
let drainQueued = false;
|
|
10065
|
+
function drain() {
|
|
10066
|
+
if (disposed) return;
|
|
10067
|
+
if (draining) {
|
|
10068
|
+
drainQueued = true;
|
|
10069
|
+
return;
|
|
10070
|
+
}
|
|
10071
|
+
draining = true;
|
|
10072
|
+
try {
|
|
10073
|
+
do {
|
|
10074
|
+
drainQueued = false;
|
|
10075
|
+
drainOnce();
|
|
10076
|
+
} while (drainQueued);
|
|
10077
|
+
} finally {
|
|
10078
|
+
draining = false;
|
|
10079
|
+
}
|
|
10080
|
+
}
|
|
10081
|
+
function drainOnce() {
|
|
10082
|
+
sweepTimeouts();
|
|
10083
|
+
const events = journal.drain();
|
|
10084
|
+
for (const event of events) {
|
|
10085
|
+
if (event.type === "task-completed" || event.type === "task-failed") {
|
|
10086
|
+
const taskName = event.taskName;
|
|
10087
|
+
dispatched.delete(taskName);
|
|
10088
|
+
clearTimeout(timeoutTimers.get(taskName));
|
|
10089
|
+
timeoutTimers.delete(taskName);
|
|
10090
|
+
}
|
|
10091
|
+
}
|
|
10092
|
+
if (events.length > 0) {
|
|
10093
|
+
live = applyEvents(live, events);
|
|
10094
|
+
}
|
|
10095
|
+
const result = schedule(live);
|
|
10096
|
+
if (onDrain && events.length > 0) {
|
|
10097
|
+
onDrain(events, live, result);
|
|
10098
|
+
}
|
|
10099
|
+
for (const taskName of result.eligible) {
|
|
10100
|
+
if (dispatched.has(taskName)) continue;
|
|
10101
|
+
dispatchTask(taskName);
|
|
10102
|
+
}
|
|
10103
|
+
for (const [taskName, entry] of dispatched) {
|
|
10104
|
+
if (entry.status === "retry-queued") {
|
|
10105
|
+
dispatchTask(taskName);
|
|
10106
|
+
}
|
|
10107
|
+
}
|
|
10108
|
+
}
|
|
10109
|
+
function dispatchTask(taskName) {
|
|
10110
|
+
const handler = handlers.get(taskName);
|
|
10111
|
+
if (!handler) {
|
|
10112
|
+
journal.append({
|
|
10113
|
+
type: "task-failed",
|
|
10114
|
+
taskName,
|
|
10115
|
+
error: `No handler registered for task "${taskName}"`,
|
|
10116
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10117
|
+
});
|
|
10118
|
+
drainQueued = true;
|
|
10119
|
+
return;
|
|
10120
|
+
}
|
|
10121
|
+
const existing = dispatched.get(taskName);
|
|
10122
|
+
const attempt = existing ? existing.dispatchAttempts + 1 : 1;
|
|
10123
|
+
if (attempt > maxDispatchRetries) {
|
|
10124
|
+
dispatched.set(taskName, {
|
|
10125
|
+
status: "abandoned",
|
|
10126
|
+
dispatchedAt: existing?.dispatchedAt ?? Date.now(),
|
|
10127
|
+
dispatchAttempts: attempt - 1,
|
|
10128
|
+
lastError: existing?.lastError
|
|
10129
|
+
});
|
|
10130
|
+
onAbandoned?.(taskName);
|
|
10131
|
+
journal.append({
|
|
10132
|
+
type: "task-failed",
|
|
10133
|
+
taskName,
|
|
10134
|
+
error: `dispatch-abandoned: handler unreachable after ${attempt - 1} attempts${existing?.lastError ? ` (${existing.lastError})` : ""}`,
|
|
10135
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10136
|
+
});
|
|
10137
|
+
drainQueued = true;
|
|
10138
|
+
return;
|
|
10139
|
+
}
|
|
10140
|
+
dispatched.set(taskName, {
|
|
10141
|
+
status: "initiated",
|
|
10142
|
+
dispatchedAt: Date.now(),
|
|
10143
|
+
dispatchAttempts: attempt
|
|
10144
|
+
});
|
|
10145
|
+
journal.append({
|
|
10146
|
+
type: "task-started",
|
|
10147
|
+
taskName,
|
|
10148
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10149
|
+
});
|
|
10150
|
+
if (defaultTimeoutMs > 0) {
|
|
10151
|
+
const timer = setTimeout(() => {
|
|
10152
|
+
if (disposed) return;
|
|
10153
|
+
const entry = dispatched.get(taskName);
|
|
10154
|
+
if (entry?.status === "initiated") {
|
|
10155
|
+
dispatched.set(taskName, {
|
|
10156
|
+
...entry,
|
|
10157
|
+
status: "timed-out"
|
|
10158
|
+
});
|
|
10159
|
+
dispatched.set(taskName, {
|
|
10160
|
+
...entry,
|
|
10161
|
+
status: entry.dispatchAttempts >= maxDispatchRetries ? "abandoned" : "retry-queued"
|
|
10162
|
+
});
|
|
10163
|
+
if (entry.dispatchAttempts >= maxDispatchRetries) {
|
|
10164
|
+
onAbandoned?.(taskName);
|
|
10165
|
+
journal.append({
|
|
10166
|
+
type: "task-failed",
|
|
10167
|
+
taskName,
|
|
10168
|
+
error: `dispatch-timeout: no callback after ${defaultTimeoutMs}ms (${entry.dispatchAttempts} attempts)`,
|
|
10169
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10170
|
+
});
|
|
10171
|
+
}
|
|
10172
|
+
drain();
|
|
10173
|
+
}
|
|
10174
|
+
}, defaultTimeoutMs);
|
|
10175
|
+
timeoutTimers.set(taskName, timer);
|
|
10176
|
+
}
|
|
10177
|
+
const ctx = {
|
|
10178
|
+
taskName,
|
|
10179
|
+
live,
|
|
10180
|
+
config: live.config.tasks[taskName]
|
|
10181
|
+
};
|
|
10182
|
+
try {
|
|
10183
|
+
const promise = handler(ctx);
|
|
10184
|
+
promise.then(
|
|
10185
|
+
(handlerResult) => {
|
|
10186
|
+
if (disposed) return;
|
|
10187
|
+
clearTimeout(timeoutTimers.get(taskName));
|
|
10188
|
+
timeoutTimers.delete(taskName);
|
|
10189
|
+
journal.append({
|
|
10190
|
+
type: "task-completed",
|
|
10191
|
+
taskName,
|
|
10192
|
+
result: handlerResult.result,
|
|
10193
|
+
data: handlerResult.data,
|
|
10194
|
+
dataHash: handlerResult.dataHash,
|
|
10195
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10196
|
+
});
|
|
10197
|
+
drain();
|
|
10198
|
+
},
|
|
10199
|
+
(error) => {
|
|
10200
|
+
if (disposed) return;
|
|
10201
|
+
clearTimeout(timeoutTimers.get(taskName));
|
|
10202
|
+
timeoutTimers.delete(taskName);
|
|
10203
|
+
journal.append({
|
|
10204
|
+
type: "task-failed",
|
|
10205
|
+
taskName,
|
|
10206
|
+
error: error.message ?? String(error),
|
|
10207
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10208
|
+
});
|
|
10209
|
+
drain();
|
|
10210
|
+
}
|
|
10211
|
+
);
|
|
10212
|
+
} catch (syncError) {
|
|
10213
|
+
const err = syncError instanceof Error ? syncError : new Error(String(syncError));
|
|
10214
|
+
dispatched.set(taskName, {
|
|
10215
|
+
status: "dispatch-failed",
|
|
10216
|
+
dispatchedAt: Date.now(),
|
|
10217
|
+
dispatchAttempts: attempt,
|
|
10218
|
+
lastError: err.message
|
|
10219
|
+
});
|
|
10220
|
+
onDispatchFailed?.(taskName, err, attempt);
|
|
10221
|
+
dispatched.set(taskName, {
|
|
10222
|
+
...dispatched.get(taskName),
|
|
10223
|
+
status: "retry-queued"
|
|
10224
|
+
});
|
|
10225
|
+
drainQueued = true;
|
|
10226
|
+
}
|
|
10227
|
+
}
|
|
10228
|
+
function sweepTimeouts() {
|
|
10229
|
+
const now = Date.now();
|
|
10230
|
+
for (const [taskName, entry] of dispatched) {
|
|
10231
|
+
if (entry.status !== "initiated") continue;
|
|
10232
|
+
if (defaultTimeoutMs <= 0) continue;
|
|
10233
|
+
if (now - entry.dispatchedAt >= defaultTimeoutMs) {
|
|
10234
|
+
dispatched.set(taskName, {
|
|
10235
|
+
...entry,
|
|
10236
|
+
status: entry.dispatchAttempts >= maxDispatchRetries ? "abandoned" : "retry-queued"
|
|
10237
|
+
});
|
|
10238
|
+
if (entry.dispatchAttempts >= maxDispatchRetries) {
|
|
10239
|
+
onAbandoned?.(taskName);
|
|
10240
|
+
journal.append({
|
|
10241
|
+
type: "task-failed",
|
|
10242
|
+
taskName,
|
|
10243
|
+
error: `dispatch-timeout: no callback after ${defaultTimeoutMs}ms (${entry.dispatchAttempts} attempts)`,
|
|
10244
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10245
|
+
});
|
|
10246
|
+
}
|
|
10247
|
+
clearTimeout(timeoutTimers.get(taskName));
|
|
10248
|
+
timeoutTimers.delete(taskName);
|
|
10249
|
+
}
|
|
10250
|
+
}
|
|
10251
|
+
}
|
|
10252
|
+
return {
|
|
10253
|
+
push(event) {
|
|
10254
|
+
if (disposed) return;
|
|
10255
|
+
live = applyEvent(live, event);
|
|
10256
|
+
drain();
|
|
10257
|
+
},
|
|
10258
|
+
pushAll(events) {
|
|
10259
|
+
if (disposed) return;
|
|
10260
|
+
if (events.length === 0) return;
|
|
10261
|
+
live = applyEvents(live, events);
|
|
10262
|
+
drain();
|
|
10263
|
+
},
|
|
10264
|
+
addNode(name, taskConfig, handler) {
|
|
10265
|
+
if (disposed) return;
|
|
10266
|
+
live = addNode(live, name, taskConfig);
|
|
10267
|
+
handlers.set(name, handler);
|
|
10268
|
+
drain();
|
|
10269
|
+
},
|
|
10270
|
+
removeNode(name) {
|
|
10271
|
+
if (disposed) return;
|
|
10272
|
+
live = removeNode(live, name);
|
|
10273
|
+
handlers.delete(name);
|
|
10274
|
+
dispatched.delete(name);
|
|
10275
|
+
clearTimeout(timeoutTimers.get(name));
|
|
10276
|
+
timeoutTimers.delete(name);
|
|
10277
|
+
},
|
|
10278
|
+
getState() {
|
|
10279
|
+
return live;
|
|
10280
|
+
},
|
|
10281
|
+
getSchedule() {
|
|
10282
|
+
return schedule(live);
|
|
10283
|
+
},
|
|
10284
|
+
getDispatchState() {
|
|
10285
|
+
return dispatched;
|
|
10286
|
+
},
|
|
10287
|
+
dispose() {
|
|
10288
|
+
disposed = true;
|
|
10289
|
+
for (const timer of timeoutTimers.values()) {
|
|
10290
|
+
clearTimeout(timer);
|
|
10291
|
+
}
|
|
10292
|
+
timeoutTimers.clear();
|
|
10293
|
+
}
|
|
10294
|
+
};
|
|
10295
|
+
}
|
|
9449
10296
|
|
|
9450
10297
|
// src/inference/core.ts
|
|
9451
10298
|
var DEFAULT_THRESHOLD = 0.5;
|
|
@@ -10011,17 +10858,17 @@ var live_cards_schema_default = {
|
|
|
10011
10858
|
};
|
|
10012
10859
|
|
|
10013
10860
|
// src/card-compute/schema-validator.ts
|
|
10014
|
-
var
|
|
10015
|
-
var
|
|
10016
|
-
function
|
|
10017
|
-
if (
|
|
10018
|
-
const ajv = new
|
|
10861
|
+
var import_ajv3 = __toESM(require_ajv());
|
|
10862
|
+
var _compiled3 = null;
|
|
10863
|
+
function getValidator3() {
|
|
10864
|
+
if (_compiled3) return _compiled3;
|
|
10865
|
+
const ajv = new import_ajv3.default({ allErrors: true });
|
|
10019
10866
|
addFormats__default.default(ajv);
|
|
10020
|
-
|
|
10021
|
-
return
|
|
10867
|
+
_compiled3 = ajv.compile(live_cards_schema_default);
|
|
10868
|
+
return _compiled3;
|
|
10022
10869
|
}
|
|
10023
10870
|
function validateLiveCardSchema(node) {
|
|
10024
|
-
const validate =
|
|
10871
|
+
const validate = getValidator3();
|
|
10025
10872
|
const valid = validate(node);
|
|
10026
10873
|
if (valid) return { ok: true, errors: [] };
|
|
10027
10874
|
const errors = (validate.errors ?? []).map((e) => {
|
|
@@ -10484,9 +11331,11 @@ exports.CardCompute = CardCompute;
|
|
|
10484
11331
|
exports.DEFAULTS = DEFAULTS;
|
|
10485
11332
|
exports.EXECUTION_MODES = EXECUTION_MODES;
|
|
10486
11333
|
exports.EXECUTION_STATUS = EXECUTION_STATUS;
|
|
11334
|
+
exports.FileJournal = FileJournal;
|
|
10487
11335
|
exports.FileStore = FileStore;
|
|
10488
11336
|
exports.FlowEngine = StepMachine;
|
|
10489
11337
|
exports.LocalStorageStore = LocalStorageStore;
|
|
11338
|
+
exports.MemoryJournal = MemoryJournal;
|
|
10490
11339
|
exports.MemoryStore = MemoryStore;
|
|
10491
11340
|
exports.StepMachine = StepMachine;
|
|
10492
11341
|
exports.TASK_STATUS = TASK_STATUS;
|
|
@@ -10497,6 +11346,7 @@ exports.addRequires = addRequires;
|
|
|
10497
11346
|
exports.apply = apply;
|
|
10498
11347
|
exports.applyAll = applyAll;
|
|
10499
11348
|
exports.applyEvent = applyEvent;
|
|
11349
|
+
exports.applyEvents = applyEvents;
|
|
10500
11350
|
exports.applyInferences = applyInferences;
|
|
10501
11351
|
exports.applyStepResult = applyStepResult;
|
|
10502
11352
|
exports.batch = batch;
|
|
@@ -10511,6 +11361,7 @@ exports.createHttpAdapter = createHttpAdapter;
|
|
|
10511
11361
|
exports.createInitialExecutionState = createInitialExecutionState;
|
|
10512
11362
|
exports.createInitialState = createInitialState;
|
|
10513
11363
|
exports.createLiveGraph = createLiveGraph;
|
|
11364
|
+
exports.createReactiveGraph = createReactiveGraph;
|
|
10514
11365
|
exports.createStepMachine = createStepMachine;
|
|
10515
11366
|
exports.detectStuckState = detectStuckState;
|
|
10516
11367
|
exports.disableNode = disableNode;
|
|
@@ -10523,8 +11374,10 @@ exports.flowToMermaid = flowToMermaid;
|
|
|
10523
11374
|
exports.getAllTasks = getAllTasks;
|
|
10524
11375
|
exports.getCandidateTasks = getCandidateTasks;
|
|
10525
11376
|
exports.getDownstream = getDownstream;
|
|
11377
|
+
exports.getMaxExecutions = getMaxExecutions;
|
|
10526
11378
|
exports.getNode = getNode;
|
|
10527
11379
|
exports.getProvides = getProvides;
|
|
11380
|
+
exports.getRefreshStrategy = getRefreshStrategy;
|
|
10528
11381
|
exports.getRequires = getRequires;
|
|
10529
11382
|
exports.getTask = getTask;
|
|
10530
11383
|
exports.getUnreachableNodes = getUnreachableNodes;
|
|
@@ -10538,7 +11391,7 @@ exports.injectTokens = injectTokens;
|
|
|
10538
11391
|
exports.inspect = inspect;
|
|
10539
11392
|
exports.isExecutionComplete = isExecutionComplete;
|
|
10540
11393
|
exports.isNonActiveTask = isNonActiveTask;
|
|
10541
|
-
exports.
|
|
11394
|
+
exports.isRerunnable = isRerunnable;
|
|
10542
11395
|
exports.isTaskCompleted = isTaskCompleted;
|
|
10543
11396
|
exports.isTaskRunning = isTaskRunning;
|
|
10544
11397
|
exports.loadGraphConfig = loadGraphConfig;
|
|
@@ -10554,8 +11407,10 @@ exports.resolveVariables = resolveVariables;
|
|
|
10554
11407
|
exports.restore = restore;
|
|
10555
11408
|
exports.schedule = schedule;
|
|
10556
11409
|
exports.snapshot = snapshot;
|
|
11410
|
+
exports.validateFlowSchema = validateFlowSchema;
|
|
10557
11411
|
exports.validateGraph = validateGraph;
|
|
10558
11412
|
exports.validateGraphConfig = validateGraphConfig;
|
|
11413
|
+
exports.validateGraphSchema = validateGraphSchema;
|
|
10559
11414
|
exports.validateLiveCardSchema = validateLiveCardSchema;
|
|
10560
11415
|
exports.validateStepFlowConfig = validateStepFlowConfig;
|
|
10561
11416
|
//# sourceMappingURL=index.cjs.map
|