@codemation/core 0.6.0 → 0.7.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/CHANGELOG.md +9 -0
- package/dist/{EngineRuntimeRegistration.types-Dm129RJ6.d.ts → EngineRuntimeRegistration.types-_M7KFD3D.d.ts} +2 -2
- package/dist/{EngineWorkflowRunnerService-Bf88QtwB.d.cts → EngineWorkflowRunnerService-D0Cwngv7.d.cts} +2 -2
- package/dist/{InMemoryRunDataFactory-Dyl4p2s8.d.cts → InMemoryRunDataFactory-BIWx6e02.d.cts} +6 -6
- package/dist/{RunIntentService-B1Y3v1H6.d.cts → RunIntentService-5k0p-J67.d.cts} +8 -4
- package/dist/{RunIntentService-BDiodxhf.d.ts → RunIntentService-CuXAIO6_.d.ts} +29 -20
- package/dist/bootstrap/index.cjs +2 -2
- package/dist/bootstrap/index.d.cts +5 -5
- package/dist/bootstrap/index.d.ts +3 -3
- package/dist/bootstrap/index.js +2 -2
- package/dist/{bootstrap-DdeiJ8cd.js → bootstrap-BhYxSivA.js} +3 -3
- package/dist/bootstrap-BhYxSivA.js.map +1 -0
- package/dist/{bootstrap-DVL2ue5v.cjs → bootstrap-D-TDU9Lu.cjs} +3 -3
- package/dist/bootstrap-D-TDU9Lu.cjs.map +1 -0
- package/dist/{index-C2af8ssM.d.ts → index-BnJ7_IrO.d.ts} +11 -10
- package/dist/index.cjs +16 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -21
- package/dist/index.d.ts +3 -3
- package/dist/index.js +11 -6
- package/dist/index.js.map +1 -1
- package/dist/{runtime-DVBwxFvX.cjs → runtime-3YVDd2vY.cjs} +42 -42
- package/dist/runtime-3YVDd2vY.cjs.map +1 -0
- package/dist/{runtime-7Xh9z3dw.js → runtime-CJnObwsU.js} +33 -33
- package/dist/runtime-CJnObwsU.js.map +1 -0
- package/dist/testing.cjs +2 -2
- package/dist/testing.d.cts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +2 -2
- package/package.json +1 -1
- package/src/ai/AgentConfigInspectorFactory.ts +2 -2
- package/src/ai/AgentMessageConfigNormalizerFactory.ts +3 -3
- package/src/ai/AiHost.ts +2 -2
- package/src/authoring/defineNode.types.ts +35 -9
- package/src/authoring/index.ts +1 -0
- package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +3 -3
- package/src/contracts/index.ts +2 -1
- package/src/contracts/{itemValue.ts → itemExpr.ts} +31 -32
- package/src/contracts/params.ts +10 -0
- package/src/contracts/workflowTypes.ts +11 -2
- package/src/execution/{ItemValueResolver.ts → ItemExprResolver.ts} +5 -5
- package/src/execution/NodeExecutor.ts +6 -6
- package/src/execution/index.ts +1 -1
- package/src/index.ts +1 -1
- package/src/runStorage/InMemoryRunData.ts +9 -5
- package/src/types/index.ts +2 -1
- package/src/workflowSnapshots/WorkflowSnapshotCodec.ts +1 -1
- package/dist/bootstrap-DVL2ue5v.cjs.map +0 -1
- package/dist/bootstrap-DdeiJ8cd.js.map +0 -1
- package/dist/runtime-7Xh9z3dw.js.map +0 -1
- package/dist/runtime-DVBwxFvX.cjs.map +0 -1
package/dist/testing.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const require_runtime = require('./runtime-
|
|
1
|
+
const require_runtime = require('./runtime-3YVDd2vY.cjs');
|
|
2
2
|
const require_workflowActivationPolicy = require('./workflowActivationPolicy-6V3OJD3N.cjs');
|
|
3
|
-
const require_bootstrap = require('./bootstrap-
|
|
3
|
+
const require_bootstrap = require('./bootstrap-D-TDU9Lu.cjs');
|
|
4
4
|
let tsyringe = require("tsyringe");
|
|
5
5
|
tsyringe = require_runtime.__toESM(tsyringe);
|
|
6
6
|
|
package/dist/testing.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as WorkflowSnapshotCodec, n as EngineRuntimeRegistrationOptions, t as EngineWorkflowRunnerService } from "./EngineWorkflowRunnerService-
|
|
1
|
+
import { A as NodeOutputs, E as NodeId, F as ParentExecutionRef, G as TriggerNodeConfig, H as RunnableNodeConfig, Ht as NodeExecutionRequest, Or as Container, Pr as TypeToken, R as RunDataFactory, Vt as NodeExecutionContext, Wt as NodeExecutionScheduler, Xr as RunEventBus, Xt as RunnableNode, Y as WorkflowDefinition, Zt as RunnableNodeExecuteArgs, br as CredentialSessionService, en as TriggerNode, f as Items, in as TriggerSetupStateRepository, jt as ExecutionContextFactory, k as NodeOffloadPolicy, ln as WorkflowRunnerService, n as InMemoryLiveWorkflowRepository, nn as TriggerSetupContext, qn as RunResult, qr as EngineExecutionLimitsPolicy, r as Engine, t as RunIntentService, tr as WorkflowExecutionRepository, tt as WorkflowId, u as Item } from "./RunIntentService-5k0p-J67.cjs";
|
|
2
|
+
import { a as WorkflowSnapshotCodec, n as EngineRuntimeRegistrationOptions, t as EngineWorkflowRunnerService } from "./EngineWorkflowRunnerService-D0Cwngv7.cjs";
|
|
3
3
|
import { DependencyContainer, InjectionToken } from "tsyringe";
|
|
4
4
|
import { ZodType } from "zod";
|
|
5
5
|
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $
|
|
2
|
-
import { t as EngineRuntimeRegistrationOptions } from "./EngineRuntimeRegistration.types-
|
|
1
|
+
import { $t as TriggerNodeConfig, Hi as TypeToken, Ii as Container, Kt as RunDataFactory, Lt as NodeOffloadPolicy, Oi as CredentialSessionService, Pt as NodeId, Qn as NodeExecutionScheduler, Rt as NodeOutputs, Ut as ParentExecutionRef, Xn as NodeExecutionRequest, Xt as RunnableNodeConfig, Yn as NodeExecutionContext, _r as WorkflowRunnerService, ar as RunnableNodeExecuteArgs, bt as Items, cr as TriggerNode, fr as TriggerSetupStateRepository, ia as RunEventBus, ir as RunnableNode, l as WorkflowSnapshotCodec, li as WorkflowExecutionRepository, ln as WorkflowId, n as InMemoryLiveWorkflowRepository, r as EngineWorkflowRunnerService, rn as WorkflowDefinition, t as RunIntentService, ta as EngineExecutionLimitsPolicy, ti as RunResult, u as Engine, ur as TriggerSetupContext, vt as Item, zn as ExecutionContextFactory } from "./RunIntentService-CuXAIO6_.js";
|
|
2
|
+
import { t as EngineRuntimeRegistrationOptions } from "./EngineRuntimeRegistration.types-_M7KFD3D.js";
|
|
3
3
|
import { DependencyContainer, InjectionToken } from "tsyringe";
|
|
4
4
|
import { ZodType } from "zod";
|
|
5
5
|
|
package/dist/testing.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as NodeExecutor, B as DefaultAsyncSleeper, D as PersistedWorkflowTokenRegistry, E as WorkflowSnapshotCodec, P as emitPorts, R as InProcessRetryRunner, T as NodeInstanceFactory, _t as CoreTokens, a as InMemoryLiveWorkflowRepository, b as HintOnlyOffloadPolicy, d as InMemoryRunDataFactory, i as RunIntentService, l as Engine, x as DefaultDrivingScheduler, y as InlineDrivingScheduler, z as DefaultExecutionContextFactory } from "./runtime-
|
|
1
|
+
import { A as NodeExecutor, B as DefaultAsyncSleeper, D as PersistedWorkflowTokenRegistry, E as WorkflowSnapshotCodec, P as emitPorts, R as InProcessRetryRunner, T as NodeInstanceFactory, _t as CoreTokens, a as InMemoryLiveWorkflowRepository, b as HintOnlyOffloadPolicy, d as InMemoryRunDataFactory, i as RunIntentService, l as Engine, x as DefaultDrivingScheduler, y as InlineDrivingScheduler, z as DefaultExecutionContextFactory } from "./runtime-CJnObwsU.js";
|
|
2
2
|
import { n as InMemoryRunEventBus, r as WorkflowBuilder, t as AllWorkflowsActiveWorkflowActivationPolicy } from "./workflowActivationPolicy-Td9HTOuD.js";
|
|
3
|
-
import { n as InMemoryWorkflowExecutionRepository, t as EngineRuntimeRegistrar } from "./bootstrap-
|
|
3
|
+
import { n as InMemoryWorkflowExecutionRepository, t as EngineRuntimeRegistrar } from "./bootstrap-BhYxSivA.js";
|
|
4
4
|
import { container } from "tsyringe";
|
|
5
5
|
|
|
6
6
|
//#region src/testing/RejectingCredentialSessionService.ts
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { NodeConfigBase } from "../types";
|
|
2
|
-
import {
|
|
2
|
+
import { isItemExpr } from "../contracts/itemExpr";
|
|
3
3
|
import type { AgentNodeConfig } from "./AiHost";
|
|
4
4
|
|
|
5
5
|
export class AgentConfigInspector {
|
|
@@ -18,7 +18,7 @@ export class AgentConfigInspector {
|
|
|
18
18
|
return messages.length > 0;
|
|
19
19
|
}
|
|
20
20
|
if (typeof messages === "object") {
|
|
21
|
-
if (
|
|
21
|
+
if (isItemExpr(messages)) {
|
|
22
22
|
return true;
|
|
23
23
|
}
|
|
24
24
|
const o = messages as { prompt?: unknown; buildMessages?: unknown };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isItemExpr } from "../contracts/itemExpr";
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
4
|
AgentMessageBuildArgs,
|
|
@@ -69,9 +69,9 @@ export class AgentMessageConfigNormalizer {
|
|
|
69
69
|
config: AgentMessageConfig<TInputJson>,
|
|
70
70
|
args: AgentMessageBuildArgs<TInputJson>,
|
|
71
71
|
): ReadonlyArray<AgentMessageDto> {
|
|
72
|
-
if (
|
|
72
|
+
if (isItemExpr(config)) {
|
|
73
73
|
throw new Error(
|
|
74
|
-
"AIAgent messages wrapped in
|
|
74
|
+
"AIAgent messages wrapped in itemExpr(...) must be resolved by the engine before prompt normalization.",
|
|
75
75
|
);
|
|
76
76
|
}
|
|
77
77
|
if (Array.isArray(config)) {
|
package/src/ai/AiHost.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TypeToken } from "../di";
|
|
2
2
|
|
|
3
3
|
import type { CredentialRequirement } from "../contracts/credentialTypes";
|
|
4
|
-
import type {
|
|
4
|
+
import type { Expr } from "../contracts/params";
|
|
5
5
|
|
|
6
6
|
import type {
|
|
7
7
|
Item,
|
|
@@ -92,7 +92,7 @@ export type AgentMessageLine<TInputJson = unknown> = AgentMessageDto | AgentMess
|
|
|
92
92
|
* Use the object form only when you need `buildMessages` to append messages after optional `prompt` lines.
|
|
93
93
|
*/
|
|
94
94
|
export type AgentMessageConfig<TInputJson = unknown> =
|
|
95
|
-
|
|
|
95
|
+
| Expr<ReadonlyArray<AgentMessageLine<TInputJson>>, TInputJson>
|
|
96
96
|
| ReadonlyArray<AgentMessageLine<TInputJson>>
|
|
97
97
|
| {
|
|
98
98
|
readonly prompt?: ReadonlyArray<AgentMessageLine<TInputJson>>;
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
CredentialRequirement,
|
|
5
5
|
CredentialTypeId,
|
|
6
6
|
} from "../contracts/credentialTypes";
|
|
7
|
+
import type { ParamDeep } from "../contracts/params";
|
|
7
8
|
import type { RunnableNode, RunnableNodeExecuteArgs, NodeExecutionContext } from "../contracts/runtimeTypes";
|
|
8
9
|
import type { Item, Items, RunnableNodeConfig } from "../contracts/workflowTypes";
|
|
9
10
|
import type { TypeToken } from "../di";
|
|
@@ -67,6 +68,11 @@ export type DefineNodeExecuteArgs<TConfig extends CredentialJsonRecord, TInputJs
|
|
|
67
68
|
ctx: NodeExecutionContext<RunnableNodeConfig<TInputJson, unknown> & Readonly<{ config: TConfig }>>;
|
|
68
69
|
}>;
|
|
69
70
|
|
|
71
|
+
export type DefinedNodeConfigInput<TConfigResolved extends CredentialJsonRecord, TItemJson> = ParamDeep<
|
|
72
|
+
TConfigResolved,
|
|
73
|
+
TItemJson
|
|
74
|
+
>;
|
|
75
|
+
|
|
70
76
|
export interface DefinedNode<
|
|
71
77
|
TKey extends string,
|
|
72
78
|
TConfig extends CredentialJsonRecord,
|
|
@@ -78,7 +84,11 @@ export interface DefinedNode<
|
|
|
78
84
|
readonly key: TKey;
|
|
79
85
|
readonly title: string;
|
|
80
86
|
readonly description?: string;
|
|
81
|
-
create
|
|
87
|
+
create<TConfigItemJson = TInputJson>(
|
|
88
|
+
config: DefinedNodeConfigInput<TConfig, TConfigItemJson>,
|
|
89
|
+
name?: string,
|
|
90
|
+
id?: string,
|
|
91
|
+
): RunnableNodeConfig<TInputJson, TOutputJson>;
|
|
82
92
|
register(context: { registerNode<TValue>(token: TypeToken<TValue>, implementation?: TypeToken<TValue>): void }): void;
|
|
83
93
|
}
|
|
84
94
|
|
|
@@ -252,9 +262,13 @@ export function defineNode<
|
|
|
252
262
|
|
|
253
263
|
constructor(
|
|
254
264
|
public readonly name: string,
|
|
255
|
-
|
|
265
|
+
config: DefinedNodeConfigInput<TConfig, unknown>,
|
|
256
266
|
public readonly id?: string,
|
|
257
|
-
) {
|
|
267
|
+
) {
|
|
268
|
+
this.config = config as unknown as TConfig;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
public readonly config: TConfig;
|
|
258
272
|
|
|
259
273
|
getCredentialRequirements(): ReadonlyArray<CredentialRequirement> {
|
|
260
274
|
return credentialRequirements;
|
|
@@ -266,8 +280,12 @@ export function defineNode<
|
|
|
266
280
|
key: options.key,
|
|
267
281
|
title: options.title,
|
|
268
282
|
description: options.description,
|
|
269
|
-
create
|
|
270
|
-
|
|
283
|
+
create<TConfigItemJson = TInputJson>(
|
|
284
|
+
config: DefinedNodeConfigInput<TConfig, TConfigItemJson>,
|
|
285
|
+
name = options.title,
|
|
286
|
+
id?: string,
|
|
287
|
+
) {
|
|
288
|
+
return new DefinedRunnableNodeConfig(name, config as DefinedNodeConfigInput<TConfig, unknown>, id);
|
|
271
289
|
},
|
|
272
290
|
register(context) {
|
|
273
291
|
context.registerNode(DefinedNodeRuntime);
|
|
@@ -327,9 +345,13 @@ export function defineBatchNode<
|
|
|
327
345
|
|
|
328
346
|
constructor(
|
|
329
347
|
public readonly name: string,
|
|
330
|
-
|
|
348
|
+
config: DefinedNodeConfigInput<TConfig, unknown>,
|
|
331
349
|
public readonly id?: string,
|
|
332
|
-
) {
|
|
350
|
+
) {
|
|
351
|
+
this.config = config as unknown as TConfig;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
public readonly config: TConfig;
|
|
333
355
|
|
|
334
356
|
getCredentialRequirements(): ReadonlyArray<CredentialRequirement> {
|
|
335
357
|
return credentialRequirements;
|
|
@@ -341,8 +363,12 @@ export function defineBatchNode<
|
|
|
341
363
|
key: options.key,
|
|
342
364
|
title: options.title,
|
|
343
365
|
description: options.description,
|
|
344
|
-
create
|
|
345
|
-
|
|
366
|
+
create<TConfigItemJson = TInputJson>(
|
|
367
|
+
config: DefinedNodeConfigInput<TConfig, TConfigItemJson>,
|
|
368
|
+
name = options.title,
|
|
369
|
+
id?: string,
|
|
370
|
+
) {
|
|
371
|
+
return new DefinedRunnableNodeConfig(name, config as DefinedNodeConfigInput<TConfig, unknown>, id);
|
|
346
372
|
},
|
|
347
373
|
register(context) {
|
|
348
374
|
context.registerNode(DefinedNodeRuntime);
|
package/src/authoring/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { EngineExecutionLimitsPolicyFactory } from "../../policies/executionLimi
|
|
|
4
4
|
import {
|
|
5
5
|
DefaultAsyncSleeper,
|
|
6
6
|
InProcessRetryRunnerFactory,
|
|
7
|
-
|
|
7
|
+
ItemExprResolver,
|
|
8
8
|
NodeExecutor,
|
|
9
9
|
NodeExecutorFactory,
|
|
10
10
|
NodeInstanceFactoryFactory,
|
|
@@ -41,8 +41,8 @@ export class EngineRuntimeRegistrar {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
private registerSupportFactories(container: DependencyContainer): void {
|
|
44
|
-
if (!container.isRegistered(
|
|
45
|
-
container.registerSingleton(
|
|
44
|
+
if (!container.isRegistered(ItemExprResolver, true)) {
|
|
45
|
+
container.registerSingleton(ItemExprResolver, ItemExprResolver);
|
|
46
46
|
}
|
|
47
47
|
if (!container.isRegistered(NodeOutputNormalizer, true)) {
|
|
48
48
|
container.registerSingleton(NodeOutputNormalizer, NodeOutputNormalizer);
|
package/src/contracts/index.ts
CHANGED
|
@@ -2,7 +2,8 @@ export * from "./credentialTypes";
|
|
|
2
2
|
export * from "./emitPorts";
|
|
3
3
|
export * from "./executionPersistenceContracts";
|
|
4
4
|
export * from "./itemMeta";
|
|
5
|
-
export * from "./
|
|
5
|
+
export * from "./params";
|
|
6
|
+
export * from "./itemExpr";
|
|
6
7
|
export * from "./runtimeTypes";
|
|
7
8
|
export * from "./runFinishedAtFactory";
|
|
8
9
|
export * from "./runTypes";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { NodeExecutionContext } from "./runtimeTypes";
|
|
2
2
|
import type { Item, Items, NodeActivationId, NodeId, RunDataSnapshot, RunId, WorkflowId } from "./workflowTypes";
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const ITEM_EXPR_BRAND = Symbol.for("codemation.itemExpr");
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type ItemExprResolvedContext = Readonly<{
|
|
7
7
|
runId: RunId;
|
|
8
8
|
workflowId: WorkflowId;
|
|
9
9
|
nodeId: NodeId;
|
|
@@ -14,52 +14,51 @@ export type ItemValueResolvedContext = Readonly<{
|
|
|
14
14
|
/**
|
|
15
15
|
* Context aligned with former {@link ItemInputMapperContext} — use **`data`** to read any completed upstream node.
|
|
16
16
|
*/
|
|
17
|
-
export type
|
|
17
|
+
export type ItemExprContext = ItemExprResolvedContext;
|
|
18
18
|
|
|
19
|
-
export type
|
|
19
|
+
export type ItemExprArgs<TItemJson = unknown> = Readonly<{
|
|
20
20
|
item: Item<TItemJson>;
|
|
21
21
|
itemIndex: number;
|
|
22
22
|
items: Items<TItemJson>;
|
|
23
|
-
ctx:
|
|
23
|
+
ctx: ItemExprContext;
|
|
24
24
|
}>;
|
|
25
25
|
|
|
26
|
-
export type
|
|
26
|
+
export type ItemExprCallback<T, TItemJson = unknown> = (args: ItemExprArgs<TItemJson>) => T | Promise<T>;
|
|
27
27
|
|
|
28
|
-
export type
|
|
29
|
-
readonly [
|
|
30
|
-
readonly fn:
|
|
28
|
+
export type ItemExpr<T, TItemJson = unknown> = Readonly<{
|
|
29
|
+
readonly [ITEM_EXPR_BRAND]: true;
|
|
30
|
+
readonly fn: ItemExprCallback<T, TItemJson>;
|
|
31
31
|
}>;
|
|
32
32
|
|
|
33
|
-
export function
|
|
34
|
-
return { [
|
|
33
|
+
export function itemExpr<T, TItemJson = unknown>(fn: ItemExprCallback<T, TItemJson>): ItemExpr<T, TItemJson> {
|
|
34
|
+
return { [ITEM_EXPR_BRAND]: true, fn };
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export function
|
|
37
|
+
export function isItemExpr<T, TItemJson = unknown>(value: unknown): value is ItemExpr<T, TItemJson> {
|
|
38
38
|
if (typeof value !== "object" || value === null) {
|
|
39
39
|
return false;
|
|
40
40
|
}
|
|
41
41
|
const v = value as Record<PropertyKey, unknown>;
|
|
42
|
-
if (v[
|
|
42
|
+
if (v[ITEM_EXPR_BRAND] === true) {
|
|
43
43
|
return true;
|
|
44
44
|
}
|
|
45
|
-
// Support snapshot-hydrated
|
|
45
|
+
// Support snapshot-hydrated itemExpr wrappers where the symbol brand was lost but the callback survived.
|
|
46
46
|
// Workflow snapshot hydration currently restores function-valued fields (like `fn`) but may drop symbol-keyed brands.
|
|
47
|
-
// We treat the minimal `{ fn: Function }` shape as an
|
|
47
|
+
// We treat the minimal `{ fn: Function }` shape as an itemExpr wrapper to keep runnable configs working.
|
|
48
48
|
const keys = Object.keys(v);
|
|
49
49
|
if (keys.length === 1 && keys[0] === "fn" && typeof (v as { fn?: unknown }).fn === "function") {
|
|
50
50
|
return true;
|
|
51
51
|
}
|
|
52
|
-
// Support legacy module-local Symbol("codemation.itemValue") brands (e.g. duplicate module graphs).
|
|
53
52
|
for (const sym of Object.getOwnPropertySymbols(v)) {
|
|
54
|
-
if (sym.description === "codemation.
|
|
53
|
+
if (sym.description === "codemation.itemExpr" && v[sym] === true) {
|
|
55
54
|
return true;
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
return false;
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
function
|
|
62
|
-
if (
|
|
60
|
+
function containsItemExprInUnknown(value: unknown, seen: WeakSet<object> = new WeakSet()): boolean {
|
|
61
|
+
if (isItemExpr(value)) {
|
|
63
62
|
return true;
|
|
64
63
|
}
|
|
65
64
|
if (value === null || typeof value !== "object") {
|
|
@@ -70,10 +69,10 @@ function containsItemValueInUnknown(value: unknown, seen: WeakSet<object> = new
|
|
|
70
69
|
}
|
|
71
70
|
seen.add(value as object);
|
|
72
71
|
if (Array.isArray(value)) {
|
|
73
|
-
return value.some((entry) =>
|
|
72
|
+
return value.some((entry) => containsItemExprInUnknown(entry, seen));
|
|
74
73
|
}
|
|
75
74
|
for (const entry of Object.values(value as Record<string, unknown>)) {
|
|
76
|
-
if (
|
|
75
|
+
if (containsItemExprInUnknown(entry, seen)) {
|
|
77
76
|
return true;
|
|
78
77
|
}
|
|
79
78
|
}
|
|
@@ -81,14 +80,14 @@ function containsItemValueInUnknown(value: unknown, seen: WeakSet<object> = new
|
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
/**
|
|
84
|
-
* Deep-resolves {@link
|
|
83
|
+
* Deep-resolves {@link itemExpr} leaves. Returns a new graph (does not mutate the original config object).
|
|
85
84
|
*/
|
|
86
|
-
export async function
|
|
85
|
+
export async function resolveItemExprsInUnknown(
|
|
87
86
|
value: unknown,
|
|
88
|
-
args:
|
|
87
|
+
args: ItemExprArgs,
|
|
89
88
|
seen: WeakSet<object> = new WeakSet(),
|
|
90
89
|
): Promise<unknown> {
|
|
91
|
-
if (
|
|
90
|
+
if (isItemExpr(value)) {
|
|
92
91
|
return await Promise.resolve(value.fn(args));
|
|
93
92
|
}
|
|
94
93
|
if (value === null || typeof value !== "object") {
|
|
@@ -101,7 +100,7 @@ export async function resolveItemValuesInUnknown(
|
|
|
101
100
|
if (Array.isArray(value)) {
|
|
102
101
|
const out: unknown[] = [];
|
|
103
102
|
for (let i = 0; i < value.length; i++) {
|
|
104
|
-
out.push(await
|
|
103
|
+
out.push(await resolveItemExprsInUnknown(value[i], args, seen));
|
|
105
104
|
}
|
|
106
105
|
return out;
|
|
107
106
|
}
|
|
@@ -113,22 +112,22 @@ export async function resolveItemValuesInUnknown(
|
|
|
113
112
|
}
|
|
114
113
|
const out = Object.create(proto) as Record<string, unknown>;
|
|
115
114
|
for (const [k, v] of entries) {
|
|
116
|
-
out[k] = await
|
|
115
|
+
out[k] = await resolveItemExprsInUnknown(v, args, seen);
|
|
117
116
|
}
|
|
118
117
|
return out;
|
|
119
118
|
}
|
|
120
119
|
|
|
121
120
|
/**
|
|
122
|
-
* Clones runnable config (best-effort) so per-item {@link
|
|
121
|
+
* Clones runnable config (best-effort) so per-item {@link itemExpr} resolution never mutates shared instances.
|
|
123
122
|
*/
|
|
124
|
-
export async function
|
|
123
|
+
export async function resolveItemExprsForExecution(
|
|
125
124
|
config: unknown,
|
|
126
125
|
nodeCtx: NodeExecutionContext,
|
|
127
126
|
item: Item,
|
|
128
127
|
itemIndex: number,
|
|
129
128
|
items: Items,
|
|
130
129
|
): Promise<unknown | undefined> {
|
|
131
|
-
const
|
|
130
|
+
const exprArgs: ItemExprArgs = {
|
|
132
131
|
item,
|
|
133
132
|
itemIndex,
|
|
134
133
|
items,
|
|
@@ -140,8 +139,8 @@ export async function resolveItemValuesForExecution(
|
|
|
140
139
|
data: nodeCtx.data,
|
|
141
140
|
},
|
|
142
141
|
};
|
|
143
|
-
if (!
|
|
142
|
+
if (!containsItemExprInUnknown(config)) {
|
|
144
143
|
return undefined;
|
|
145
144
|
}
|
|
146
|
-
return await
|
|
145
|
+
return await resolveItemExprsInUnknown(config, exprArgs);
|
|
147
146
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ItemExpr } from "./itemExpr";
|
|
2
|
+
|
|
3
|
+
export type Expr<T, TItemJson = unknown> = ItemExpr<T, TItemJson>;
|
|
4
|
+
|
|
5
|
+
export type Param<T, TItemJson = unknown> = T | Expr<T, TItemJson>;
|
|
6
|
+
|
|
7
|
+
export type ParamDeep<T, TItemJson = unknown> =
|
|
8
|
+
| Expr<T, TItemJson>
|
|
9
|
+
| (T extends readonly (infer U)[] ? ReadonlyArray<ParamDeep<U, TItemJson>> : never)
|
|
10
|
+
| (T extends object ? { [K in keyof T]: ParamDeep<T[K], TItemJson> } : T);
|
|
@@ -6,6 +6,7 @@ import type { RetryPolicySpec } from "./retryPolicySpec.types";
|
|
|
6
6
|
|
|
7
7
|
export type WorkflowId = string;
|
|
8
8
|
export type NodeId = string;
|
|
9
|
+
export type NodeIdRef<TJson = unknown> = NodeId & Readonly<{ __codemationNodeJson?: TJson }>;
|
|
9
10
|
export type OutputPortKey = string;
|
|
10
11
|
export type InputPortKey = string;
|
|
11
12
|
export type PersistedTokenId = string;
|
|
@@ -154,6 +155,10 @@ export interface NodeRef {
|
|
|
154
155
|
name?: string;
|
|
155
156
|
}
|
|
156
157
|
|
|
158
|
+
export function nodeRef<TJson>(nodeId: NodeId): NodeIdRef<TJson> {
|
|
159
|
+
return nodeId as NodeIdRef<TJson>;
|
|
160
|
+
}
|
|
161
|
+
|
|
157
162
|
export type PairedItemRef = Readonly<{ nodeId: NodeId; output: OutputPortKey; itemIndex: number }>;
|
|
158
163
|
|
|
159
164
|
export type BinaryPreviewKind = "image" | "audio" | "video" | "download";
|
|
@@ -204,8 +209,12 @@ export interface ParentExecutionRef {
|
|
|
204
209
|
|
|
205
210
|
export interface RunDataSnapshot {
|
|
206
211
|
getOutputs(nodeId: NodeId): NodeOutputs | undefined;
|
|
207
|
-
getOutputItems(nodeId: NodeId
|
|
208
|
-
getOutputItem
|
|
212
|
+
getOutputItems<TJson = unknown>(nodeId: NodeId | NodeIdRef<TJson>, output?: OutputPortKey): Items<TJson>;
|
|
213
|
+
getOutputItem<TJson = unknown>(
|
|
214
|
+
nodeId: NodeId | NodeIdRef<TJson>,
|
|
215
|
+
itemIndex: number,
|
|
216
|
+
output?: OutputPortKey,
|
|
217
|
+
): Item<TJson> | undefined;
|
|
209
218
|
}
|
|
210
219
|
|
|
211
220
|
export interface MutableRunData extends RunDataSnapshot {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveItemExprsForExecution } from "../contracts/itemExpr";
|
|
2
2
|
import type { Item, NodeExecutionContext, RunnableNodeConfig } from "../types";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Resolves {@link import("../contracts/
|
|
5
|
+
* Resolves {@link import("../contracts/itemExpr").ItemExpr} leaves on runnable config before {@link RunnableNode.execute}.
|
|
6
6
|
*/
|
|
7
|
-
export class
|
|
7
|
+
export class ItemExprResolver {
|
|
8
8
|
async resolveConfigForItem<TConfig extends RunnableNodeConfig<any, any>>(
|
|
9
9
|
ctx: NodeExecutionContext<TConfig>,
|
|
10
10
|
item: Item,
|
|
@@ -12,9 +12,9 @@ export class ItemValueResolver {
|
|
|
12
12
|
items: ReadonlyArray<Item>,
|
|
13
13
|
): Promise<NodeExecutionContext<TConfig>> {
|
|
14
14
|
if (!ctx) {
|
|
15
|
-
throw new Error("
|
|
15
|
+
throw new Error("ItemExprResolver.resolveConfigForItem: ctx is required");
|
|
16
16
|
}
|
|
17
|
-
const resolvedConfig = await
|
|
17
|
+
const resolvedConfig = await resolveItemExprsForExecution(ctx.config, ctx, item, itemIndex, items);
|
|
18
18
|
const merged = resolvedConfig !== undefined && resolvedConfig !== null ? resolvedConfig : ctx.config;
|
|
19
19
|
if (merged === undefined || merged === null) {
|
|
20
20
|
return ctx;
|
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
} from "../types";
|
|
16
16
|
|
|
17
17
|
import { FanInMergeByOriginMerger } from "./FanInMergeByOriginMerger";
|
|
18
|
-
import {
|
|
18
|
+
import { ItemExprResolver } from "./ItemExprResolver";
|
|
19
19
|
import { InProcessRetryRunner } from "./InProcessRetryRunner";
|
|
20
20
|
import { NodeOutputNormalizer } from "./NodeOutputNormalizer";
|
|
21
21
|
import { RunnableOutputBehaviorResolver } from "./RunnableOutputBehaviorResolver";
|
|
@@ -23,16 +23,16 @@ import { RunnableOutputBehaviorResolver } from "./RunnableOutputBehaviorResolver
|
|
|
23
23
|
export class NodeExecutor {
|
|
24
24
|
private readonly fanInMerger = new FanInMergeByOriginMerger();
|
|
25
25
|
private readonly outputNormalizer = new NodeOutputNormalizer();
|
|
26
|
-
private readonly
|
|
26
|
+
private readonly itemExprResolver: ItemExprResolver;
|
|
27
27
|
private readonly outputBehaviorResolver: RunnableOutputBehaviorResolver;
|
|
28
28
|
|
|
29
29
|
constructor(
|
|
30
30
|
private readonly nodeInstanceFactory: WorkflowNodeInstanceFactory,
|
|
31
31
|
private readonly retryRunner: InProcessRetryRunner,
|
|
32
|
-
|
|
32
|
+
itemExprResolver?: ItemExprResolver,
|
|
33
33
|
outputBehaviorResolver?: RunnableOutputBehaviorResolver,
|
|
34
34
|
) {
|
|
35
|
-
this.
|
|
35
|
+
this.itemExprResolver = itemExprResolver ?? new ItemExprResolver();
|
|
36
36
|
this.outputBehaviorResolver = outputBehaviorResolver ?? new RunnableOutputBehaviorResolver();
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -135,7 +135,7 @@ export class NodeExecutor {
|
|
|
135
135
|
const syntheticItem: Item = { json: {} };
|
|
136
136
|
const parsed = inputSchema.parse(syntheticItem.json);
|
|
137
137
|
const runnableCtx = request.ctx as NodeExecutionContext<RunnableNodeConfig>;
|
|
138
|
-
const resolvedCtx = await this.
|
|
138
|
+
const resolvedCtx = await this.itemExprResolver.resolveConfigForItem(runnableCtx, syntheticItem, 0, inputBatch);
|
|
139
139
|
const ctx = this.pickExecutionContext(runnableCtx, resolvedCtx);
|
|
140
140
|
const args: RunnableNodeExecuteArgs = {
|
|
141
141
|
input: parsed,
|
|
@@ -157,7 +157,7 @@ export class NodeExecutor {
|
|
|
157
157
|
this.assertItemJsonNotTopLevelArray(request.nodeId, item);
|
|
158
158
|
const parsed = inputSchema.parse(item.json);
|
|
159
159
|
const runnableCtx = request.ctx as NodeExecutionContext<RunnableNodeConfig>;
|
|
160
|
-
const resolvedCtx = await this.
|
|
160
|
+
const resolvedCtx = await this.itemExprResolver.resolveConfigForItem(runnableCtx, item, i, inputBatch);
|
|
161
161
|
const ctx = this.pickExecutionContext(runnableCtx, resolvedCtx);
|
|
162
162
|
const args: RunnableNodeExecuteArgs = {
|
|
163
163
|
input: parsed,
|
package/src/execution/index.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { CredentialResolverFactory } from "./CredentialResolverFactory";
|
|
|
5
5
|
export { DefaultAsyncSleeper } from "./DefaultAsyncSleeper";
|
|
6
6
|
export { DefaultExecutionContextFactory } from "./DefaultExecutionContextFactory";
|
|
7
7
|
export { InProcessRetryRunner } from "./InProcessRetryRunner";
|
|
8
|
-
export {
|
|
8
|
+
export { ItemExprResolver } from "./ItemExprResolver";
|
|
9
9
|
export { NodeOutputNormalizer } from "./NodeOutputNormalizer";
|
|
10
10
|
export { RunnableOutputBehaviorResolver } from "./RunnableOutputBehaviorResolver";
|
|
11
11
|
export { InProcessRetryRunnerFactory } from "./InProcessRetryRunnerFactory";
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Items, MutableRunData, NodeId, NodeOutputs, OutputPortKey } from "../types";
|
|
1
|
+
import type { Items, MutableRunData, NodeId, NodeIdRef, NodeOutputs, OutputPortKey, Item } from "../types";
|
|
2
2
|
|
|
3
3
|
export class InMemoryRunData implements MutableRunData {
|
|
4
4
|
private readonly byNode = new Map<NodeId, NodeOutputs>();
|
|
@@ -17,12 +17,16 @@ export class InMemoryRunData implements MutableRunData {
|
|
|
17
17
|
return this.byNode.get(nodeId);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
getOutputItems(nodeId: NodeId
|
|
21
|
-
return this.byNode.get(nodeId)?.[output] ?? []
|
|
20
|
+
getOutputItems<TJson = unknown>(nodeId: NodeId | NodeIdRef<TJson>, output: OutputPortKey = "main"): Items<TJson> {
|
|
21
|
+
return (this.byNode.get(nodeId)?.[output] ?? []) as Items<TJson>;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
getOutputItem
|
|
25
|
-
|
|
24
|
+
getOutputItem<TJson = unknown>(
|
|
25
|
+
nodeId: NodeId | NodeIdRef<TJson>,
|
|
26
|
+
itemIndex: number,
|
|
27
|
+
output: OutputPortKey = "main",
|
|
28
|
+
): Item<TJson> | undefined {
|
|
29
|
+
return this.getOutputItems<TJson>(nodeId, output)[itemIndex];
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
dump(): Record<NodeId, NodeOutputs> {
|
package/src/types/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from "../contracts/emitPorts";
|
|
2
2
|
export * from "../contracts/itemMeta";
|
|
3
|
-
export * from "../contracts/
|
|
3
|
+
export * from "../contracts/params";
|
|
4
|
+
export * from "../contracts/itemExpr";
|
|
4
5
|
export * from "../contracts/retryPolicySpec.types";
|
|
5
6
|
export * from "../contracts/NoRetryPolicy";
|
|
6
7
|
export * from "../contracts/RetryPolicy";
|
|
@@ -134,7 +134,7 @@ export class WorkflowSnapshotCodec {
|
|
|
134
134
|
hydrated[key] = value;
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
|
-
// Preserve symbol-keyed brands (e.g.
|
|
137
|
+
// Preserve symbol-keyed brands (e.g. itemExpr / emitPorts) and other runtime-only keys.
|
|
138
138
|
for (const sym of Object.getOwnPropertySymbols(liveRecord)) {
|
|
139
139
|
hydrated[sym] = liveRecord[sym];
|
|
140
140
|
}
|