ai-data-workflow-logic 0.2.0 → 0.2.1
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/package.json +11 -10
- package/src/after.ts +78 -0
- package/src/filesystem.ts +12 -1
- package/src/index.ts +22 -61
- package/src/source-loader.ts +72 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-data-workflow-logic",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "EagerDataFlow-backed AI Data Workflow RunGraph helpers",
|
|
6
6
|
"type": "module",
|
|
@@ -8,18 +8,19 @@
|
|
|
8
8
|
"exports": {
|
|
9
9
|
".": "./src/index.ts",
|
|
10
10
|
"./browser": "./src/browser.ts",
|
|
11
|
-
"./filesystem": "./src/filesystem.ts"
|
|
11
|
+
"./filesystem": "./src/filesystem.ts",
|
|
12
|
+
"./sources": "./src/source-loader.ts"
|
|
12
13
|
},
|
|
13
14
|
"dependencies": {
|
|
14
|
-
"ai-data-workflow-contract": "0.2.
|
|
15
|
-
"ai-workflow-contract": "0.2.
|
|
16
|
-
"ai-workflow-logic": "0.2.
|
|
15
|
+
"ai-data-workflow-contract": "0.2.1",
|
|
16
|
+
"ai-workflow-contract": "0.2.2",
|
|
17
|
+
"ai-workflow-logic": "0.2.2",
|
|
17
18
|
"eager-data-flow-contract": "0.1.4",
|
|
18
|
-
"eager-data-flow-logic": "0.1.
|
|
19
|
-
"flow-step-space-logic": "0.1.
|
|
20
|
-
"task-manager-contract": "0.1.
|
|
21
|
-
"task-manager-logic": "0.1.
|
|
22
|
-
"work-ctrl-flow-logic": "0.1.
|
|
19
|
+
"eager-data-flow-logic": "0.1.8",
|
|
20
|
+
"flow-step-space-logic": "0.1.2",
|
|
21
|
+
"task-manager-contract": "0.1.4",
|
|
22
|
+
"task-manager-logic": "0.1.7",
|
|
23
|
+
"work-ctrl-flow-logic": "0.1.6"
|
|
23
24
|
},
|
|
24
25
|
"files": [
|
|
25
26
|
"src"
|
package/src/after.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type {AIDataWorkflowAfterPolicy, AIDataWorkflowGraphPatch, AIDataWorkflowRunGraph} from 'ai-data-workflow-contract';
|
|
2
|
+
import {normalizeFlowClosedObject} from 'ai-workflow-logic';
|
|
3
|
+
import {canonicalOwnDataDigest} from 'task-manager-contract';
|
|
4
|
+
import type {EagerDataFlowValue} from 'eager-data-flow-contract';
|
|
5
|
+
import type {FlowClosedValue} from 'ai-workflow-contract';
|
|
6
|
+
|
|
7
|
+
function requireThat(condition: unknown, code: string): asserts condition {
|
|
8
|
+
if (!condition) throw new Error(code);
|
|
9
|
+
}
|
|
10
|
+
/** 旧 Eager 合同的数组可写;只作脱离输入引用的纯值转换,不放宽合同。 */
|
|
11
|
+
function eagerValue(value: FlowClosedValue): EagerDataFlowValue {
|
|
12
|
+
if (Array.isArray(value)) return value.map(eagerValue);
|
|
13
|
+
if (value !== null && typeof value === 'object') return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, eagerValue(item)]));
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
function policy(value: unknown): AIDataWorkflowAfterPolicy {
|
|
17
|
+
const row = normalizeFlowClosedObject(value);
|
|
18
|
+
const keys = ['schemaVersion', 'targetNodeId', 'resultPort', 'decisionField', 'reopenValue', 'completeValue', 'maxReopens'];
|
|
19
|
+
requireThat(Object.keys(row).length === keys.length && keys.every(key => Object.hasOwn(row, key)), 'AI_DATA_AFTER_POLICY_FIELDS');
|
|
20
|
+
requireThat(row.schemaVersion === 'depa.ai-data-after/v1', 'AI_DATA_AFTER_POLICY_VERSION');
|
|
21
|
+
for (const key of ['targetNodeId', 'resultPort', 'decisionField', 'reopenValue', 'completeValue']) requireThat(typeof row[key] === 'string' && row[key].length > 0 && row[key].length <= 512 && row[key].trim() === row[key], 'AI_DATA_AFTER_POLICY_IDENTITY');
|
|
22
|
+
requireThat(typeof row.targetNodeId === 'string' && typeof row.resultPort === 'string' && typeof row.decisionField === 'string' && typeof row.reopenValue === 'string' && typeof row.completeValue === 'string', 'AI_DATA_AFTER_POLICY_IDENTITY');
|
|
23
|
+
requireThat(row.reopenValue !== row.completeValue && typeof row.maxReopens === 'number' && Number.isSafeInteger(row.maxReopens) && row.maxReopens >= 0 && row.maxReopens <= 5, 'AI_DATA_AFTER_POLICY_BUDGET');
|
|
24
|
+
return {schemaVersion: row.schemaVersion, targetNodeId: row.targetNodeId, resultPort: row.resultPort, decisionField: row.decisionField, reopenValue: row.reopenValue, completeValue: row.completeValue, maxReopens: row.maxReopens};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** 纯规划;调用 owner 必须通过原 checkpoint CAS 应用返回的补丁。 */
|
|
28
|
+
export function planAIDataWorkflowAfterPatch(graph: AIDataWorkflowRunGraph, sourceNodeId: string): AIDataWorkflowGraphPatch | undefined {
|
|
29
|
+
const source = graph.nodes[sourceNodeId];
|
|
30
|
+
if (!source || source.config.workflowAfter === undefined || !['Succeeded', 'Reused'].includes(source.status)) return;
|
|
31
|
+
const declared = policy(source.config.workflowAfter);
|
|
32
|
+
requireThat(source.result?.generation === source.generation && source.result.status === source.status, 'AI_DATA_AFTER_SOURCE_GENERATION');
|
|
33
|
+
const outputs = normalizeFlowClosedObject(source.result.output);
|
|
34
|
+
requireThat(Object.hasOwn(outputs, declared.resultPort), 'AI_DATA_AFTER_RESULT_PORT');
|
|
35
|
+
const report = normalizeFlowClosedObject(outputs[declared.resultPort]);
|
|
36
|
+
const decision = report[declared.decisionField];
|
|
37
|
+
if (decision === declared.completeValue) return;
|
|
38
|
+
requireThat(decision === declared.reopenValue, 'AI_DATA_AFTER_DECISION_UNSETTLED');
|
|
39
|
+
const target = graph.nodes[declared.targetNodeId];
|
|
40
|
+
requireThat(target?.tag === 'TransformNode' && target.nodeType !== 'manual' && target.config.workflowReopenable === true, 'AI_DATA_AFTER_TARGET_NOT_REOPENABLE');
|
|
41
|
+
const seen = new Set<string>();
|
|
42
|
+
const visit = (nodeId: string): void => {
|
|
43
|
+
if (seen.has(nodeId)) return;
|
|
44
|
+
seen.add(nodeId);
|
|
45
|
+
for (const parent of graph.nodes[nodeId]?.dependsOn ?? []) visit(parent);
|
|
46
|
+
};
|
|
47
|
+
visit(sourceNodeId);
|
|
48
|
+
requireThat(declared.targetNodeId !== sourceNodeId && seen.has(declared.targetNodeId), 'AI_DATA_AFTER_TARGET_NOT_PREDECESSOR');
|
|
49
|
+
const affected = new Set<string>();
|
|
50
|
+
const downstream = (nodeId: string): void => {
|
|
51
|
+
if (affected.has(nodeId)) return;
|
|
52
|
+
affected.add(nodeId);
|
|
53
|
+
for (const node of Object.values(graph.nodes)) if (node.dependsOn.includes(nodeId)) downstream(node.id);
|
|
54
|
+
};
|
|
55
|
+
downstream(declared.targetNodeId);
|
|
56
|
+
for (const nodeId of affected) {
|
|
57
|
+
const node = graph.nodes[nodeId]!;
|
|
58
|
+
requireThat(node.config.humanReview !== true && node.config.workflowReopenProtected !== true, 'AI_DATA_AFTER_PROTECTED_NODE');
|
|
59
|
+
requireThat(node.status !== 'Running' && node.result?.status !== 'Waiting', 'AI_DATA_AFTER_UNSETTLED_NODE');
|
|
60
|
+
}
|
|
61
|
+
const prefix = 'after-reopen:' + canonicalOwnDataDigest([sourceNodeId, declared]).slice('sha256:'.length) + ':';
|
|
62
|
+
const previous = graph.patchHistory.filter(receipt => receipt.patchId.startsWith(prefix));
|
|
63
|
+
requireThat(previous.length < declared.maxReopens, 'AI_DATA_AFTER_BUDGET_EXHAUSTED');
|
|
64
|
+
const outputHash = canonicalOwnDataDigest(report);
|
|
65
|
+
const patchId = prefix + source.generation + ':' + outputHash;
|
|
66
|
+
requireThat(!graph.patchHistory.some(receipt => receipt.patchId === patchId), 'AI_DATA_AFTER_ALREADY_APPLIED');
|
|
67
|
+
const nodeResults = Object.fromEntries(Object.values(graph.nodes).filter(node => node.result).map(node => [node.id, {
|
|
68
|
+
nodeId: node.id, generation: node.generation, status: node.status,
|
|
69
|
+
...(node.result!.output === undefined ? {} : {output: node.result!.output}),
|
|
70
|
+
}]));
|
|
71
|
+
const afterFeedback = normalizeFlowClosedObject({sourceNode: sourceNodeId, sourceGeneration: source.generation, outputHash, output: report, nodeResults});
|
|
72
|
+
return {
|
|
73
|
+
patchId,
|
|
74
|
+
generation: graph.currentGeneration + 1,
|
|
75
|
+
reason: '原生 after 准入的有界整改:' + sourceNodeId,
|
|
76
|
+
operations: [{op: 'update-node', nodeId: target.id, changes: {config: Object.fromEntries(Object.entries(normalizeFlowClosedObject({...target.config, afterFeedback})).map(([key, value]) => [key, eagerValue(value)]))}}],
|
|
77
|
+
};
|
|
78
|
+
}
|
package/src/filesystem.ts
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
normalizeAIWorkflowProfileDurableState,
|
|
41
41
|
normalizeFlowClosedObject,
|
|
42
42
|
normalizeFlowClosedValue,
|
|
43
|
+
WorkflowDelegationSuspendedError,
|
|
43
44
|
type FlowRunProfileAuthorityPort,
|
|
44
45
|
type FlowRunProfileAuthorityRequest,
|
|
45
46
|
type FrozenFlowRunProfileAuthority,
|
|
@@ -339,7 +340,8 @@ async function executeAIDataCheckpoint(
|
|
|
339
340
|
return commitGraph((current) => {
|
|
340
341
|
const node = current.nodes[nodeId];
|
|
341
342
|
if (!node) throw new Error(`AI Data Workflow node ${nodeId} does not exist in the durable graph.`);
|
|
342
|
-
if (cause
|
|
343
|
+
if (findDelegationSuspension(cause)
|
|
344
|
+
|| cause instanceof AIDataChildInvocationSuspendedError
|
|
343
345
|
|| cause instanceof AIDataChildInvocationTerminalFailure
|
|
344
346
|
|| findCheckpointObserverError(cause)) return current;
|
|
345
347
|
return recordAIDataWorkflowNodeResult(current, nodeId, {
|
|
@@ -351,6 +353,7 @@ async function executeAIDataCheckpoint(
|
|
|
351
353
|
},
|
|
352
354
|
});
|
|
353
355
|
} catch (error) {
|
|
356
|
+
if (findDelegationSuspension(error)) return { checkpoint: accepted, graph };
|
|
354
357
|
const observerError = findCheckpointObserverError(error);
|
|
355
358
|
if (observerError) throw observerError.cause;
|
|
356
359
|
throw error;
|
|
@@ -371,6 +374,14 @@ class AIDataChildInvocationSuspendedError extends Error {
|
|
|
371
374
|
}
|
|
372
375
|
}
|
|
373
376
|
|
|
377
|
+
function findDelegationSuspension(value: unknown, seen = new Set<unknown>()): WorkflowDelegationSuspendedError | undefined {
|
|
378
|
+
if (value instanceof WorkflowDelegationSuspendedError) return value;
|
|
379
|
+
if (!value || typeof value !== 'object' || seen.has(value)) return undefined;
|
|
380
|
+
seen.add(value);
|
|
381
|
+
if ('cause' in value) return findDelegationSuspension(value.cause, seen);
|
|
382
|
+
return undefined;
|
|
383
|
+
}
|
|
384
|
+
|
|
374
385
|
class AIDataChildInvocationTerminalFailure extends Error {
|
|
375
386
|
constructor(nodeId: string, code: string, message: string) {
|
|
376
387
|
super(`AI Data child invocation ${nodeId} failed (${code}): ${message}`);
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export {planAIDataWorkflowAfterPatch} from './after.js';
|
|
1
2
|
import type {
|
|
2
3
|
AIDataWorkflowGraphPatch,
|
|
3
4
|
AIDataWorkflowGraphPatchNodeSpec,
|
|
@@ -20,6 +21,7 @@ import type {
|
|
|
20
21
|
AIDataWorkflowRunProfileState,
|
|
21
22
|
AIDataWorkflowRuntime,
|
|
22
23
|
AIAgentHostEffectPort,
|
|
24
|
+
AIAgentProcessorRuntime,
|
|
23
25
|
FrozenAIAgentTaskBinding,
|
|
24
26
|
AIWorkflowAuthoredEffects,
|
|
25
27
|
AIWorkflowDefinitionRef,
|
|
@@ -52,15 +54,15 @@ import type {
|
|
|
52
54
|
EagerDataFlowValue,
|
|
53
55
|
LoadEagerDataFlowOptions,
|
|
54
56
|
} from 'eager-data-flow-contract';
|
|
55
|
-
import { loadEagerDataFlowProfileSources, loadEagerDataFlowProfileSourcesWithRuntime } from 'eager-data-flow-logic';
|
|
56
|
-
import { createDefinitionStepSourceRuntime, type DefinitionStepAssemblyRuntime } from 'flow-step-space-logic';
|
|
57
57
|
import {
|
|
58
58
|
createAIWorkflowRuntimeContext,
|
|
59
59
|
commitFlowRunCheckpoint,
|
|
60
|
-
defineAIDataWorkflow,
|
|
61
60
|
loadFlowRunCheckpoint,
|
|
62
61
|
resolveAIWorkflowReusePolicy,
|
|
63
62
|
bindAIAgentProcessors,
|
|
63
|
+
bindWorkflowNodeTasks,
|
|
64
|
+
bindWorkflowTaskDelegation,
|
|
65
|
+
normalizeFlowClosedObject,
|
|
64
66
|
} from 'ai-workflow-logic';
|
|
65
67
|
import { assertFrozenAIAgentTaskBinding } from 'ai-workflow-logic/run-freeze';
|
|
66
68
|
|
|
@@ -178,7 +180,7 @@ export function createAIDataWorkflowAgentNodeRuntimeBinder(
|
|
|
178
180
|
const proof = options.taskProofs[identity.nodeId];
|
|
179
181
|
if (!proof) throw new Error(`AI_AGENT_TASK_PROOF_REQUIRED: no frozen proof for node ${identity.nodeId}.`);
|
|
180
182
|
const taskBinding = assertFrozenAIAgentTaskBinding(proof).task;
|
|
181
|
-
const
|
|
183
|
+
const agentRuntime = {
|
|
182
184
|
checkpointRuntime: options.checkpointRuntime,
|
|
183
185
|
checkpointKey: { instanceId: options.flowInstanceId, runId: options.runId },
|
|
184
186
|
nodeId: identity.nodeId,
|
|
@@ -189,66 +191,23 @@ export function createAIDataWorkflowAgentNodeRuntimeBinder(
|
|
|
189
191
|
taskBinding,
|
|
190
192
|
effects: options.effects,
|
|
191
193
|
...(options.metadata === undefined ? {} : { metadata: options.metadata }),
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
+
} satisfies AIAgentProcessorRuntime;
|
|
195
|
+
const effects = bindAIAgentProcessors(agentRuntime);
|
|
196
|
+
const delegation=options.effects.delegation ? bindWorkflowTaskDelegation({
|
|
197
|
+
checkpointRuntime: options.checkpointRuntime,
|
|
198
|
+
checkpointKey: { instanceId: options.flowInstanceId, runId: options.runId },
|
|
199
|
+
nodeId: identity.nodeId, invocationKey: `${identity.nodeId}#${generation}`,
|
|
200
|
+
workflowKind: 'AIDataWorkflow', workflowRef: options.workflowRef, taskBinding,
|
|
201
|
+
visit: `generation:${generation}`, generation, effects: options.effects.delegation,
|
|
202
|
+
}) : undefined;
|
|
203
|
+
return Object.freeze({ ai: Object.freeze({ ...runtime.ai, effects,
|
|
204
|
+
tasks:bindWorkflowNodeTasks(agentRuntime,delegation),
|
|
205
|
+
...(delegation?{delegation}:{}),
|
|
206
|
+
}) });
|
|
194
207
|
};
|
|
195
208
|
}
|
|
196
209
|
|
|
197
|
-
export
|
|
198
|
-
definition: AIDataWorkflowDefinitionBinding['definition'],
|
|
199
|
-
): AIDataWorkflowDefinitionBinding {
|
|
200
|
-
return defineAIDataWorkflow(definition);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export interface AIDataWorkflowSourceLoadResult {
|
|
204
|
-
readonly binding?: AIDataWorkflowDefinitionBinding;
|
|
205
|
-
readonly diagnostics: readonly EagerDataFlowDiagnostic[];
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export interface AIDataWorkflowSourceLoadRuntime {
|
|
209
|
-
readonly extensionCodecs: DefinitionStepAssemblyRuntime['extensionCodecs'];
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export interface AIDataWorkflowSourceLoadInput {
|
|
213
|
-
readonly sources: EagerDataFlowSourceCollection;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export type AIDataWorkflowSourceLoadConfig = LoadEagerDataFlowOptions;
|
|
217
|
-
|
|
218
|
-
/** Processor form for profile admission with runtime-owned extension codecs. */
|
|
219
|
-
export function loadAIDataWorkflow(
|
|
220
|
-
runtime: AIDataWorkflowSourceLoadRuntime,
|
|
221
|
-
input: AIDataWorkflowSourceLoadInput,
|
|
222
|
-
config: AIDataWorkflowSourceLoadConfig = {},
|
|
223
|
-
): AIDataWorkflowSourceLoadResult {
|
|
224
|
-
const loaded = loadEagerDataFlowProfileSourcesWithRuntime(
|
|
225
|
-
createDefinitionStepSourceRuntime(input.sources, runtime.extensionCodecs),
|
|
226
|
-
input.sources,
|
|
227
|
-
{ ...config, profileRoot: 'AIDataWorkflow' },
|
|
228
|
-
);
|
|
229
|
-
if (!loaded.plan || loaded.diagnostics.length > 0) return { diagnostics: loaded.diagnostics };
|
|
230
|
-
return {
|
|
231
|
-
binding: defineEagerBackedAIDataWorkflow(loaded.plan),
|
|
232
|
-
diagnostics: loaded.diagnostics,
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export function loadAIDataWorkflowSources(
|
|
237
|
-
sources: EagerDataFlowSourceCollection,
|
|
238
|
-
options: LoadEagerDataFlowOptions = {},
|
|
239
|
-
): AIDataWorkflowSourceLoadResult {
|
|
240
|
-
const loaded = loadEagerDataFlowProfileSources(sources, {
|
|
241
|
-
...options,
|
|
242
|
-
profileRoot: 'AIDataWorkflow',
|
|
243
|
-
});
|
|
244
|
-
if (!loaded.plan || loaded.diagnostics.length > 0) {
|
|
245
|
-
return { diagnostics: loaded.diagnostics };
|
|
246
|
-
}
|
|
247
|
-
return {
|
|
248
|
-
binding: defineEagerBackedAIDataWorkflow(loaded.plan),
|
|
249
|
-
diagnostics: loaded.diagnostics,
|
|
250
|
-
};
|
|
251
|
-
}
|
|
210
|
+
export * from './source-loader.js';
|
|
252
211
|
|
|
253
212
|
export interface CreateAIDataWorkflowRunGraphOptions {
|
|
254
213
|
readonly binding: AIDataWorkflowDefinitionBinding;
|
|
@@ -329,6 +288,7 @@ function cloneNodeResult(result: AIWorkflowNodeResult): AIWorkflowNodeResult {
|
|
|
329
288
|
...result,
|
|
330
289
|
...(result.semanticFingerprint ? { semanticFingerprint: cloneFingerprint(result.semanticFingerprint) } : {}),
|
|
331
290
|
...(result.reusedFrom ? { reusedFrom: { ...result.reusedFrom } } : {}),
|
|
291
|
+
...(result.waitContext===undefined?{}:{waitContext:normalizeFlowClosedObject(result.waitContext)}),
|
|
332
292
|
};
|
|
333
293
|
}
|
|
334
294
|
|
|
@@ -1190,6 +1150,7 @@ export function recordAIDataWorkflowNodeResult(
|
|
|
1190
1150
|
`AI Data Workflow result generation ${result.generation} does not match node ${nodeId}@${node.generation}`,
|
|
1191
1151
|
);
|
|
1192
1152
|
}
|
|
1153
|
+
if(node.result?.waitContext!==undefined&&(result.waitContext===undefined||JSON.stringify(normalizeFlowClosedObject(node.result.waitContext))!==JSON.stringify(normalizeFlowClosedObject(result.waitContext))))throw new AIDataWorkflowRunGraphError(`AI Data Workflow native wait context ${nodeId}@${node.generation} is immutable`);
|
|
1193
1154
|
if (node.result
|
|
1194
1155
|
&& (node.result.status === 'Succeeded' || node.result.status === 'Failed' || node.result.status === 'Reused')) {
|
|
1195
1156
|
if (JSON.stringify(node.result) === JSON.stringify(result)) return cloneGraph(graph);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { AIDataWorkflowDefinitionBinding } from "ai-workflow-contract";
|
|
2
|
+
import { defineAIDataWorkflow } from "ai-workflow-logic/definitions";
|
|
3
|
+
import type {
|
|
4
|
+
EagerDataFlowDiagnostic,
|
|
5
|
+
EagerDataFlowSourceCollection,
|
|
6
|
+
LoadEagerDataFlowOptions,
|
|
7
|
+
} from "eager-data-flow-contract";
|
|
8
|
+
import {
|
|
9
|
+
loadEagerDataFlowProfileSources,
|
|
10
|
+
loadEagerDataFlowProfileSourcesWithRuntime,
|
|
11
|
+
} from "eager-data-flow-logic/browser";
|
|
12
|
+
import {
|
|
13
|
+
createDefinitionStepSourceRuntime,
|
|
14
|
+
type DefinitionStepAssemblyRuntime,
|
|
15
|
+
} from "flow-step-space-logic/browser";
|
|
16
|
+
|
|
17
|
+
export function defineEagerBackedAIDataWorkflow(
|
|
18
|
+
definition: AIDataWorkflowDefinitionBinding["definition"],
|
|
19
|
+
): AIDataWorkflowDefinitionBinding {
|
|
20
|
+
return defineAIDataWorkflow(definition);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AIDataWorkflowSourceLoadResult {
|
|
24
|
+
readonly binding?: AIDataWorkflowDefinitionBinding;
|
|
25
|
+
readonly diagnostics: readonly EagerDataFlowDiagnostic[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AIDataWorkflowSourceLoadRuntime {
|
|
29
|
+
readonly extensionCodecs: DefinitionStepAssemblyRuntime["extensionCodecs"];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AIDataWorkflowSourceLoadInput {
|
|
33
|
+
readonly sources: EagerDataFlowSourceCollection;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type AIDataWorkflowSourceLoadConfig = LoadEagerDataFlowOptions;
|
|
37
|
+
|
|
38
|
+
/** Processor form for profile admission with runtime-owned extension codecs. */
|
|
39
|
+
export function loadAIDataWorkflow(
|
|
40
|
+
runtime: AIDataWorkflowSourceLoadRuntime,
|
|
41
|
+
input: AIDataWorkflowSourceLoadInput,
|
|
42
|
+
config: AIDataWorkflowSourceLoadConfig = {},
|
|
43
|
+
): AIDataWorkflowSourceLoadResult {
|
|
44
|
+
const loaded = loadEagerDataFlowProfileSourcesWithRuntime(
|
|
45
|
+
createDefinitionStepSourceRuntime(input.sources, runtime.extensionCodecs),
|
|
46
|
+
input.sources,
|
|
47
|
+
{ ...config, profileRoot: "AIDataWorkflow" },
|
|
48
|
+
);
|
|
49
|
+
if (!loaded.plan || loaded.diagnostics.length > 0)
|
|
50
|
+
return { diagnostics: loaded.diagnostics };
|
|
51
|
+
return {
|
|
52
|
+
binding: defineEagerBackedAIDataWorkflow(loaded.plan),
|
|
53
|
+
diagnostics: loaded.diagnostics,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function loadAIDataWorkflowSources(
|
|
58
|
+
sources: EagerDataFlowSourceCollection,
|
|
59
|
+
options: LoadEagerDataFlowOptions = {},
|
|
60
|
+
): AIDataWorkflowSourceLoadResult {
|
|
61
|
+
const loaded = loadEagerDataFlowProfileSources(sources, {
|
|
62
|
+
...options,
|
|
63
|
+
profileRoot: "AIDataWorkflow",
|
|
64
|
+
});
|
|
65
|
+
if (!loaded.plan || loaded.diagnostics.length > 0) {
|
|
66
|
+
return { diagnostics: loaded.diagnostics };
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
binding: defineEagerBackedAIDataWorkflow(loaded.plan),
|
|
70
|
+
diagnostics: loaded.diagnostics,
|
|
71
|
+
};
|
|
72
|
+
}
|