yaml-flow 2.8.0 → 3.1.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.
Files changed (41) hide show
  1. package/README.md +189 -3
  2. package/dist/{constants-BEbO2_OK.d.ts → constants-B2zqu10b.d.ts} +32 -52
  3. package/dist/{constants-BNjeIlZ8.d.cts → constants-DJZU1pwJ.d.cts} +32 -52
  4. package/dist/continuous-event-graph/index.cjs +1388 -52
  5. package/dist/continuous-event-graph/index.cjs.map +1 -1
  6. package/dist/continuous-event-graph/index.d.cts +643 -5
  7. package/dist/continuous-event-graph/index.d.ts +643 -5
  8. package/dist/continuous-event-graph/index.js +1374 -53
  9. package/dist/continuous-event-graph/index.js.map +1 -1
  10. package/dist/event-graph/index.cjs +6817 -53
  11. package/dist/event-graph/index.cjs.map +1 -1
  12. package/dist/event-graph/index.d.cts +15 -6
  13. package/dist/event-graph/index.d.ts +15 -6
  14. package/dist/event-graph/index.js +6808 -51
  15. package/dist/event-graph/index.js.map +1 -1
  16. package/dist/index.cjs +1827 -441
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +6 -5
  19. package/dist/index.d.ts +6 -5
  20. package/dist/index.js +1808 -440
  21. package/dist/index.js.map +1 -1
  22. package/dist/inference/index.cjs +46 -13
  23. package/dist/inference/index.cjs.map +1 -1
  24. package/dist/inference/index.d.cts +2 -2
  25. package/dist/inference/index.d.ts +2 -2
  26. package/dist/inference/index.js +46 -13
  27. package/dist/inference/index.js.map +1 -1
  28. package/dist/step-machine/index.cjs +6600 -0
  29. package/dist/step-machine/index.cjs.map +1 -1
  30. package/dist/step-machine/index.d.cts +26 -1
  31. package/dist/step-machine/index.d.ts +26 -1
  32. package/dist/step-machine/index.js +6596 -1
  33. package/dist/step-machine/index.js.map +1 -1
  34. package/dist/{types-C2lOwquM.d.cts → types-BwvgvlOO.d.cts} +2 -2
  35. package/dist/{types-mS_pPftm.d.ts → types-ClRA8hzC.d.ts} +2 -2
  36. package/dist/{types-DAI_a2as.d.ts → types-DEj7OakX.d.cts} +29 -10
  37. package/dist/{types-DAI_a2as.d.cts → types-DEj7OakX.d.ts} +29 -10
  38. package/dist/validate-DEZ2Ymdb.d.ts +53 -0
  39. package/dist/validate-DqKTZg_o.d.cts +53 -0
  40. package/package.json +1 -1
  41. package/schema/event-graph.schema.json +254 -0
@@ -1,4 +1,4 @@
1
- import { G as GraphConfig, c as ExecutionState, T as TaskConfig, l as TaskState } from './types-DAI_a2as.cjs';
1
+ import { G as GraphConfig, c as ExecutionState, T as TaskConfig, e as GraphEngineStore } from './types-DEj7OakX.cjs';
2
2
 
3
3
  /**
4
4
  * Continuous Event Graph — Types
@@ -77,7 +77,7 @@ interface NodeInfo {
77
77
  /** The task configuration */
78
78
  config: TaskConfig;
79
79
  /** The current runtime state */
80
- state: TaskState;
80
+ state: GraphEngineStore;
81
81
  }
82
82
  interface LiveGraphSnapshot {
83
83
  /** Schema version for forward compatibility */
@@ -1,4 +1,4 @@
1
- import { G as GraphConfig, c as ExecutionState, T as TaskConfig, l as TaskState } from './types-DAI_a2as.js';
1
+ import { G as GraphConfig, c as ExecutionState, T as TaskConfig, e as GraphEngineStore } from './types-DEj7OakX.js';
2
2
 
3
3
  /**
4
4
  * Continuous Event Graph — Types
@@ -77,7 +77,7 @@ interface NodeInfo {
77
77
  /** The task configuration */
78
78
  config: TaskConfig;
79
79
  /** The current runtime state */
80
- state: TaskState;
80
+ state: GraphEngineStore;
81
81
  }
