@codemation/core 0.0.16 → 0.0.19
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 +15 -0
- package/LICENSE +37 -0
- package/dist/{RunIntentService-CYnn140t.js → RunIntentService-C1nu_YwM.js} +170 -118
- package/dist/RunIntentService-C1nu_YwM.js.map +1 -0
- package/dist/{RunIntentService-ByuUYsAL.d.cts → RunIntentService-DjbxzBBP.d.cts} +10 -1
- package/dist/{RunIntentService-DlQH5eZ2.cjs → RunIntentService-ZkjpY7MS.cjs} +170 -118
- package/dist/RunIntentService-ZkjpY7MS.cjs.map +1 -0
- package/dist/bootstrap/index.cjs +1 -1
- package/dist/bootstrap/index.d.cts +1 -1
- package/dist/bootstrap/index.d.ts +1 -1
- package/dist/bootstrap/index.js +1 -1
- package/dist/{index-k0hwnJyT.d.ts → index-BIewO9-9.d.ts} +89 -10
- package/dist/index.cjs +181 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +82 -12
- package/dist/index.d.ts +2 -2
- package/dist/index.js +180 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/authoring/DefinedNodeRegistry.ts +16 -0
- package/src/authoring/defineCredential.types.ts +172 -0
- package/src/authoring/defineNode.types.ts +227 -0
- package/src/authoring/index.ts +12 -0
- package/src/index.ts +1 -0
- package/src/planning/CurrentStateFrontierPlanner.ts +24 -1
- package/src/runtime/RunIntentService.ts +68 -14
- package/dist/RunIntentService-CYnn140t.js.map +0 -1
- package/dist/RunIntentService-DlQH5eZ2.cjs.map +0 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnyCredentialType,
|
|
3
|
+
CredentialFieldSchema,
|
|
4
|
+
CredentialHealth,
|
|
5
|
+
CredentialJsonRecord,
|
|
6
|
+
CredentialSessionFactoryArgs,
|
|
7
|
+
CredentialType,
|
|
8
|
+
CredentialTypeDefinition,
|
|
9
|
+
} from "../contracts/credentialTypes";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
12
|
+
type MaybePromise<TValue> = TValue | Promise<TValue>;
|
|
13
|
+
|
|
14
|
+
type CredentialFieldInput = CredentialFieldSchema["type"] | Readonly<Omit<CredentialFieldSchema, "key">>;
|
|
15
|
+
|
|
16
|
+
type CredentialFieldMap<TConfig extends CredentialJsonRecord> = Readonly<
|
|
17
|
+
Record<keyof TConfig & string, CredentialFieldInput>
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
type ZodObjectSchema<TConfig extends CredentialJsonRecord = CredentialJsonRecord> = z.ZodType<TConfig>;
|
|
21
|
+
|
|
22
|
+
type InferCredentialConfig<TSource> =
|
|
23
|
+
TSource extends z.ZodType<infer TConfig, any, any>
|
|
24
|
+
? Readonly<TConfig> & CredentialJsonRecord
|
|
25
|
+
: TSource extends CredentialFieldMap<infer TConfig>
|
|
26
|
+
? TConfig
|
|
27
|
+
: CredentialJsonRecord;
|
|
28
|
+
|
|
29
|
+
export interface DefineCredentialOptions<
|
|
30
|
+
TPublicSource extends CredentialFieldMap<any> | ZodObjectSchema<any>,
|
|
31
|
+
TSecretSource extends CredentialFieldMap<any> | ZodObjectSchema<any>,
|
|
32
|
+
TSession,
|
|
33
|
+
> {
|
|
34
|
+
readonly key: string;
|
|
35
|
+
readonly label: string;
|
|
36
|
+
readonly description?: string;
|
|
37
|
+
readonly public: TPublicSource;
|
|
38
|
+
readonly secret: TSecretSource;
|
|
39
|
+
readonly supportedSourceKinds?: CredentialTypeDefinition["supportedSourceKinds"];
|
|
40
|
+
readonly auth?: CredentialTypeDefinition["auth"];
|
|
41
|
+
createSession(
|
|
42
|
+
args: CredentialSessionFactoryArgs<InferCredentialConfig<TPublicSource>, InferCredentialConfig<TSecretSource>>,
|
|
43
|
+
): MaybePromise<TSession>;
|
|
44
|
+
test(
|
|
45
|
+
args: CredentialSessionFactoryArgs<InferCredentialConfig<TPublicSource>, InferCredentialConfig<TSecretSource>>,
|
|
46
|
+
): MaybePromise<CredentialHealth>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class CredentialFieldSchemaFactory {
|
|
50
|
+
static create<TConfig extends CredentialJsonRecord>(
|
|
51
|
+
source: CredentialFieldMap<TConfig> | ZodObjectSchema<TConfig>,
|
|
52
|
+
): ReadonlyArray<CredentialFieldSchema> {
|
|
53
|
+
if (source instanceof z.ZodObject) {
|
|
54
|
+
return this.createFromZodObject(source);
|
|
55
|
+
}
|
|
56
|
+
return this.createFromMap(source as CredentialFieldMap<TConfig>);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private static createFromMap<TConfig extends CredentialJsonRecord>(
|
|
60
|
+
source: CredentialFieldMap<TConfig>,
|
|
61
|
+
): ReadonlyArray<CredentialFieldSchema> {
|
|
62
|
+
return Object.entries(source).map(([key, input], index) => {
|
|
63
|
+
if (typeof input === "string") {
|
|
64
|
+
return {
|
|
65
|
+
key,
|
|
66
|
+
label: this.humanize(key),
|
|
67
|
+
order: index,
|
|
68
|
+
type: input as CredentialFieldSchema["type"],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
key,
|
|
73
|
+
order: index,
|
|
74
|
+
...(input as Readonly<Omit<CredentialFieldSchema, "key">>),
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private static createFromZodObject<_TConfig extends CredentialJsonRecord>(
|
|
80
|
+
source: z.ZodObject,
|
|
81
|
+
): ReadonlyArray<CredentialFieldSchema> {
|
|
82
|
+
const shape = source.shape;
|
|
83
|
+
return Object.entries(shape).map(([key, schema], index) => {
|
|
84
|
+
const resolved = this.unwrap(schema);
|
|
85
|
+
return {
|
|
86
|
+
key,
|
|
87
|
+
label: this.humanize(key),
|
|
88
|
+
order: index,
|
|
89
|
+
required: this.isRequired(schema) ? true : undefined,
|
|
90
|
+
type: this.resolveType(resolved),
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private static isRequired(schema: z.ZodTypeAny): boolean {
|
|
96
|
+
return !(schema instanceof z.ZodOptional || schema instanceof z.ZodDefault);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private static unwrap(schema: z.ZodTypeAny): z.ZodTypeAny {
|
|
100
|
+
let current: z.ZodTypeAny = schema;
|
|
101
|
+
while (current instanceof z.ZodOptional || current instanceof z.ZodDefault) {
|
|
102
|
+
current = current.unwrap() as z.ZodTypeAny;
|
|
103
|
+
}
|
|
104
|
+
return current;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private static resolveType(schema: z.ZodTypeAny): CredentialFieldSchema["type"] {
|
|
108
|
+
if (schema instanceof z.ZodBoolean) {
|
|
109
|
+
return "boolean";
|
|
110
|
+
}
|
|
111
|
+
if (schema instanceof z.ZodString) {
|
|
112
|
+
return "string";
|
|
113
|
+
}
|
|
114
|
+
return "json";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private static humanize(key: string): string {
|
|
118
|
+
return key
|
|
119
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
120
|
+
.replace(/[-_.]+/g, " ")
|
|
121
|
+
.replace(/\s+/g, " ")
|
|
122
|
+
.trim()
|
|
123
|
+
.replace(/^./, (character) => character.toUpperCase());
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function defineCredential<
|
|
128
|
+
TPublicSource extends CredentialFieldMap<any> | ZodObjectSchema<any>,
|
|
129
|
+
TSecretSource extends CredentialFieldMap<any> | ZodObjectSchema<any>,
|
|
130
|
+
TSession,
|
|
131
|
+
>(
|
|
132
|
+
options: DefineCredentialOptions<TPublicSource, TSecretSource, TSession>,
|
|
133
|
+
): CredentialType<InferCredentialConfig<TPublicSource>, InferCredentialConfig<TSecretSource>, TSession> & {
|
|
134
|
+
readonly key: string;
|
|
135
|
+
} {
|
|
136
|
+
const definition: CredentialTypeDefinition = {
|
|
137
|
+
typeId: options.key,
|
|
138
|
+
displayName: options.label,
|
|
139
|
+
description: options.description,
|
|
140
|
+
publicFields: CredentialFieldSchemaFactory.create(options.public),
|
|
141
|
+
secretFields: CredentialFieldSchemaFactory.create(options.secret),
|
|
142
|
+
supportedSourceKinds: options.supportedSourceKinds ?? ["db", "env", "code"],
|
|
143
|
+
auth: options.auth,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const credentialType: AnyCredentialType = {
|
|
147
|
+
definition,
|
|
148
|
+
async createSession(args) {
|
|
149
|
+
return await options.createSession(
|
|
150
|
+
args as CredentialSessionFactoryArgs<
|
|
151
|
+
InferCredentialConfig<TPublicSource>,
|
|
152
|
+
InferCredentialConfig<TSecretSource>
|
|
153
|
+
>,
|
|
154
|
+
);
|
|
155
|
+
},
|
|
156
|
+
async test(args) {
|
|
157
|
+
return await options.test(
|
|
158
|
+
args as CredentialSessionFactoryArgs<
|
|
159
|
+
InferCredentialConfig<TPublicSource>,
|
|
160
|
+
InferCredentialConfig<TSecretSource>
|
|
161
|
+
>,
|
|
162
|
+
);
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
...credentialType,
|
|
168
|
+
key: options.key,
|
|
169
|
+
} as CredentialType<InferCredentialConfig<TPublicSource>, InferCredentialConfig<TSecretSource>, TSession> & {
|
|
170
|
+
readonly key: string;
|
|
171
|
+
};
|
|
172
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnyCredentialType,
|
|
3
|
+
CredentialJsonRecord,
|
|
4
|
+
CredentialRequirement,
|
|
5
|
+
CredentialTypeId,
|
|
6
|
+
} from "../contracts/credentialTypes";
|
|
7
|
+
import type { Node, NodeExecutionContext } from "../contracts/runtimeTypes";
|
|
8
|
+
import type { Items, NodeOutputs, RunnableNodeConfig } from "../contracts/workflowTypes";
|
|
9
|
+
import type { TypeToken } from "../di";
|
|
10
|
+
import { node as persistedNode } from "../runtime-types/runtimeTypeDecorators.types";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { DefinedNodeRegistry } from "./DefinedNodeRegistry";
|
|
13
|
+
|
|
14
|
+
type MaybePromise<TValue> = TValue | Promise<TValue>;
|
|
15
|
+
|
|
16
|
+
type ResolvableCredentialType = AnyCredentialType | CredentialTypeId;
|
|
17
|
+
|
|
18
|
+
type SessionForCredentialType<TCredential extends ResolvableCredentialType> = TCredential extends AnyCredentialType
|
|
19
|
+
? Awaited<ReturnType<TCredential["createSession"]>>
|
|
20
|
+
: unknown;
|
|
21
|
+
|
|
22
|
+
export type DefinedNodeCredentialBinding =
|
|
23
|
+
| ResolvableCredentialType
|
|
24
|
+
| Readonly<{
|
|
25
|
+
readonly type: ResolvableCredentialType | ReadonlyArray<ResolvableCredentialType>;
|
|
26
|
+
readonly label?: string;
|
|
27
|
+
readonly optional?: true;
|
|
28
|
+
readonly helpText?: string;
|
|
29
|
+
readonly helpUrl?: string;
|
|
30
|
+
}>;
|
|
31
|
+
|
|
32
|
+
export type DefinedNodeCredentialBindings = Readonly<Record<string, DefinedNodeCredentialBinding>>;
|
|
33
|
+
|
|
34
|
+
type SessionForBinding<TBinding extends DefinedNodeCredentialBinding> =
|
|
35
|
+
TBinding extends Readonly<{ type: infer TType }>
|
|
36
|
+
? TType extends ReadonlyArray<infer TEntry>
|
|
37
|
+
? SessionForCredentialType<TEntry & ResolvableCredentialType>
|
|
38
|
+
: SessionForCredentialType<TType & ResolvableCredentialType>
|
|
39
|
+
: SessionForCredentialType<TBinding & ResolvableCredentialType>;
|
|
40
|
+
|
|
41
|
+
export type DefinedNodeCredentialAccessors<TBindings extends DefinedNodeCredentialBindings | undefined> =
|
|
42
|
+
TBindings extends DefinedNodeCredentialBindings
|
|
43
|
+
? Readonly<{
|
|
44
|
+
[TKey in keyof TBindings]: () => Promise<SessionForBinding<TBindings[TKey]>>;
|
|
45
|
+
}>
|
|
46
|
+
: Readonly<Record<string, never>>;
|
|
47
|
+
|
|
48
|
+
export interface DefinedNodeRunContext<
|
|
49
|
+
TConfig extends CredentialJsonRecord,
|
|
50
|
+
TBindings extends DefinedNodeCredentialBindings | undefined,
|
|
51
|
+
> {
|
|
52
|
+
readonly config: TConfig;
|
|
53
|
+
readonly credentials: DefinedNodeCredentialAccessors<TBindings>;
|
|
54
|
+
readonly execution: NodeExecutionContext<RunnableNodeConfig<TConfig, unknown>>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface DefinedNode<
|
|
58
|
+
TKey extends string,
|
|
59
|
+
TConfig extends CredentialJsonRecord,
|
|
60
|
+
TInputJson,
|
|
61
|
+
TOutputJson,
|
|
62
|
+
_TBindings extends DefinedNodeCredentialBindings | undefined = undefined,
|
|
63
|
+
> {
|
|
64
|
+
readonly kind: "defined-node";
|
|
65
|
+
readonly key: TKey;
|
|
66
|
+
readonly title: string;
|
|
67
|
+
readonly description?: string;
|
|
68
|
+
create(config: TConfig, name?: string, id?: string): RunnableNodeConfig<TInputJson, TOutputJson>;
|
|
69
|
+
register(context: { registerNode<TValue>(token: TypeToken<TValue>, implementation?: TypeToken<TValue>): void }): void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface DefineNodeOptions<
|
|
73
|
+
TKey extends string,
|
|
74
|
+
TConfig extends CredentialJsonRecord,
|
|
75
|
+
TInputJson,
|
|
76
|
+
TOutputJson,
|
|
77
|
+
TBindings extends DefinedNodeCredentialBindings | undefined = undefined,
|
|
78
|
+
> {
|
|
79
|
+
readonly key: TKey;
|
|
80
|
+
readonly title: string;
|
|
81
|
+
readonly description?: string;
|
|
82
|
+
readonly input?: Readonly<Record<keyof TConfig & string, unknown>>;
|
|
83
|
+
readonly configSchema?: z.ZodType<TConfig>;
|
|
84
|
+
readonly credentials?: TBindings;
|
|
85
|
+
run(
|
|
86
|
+
items: ReadonlyArray<TInputJson>,
|
|
87
|
+
context: DefinedNodeRunContext<TConfig, TBindings>,
|
|
88
|
+
): MaybePromise<ReadonlyArray<TOutputJson>>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const definedNodeCredentialRequirementFactory = {
|
|
92
|
+
create(bindings: DefinedNodeCredentialBindings | undefined): ReadonlyArray<CredentialRequirement> {
|
|
93
|
+
if (!bindings) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
return Object.entries(bindings).map(([slotKey, binding]) => {
|
|
97
|
+
if (typeof binding === "string" || this.isCredentialType(binding)) {
|
|
98
|
+
return {
|
|
99
|
+
slotKey,
|
|
100
|
+
label: this.humanize(slotKey),
|
|
101
|
+
acceptedTypes: [this.resolveTypeId(binding)],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const types = Array.isArray(binding.type) ? binding.type : [binding.type];
|
|
106
|
+
return {
|
|
107
|
+
slotKey,
|
|
108
|
+
label: binding.label ?? this.humanize(slotKey),
|
|
109
|
+
acceptedTypes: types.map((entry) => this.resolveTypeId(entry)),
|
|
110
|
+
optional: binding.optional,
|
|
111
|
+
helpText: binding.helpText,
|
|
112
|
+
helpUrl: binding.helpUrl,
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
isCredentialType(value: unknown): value is AnyCredentialType {
|
|
118
|
+
return (
|
|
119
|
+
Boolean(value) &&
|
|
120
|
+
typeof value === "object" &&
|
|
121
|
+
"definition" in (value as Record<string, unknown>) &&
|
|
122
|
+
typeof (value as AnyCredentialType).definition?.typeId === "string"
|
|
123
|
+
);
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
resolveTypeId(type: ResolvableCredentialType): string {
|
|
127
|
+
return typeof type === "string" ? type : type.definition.typeId;
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
humanize(key: string): string {
|
|
131
|
+
return key
|
|
132
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
133
|
+
.replace(/[-_.]+/g, " ")
|
|
134
|
+
.replace(/\s+/g, " ")
|
|
135
|
+
.trim()
|
|
136
|
+
.replace(/^./, (character) => character.toUpperCase());
|
|
137
|
+
},
|
|
138
|
+
} as const;
|
|
139
|
+
|
|
140
|
+
const definedNodeCredentialAccessorFactory = {
|
|
141
|
+
create<TBindings extends DefinedNodeCredentialBindings | undefined>(
|
|
142
|
+
bindings: TBindings,
|
|
143
|
+
ctx: NodeExecutionContext<RunnableNodeConfig<any, any>>,
|
|
144
|
+
): DefinedNodeCredentialAccessors<TBindings> {
|
|
145
|
+
if (!bindings) {
|
|
146
|
+
return {} as DefinedNodeCredentialAccessors<TBindings>;
|
|
147
|
+
}
|
|
148
|
+
const entries = Object.keys(bindings).map((slotKey) => [slotKey, () => ctx.getCredential(slotKey)] as const);
|
|
149
|
+
return Object.fromEntries(entries) as DefinedNodeCredentialAccessors<TBindings>;
|
|
150
|
+
},
|
|
151
|
+
} as const;
|
|
152
|
+
|
|
153
|
+
export function defineNode<
|
|
154
|
+
TKey extends string,
|
|
155
|
+
TConfig extends CredentialJsonRecord,
|
|
156
|
+
TInputJson,
|
|
157
|
+
TOutputJson,
|
|
158
|
+
TBindings extends DefinedNodeCredentialBindings | undefined = undefined,
|
|
159
|
+
>(
|
|
160
|
+
options: DefineNodeOptions<TKey, TConfig, TInputJson, TOutputJson, TBindings>,
|
|
161
|
+
): DefinedNode<TKey, TConfig, TInputJson, TOutputJson, TBindings> {
|
|
162
|
+
const credentialRequirements = definedNodeCredentialRequirementFactory.create(options.credentials);
|
|
163
|
+
type DefinedRunnableNodeConfigShape = RunnableNodeConfig<TInputJson, TOutputJson> & Readonly<{ config: TConfig }>;
|
|
164
|
+
|
|
165
|
+
const DefinedNodeRuntime = class implements Node<DefinedRunnableNodeConfigShape> {
|
|
166
|
+
readonly kind = "node" as const;
|
|
167
|
+
readonly outputPorts = ["main"] as const;
|
|
168
|
+
|
|
169
|
+
async execute(items: Items, ctx: NodeExecutionContext<DefinedRunnableNodeConfigShape>): Promise<NodeOutputs> {
|
|
170
|
+
const outputs = await options.run(
|
|
171
|
+
items.map((item) => item.json as TInputJson),
|
|
172
|
+
{
|
|
173
|
+
config: ctx.config.config,
|
|
174
|
+
credentials: definedNodeCredentialAccessorFactory.create(
|
|
175
|
+
options.credentials,
|
|
176
|
+
ctx,
|
|
177
|
+
) as DefinedNodeCredentialAccessors<TBindings>,
|
|
178
|
+
execution: ctx as unknown as NodeExecutionContext<RunnableNodeConfig<TConfig, unknown>>,
|
|
179
|
+
},
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
main: outputs.map((json, index) => {
|
|
184
|
+
const existing = items[index];
|
|
185
|
+
if (!existing) {
|
|
186
|
+
return { json };
|
|
187
|
+
}
|
|
188
|
+
return { ...existing, json };
|
|
189
|
+
}),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
persistedNode({ name: options.key })(DefinedNodeRuntime);
|
|
195
|
+
|
|
196
|
+
const DefinedRunnableNodeConfig = class implements RunnableNodeConfig<TInputJson, TOutputJson> {
|
|
197
|
+
readonly kind = "node" as const;
|
|
198
|
+
readonly type: TypeToken<unknown> = DefinedNodeRuntime;
|
|
199
|
+
|
|
200
|
+
constructor(
|
|
201
|
+
public readonly name: string,
|
|
202
|
+
public readonly config: TConfig,
|
|
203
|
+
public readonly id?: string,
|
|
204
|
+
) {}
|
|
205
|
+
|
|
206
|
+
getCredentialRequirements(): ReadonlyArray<CredentialRequirement> {
|
|
207
|
+
return credentialRequirements;
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const definition: DefinedNode<TKey, TConfig, TInputJson, TOutputJson, TBindings> = {
|
|
212
|
+
kind: "defined-node",
|
|
213
|
+
key: options.key,
|
|
214
|
+
title: options.title,
|
|
215
|
+
description: options.description,
|
|
216
|
+
create(config, name = options.title, id) {
|
|
217
|
+
return new DefinedRunnableNodeConfig(name, config, id);
|
|
218
|
+
},
|
|
219
|
+
register(context) {
|
|
220
|
+
context.registerNode(DefinedNodeRuntime);
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
DefinedNodeRegistry.register(definition as DefinedNode<string, Record<string, unknown>, unknown, unknown>);
|
|
225
|
+
|
|
226
|
+
return definition;
|
|
227
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { DefinedNodeRegistry } from "./DefinedNodeRegistry";
|
|
2
|
+
export type {
|
|
3
|
+
DefinedNode,
|
|
4
|
+
DefinedNodeCredentialAccessors,
|
|
5
|
+
DefinedNodeCredentialBinding,
|
|
6
|
+
DefinedNodeCredentialBindings,
|
|
7
|
+
DefinedNodeRunContext,
|
|
8
|
+
DefineNodeOptions,
|
|
9
|
+
} from "./defineNode.types";
|
|
10
|
+
export { defineNode } from "./defineNode.types";
|
|
11
|
+
export type { DefineCredentialOptions } from "./defineCredential.types";
|
|
12
|
+
export { defineCredential } from "./defineCredential.types";
|
package/src/index.ts
CHANGED
|
@@ -303,7 +303,17 @@ export class CurrentStateFrontierPlanner {
|
|
|
303
303
|
if (!incomingEdge) {
|
|
304
304
|
return false;
|
|
305
305
|
}
|
|
306
|
-
|
|
306
|
+
if (!this.hasOutputPort(currentState, incomingEdge.from.nodeId, incomingEdge.from.output)) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
if (this.usesCollect(nodeId)) {
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
const items = this.resolveOutputItems(currentState, incomingEdge.from.nodeId, incomingEdge.from.output);
|
|
313
|
+
if (items.length > 0) {
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
return this.shouldContinueAfterEmptyOutputFromSource(incomingEdge.from.nodeId);
|
|
307
317
|
}
|
|
308
318
|
|
|
309
319
|
private resolveInput(currentState: RunCurrentState, nodeId: NodeId, input: InputPortKey): Items {
|
|
@@ -335,6 +345,19 @@ export class CurrentStateFrontierPlanner {
|
|
|
335
345
|
return currentState.outputsByNode[nodeId]?.[output] ?? [];
|
|
336
346
|
}
|
|
337
347
|
|
|
348
|
+
private usesCollect(nodeId: NodeId): boolean {
|
|
349
|
+
const expectedInputs = this.topology.expectedInputsByNode.get(nodeId) ?? [];
|
|
350
|
+
return expectedInputs.length !== 1 || expectedInputs[0] !== "in";
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private shouldContinueAfterEmptyOutputFromSource(nodeId: NodeId): boolean {
|
|
354
|
+
const definition = this.topology.defsById.get(nodeId);
|
|
355
|
+
if (!definition) {
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
return definition.config.continueWhenEmptyOutput === true;
|
|
359
|
+
}
|
|
360
|
+
|
|
338
361
|
private getPinnedOutputs(currentState: RunCurrentState, nodeId: NodeId): NodeOutputs | undefined {
|
|
339
362
|
return currentState.mutableState?.nodesById?.[nodeId]?.pinnedOutputsByPort;
|
|
340
363
|
}
|
|
@@ -20,6 +20,7 @@ export type StartWorkflowIntent = {
|
|
|
20
20
|
workflow: WorkflowDefinition;
|
|
21
21
|
startAt?: string;
|
|
22
22
|
items: Items;
|
|
23
|
+
synthesizeTriggerItems?: boolean;
|
|
23
24
|
parent?: CurrentStateExecutionRequest["parent"];
|
|
24
25
|
executionOptions?: RunExecutionOptions;
|
|
25
26
|
workflowSnapshot?: CurrentStateExecutionRequest["workflowSnapshot"];
|
|
@@ -34,6 +35,7 @@ export type RerunFromNodeIntent = {
|
|
|
34
35
|
nodeId: NodeId;
|
|
35
36
|
currentState: RunCurrentState;
|
|
36
37
|
items?: Items;
|
|
38
|
+
synthesizeTriggerItems?: boolean;
|
|
37
39
|
parent?: CurrentStateExecutionRequest["parent"];
|
|
38
40
|
executionOptions?: RunExecutionOptions;
|
|
39
41
|
workflowSnapshot?: CurrentStateExecutionRequest["workflowSnapshot"];
|
|
@@ -58,22 +60,16 @@ export class RunIntentService {
|
|
|
58
60
|
) {}
|
|
59
61
|
|
|
60
62
|
async startWorkflow(args: StartWorkflowIntent): Promise<RunResult> {
|
|
63
|
+
const items = await this.resolveStartWorkflowItems(args);
|
|
61
64
|
if (args.startAt && !args.currentState && !args.stopCondition && !args.reset) {
|
|
62
|
-
return await this.engine.runWorkflow(
|
|
63
|
-
args.
|
|
64
|
-
args.
|
|
65
|
-
|
|
66
|
-
args.parent,
|
|
67
|
-
args.executionOptions,
|
|
68
|
-
{
|
|
69
|
-
workflowSnapshot: args.workflowSnapshot,
|
|
70
|
-
mutableState: args.mutableState,
|
|
71
|
-
},
|
|
72
|
-
);
|
|
65
|
+
return await this.engine.runWorkflow(args.workflow, args.startAt, items, args.parent, args.executionOptions, {
|
|
66
|
+
workflowSnapshot: args.workflowSnapshot,
|
|
67
|
+
mutableState: args.mutableState,
|
|
68
|
+
});
|
|
73
69
|
}
|
|
74
70
|
return await this.engine.runWorkflowFromState({
|
|
75
71
|
workflow: args.workflow,
|
|
76
|
-
items
|
|
72
|
+
items,
|
|
77
73
|
parent: args.parent,
|
|
78
74
|
executionOptions: args.executionOptions,
|
|
79
75
|
workflowSnapshot: args.workflowSnapshot,
|
|
@@ -85,8 +81,9 @@ export class RunIntentService {
|
|
|
85
81
|
}
|
|
86
82
|
|
|
87
83
|
async rerunFromNode(args: RerunFromNodeIntent): Promise<RunResult> {
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
const items = await this.resolveRerunItems(args);
|
|
85
|
+
if (items) {
|
|
86
|
+
return await this.engine.runWorkflow(args.workflow, args.nodeId, items, args.parent, args.executionOptions, {
|
|
90
87
|
workflowSnapshot: args.workflowSnapshot,
|
|
91
88
|
mutableState: args.mutableState,
|
|
92
89
|
});
|
|
@@ -103,6 +100,63 @@ export class RunIntentService {
|
|
|
103
100
|
});
|
|
104
101
|
}
|
|
105
102
|
|
|
103
|
+
private async resolveStartWorkflowItems(args: StartWorkflowIntent): Promise<Items> {
|
|
104
|
+
if (this.hasNonEmptyItems(args.items)) {
|
|
105
|
+
return args.items;
|
|
106
|
+
}
|
|
107
|
+
const triggerNodeId = this.resolveStartWorkflowTriggerNodeId(args);
|
|
108
|
+
if (!triggerNodeId) {
|
|
109
|
+
return args.items;
|
|
110
|
+
}
|
|
111
|
+
return (await this.engine.createTriggerTestItems({ workflow: args.workflow, nodeId: triggerNodeId })) ?? args.items;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private async resolveRerunItems(args: RerunFromNodeIntent): Promise<Items | undefined> {
|
|
115
|
+
if (this.hasNonEmptyItems(args.items)) {
|
|
116
|
+
return args.items;
|
|
117
|
+
}
|
|
118
|
+
const triggerNodeId = this.resolveRerunTriggerNodeId(args);
|
|
119
|
+
if (!triggerNodeId) {
|
|
120
|
+
return args.items;
|
|
121
|
+
}
|
|
122
|
+
return (await this.engine.createTriggerTestItems({ workflow: args.workflow, nodeId: triggerNodeId })) ?? args.items;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private resolveStartWorkflowTriggerNodeId(args: StartWorkflowIntent): NodeId | undefined {
|
|
126
|
+
if (args.stopCondition?.kind === "nodeCompleted" && this.isTriggerNode(args.workflow, args.stopCondition.nodeId)) {
|
|
127
|
+
return args.stopCondition.nodeId;
|
|
128
|
+
}
|
|
129
|
+
if (!args.synthesizeTriggerItems) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
if (args.startAt && this.isTriggerNode(args.workflow, args.startAt)) {
|
|
133
|
+
return args.startAt;
|
|
134
|
+
}
|
|
135
|
+
return this.firstTriggerNodeId(args.workflow);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private resolveRerunTriggerNodeId(args: RerunFromNodeIntent): NodeId | undefined {
|
|
139
|
+
if (this.isTriggerNode(args.workflow, args.nodeId)) {
|
|
140
|
+
return args.nodeId;
|
|
141
|
+
}
|
|
142
|
+
if (!args.synthesizeTriggerItems) {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
return this.firstTriggerNodeId(args.workflow);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private firstTriggerNodeId(workflow: WorkflowDefinition): NodeId | undefined {
|
|
149
|
+
return workflow.nodes.find((node) => node.kind === "trigger")?.id;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private isTriggerNode(workflow: WorkflowDefinition, nodeId: string): boolean {
|
|
153
|
+
return workflow.nodes.find((node) => node.id === nodeId)?.kind === "trigger";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private hasNonEmptyItems(items: Items | undefined): boolean {
|
|
157
|
+
return (items?.length ?? 0) > 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
106
160
|
resolveWebhookTrigger(args: { endpointPath: string; method: HttpMethod }): WebhookTriggerResolution {
|
|
107
161
|
return this.engine.resolveWebhookTrigger(args);
|
|
108
162
|
}
|