82
82
  interface LiveGraphSnapshot {
83
83
  /** Schema version for forward compatibility */
@@ -16,6 +16,8 @@ interface GraphSettings {
16
16
  conflict_strategy?: ConflictStrategy;
17
17
  /** Execution mode */
18
18
  execution_mode?: ExecutionMode;
19
+ /** Default refresh strategy for all tasks (default: 'data-changed') */
20
+ refreshStrategy?: RefreshStrategy;
19
21
  /** Goal outputs — used with 'goal-reached' completion */
20
22
  goal?: string[];
21
23
  /** Max total scheduler iterations (safety limit, default: 1000) */
@@ -34,6 +36,8 @@ interface TaskConfig {
34
36
  on_failure?: string[];
35
37
  /** Task execution method (informational — driver concern) */
36
38
  method?: string;
39
+ /** Named task handler references — looked up in the handler registry at dispatch time */
40
+ taskHandlers?: string[];
37
41
  /** Arbitrary task configuration (driver concern) */
38
42
  config?: Record<string, unknown>;
39
43
  /** Task priority (higher = preferred in conflict resolution) */
@@ -46,8 +50,12 @@ interface TaskConfig {
46
50
  estimatedResources?: Record<string, number>;
47
51
  /** Retry configuration */
48
52
  retry?: TaskRetryConfig;
49
- /** Repeatable task configuration */
50
- repeatable?: boolean | RepeatableConfig;
53
+ /** Refresh strategy — controls when a completed task re-runs (default: 'data-changed') */
54
+ refreshStrategy?: RefreshStrategy;
55
+ /** Refresh interval in seconds — only used with 'time-based' strategy */
56
+ refreshInterval?: number;
57
+ /** Max executions cap (safety limit, optional) */
58
+ maxExecutions?: number;
51
59
  /** Circuit breaker: max executions before breaking */
52
60
  circuit_breaker?: TaskCircuitBreakerConfig;
53
61
  /** Description */
@@ -69,10 +77,6 @@ interface TaskRetryConfig {
69
77
  delay_ms?: number;
70
78
  backoff_multiplier?: number;
71
79
  }
72
- interface RepeatableConfig {
73
- /** Max times this task can repeat (undefined = unlimited) */
74
- max?: number;
75
- }
76
80
  interface TaskCircuitBreakerConfig {
77
81
  /** Max executions before injecting break tokens */
78
82
  max_executions: number;
@@ -83,7 +87,7 @@ interface ExecutionState {
83
87
  /** Current status of the execution */
84
88
  status: ExecutionStatus;
85
89
  /** Task states keyed by task name */
86
- tasks: Record<string, TaskState>;
90
+ tasks: Record<string, GraphEngineStore>;
87
91
  /** Tokens currently available in the system */
88
92
  availableOutputs: string[];
89
93
  /** Stuck detection result */
@@ -100,11 +104,17 @@ interface ExecutionConfig {
100
104
  conflictStrategy: ConflictStrategy;
101
105
  completionStrategy: CompletionStrategy;
102
106
  }
103
- interface TaskState {
107
+ interface GraphEngineStore {
104
108
  status: TaskStatus;
105
109
  executionCount: number;
106
110
  retryCount: number;
107
111
  lastEpoch: number;
112
+ /** Hash of this task's last output (for data-changed strategy) */
113
+ lastDataHash?: string;
114
+ /** The task's last output data payload */
115
+ data?: Record<string, unknown>;
116
+ /** Per-require token: the data hash consumed on last run */
117
+ lastConsumedHashes?: Record<string, string>;
108
118
  startedAt?: string;
109
119
  completedAt?: string;
110
120
  failedAt?: string;
@@ -124,7 +134,7 @@ interface StuckDetection {
124
134
  outputs_unresolvable: string[];
125
135
  tasks_blocked: string[];
126
136
  }
127
- type GraphEvent = TaskStartedEvent | TaskCompletedEvent | TaskFailedEvent | TaskProgressEvent | InjectTokensEvent | AgentActionEvent | TaskCreationEvent;
137
+ type GraphEvent = TaskStartedEvent | TaskCompletedEvent | TaskFailedEvent | TaskProgressEvent | TaskRestartEvent | InjectTokensEvent | AgentActionEvent | TaskCreationEvent;
128
138
  interface TaskStartedEvent {
129
139
  type: 'task-started';
130
140
  taskName: string;
@@ -138,6 +148,8 @@ interface TaskCompletedEvent {
138
148
  result?: string;
139
149
  /** Data payload from task execution */
140
150
  data?: Record<string, unknown>;
151
+ /** Content hash of the output — used by 'data-changed' refresh strategy */
152
+ dataHash?: string;
141
153
  timestamp: string;
142
154
  executionId?: string;
143
155
  }
@@ -156,6 +168,12 @@ interface TaskProgressEvent {
156
168
  timestamp: string;
157
169
  executionId?: string;
158
170
  }
171
+ interface TaskRestartEvent {
172
+ type: 'task-restart';
173
+ taskName: string;
174
+ timestamp: string;
175
+ executionId?: string;
176
+ }
159
177
  interface InjectTokensEvent {
160
178
  type: 'inject-tokens';
161
179
  tokens: string[];
@@ -194,5 +212,6 @@ type ExecutionStatus = 'created' | 'running' | 'paused' | 'stopped' | 'completed
194
212
  type CompletionStrategy = 'all-tasks-done' | 'all-outputs-done' | 'only-resolved' | 'goal-reached' | 'manual';
195
213
  type ExecutionMode = 'dependency-mode' | 'eligibility-mode';
196
214
  type ConflictStrategy = 'alphabetical' | 'priority-first' | 'duration-first' | 'cost-optimized' | 'resource-aware' | 'random-select' | 'user-choice' | 'parallel-all' | 'skip-conflicts' | 'round-robin';
215
+ type RefreshStrategy = 'data-changed' | 'epoch-changed' | 'time-based' | 'manual' | 'once';
197
216
 
198
- export type { AgentActionEvent as A, CompletionStrategy as C, ExecutionConfig as E, GraphConfig as G, InjectTokensEvent as I, RepeatableConfig as R, SchedulerResult as S, TaskConfig as T, ConflictStrategy as a, ExecutionMode as b, ExecutionState as c, ExecutionStatus as d, GraphEvent as e, GraphSettings as f, StuckDetection as g, TaskCompletedEvent as h, TaskCreationEvent as i, TaskFailedEvent as j, TaskStartedEvent as k, TaskState as l, TaskStatus as m, TaskCircuitBreakerConfig as n, TaskMessage as o, TaskProgressEvent as p, TaskRetryConfig as q };
217
+ export type { AgentActionEvent as A, CompletionStrategy as C, ExecutionConfig as E, GraphConfig as G, InjectTokensEvent as I, RefreshStrategy as R, SchedulerResult as S, TaskConfig as T, ConflictStrategy as a, ExecutionMode as b, ExecutionState as c, ExecutionStatus as d, GraphEngineStore as e, GraphEvent as f, GraphSettings as g, StuckDetection as h, TaskCompletedEvent as i, TaskCreationEvent as j, TaskFailedEvent as k, TaskStartedEvent as l, TaskStatus as m, TaskCircuitBreakerConfig as n, TaskMessage as o, TaskProgressEvent as p, TaskRestartEvent as q, TaskRetryConfig as r };
@@ -16,6 +16,8 @@ interface GraphSettings {
16
16
  conflict_strategy?: ConflictStrategy;
17
17
  /** Execution mode */
18
18
  execution_mode?: ExecutionMode;
19
+ /** Default refresh strategy for all tasks (default: 'data-changed') */
20
+ refreshStrategy?: RefreshStrategy;
19
21
  /** Goal outputs — used with 'goal-reached' completion */
20
22
  goal?: string[];
21
23
  /** Max total scheduler iterations (safety limit, default: 1000) */
@@ -34,6 +36,8 @@ interface TaskConfig {
34
36
  on_failure?: string[];
35
37
  /** Task execution method (informational — driver concern) */
36
38
  method?: string;
39
+ /** Named task handler references — looked up in the handler registry at dispatch time */
40
+ taskHandlers?: string[];
37
41
  /** Arbitrary task configuration (driver concern) */
38
42
  config?: Record<string, unknown>;
39
43
  /** Task priority (higher = preferred in conflict resolution) */
@@ -46,8 +50,12 @@ interface TaskConfig {
46
50
  estimatedResources?: Record<string, number>;
47
51
  /** Retry configuration */
48
52
  retry?: TaskRetryConfig;
49
- /** Repeatable task configuration */
50
- repeatable?: boolean | RepeatableConfig;
53
+ /** Refresh strategy — controls when a completed task re-runs (default: 'data-changed') */
54
+ refreshStrategy?: RefreshStrategy;
55
+ /** Refresh interval in seconds — only used with 'time-based' strategy */
56
+ refreshInterval?: number;
57
+ /** Max executions cap (safety limit, optional) */
58
+ maxExecutions?: number;
51
59
  /** Circuit breaker: max executions before breaking */
52
60
  circuit_breaker?: TaskCircuitBreakerConfig;
53
61
  /** Description */
@@ -69,10 +77,6 @@ interface TaskRetryConfig {
69
77
  delay_ms?: number;
70
78
  backoff_multiplier?: number;
71
79
  }
72
- interface RepeatableConfig {
73
- /** Max times this task can repeat (undefined = unlimited) */
74
- max?: number;
75
- }
76
80
  interface TaskCircuitBreakerConfig {
77
81
  /** Max executions before injecting break tokens */
78
82
  max_executions: number;
@@ -83,7 +87,7 @@ interface ExecutionState {
83
87
  /** Current status of the execution */
84
88
  status: ExecutionStatus;
85
89
  /** Task states keyed by task name */
86
- tasks: Record<string, TaskState>;
90
+ tasks: Record<string, GraphEngineStore>;
87
91
  /** Tokens currently available in the system */
88
92
  availableOutputs: string[];
89
93
  /** Stuck detection result */
@@ -100,11 +104,17 @@ interface ExecutionConfig {
100
104
  conflictStrategy: ConflictStrategy;
101
105
  completionStrategy: CompletionStrategy;
102
106
  }
103
- interface TaskState {
107
+ interface GraphEngineStore {
104
108
  status: TaskStatus;
105
109
  executionCount: number;
106
110
  retryCount: number;
107
111
  lastEpoch: number;
112
+ /** Hash of this task's last output (for data-changed strategy) */
113
+ lastDataHash?: string;
114
+ /** The task's last output data payload */
115
+ data?: Record<string, unknown>;
116
+ /** Per-require token: the data hash consumed on last run */
117
+ lastConsumedHashes?: Record<string, string>;
108
118
  startedAt?: string;
109
119
  completedAt?: string;
110
120
  failedAt?: string;
@@ -124,7 +134,7 @@ interface StuckDetection {
124
134
  outputs_unresolvable: string[];
125
135
  tasks_blocked: string[];
126
136
  }
127
- type GraphEvent = TaskStartedEvent | TaskCompletedEvent | TaskFailedEvent | TaskProgressEvent | InjectTokensEvent | AgentActionEvent | TaskCreationEvent;
137
+ type GraphEvent = TaskStartedEvent | TaskCompletedEvent | TaskFailedEvent | TaskProgressEvent | TaskRestartEvent | InjectTokensEvent | AgentActionEvent | TaskCreationEvent;
128
138
  interface TaskStartedEvent {
129
139
  type: 'task-started';
130
140
  taskName: string;
@@ -138,6 +148,8 @@ interface TaskCompletedEvent {
138
148
  result?: string;
139
149
  /** Data payload from task execution */
140
150
  data?: Record<string, unknown>;
151
+ /** Content hash of the output — used by 'data-changed' refresh strategy */
152
+ dataHash?: string;
141
153
  timestamp: string;
142
154
  executionId?: string;
143
155
  }
@@ -156,6 +168,12 @@ interface TaskProgressEvent {
156
168
  timestamp: string;
157
169
  executionId?: string;
158
170
  }
171
+ interface TaskRestartEvent {
172
+ type: 'task-restart';
173
+ taskName: string;
174
+ timestamp: string;
175
+ executionId?: string;
176
+ }
159
177
  interface InjectTokensEvent {
160
178
  type: 'inject-tokens';
161
179
  tokens: string[];
@@ -194,5 +212,6 @@ type ExecutionStatus = 'created' | 'running' | 'paused' | 'stopped' | 'completed
194
212
  type CompletionStrategy = 'all-tasks-done' | 'all-outputs-done' | 'only-resolved' | 'goal-reached' | 'manual';
195
213
  type ExecutionMode = 'dependency-mode' | 'eligibility-mode';
196
214
  type ConflictStrategy = 'alphabetical' | 'priority-first' | 'duration-first' | 'cost-optimized' | 'resource-aware' | 'random-select' | 'user-choice' | 'parallel-all' | 'skip-conflicts' | 'round-robin';
215
+ type RefreshStrategy = 'data-changed' | 'epoch-changed' | 'time-based' | 'manual' | 'once';
197
216
 
198
- export type { AgentActionEvent as A, CompletionStrategy as C, ExecutionConfig as E, GraphConfig as G, InjectTokensEvent as I, RepeatableConfig as R, SchedulerResult as S, TaskConfig as T, ConflictStrategy as a, ExecutionMode as b, ExecutionState as c, ExecutionStatus as d, GraphEvent as e, GraphSettings as f, StuckDetection as g, TaskCompletedEvent as h, TaskCreationEvent as i, TaskFailedEvent as j, TaskStartedEvent as k, TaskState as l, TaskStatus as m, TaskCircuitBreakerConfig as n, TaskMessage as o, TaskProgressEvent as p, TaskRetryConfig as q };
217
+ export type { AgentActionEvent as A, CompletionStrategy as C, ExecutionConfig as E, GraphConfig as G, InjectTokensEvent as I, RefreshStrategy as R, SchedulerResult as S, TaskConfig as T, ConflictStrategy as a, ExecutionMode as b, ExecutionState as c, ExecutionStatus as d, GraphEngineStore as e, GraphEvent as f, GraphSettings as g, StuckDetection as h, TaskCompletedEvent as i, TaskCreationEvent as j, TaskFailedEvent as k, TaskStartedEvent as l, TaskStatus as m, TaskCircuitBreakerConfig as n, TaskMessage as o, TaskProgressEvent as p, TaskRestartEvent as q, TaskRetryConfig as r };
@@ -0,0 +1,53 @@
1
+ import { G as GraphConfig } from './types-DEj7OakX.js';
2
+
3
+ /**
4
+ * Event Graph — Semantic Graph Validation
5
+ *
6
+ * Validates the logical correctness of a static graph configuration.
7
+ * Unlike validateGraphConfig() which checks JSON structure, this checks:
8
+ * - Dangling requires (tokens no task produces)
9
+ * - Circular dependencies
10
+ * - Provide conflicts (multiple tasks producing same token)
11
+ * - Unreachable goal tokens
12
+ * - Dead-end tasks (no provides)
13
+ * - Self-dependencies
14
+ * - Orphaned tasks (disconnected from the graph)
15
+ *
16
+ * Pure function — config in, diagnostics out.
17
+ */
18
+
19
+ type IssueSeverity = 'error' | 'warning' | 'info';
20
+ interface GraphIssue {
21
+ /** Severity: error = will break execution, warning = may cause problems, info = notable */
22
+ severity: IssueSeverity;
23
+ /** Machine-readable issue code */
24
+ code: string;
25
+ /** Human-readable description */
26
+ message: string;
27
+ /** Affected task names (if applicable) */
28
+ tasks?: string[];
29
+ /** Affected tokens (if applicable) */
30
+ tokens?: string[];
31
+ }
32
+ interface GraphValidationResult {
33
+ /** true if no errors (warnings/info are allowed) */
34
+ valid: boolean;
35
+ /** All issues found */
36
+ issues: GraphIssue[];
37
+ /** Just the errors */
38
+ errors: GraphIssue[];
39
+ /** Just the warnings */
40
+ warnings: GraphIssue[];
41
+ }
42
+ /**
43
+ * Validate the semantic correctness of a static event-graph configuration.
44
+ *
45
+ * Checks for logical issues that would cause execution failures, stuck states,
46
+ * or unexpected behavior. Does NOT check JSON structure (use validateGraphConfig for that).
47
+ *
48
+ * @param graph - The event-graph configuration to validate
49
+ * @returns Validation result with categorized issues
50
+ */
51
+ declare function validateGraph(graph: GraphConfig): GraphValidationResult;
52
+
53
+ export { type GraphIssue as G, type IssueSeverity as I, type GraphValidationResult as a, validateGraph as v };
@@ -0,0 +1,53 @@
1
+ import { G as GraphConfig } from './types-DEj7OakX.cjs';
2
+
3
+ /**
4
+ * Event Graph — Semantic Graph Validation
5
+ *
6
+ * Validates the logical correctness of a static graph configuration.
7
+ * Unlike validateGraphConfig() which checks JSON structure, this checks:
8
+ * - Dangling requires (tokens no task produces)
9
+ * - Circular dependencies
10
+ * - Provide conflicts (multiple tasks producing same token)
11
+ * - Unreachable goal tokens
12
+ * - Dead-end tasks (no provides)
13
+ * - Self-dependencies
14
+ * - Orphaned tasks (disconnected from the graph)
15
+ *
16
+ * Pure function — config in, diagnostics out.
17
+ */
18
+
19
+ type IssueSeverity = 'error' | 'warning' | 'info';
20
+ interface GraphIssue {
21
+ /** Severity: error = will break execution, warning = may cause problems, info = notable */
22
+ severity: IssueSeverity;
23
+ /** Machine-readable issue code */
24
+ code: string;
25
+ /** Human-readable description */
26
+ message: string;
27
+ /** Affected task names (if applicable) */
28
+ tasks?: string[];
29
+ /** Affected tokens (if applicable) */
30
+ tokens?: string[];
31
+ }
32
+ interface GraphValidationResult {
33
+ /** true if no errors (warnings/info are allowed) */
34
+ valid: boolean;
35
+ /** All issues found */
36
+ issues: GraphIssue[];
37
+ /** Just the errors */
38
+ errors: GraphIssue[];
39
+ /** Just the warnings */
40
+ warnings: GraphIssue[];
41
+ }
42
+ /**
43
+ * Validate the semantic correctness of a static event-graph configuration.
44
+ *
45
+ * Checks for logical issues that would cause execution failures, stuck states,
46
+ * or unexpected behavior. Does NOT check JSON structure (use validateGraphConfig for that).
47
+ *
48
+ * @param graph - The event-graph configuration to validate
49
+ * @returns Validation result with categorized issues
50
+ */
51
+ declare function validateGraph(graph: GraphConfig): GraphValidationResult;
52
+
53
+ export { type GraphIssue as G, type IssueSeverity as I, type GraphValidationResult as a, validateGraph as v };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yaml-flow",
3
- "version": "2.8.0",
3
+ "version": "3.1.0",
4
4
  "description": "Unified workflow engine: step-machine (sequential) + event-graph (stateless DAG) with pluggable storage",
5
5
  "author": "",
6
6
  "license": "MIT",
@@ -0,0 +1,254 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://github.com/yaml-flow/schema/event-graph.json",
4
+ "title": "Event Graph Configuration",
5
+ "description": "Schema for stateless event-graph (DAG) workflow definitions in yaml-flow",
6
+ "type": "object",
7
+ "required": ["settings", "tasks"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "id": {
11
+ "type": "string",
12
+ "description": "Optional graph identifier"
13
+ },
14
+ "settings": {
15
+ "$ref": "#/definitions/settings"
16
+ },
17
+ "tasks": {
18
+ "type": "object",
19
+ "description": "Task definitions keyed by name",
20
+ "minProperties": 1,
21
+ "additionalProperties": {
22
+ "$ref": "#/definitions/task"
23
+ }
24
+ }
25
+ },
26
+
27
+ "definitions": {
28
+
29
+ "settings": {
30
+ "type": "object",
31
+ "required": ["completion"],
32
+ "properties": {
33
+ "completion": {
34
+ "type": "string",
35
+ "enum": [
36
+ "all-tasks-done",
37
+ "all-outputs-done",
38
+ "only-resolved",
39
+ "goal-reached",
40
+ "manual"
41
+ ],
42
+ "description": "Completion strategy"
43
+ },
44
+ "conflict_strategy": {
45
+ "type": "string",
46
+ "enum": [
47
+ "alphabetical",
48
+ "priority-first",
49
+ "duration-first",
50
+ "cost-optimized",
51
+ "resource-aware",
52
+ "random-select",
53
+ "user-choice",
54
+ "parallel-all",
55
+ "skip-conflicts",
56
+ "round-robin"
57
+ ],
58
+ "description": "Conflict resolution strategy"
59
+ },
60
+ "execution_mode": {
61
+ "type": "string",
62
+ "enum": ["dependency-mode", "eligibility-mode"],
63
+ "description": "Execution mode"
64
+ },
65
+ "goal": {
66
+ "type": "array",
67
+ "items": { "type": "string" },
68
+ "minItems": 1,
69
+ "description": "Goal outputs — required when completion is 'goal-reached'"
70
+ },
71
+ "max_iterations": {
72
+ "type": "integer",
73
+ "minimum": 1,
74
+ "description": "Max scheduler iterations (safety limit, default: 1000)"
75
+ },
76
+ "timeout_ms": {
77
+ "type": "integer",
78
+ "minimum": 0,
79
+ "description": "Timeout in ms (declared for drivers, not enforced by pure engine)"
80
+ },
81
+ "refreshStrategy": {
82
+ "$ref": "#/definitions/refresh_strategy",
83
+ "description": "Default refresh strategy for all tasks (default: 'data-changed')"
84
+ }
85
+ },
86
+ "additionalProperties": false,
87
+ "if": {
88
+ "properties": { "completion": { "const": "goal-reached" } }
89
+ },
90
+ "then": {
91
+ "required": ["completion", "goal"]
92
+ }
93
+ },
94
+
95
+ "task": {
96
+ "type": "object",
97
+ "required": ["provides"],
98
+ "properties": {
99
+ "requires": {
100
+ "type": "array",
101
+ "items": { "type": "string" },
102
+ "description": "Tokens this task needs to become eligible"
103
+ },
104
+ "provides": {
105
+ "type": "array",
106
+ "items": { "type": "string" },
107
+ "description": "Tokens this task produces on successful completion"
108
+ },
109
+ "on": {
110
+ "type": "object",
111
+ "description": "Conditional provides based on handler result key",
112
+ "additionalProperties": {
113
+ "type": "array",
114
+ "items": { "type": "string" }
115
+ }
116
+ },
117
+ "on_failure": {
118
+ "type": "array",
119
+ "items": { "type": "string" },
120
+ "description": "Tokens to inject when this task fails"
121
+ },
122
+ "method": {
123
+ "type": "string",
124
+ "description": "Task execution method (informational — driver concern)"
125
+ },
126
+ "config": {
127
+ "type": "object",
128
+ "description": "Arbitrary task configuration (driver concern)"
129
+ },
130
+ "priority": {
131
+ "type": "number",
132
+ "description": "Higher = preferred in conflict resolution"
133
+ },
134
+ "estimatedDuration": {
135
+ "type": "number",
136
+ "minimum": 0,
137
+ "description": "Estimated duration in ms (used by duration-first strategy)"
138
+ },
139
+ "estimatedCost": {
140
+ "type": "number",
141
+ "minimum": 0,
142
+ "description": "Estimated cost (used by cost-optimized strategy)"
143
+ },
144
+ "estimatedResources": {
145
+ "type": "object",
146
+ "additionalProperties": { "type": "number" },
147
+ "description": "Resource requirements (used by resource-aware strategy)"
148
+ },
149
+ "retry": {
150
+ "$ref": "#/definitions/task_retry"
151
+ },
152
+ "refreshStrategy": {
153
+ "$ref": "#/definitions/refresh_strategy",
154
+ "description": "Task-level refresh strategy (overrides settings default)"
155
+ },
156
+ "refreshInterval": {
157
+ "type": "number",
158
+ "minimum": 0,
159
+ "description": "Interval in seconds for time-based refresh strategy"
160
+ },
161
+ "maxExecutions": {
162
+ "type": "integer",
163
+ "minimum": 1,
164
+ "description": "Maximum number of times this task can execute"
165
+ },
166
+ "circuit_breaker": {
167
+ "$ref": "#/definitions/task_circuit_breaker"
168
+ },
169
+ "description": {
170
+ "type": "string",
171
+ "description": "Human-readable description"
172
+ },
173
+ "inference": {
174
+ "$ref": "#/definitions/inference_hints"
175
+ }
176
+ },
177
+ "additionalProperties": false
178
+ },
179
+
180
+ "task_retry": {
181
+ "type": "object",
182
+ "required": ["max_attempts"],
183
+ "properties": {
184
+ "max_attempts": {
185
+ "type": "integer",
186
+ "minimum": 1,
187
+ "description": "Maximum retry attempts"
188
+ },
189
+ "delay_ms": {
190
+ "type": "integer",
191
+ "minimum": 0,
192
+ "description": "Delay between retries in ms"
193
+ },
194
+ "backoff_multiplier": {
195
+ "type": "number",
196
+ "minimum": 1,
197
+ "description": "Backoff multiplier (e.g., 2 for exponential)"
198
+ }
199
+ },
200
+ "additionalProperties": false
201
+ },
202
+
203
+ "refresh_strategy": {
204
+ "type": "string",
205
+ "enum": ["data-changed", "epoch-changed", "time-based", "manual", "once"],
206
+ "description": "Strategy for determining when a completed task should re-run"
207
+ },
208
+
209
+ "task_circuit_breaker": {
210
+ "type": "object",
211
+ "required": ["max_executions", "on_break"],
212
+ "properties": {
213
+ "max_executions": {
214
+ "type": "integer",
215
+ "minimum": 1,
216
+ "description": "Max executions before breaker trips"
217
+ },
218
+ "on_break": {
219
+ "type": "array",
220
+ "items": { "type": "string" },
221
+ "minItems": 1,
222
+ "description": "Tokens to inject when breaker trips"
223
+ }
224
+ },
225
+ "additionalProperties": false
226
+ },
227
+
228
+ "inference_hints": {
229
+ "type": "object",
230
+ "description": "LLM inference hints — opt-in metadata for AI-assisted completion detection",
231
+ "properties": {
232
+ "criteria": {
233
+ "type": "string",
234
+ "description": "Human-readable completion criteria"
235
+ },
236
+ "keywords": {
237
+ "type": "array",
238
+ "items": { "type": "string" },
239
+ "description": "Keywords to help the LLM understand the domain"
240
+ },
241
+ "suggestedChecks": {
242
+ "type": "array",
243
+ "items": { "type": "string" },
244
+ "description": "Suggested checks for verification"
245
+ },
246
+ "autoDetectable": {
247
+ "type": "boolean",
248
+ "description": "Whether the LLM should attempt to auto-detect completion (default: false)"
249
+ }
250
+ },
251
+ "additionalProperties": false
252
+ }
253
+ }
254
+ }