@codemation/core-nodes 1.0.1 → 1.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/CHANGELOG.md +130 -0
  2. package/dist/index.cjs +3002 -65
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +1521 -551
  5. package/dist/index.d.ts +1521 -551
  6. package/dist/index.js +2969 -73
  7. package/dist/index.js.map +1 -1
  8. package/package.json +5 -3
  9. package/src/authoring/defineRestNode.types.ts +204 -0
  10. package/src/credentials/ApiKeyCredentialType.ts +60 -0
  11. package/src/credentials/BasicAuthCredentialType.ts +51 -0
  12. package/src/credentials/BearerTokenCredentialType.ts +40 -0
  13. package/src/credentials/OAuth2ClientCredentialsTypeFactory.ts +117 -0
  14. package/src/credentials/OAuth2TokenExchangeFactory.ts +52 -0
  15. package/src/credentials/index.ts +4 -0
  16. package/src/http/HttpBodyBuilder.ts +90 -0
  17. package/src/http/HttpRequestExecutor.ts +150 -0
  18. package/src/http/HttpUrlBuilder.ts +22 -0
  19. package/src/http/httpRequest.types.ts +69 -0
  20. package/src/index.ts +9 -0
  21. package/src/nodes/AIAgentNode.ts +101 -3
  22. package/src/nodes/AgentToolExecutionCoordinator.ts +29 -3
  23. package/src/nodes/AssertionNode.ts +42 -0
  24. package/src/nodes/CronTriggerFactory.ts +45 -0
  25. package/src/nodes/CronTriggerNode.ts +40 -0
  26. package/src/nodes/HttpRequestNodeFactory.ts +99 -23
  27. package/src/nodes/IsTestRunNode.ts +25 -0
  28. package/src/nodes/NodeBackedToolRuntime.ts +40 -4
  29. package/src/nodes/TestTriggerNode.ts +33 -0
  30. package/src/nodes/aiAgentSupport.types.ts +18 -3
  31. package/src/nodes/assertion.ts +42 -0
  32. package/src/nodes/collections/collectionDeleteNode.types.ts +23 -0
  33. package/src/nodes/collections/collectionFindOneNode.types.ts +26 -0
  34. package/src/nodes/collections/collectionGetNode.types.ts +26 -0
  35. package/src/nodes/collections/collectionInsertNode.types.ts +22 -0
  36. package/src/nodes/collections/collectionListNode.types.ts +30 -0
  37. package/src/nodes/collections/collectionUpdateNode.types.ts +23 -0
  38. package/src/nodes/collections/index.ts +6 -0
  39. package/src/nodes/httpRequest.ts +61 -1
  40. package/src/nodes/isTestRun.ts +24 -0
  41. package/src/nodes/testTrigger.ts +72 -0
package/dist/index.d.cts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { ReadableStream } from "node:stream/web";
2
- import { DependencyContainer as Container, InjectionToken as TypeToken } from "tsyringe";
3
2
  import { ZodType, input, output, z } from "zod";
3
+ import { DependencyContainer as Container, InjectionToken as TypeToken } from "tsyringe";
4
4
  import { AssistantModelMessage, ModelMessage, ToolModelMessage } from "ai";
5
+ import { Cron, CronCallback } from "croner";
5
6
 
6
7
  //#region src/canvasIconName.d.ts
7
-
8
8
  /**
9
9
  * Canvas / agent presentation:
10
10
  * - Lucide: `lucide:<kebab-name>` or legacy kebab name
@@ -14,170 +14,223 @@ import { AssistantModelMessage, ModelMessage, ToolModelMessage } from "ai";
14
14
  */
15
15
  type CanvasIconName = string;
16
16
  //#endregion
17
- //#region ../core/src/contracts/emitPorts.d.ts
18
- declare const EMIT_PORTS_BRAND: unique symbol;
19
- type PortsEmission = Readonly<{
20
- readonly [EMIT_PORTS_BRAND]: true;
21
- readonly ports: Readonly<Partial<Record<OutputPortKey, Items | ReadonlyArray<JsonNonArray>>>>;
22
- }>;
17
+ //#region ../core/src/contracts/baseTypes.d.ts
18
+ /**
19
+ * Minimal base types that have no dependencies on other contracts.
20
+ * Used by credentialTypes, workflowTypes, and other contract layers
21
+ * to avoid circular dependencies.
22
+ */
23
+ type WorkflowId = string;
24
+ type NodeId = string;
25
+ type OutputPortKey = string;
26
+ type InputPortKey = string;
27
+ type NodeConnectionName = string;
23
28
  //#endregion
24
- //#region ../core/src/contracts/itemExpr.d.ts
25
- declare const ITEM_EXPR_BRAND: unique symbol;
26
- type ItemExprResolvedContext = Readonly<{
27
- runId: RunId;
28
- workflowId: WorkflowId;
29
- nodeId: NodeId;
30
- activationId: NodeActivationId;
31
- data: RunDataSnapshot;
29
+ //#region ../core/src/contracts/credentialTypes.d.ts
30
+ type CredentialTypeId = string;
31
+ type CredentialInstanceId = string;
32
+ type CredentialMaterialSourceKind = "db" | "env" | "code";
33
+ type CredentialSetupStatus = "draft" | "ready";
34
+ type CredentialHealthStatus = "unknown" | "healthy" | "failing";
35
+ type CredentialFieldSchema = Readonly<{
36
+ key: string;
37
+ label: string;
38
+ type: "string" | "password" | "textarea" | "json" | "boolean";
39
+ required?: true;
40
+ order?: number;
41
+ /**
42
+ * Where this field appears in the credential dialog. Use `"advanced"` for optional or
43
+ * power-user fields; they render inside a collapsible section (see `CredentialTypeDefinition.advancedSection`).
44
+ * Defaults to `"default"` when omitted.
45
+ */
46
+ visibility?: "default" | "advanced";
47
+ placeholder?: string;
48
+ helpText?: string;
49
+ /** When set, host resolves this field from process.env at runtime; env wins over stored values. */
50
+ envVarName?: string;
51
+ /**
52
+ * When set, the dialog shows a copy action for this exact string (e.g. a static OAuth redirect URI
53
+ * pattern or documentation URL). Do not use for secret values.
54
+ */
55
+ copyValue?: string;
56
+ /** Accessible label for the copy control (default: Copy). */
57
+ copyButtonLabel?: string;
58
+ }>;
59
+ type CredentialRequirement = Readonly<{
60
+ slotKey: string;
61
+ label: string;
62
+ acceptedTypes: ReadonlyArray<CredentialTypeId>;
63
+ optional?: true;
64
+ helpText?: string;
65
+ helpUrl?: string;
66
+ }>;
67
+ type CredentialHealth = Readonly<{
68
+ status: CredentialHealthStatus;
69
+ message?: string;
70
+ testedAt?: string;
71
+ expiresAt?: string;
72
+ details?: Readonly<Record<string, unknown>>;
73
+ }>;
74
+ type OAuth2ProviderFromPublicConfig = Readonly<{
75
+ authorizeUrlFieldKey: string;
76
+ tokenUrlFieldKey: string;
77
+ userInfoUrlFieldKey?: string;
78
+ }>;
79
+ type CredentialOAuth2ScopesFromPublicConfig = Readonly<{
80
+ presetFieldKey: string;
81
+ presetScopes: Readonly<Record<string, ReadonlyArray<string>>>;
82
+ customPresetKey?: string;
83
+ customScopesFieldKey?: string;
84
+ }>;
85
+ type CredentialOAuth2AuthDefinition = Readonly<{
86
+ kind: "oauth2";
87
+ providerId: string;
88
+ scopes: ReadonlyArray<string>;
89
+ scopesFromPublicConfig?: CredentialOAuth2ScopesFromPublicConfig;
90
+ clientIdFieldKey?: string;
91
+ clientSecretFieldKey?: string;
92
+ } | {
93
+ kind: "oauth2";
94
+ providerFromPublicConfig: OAuth2ProviderFromPublicConfig;
95
+ scopes: ReadonlyArray<string>;
96
+ scopesFromPublicConfig?: CredentialOAuth2ScopesFromPublicConfig;
97
+ clientIdFieldKey?: string;
98
+ clientSecretFieldKey?: string;
99
+ } | {
100
+ kind: "oauth2";
101
+ /**
102
+ * Free-form provider identifier for telemetry, DB rows, and Better Auth provider naming.
103
+ * Not used for any registry lookup — URLs come from {@link authorizeUrl} / {@link tokenUrl}.
104
+ */
105
+ providerId: string;
106
+ /**
107
+ * Authorization endpoint. May contain `{publicFieldKey}` placeholders that the runtime
108
+ * substitutes from the credential's resolved public config (URL-encoded).
109
+ * Example: `https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize`
110
+ */
111
+ authorizeUrl: string;
112
+ /** Token endpoint. Same templating rules as {@link authorizeUrl}. */
113
+ tokenUrl: string;
114
+ /** Optional userinfo endpoint. Same templating rules as {@link authorizeUrl}. */
115
+ userInfoUrl?: string;
116
+ scopes: ReadonlyArray<string>;
117
+ scopesFromPublicConfig?: CredentialOAuth2ScopesFromPublicConfig;
118
+ clientIdFieldKey?: string;
119
+ clientSecretFieldKey?: string;
120
+ }>;
121
+ type CredentialAuthDefinition = CredentialOAuth2AuthDefinition;
122
+ type CredentialAdvancedSectionPresentation = Readonly<{
123
+ /** Collapsible section title (default: "Advanced"). */
124
+ title?: string;
125
+ /** Optional short helper text shown inside the section (above the fields). */
126
+ description?: string;
127
+ /** When true, the advanced section starts expanded. Default: false (collapsed). */
128
+ defaultOpen?: boolean;
129
+ }>;
130
+ type CredentialTypeDefinition = Readonly<{
131
+ typeId: CredentialTypeId;
132
+ displayName: string;
133
+ description?: string;
134
+ publicFields?: ReadonlyArray<CredentialFieldSchema>;
135
+ secretFields?: ReadonlyArray<CredentialFieldSchema>;
136
+ /**
137
+ * Optional labels for the collapsible block that contains every field with `visibility: "advanced"`.
138
+ * If omitted, the UI still shows that block with defaults (title "Advanced", collapsed).
139
+ */
140
+ advancedSection?: CredentialAdvancedSectionPresentation;
141
+ supportedSourceKinds?: ReadonlyArray<CredentialMaterialSourceKind>;
142
+ auth?: CredentialAuthDefinition;
32
143
  }>;
33
144
  /**
34
- * Context aligned with former {@link ItemInputMapperContext} use **`data`** to read any completed upstream node.
145
+ * JSON-shaped credential field bag (public config, resolved secret material, etc.).
35
146
  */
36
- type ItemExprContext = ItemExprResolvedContext;
37
- type ItemExprArgs<TItemJson = unknown> = Readonly<{
38
- item: Item<TItemJson>;
39
- itemIndex: number;
40
- items: Items<TItemJson>;
41
- ctx: ItemExprContext;
147
+ type CredentialJsonRecord = Readonly<Record<string, unknown>>;
148
+ /**
149
+ * Persisted credential instance with typed `publicConfig`.
150
+ * Hosts may specialize `secretRef` with a stricter union while remaining
151
+ * assignable here for session/test callbacks.
152
+ */
153
+ type CredentialInstanceRecord<TPublicConfig extends CredentialJsonRecord = CredentialJsonRecord> = Readonly<{
154
+ instanceId: CredentialInstanceId;
155
+ typeId: CredentialTypeId;
156
+ displayName: string;
157
+ sourceKind: CredentialMaterialSourceKind;
158
+ publicConfig: TPublicConfig;
159
+ secretRef: CredentialJsonRecord;
160
+ tags: ReadonlyArray<string>;
161
+ setupStatus: CredentialSetupStatus;
162
+ createdAt: string;
163
+ updatedAt: string;
42
164
  }>;
43
- type ItemExprCallback<T, TItemJson = unknown> = (args: ItemExprArgs<TItemJson>) => T | Promise<T>;
44
- type ItemExpr<T, TItemJson = unknown> = Readonly<{
45
- readonly [ITEM_EXPR_BRAND]: true;
46
- readonly fn: ItemExprCallback<T, TItemJson>;
165
+ /**
166
+ * Arguments passed to `CredentialType.createSession` and `CredentialType.test`.
167
+ * Declare `TPublicConfig` / `TMaterial` on `CredentialType` so implementations are checked
168
+ * against your credential shapes (similar to `NodeExecutionContext.config` for nodes).
169
+ */
170
+ type CredentialSessionFactoryArgs<TPublicConfig extends CredentialJsonRecord = CredentialJsonRecord, TMaterial extends CredentialJsonRecord = CredentialJsonRecord> = Readonly<{
171
+ instance: CredentialInstanceRecord<TPublicConfig>;
172
+ material: TMaterial;
173
+ publicConfig: TPublicConfig;
47
174
  }>;
48
- //#endregion
49
- //#region ../core/src/contracts/params.d.ts
50
- type Expr<T, TItemJson = unknown> = ItemExpr<T, TItemJson>;
51
- type ParamDeep<T, TItemJson = unknown> = Expr<T, TItemJson> | (T extends readonly (infer U)[] ? ReadonlyArray<ParamDeep<U, TItemJson>> : never) | (T extends object ? { [K in keyof T]: ParamDeep<T[K], TItemJson> } : T);
52
- //#endregion
53
- //#region ../core/src/contracts/retryPolicySpec.types.d.ts
175
+ type CredentialSessionFactory<TPublicConfig extends CredentialJsonRecord = CredentialJsonRecord, TMaterial extends CredentialJsonRecord = CredentialJsonRecord, TSession = unknown> = (args: CredentialSessionFactoryArgs<TPublicConfig, TMaterial>) => Promise<TSession>;
176
+ type CredentialHealthTester<TPublicConfig extends CredentialJsonRecord = CredentialJsonRecord, TMaterial extends CredentialJsonRecord = CredentialJsonRecord> = (args: CredentialSessionFactoryArgs<TPublicConfig, TMaterial>) => Promise<CredentialHealth>;
54
177
  /**
55
- * In-process retry policy for runnable nodes. Serialized configs use the same
56
- * `kind` discriminator (`JSON.stringify` / persisted workflows).
57
- *
58
- * `maxAttempts` is the total number of tries including the first (e.g. 3 means up to 2 delays after failures).
178
+ * Full credential type implementation: `definition` (UI/schema), `createSession`, and `test`.
179
+ * Use this at registration and config boundaries; `CredentialTypeDefinition` is only the schema slice.
59
180
  */
60
- type RetryPolicySpec = NoneRetryPolicySpec | FixedRetryPolicySpec | ExponentialRetryPolicySpec;
61
- interface NoneRetryPolicySpec {
62
- readonly kind: "none";
63
- }
64
- interface FixedRetryPolicySpec {
65
- readonly kind: "fixed";
66
- /** Total attempts including the first execution. Must be >= 1. */
67
- readonly maxAttempts: number;
68
- readonly delayMs: number;
69
- }
70
- interface ExponentialRetryPolicySpec {
71
- readonly kind: "exponential";
72
- /** Total attempts including the first execution. Must be >= 1. */
73
- readonly maxAttempts: number;
74
- readonly initialDelayMs: number;
75
- readonly multiplier: number;
76
- readonly maxDelayMs?: number;
77
- /** When true, each delay is multiplied by a random factor in [1, 1.2). */
78
- readonly jitter?: boolean;
181
+ type CredentialType<TPublicConfig extends CredentialJsonRecord = CredentialJsonRecord, TMaterial extends CredentialJsonRecord = CredentialJsonRecord, TSession = unknown> = Readonly<{
182
+ definition: CredentialTypeDefinition;
183
+ createSession: CredentialSessionFactory<TPublicConfig, TMaterial, TSession>;
184
+ test: CredentialHealthTester<TPublicConfig, TMaterial>;
185
+ }>;
186
+ /**
187
+ * Credential type with unspecified generics used for `CodemationConfig.credentialTypes`, the host registry,
188
+ * and anywhere a concrete `CredentialType<YourPublic, YourMaterial, YourSession>` is placed in a heterogeneous list.
189
+ * Using `any` here avoids unsafe `as` casts while keeping typed `satisfies CredentialType<…>` definitions.
190
+ */
191
+ type AnyCredentialType = CredentialType<any, any, unknown>;
192
+ interface CredentialSessionService {
193
+ getSession<TSession = unknown>(args: Readonly<{
194
+ workflowId: WorkflowId;
195
+ nodeId: NodeId;
196
+ slotKey: string;
197
+ }>): Promise<TSession>;
79
198
  }
80
199
  //#endregion
81
- //#region ../core/src/contracts/telemetryTypes.d.ts
82
- type TelemetryAttributePrimitive = string | number | boolean | null;
83
- interface TelemetryAttributes {
84
- readonly [key: string]: TelemetryAttributePrimitive | undefined;
85
- }
86
- interface TelemetryMetricRecord {
87
- readonly name: string;
88
- readonly value: number;
89
- readonly unit?: string;
90
- readonly attributes?: TelemetryAttributes;
200
+ //#region ../core/src/triggers/polling/PollingTriggerDedupWindow.d.ts
201
+ /**
202
+ * Merges processed-ID windows for polling triggers, capping the total to avoid unbounded growth.
203
+ * Plugin code receives an instance of this class via {@link PollingTriggerHandle.dedup}.
204
+ */
205
+ declare class PollingTriggerDedupWindow {
206
+ static readonly defaultCapN = 2000;
207
+ merge(previous: ReadonlyArray<string>, incoming: ReadonlyArray<string>, capN?: number): ReadonlyArray<string>;
91
208
  }
92
- interface TelemetrySpanEventRecord {
93
- readonly name: string;
94
- readonly occurredAt?: Date;
95
- readonly attributes?: TelemetryAttributes;
209
+ //#endregion
210
+ //#region ../core/src/contracts/runTypes.d.ts
211
+ /**
212
+ * Test-suite linkage for a run. When set, this run was started by a TestSuiteOrchestrator
213
+ * as one test case inside a TestSuiteRun. The `IsTestRun` node and host-side persisters key
214
+ * off the presence of this field. Subworkflow runs inherit it from their parent run.
215
+ */
216
+ interface RunTestContext {
217
+ readonly testSuiteRunId: string;
218
+ readonly testCaseIndex: number;
219
+ /**
220
+ * Optional human-friendly label for this test case (e.g. an email subject when fixtures
221
+ * are loaded from a mailbox). Resolved per item by `TestTrigger.caseLabel(item)` if set,
222
+ * persisted on `Run.test_case_label` so the Tests-tab tree-table can show "RFQ for batch 14"
223
+ * instead of "run_1777755971399_bbb86beac1396".
224
+ */
225
+ readonly testCaseLabel?: string;
96
226
  }
97
- interface TelemetryArtifactAttachment {
98
- readonly kind: string;
99
- readonly contentType: string;
100
- readonly previewText?: string;
101
- readonly previewJson?: JsonValue;
102
- readonly payloadText?: string;
103
- readonly payloadJson?: JsonValue;
104
- readonly bytes?: number;
105
- readonly truncated?: boolean;
106
- readonly expiresAt?: Date;
107
- }
108
- interface TelemetryArtifactReference {
109
- readonly artifactId: string;
110
- readonly traceId?: string;
111
- readonly spanId?: string;
112
- }
113
- interface TelemetrySpanEnd {
114
- readonly status?: "ok" | "error";
115
- readonly statusMessage?: string;
116
- readonly endedAt?: Date;
117
- readonly attributes?: TelemetryAttributes;
118
- }
119
- interface TelemetryChildSpanStart {
120
- readonly name: string;
121
- readonly kind?: "internal" | "client";
122
- readonly startedAt?: Date;
123
- readonly attributes?: TelemetryAttributes;
124
- }
125
- interface TelemetryScope {
126
- readonly traceId?: string;
127
- readonly spanId?: string;
128
- readonly costTracking?: CostTrackingTelemetry;
129
- addSpanEvent(args: TelemetrySpanEventRecord): Promise<void> | void;
130
- recordMetric(args: TelemetryMetricRecord): Promise<void> | void;
131
- attachArtifact(args: TelemetryArtifactAttachment): Promise<TelemetryArtifactReference> | TelemetryArtifactReference;
132
- }
133
- interface TelemetrySpanScope extends TelemetryScope {
134
- readonly traceId: string;
135
- readonly spanId: string;
136
- end(args?: TelemetrySpanEnd): Promise<void> | void;
137
- }
138
- interface NodeExecutionTelemetry extends ExecutionTelemetry, TelemetrySpanScope {
139
- startChildSpan(args: TelemetryChildSpanStart): TelemetrySpanScope;
140
- }
141
- interface ExecutionTelemetry extends TelemetryScope {
142
- readonly traceId: string;
143
- readonly spanId: string;
144
- forNode(args: Readonly<{
145
- nodeId: NodeId;
146
- activationId: NodeActivationId;
147
- }>): NodeExecutionTelemetry;
148
- }
149
- //#endregion
150
- //#region ../core/src/contracts/CostTrackingTelemetryContract.d.ts
151
- type CostTrackingComponent = "chat" | "ocr" | "rag";
152
- interface CostTrackingUsageRecord {
153
- readonly component: CostTrackingComponent;
154
- readonly provider: string;
155
- readonly operation: string;
156
- readonly pricingKey: string;
157
- readonly usageUnit: string;
158
- readonly quantity: number;
159
- readonly modelName?: string;
160
- readonly attributes?: TelemetryAttributes;
161
- }
162
- interface CostTrackingPriceQuote {
163
- readonly currency: string;
164
- readonly currencyScale: number;
165
- readonly estimatedAmountMinor: number;
166
- readonly estimateKind: "catalog";
167
- }
168
- interface CostTrackingTelemetry {
169
- captureUsage(args: CostTrackingUsageRecord): Promise<CostTrackingPriceQuote | undefined>;
170
- forScope(scope: TelemetryScope): CostTrackingTelemetry;
171
- }
172
- //#endregion
173
- //#region ../core/src/contracts/runTypes.d.ts
174
- type NodeInputsByPort = Readonly<Record<InputPortKey, Items>>;
175
- type NodeExecutionStatus = "pending" | "queued" | "running" | "completed" | "failed" | "skipped";
176
- interface NodeExecutionError {
177
- message: string;
178
- name?: string;
179
- stack?: string;
180
- details?: JsonValue;
227
+ type NodeInputsByPort = Readonly<Record<InputPortKey, Items>>;
228
+ type NodeExecutionStatus = "pending" | "queued" | "running" | "completed" | "failed" | "skipped";
229
+ interface NodeExecutionError {
230
+ message: string;
231
+ name?: string;
232
+ stack?: string;
233
+ details?: JsonValue;
181
234
  }
182
235
  /** Stable id for a single connection invocation row in {@link ConnectionInvocationRecord}. */
183
236
  type ConnectionInvocationId = string;
@@ -194,6 +247,9 @@ type ConnectionInvocationAppendArgs = Readonly<{
194
247
  queuedAt?: string;
195
248
  startedAt?: string;
196
249
  finishedAt?: string;
250
+ iterationId?: NodeIterationId;
251
+ itemIndex?: number;
252
+ parentInvocationId?: ConnectionInvocationId;
197
253
  }>;
198
254
  interface PendingNodeExecution {
199
255
  runId: RunId;
@@ -229,275 +285,69 @@ type RunResult = {
229
285
  };
230
286
  };
231
287
  //#endregion
232
- //#region ../core/src/contracts/webhookTypes.d.ts
233
- type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
234
- interface WebhookControlSignal {
235
- readonly __webhookControl: true;
236
- readonly kind: "respondNow" | "respondNowAndContinue";
237
- readonly responseItems: Items;
238
- readonly continueItems?: Items;
288
+ //#region ../core/src/contracts/retryPolicySpec.types.d.ts
289
+ /**
290
+ * In-process retry policy for runnable nodes. Serialized configs use the same
291
+ * `kind` discriminator (`JSON.stringify` / persisted workflows).
292
+ *
293
+ * `maxAttempts` is the total number of tries including the first (e.g. 3 means up to 2 delays after failures).
294
+ */
295
+ type RetryPolicySpec = NoneRetryPolicySpec | FixedRetryPolicySpec | ExponentialRetryPolicySpec;
296
+ interface NoneRetryPolicySpec {
297
+ readonly kind: "none";
239
298
  }
240
- interface TriggerInstanceId {
241
- workflowId: WorkflowId;
242
- nodeId: NodeId;
299
+ interface FixedRetryPolicySpec {
300
+ readonly kind: "fixed";
301
+ /** Total attempts including the first execution. Must be >= 1. */
302
+ readonly maxAttempts: number;
303
+ readonly delayMs: number;
243
304
  }
244
- //#endregion
245
- //#region ../core/src/workflow/dsl/workflowBuilderTypes.d.ts
246
- type AnyRunnableNodeConfig = RunnableNodeConfig<any, any>;
247
- type AnyTriggerNodeConfig = TriggerNodeConfig<any>;
248
- type ValidStepSequence<TCurrentJson, TSteps extends ReadonlyArray<AnyRunnableNodeConfig>> = TSteps extends readonly [] ? readonly [] : TSteps extends readonly [infer TFirst, ...infer TRest] ? TFirst extends RunnableNodeConfig<TCurrentJson, infer TNextJson> ? TRest extends ReadonlyArray<AnyRunnableNodeConfig> ? readonly [TFirst, ...ValidStepSequence<TNextJson, TRest>] : never : never : TSteps;
249
- type StepSequenceOutput<TCurrentJson, TSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined> = TSteps extends ReadonlyArray<AnyRunnableNodeConfig> ? TSteps extends readonly [] ? TCurrentJson : TSteps extends readonly [infer TFirst, ...infer TRest] ? TFirst extends RunnableNodeConfig<TCurrentJson, infer TNextJson> ? TRest extends ReadonlyArray<AnyRunnableNodeConfig> ? StepSequenceOutput<TNextJson, TRest> : never : never : TCurrentJson : TCurrentJson;
250
- type TypesMatch<TLeft, TRight> = [TLeft] extends [TRight] ? ([TRight] extends [TLeft] ? true : false) : false;
251
- type BranchOutputGuard<TCurrentJson, TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined, TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined> = TypesMatch<StepSequenceOutput<TCurrentJson, TTrueSteps>, StepSequenceOutput<TCurrentJson, TFalseSteps>> extends true ? unknown : never;
252
- type BranchStepsArg<TCurrentJson, TSteps extends ReadonlyArray<AnyRunnableNodeConfig>> = TSteps & ValidStepSequence<TCurrentJson, TSteps>;
253
- type BranchMoreArgs<TCurrentJson, TFirstStep extends RunnableNodeConfig<TCurrentJson, any>, TRestSteps extends ReadonlyArray<AnyRunnableNodeConfig>> = TRestSteps & ValidStepSequence<RunnableNodeOutputJson<TFirstStep>, TRestSteps>;
254
- type BooleanWhenOverloads<TCurrentJson, TReturn> = {
255
- <TSteps extends ReadonlyArray<AnyRunnableNodeConfig>>(branch: boolean, steps: BranchStepsArg<TCurrentJson, TSteps>): TReturn;
256
- <TFirstStep extends RunnableNodeConfig<TCurrentJson, any>, TRestSteps extends ReadonlyArray<AnyRunnableNodeConfig>>(branch: boolean, step: TFirstStep, ...more: BranchMoreArgs<TCurrentJson, TFirstStep, TRestSteps>): TReturn;
257
- };
258
- //#endregion
259
- //#region ../core/src/workflow/dsl/WhenBuilder.d.ts
260
- declare class WhenBuilder<TCurrentJson> {
261
- private readonly wf;
262
- private readonly from;
263
- private readonly branchPort;
264
- constructor(wf: WorkflowBuilder, from: NodeRef, branchPort: OutputPortKey);
265
- addBranch<TSteps extends ReadonlyArray<AnyRunnableNodeConfig>>(steps: TSteps & ValidStepSequence<TCurrentJson, TSteps>): this;
266
- readonly when: BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>>;
267
- build(): WorkflowDefinition;
305
+ interface ExponentialRetryPolicySpec {
306
+ readonly kind: "exponential";
307
+ /** Total attempts including the first execution. Must be >= 1. */
308
+ readonly maxAttempts: number;
309
+ readonly initialDelayMs: number;
310
+ readonly multiplier: number;
311
+ readonly maxDelayMs?: number;
312
+ /** When true, each delay is multiplied by a random factor in [1, 1.2). */
313
+ readonly jitter?: boolean;
268
314
  }
269
315
  //#endregion
270
- //#region ../core/src/workflow/dsl/ChainCursorResolver.d.ts
271
- type ChainCursorEndpoint = Readonly<{
272
- node: NodeRef;
273
- output: OutputPortKey;
274
- inputPortHint?: InputPortKey;
316
+ //#region ../core/src/contracts/workflowTypes.d.ts
317
+ type NodeIdRef<TJson = unknown> = NodeId & Readonly<{
318
+ __codemationNodeJson?: TJson;
275
319
  }>;
276
- type ChainCursorWhenOverloads<TCurrentJson> = BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>> & {
277
- <TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined, TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined>(branches: Readonly<{
278
- true?: TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> ? BranchStepsArg<TCurrentJson, TTrueSteps> : never;
279
- false?: TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig> ? BranchStepsArg<TCurrentJson, TFalseSteps> : never;
280
- }> & BranchOutputGuard<TCurrentJson, TTrueSteps, TFalseSteps>): ChainCursor<StepSequenceOutput<TCurrentJson, TTrueSteps>>;
281
- };
282
- declare class ChainCursor<TCurrentJson> {
283
- private readonly wf;
284
- private readonly endpoints;
285
- constructor(wf: WorkflowBuilder, endpoints: ReadonlyArray<ChainCursorEndpoint>);
286
- then<TOutputJson$1, TConfig extends RunnableNodeConfig<TCurrentJson, TOutputJson$1>>(config: TConfig): ChainCursor<RunnableNodeOutputJson<TConfig>>;
287
- thenIntoInputHints<TOutputJson$1, TConfig extends RunnableNodeConfig<any, TOutputJson$1>>(config: TConfig): ChainCursor<RunnableNodeOutputJson<TConfig>>;
288
- readonly when: ChainCursorWhenOverloads<TCurrentJson>;
289
- route<TNextJson$1>(branches: Readonly<Record<OutputPortKey, (branch: ChainCursor<TCurrentJson>) => ChainCursor<TNextJson$1> | undefined>>): ChainCursor<TNextJson$1>;
290
- build(): WorkflowDefinition;
291
- private resolveSharedInputPortHint;
292
- }
293
- //#endregion
294
- //#region ../core/src/workflow/dsl/WorkflowBuilder.d.ts
295
- declare class WorkflowBuilder {
296
- private readonly meta;
297
- private readonly options?;
298
- private readonly nodes;
299
- private readonly edges;
300
- private seq;
301
- constructor(meta: {
302
- id: WorkflowId;
303
- name: string;
304
- }, options?: Readonly<Record<string, never>> | undefined);
305
- private add;
306
- private connect;
307
- trigger<TConfig extends AnyTriggerNodeConfig>(config: TConfig): ChainCursor<TriggerNodeOutputJson<TConfig>>;
308
- start<TConfig extends AnyRunnableNodeConfig>(config: TConfig): ChainCursor<RunnableNodeOutputJson<TConfig>>;
309
- build(): WorkflowDefinition;
310
- }
311
- //#endregion
312
- //#region ../core/src/contracts/runtimeTypes.d.ts
313
- interface WorkflowRunnerService {
314
- runById(args: {
315
- workflowId: WorkflowId;
316
- startAt?: NodeId;
317
- items: Items;
318
- parent?: ParentExecutionRef;
319
- }): Promise<RunResult>;
320
- }
321
- interface NodeResolver {
322
- resolve<T>(token: TypeToken<T>): T;
320
+ type NodeKind = "trigger" | "node";
321
+ type JsonPrimitive = string | number | boolean | null;
322
+ interface JsonObject {
323
+ readonly [key: string]: JsonValue;
323
324
  }
324
- interface NodeExecutionStatePublisher {
325
- markQueued(args: {
326
- nodeId: NodeId;
327
- activationId?: NodeActivationId;
328
- inputsByPort?: NodeInputsByPort;
329
- }): Promise<void>;
330
- markRunning(args: {
331
- nodeId: NodeId;
332
- activationId?: NodeActivationId;
333
- inputsByPort?: NodeInputsByPort;
334
- }): Promise<void>;
335
- markCompleted(args: {
325
+ type JsonValue = JsonPrimitive | JsonObject | JsonArray;
326
+ type JsonArray = ReadonlyArray<JsonValue>;
327
+ /** JSON value that is not a top-level array (nested arrays inside objects are allowed). */
328
+ type JsonNonArray = JsonPrimitive | JsonObject;
329
+ interface Edge {
330
+ from: {
336
331
  nodeId: NodeId;
337
- activationId?: NodeActivationId;
338
- inputsByPort?: NodeInputsByPort;
339
- outputs?: NodeOutputs;
340
- }): Promise<void>;
341
- markFailed(args: {
332
+ output: OutputPortKey;
333
+ };
334
+ to: {
342
335
  nodeId: NodeId;
343
- activationId?: NodeActivationId;
344
- inputsByPort?: NodeInputsByPort;
345
- error: Error;
346
- }): Promise<void>;
347
- appendConnectionInvocation(args: ConnectionInvocationAppendArgs): Promise<void>;
336
+ input: InputPortKey;
337
+ };
348
338
  }
349
- type BinaryBody = ReadableStream<Uint8Array> | AsyncIterable<Uint8Array> | Uint8Array | ArrayBuffer;
350
- interface BinaryStorageReadResult {
351
- body: ReadableStream<Uint8Array>;
352
- size?: number;
339
+ /**
340
+ * Named connection from a parent node to child nodes that exist in {@link WorkflowDefinition.nodes}
341
+ * but are not traversed by the main execution graph. Parents are commonly executable nodes, but may
342
+ * also be connection-owned nodes for recursive agent attachments.
343
+ */
344
+ interface WorkflowNodeConnection {
345
+ readonly parentNodeId: NodeId;
346
+ readonly connectionName: NodeConnectionName;
347
+ readonly childNodeIds: ReadonlyArray<NodeId>;
353
348
  }
354
- interface BinaryAttachmentCreateRequest {
355
- name: string;
356
- body: BinaryBody;
357
- mimeType: string;
358
- filename?: string;
359
- previewKind?: BinaryAttachment["previewKind"];
360
- }
361
- interface NodeBinaryAttachmentService extends ExecutionBinaryService {
362
- attach(args: BinaryAttachmentCreateRequest): Promise<BinaryAttachment>;
363
- withAttachment<TJson>(item: Item<TJson>, name: string, attachment: BinaryAttachment): Item<TJson>;
364
- }
365
- interface ExecutionBinaryService {
366
- forNode(args: {
367
- nodeId: NodeId;
368
- activationId: NodeActivationId;
369
- }): NodeBinaryAttachmentService;
370
- openReadStream(attachment: BinaryAttachment): Promise<BinaryStorageReadResult | undefined>;
371
- }
372
- interface ExecutionContext {
373
- runId: RunId;
374
- workflowId: WorkflowId;
375
- parent?: ParentExecutionRef;
376
- /** This run's subworkflow depth (0 = root). */
377
- subworkflowDepth: number;
378
- /** Effective activation budget cap for this run (after policy merge). */
379
- engineMaxNodeActivations: number;
380
- /** Effective subworkflow nesting cap for this run (after policy merge). */
381
- engineMaxSubworkflowDepth: number;
382
- now: () => Date;
383
- data: RunDataSnapshot;
384
- nodeState?: NodeExecutionStatePublisher;
385
- telemetry: ExecutionTelemetry;
386
- binary: ExecutionBinaryService;
387
- getCredential<TSession = unknown>(slotKey: string): Promise<TSession>;
388
- }
389
- interface NodeExecutionContext<TConfig extends NodeConfigBase = NodeConfigBase> extends ExecutionContext {
390
- nodeId: NodeId;
391
- activationId: NodeActivationId;
392
- config: TConfig;
393
- telemetry: NodeExecutionTelemetry;
394
- binary: NodeBinaryAttachmentService;
395
- }
396
- interface TriggerSetupContext<TConfig extends TriggerNodeConfig<any, any> = TriggerNodeConfig<any, any>, TSetupState$1 extends JsonValue | undefined = TriggerNodeSetupState<TConfig>> extends ExecutionContext {
397
- trigger: TriggerInstanceId;
398
- config: TConfig;
399
- previousState: TSetupState$1;
400
- registerCleanup(cleanup: TriggerCleanupHandle): void;
401
- emit(items: Items): Promise<void>;
402
- }
403
- interface TriggerTestItemsContext<TConfig extends TriggerNodeConfig<any, any> = TriggerNodeConfig<any, any>, TSetupState$1 extends JsonValue | undefined = TriggerNodeSetupState<TConfig>> extends ExecutionContext {
404
- trigger: TriggerInstanceId;
405
- nodeId: NodeId;
406
- config: TConfig;
407
- previousState: TSetupState$1;
408
- }
409
- interface TriggerCleanupHandle {
410
- stop(): Promise<void> | void;
411
- }
412
- /**
413
- * Per-item runnable node: return JSON, an array to fan-out on `main`, an explicit `Item`, or {@link emitPorts}
414
- * for multi-port emission. Engine applies `inputSchema.parse(item.json)` and passes the result as `args.input`
415
- * (wire `item.json` is unchanged). Transform helpers may opt into binary preservation, while routers and
416
- * pass-through nodes should return explicit items when they need to preserve full item state.
417
- */
418
- interface RunnableNodeExecuteArgs<TConfig extends RunnableNodeConfig<any, any> = RunnableNodeConfig<any, any>, TInputJson$1 = unknown> {
419
- readonly input: TInputJson$1;
420
- readonly item: Item;
421
- readonly itemIndex: number;
422
- readonly items: Items;
423
- readonly ctx: NodeExecutionContext<TConfig>;
424
- }
425
- interface RunnableNode<TConfig extends RunnableNodeConfig<any, any> = RunnableNodeConfig<any, any>, TInputJson$1 = unknown, _TOutputJson = unknown> {
426
- readonly kind: "node";
427
- /**
428
- * Declared output ports (e.g. `["main"]`).
429
- *
430
- * Prefer describing dynamic router ports (Switch) and fixed multi-ports (If true/false)
431
- * via {@link NodeConfigBase.declaredOutputPorts}. Engine defaults to `["main"]` when omitted.
432
- */
433
- readonly outputPorts?: ReadonlyArray<OutputPortKey>;
434
- /** When omitted, engine uses {@link RunnableNodeConfig.inputSchema} or `z.unknown()`. */
435
- readonly inputSchema?: ZodType<TInputJson$1>;
436
- execute(args: RunnableNodeExecuteArgs<TConfig, TInputJson$1>): Promise<unknown> | unknown;
437
- }
438
- interface MultiInputNode<TConfig extends NodeConfigBase = NodeConfigBase> {
439
- kind: "node";
440
- /**
441
- * Declared output ports (typically `["main"]`).
442
- *
443
- * Prefer describing ports for authoring/canvas via {@link NodeConfigBase.declaredOutputPorts}.
444
- * Engine defaults to `["main"]` when omitted.
445
- */
446
- outputPorts?: ReadonlyArray<OutputPortKey>;
447
- executeMulti(inputsByPort: NodeInputsByPort, ctx: NodeExecutionContext<TConfig>): Promise<NodeOutputs>;
448
- }
449
- type TriggerSetupStateFor<TConfig extends TriggerNodeConfig<any, any>> = TriggerNodeSetupState<TConfig>;
450
- interface TriggerNode<TConfig extends TriggerNodeConfig<any, any> = TriggerNodeConfig<any, any>> {
451
- kind: "trigger";
452
- outputPorts: readonly ["main"];
453
- setup(ctx: TriggerSetupContext<TConfig>): Promise<TriggerSetupStateFor<TConfig>>;
454
- execute(items: Items, ctx: NodeExecutionContext<TConfig>): Promise<NodeOutputs>;
455
- }
456
- interface TestableTriggerNode<TConfig extends TriggerNodeConfig<any, any> = TriggerNodeConfig<any, any>> extends TriggerNode<TConfig> {
457
- getTestItems(ctx: TriggerTestItemsContext<TConfig>): Promise<Items>;
458
- }
459
- type ExecutableTriggerNode<TConfig extends TriggerNodeConfig<any, any> = TriggerNodeConfig<any, any>> = TriggerNode<TConfig>;
460
- //#endregion
461
- //#region ../core/src/contracts/workflowTypes.d.ts
462
- type WorkflowId = string;
463
- type NodeId = string;
464
- type NodeIdRef<TJson = unknown> = NodeId & Readonly<{
465
- __codemationNodeJson?: TJson;
466
- }>;
467
- type OutputPortKey = string;
468
- type InputPortKey = string;
469
- type NodeKind = "trigger" | "node";
470
- type JsonPrimitive = string | number | boolean | null;
471
- interface JsonObject {
472
- readonly [key: string]: JsonValue;
473
- }
474
- type JsonValue = JsonPrimitive | JsonObject | JsonArray;
475
- type JsonArray = ReadonlyArray<JsonValue>;
476
- /** JSON value that is not a top-level array (nested arrays inside objects are allowed). */
477
- type JsonNonArray = JsonPrimitive | JsonObject;
478
- interface Edge {
479
- from: {
480
- nodeId: NodeId;
481
- output: OutputPortKey;
482
- };
483
- to: {
484
- nodeId: NodeId;
485
- input: InputPortKey;
486
- };
487
- }
488
- type NodeConnectionName = string;
489
- /**
490
- * Named connection from a parent node to child nodes that exist in {@link WorkflowDefinition.nodes}
491
- * but are not traversed by the main execution graph. Parents are commonly executable nodes, but may
492
- * also be connection-owned nodes for recursive agent attachments.
493
- */
494
- interface WorkflowNodeConnection {
495
- readonly parentNodeId: NodeId;
496
- readonly connectionName: NodeConnectionName;
497
- readonly childNodeIds: ReadonlyArray<NodeId>;
498
- }
499
- interface WorkflowDefinition {
500
- id: WorkflowId;
349
+ interface WorkflowDefinition {
350
+ id: WorkflowId;
501
351
  name: string;
502
352
  nodes: NodeDefinition[];
503
353
  edges: Edge[];
@@ -542,6 +392,14 @@ interface NodeConfigBase {
542
392
  readonly declaredOutputPorts?: ReadonlyArray<OutputPortKey>;
543
393
  readonly declaredInputPorts?: ReadonlyArray<InputPortKey>;
544
394
  getCredentialRequirements?(): ReadonlyArray<CredentialRequirement>;
395
+ /**
396
+ * Marker: this node emits {@link import("./assertionTypes").AssertionResult}-shaped items on its
397
+ * `main` port. The TestSuiteOrchestrator (and host-side TestAssertionPersister) listen for
398
+ * `nodeCompleted` events from nodes with this flag set, and persist their output items as
399
+ * TestAssertion records (only when the run carries a `testContext`). Set on assertion node
400
+ * configs (e.g. `AssertionNodeConfig`, `StringEqualsAssertionNodeConfig`).
401
+ */
402
+ readonly emitsAssertions?: true;
545
403
  }
546
404
  declare const runnableNodeInputType: unique symbol;
547
405
  declare const runnableNodeOutputType: unique symbol;
@@ -571,6 +429,12 @@ interface TriggerNodeConfig<TOutputJson$1 = unknown, TSetupState$1 extends JsonV
571
429
  readonly kind: "trigger";
572
430
  readonly [triggerNodeOutputType]?: TOutputJson$1;
573
431
  readonly [triggerNodeSetupStateType]?: TSetupState$1;
432
+ /**
433
+ * Distinguishes triggers driven by the live activation policy (webhooks, cron, polling) from
434
+ * triggers driven only by the {@link TestSuiteOrchestrator}. `WorkflowActivation` skips
435
+ * `"test"` triggers; the orchestrator skips `"live"` triggers. Defaults to `"live"` when omitted.
436
+ */
437
+ readonly triggerKind?: "live" | "test";
574
438
  }
575
439
  type RunnableNodeInputJson<TConfig extends RunnableNodeConfig<any, any>> = TConfig extends RunnableNodeConfig<infer TInputJson, any> ? TInputJson : never;
576
440
  type RunnableNodeOutputJson<TConfig extends RunnableNodeConfig<any, any>> = TConfig extends RunnableNodeConfig<any, infer TOutputJson> ? TOutputJson : never;
@@ -620,6 +484,12 @@ type Items<TJson = unknown> = ReadonlyArray<Item<TJson>>;
620
484
  type NodeOutputs = Partial<Record<OutputPortKey, Items>>;
621
485
  type RunId = string;
622
486
  type NodeActivationId = string;
487
+ /**
488
+ * One per-item iteration of a runnable node's execute loop. Refines `NodeActivationId` for
489
+ * per-item connection invocations and telemetry. Undefined when the executing node is a batch
490
+ * node or trigger that does not iterate items.
491
+ */
492
+ type NodeIterationId = string;
623
493
  interface ParentExecutionRef {
624
494
  runId: RunId;
625
495
  workflowId: WorkflowId;
@@ -630,12 +500,21 @@ interface ParentExecutionRef {
630
500
  engineMaxNodeActivations?: number;
631
501
  /** Effective max subworkflow depth from the parent run (propagated to child policy merge). */
632
502
  engineMaxSubworkflowDepth?: number;
503
+ /**
504
+ * Test-suite linkage inherited by the child subworkflow run. Set by whichever node
505
+ * spawns the subworkflow when its own `ctx.testContext` is present, so assertions
506
+ * emitted inside a subworkflow land under the correct parent test case.
507
+ */
508
+ testContext?: RunTestContext;
633
509
  }
634
510
  interface RunDataSnapshot {
635
511
  getOutputs(nodeId: NodeId): NodeOutputs | undefined;
636
512
  getOutputItems<TJson = unknown>(nodeId: NodeId | NodeIdRef<TJson>, output?: OutputPortKey): Items<TJson>;
637
513
  getOutputItem<TJson = unknown>(nodeId: NodeId | NodeIdRef<TJson>, itemIndex: number, output?: OutputPortKey): Item<TJson> | undefined;
638
514
  }
515
+ interface ActivationIdFactory {
516
+ makeActivationId(): NodeActivationId;
517
+ }
639
518
  type UpstreamRefPlaceholder = `$${number}`;
640
519
  /** Whether to persist run execution data after the workflow finishes. */
641
520
  type WorkflowStoragePolicyMode = "ALL" | "SUCCESS" | "ERROR" | "NEVER";
@@ -683,155 +562,564 @@ interface NodeErrorHandler {
683
562
  }
684
563
  type NodeErrorHandlerSpec = TypeToken<NodeErrorHandler> | NodeErrorHandler;
685
564
  //#endregion
686
- //#region ../core/src/contracts/credentialTypes.d.ts
687
- type CredentialTypeId = string;
688
- type CredentialInstanceId = string;
689
- type CredentialMaterialSourceKind = "db" | "env" | "code";
690
- type CredentialSetupStatus = "draft" | "ready";
691
- type CredentialHealthStatus = "unknown" | "healthy" | "failing";
692
- type CredentialFieldSchema = Readonly<{
693
- key: string;
694
- label: string;
695
- type: "string" | "password" | "textarea" | "json" | "boolean";
696
- required?: true;
697
- order?: number;
565
+ //#region ../core/src/contracts/testTriggerTypes.d.ts
566
+ /**
567
+ * Identifier minted by the host (or in-memory test runner) for one execution of a test suite.
568
+ * One TestSuiteRun produces N child workflow runs, one per item yielded by `generateItems`.
569
+ */
570
+ type TestSuiteRunId = string;
571
+ /**
572
+ * Setup context passed to a {@link TestTriggerNodeConfig.generateItems} callback. Distinct from
573
+ * {@link import("./runtimeTypes").TriggerSetupContext} on purpose: test triggers are not
574
+ * activated by the live trigger lifecycle (webhooks, cron, polling) and never call `emit` —
575
+ * the orchestrator pulls from the iterable they return and dispatches one run per item.
576
+ */
577
+ interface TestTriggerSetupContext<TConfig extends TestTriggerNodeConfig<unknown> = TestTriggerNodeConfig<unknown>> {
578
+ readonly workflowId: WorkflowId;
579
+ readonly nodeId: NodeId;
580
+ readonly config: TConfig;
581
+ readonly testSuiteRunId: TestSuiteRunId;
698
582
  /**
699
- * Where this field appears in the credential dialog. Use `"advanced"` for optional or
700
- * power-user fields; they render inside a collapsible section (see `CredentialTypeDefinition.advancedSection`).
701
- * Defaults to `"default"` when omitted.
583
+ * Resolves a credential session for a slot declared on this trigger's
584
+ * {@link import("./workflowTypes").NodeConfigBase.getCredentialRequirements}. Same contract as
585
+ * {@link import("./runtimeTypes").ExecutionContext.getCredential}.
702
586
  */
703
- visibility?: "default" | "advanced";
704
- placeholder?: string;
705
- helpText?: string;
706
- /** When set, host resolves this field from process.env at runtime; env wins over stored values. */
707
- envVarName?: string;
587
+ getCredential<TSession = unknown>(slotKey: string): Promise<TSession>;
588
+ /** AbortSignal raised when the suite is cancelled — long-running pulls should bail out. */
589
+ readonly signal: AbortSignal;
590
+ }
591
+ /**
592
+ * A trigger config that emits **test cases**. Each item yielded by {@link generateItems}
593
+ * becomes one workflow run (with `executionOptions.testContext` set), so 10 yielded items
594
+ * → 10 runs marked under the same TestSuiteRun.
595
+ *
596
+ * The trigger is otherwise a normal {@link TriggerNodeConfig} (so the canvas treats it like
597
+ * any other trigger), but its `triggerKind` is `"test"` so the live activation policy skips it.
598
+ */
599
+ interface TestTriggerNodeConfig<TOutputJson$1 = unknown> extends TriggerNodeConfig<TOutputJson$1, undefined> {
600
+ readonly triggerKind: "test";
708
601
  /**
709
- * When set, the dialog shows a copy action for this exact string (e.g. a static OAuth redirect URI
710
- * pattern or documentation URL). Do not use for secret values.
602
+ * Author-supplied async iterable of items, evaluated lazily. Implementations may fetch from
603
+ * credentialed APIs, read fixture files, or yield hard-coded items. The orchestrator iterates
604
+ * and dispatches one run per item, with concurrency capped by {@link concurrency} (default 4).
711
605
  */
712
- copyValue?: string;
713
- /** Accessible label for the copy control (default: Copy). */
714
- copyButtonLabel?: string;
715
- }>;
716
- type CredentialRequirement = Readonly<{
717
- slotKey: string;
718
- label: string;
719
- acceptedTypes: ReadonlyArray<CredentialTypeId>;
720
- optional?: true;
721
- helpText?: string;
722
- helpUrl?: string;
723
- }>;
724
- type CredentialHealth = Readonly<{
725
- status: CredentialHealthStatus;
726
- message?: string;
727
- testedAt?: string;
728
- expiresAt?: string;
729
- details?: Readonly<Record<string, unknown>>;
730
- }>;
731
- type OAuth2ProviderFromPublicConfig = Readonly<{
732
- authorizeUrlFieldKey: string;
733
- tokenUrlFieldKey: string;
734
- userInfoUrlFieldKey?: string;
735
- }>;
736
- type CredentialOAuth2ScopesFromPublicConfig = Readonly<{
737
- presetFieldKey: string;
738
- presetScopes: Readonly<Record<string, ReadonlyArray<string>>>;
739
- customPresetKey?: string;
740
- customScopesFieldKey?: string;
741
- }>;
742
- type CredentialOAuth2AuthDefinition = Readonly<{
743
- kind: "oauth2";
744
- providerId: string;
745
- scopes: ReadonlyArray<string>;
746
- scopesFromPublicConfig?: CredentialOAuth2ScopesFromPublicConfig;
747
- clientIdFieldKey?: string;
748
- clientSecretFieldKey?: string;
749
- } | {
750
- kind: "oauth2";
751
- providerFromPublicConfig: OAuth2ProviderFromPublicConfig;
752
- scopes: ReadonlyArray<string>;
753
- scopesFromPublicConfig?: CredentialOAuth2ScopesFromPublicConfig;
754
- clientIdFieldKey?: string;
755
- clientSecretFieldKey?: string;
756
- }>;
757
- type CredentialAuthDefinition = CredentialOAuth2AuthDefinition;
758
- type CredentialAdvancedSectionPresentation = Readonly<{
759
- /** Collapsible section title (default: "Advanced"). */
760
- title?: string;
761
- /** Optional short helper text shown inside the section (above the fields). */
762
- description?: string;
763
- /** When true, the advanced section starts expanded. Default: false (collapsed). */
764
- defaultOpen?: boolean;
765
- }>;
766
- type CredentialTypeDefinition = Readonly<{
767
- typeId: CredentialTypeId;
768
- displayName: string;
769
- description?: string;
770
- publicFields?: ReadonlyArray<CredentialFieldSchema>;
771
- secretFields?: ReadonlyArray<CredentialFieldSchema>;
606
+ generateItems(ctx: TestTriggerSetupContext<TestTriggerNodeConfig<TOutputJson$1>>): AsyncIterable<Item<TOutputJson$1>>;
607
+ /** Per-suite-run cap on simultaneously-executing test cases. Default: 4. */
608
+ readonly concurrency?: number;
772
609
  /**
773
- * Optional labels for the collapsible block that contains every field with `visibility: "advanced"`.
774
- * If omitted, the UI still shows that block with defaults (title "Advanced", collapsed).
610
+ * Free-form description of where the test cases come from surfaced in the node properties
611
+ * panel and the suite-detail header so authors revisiting the workflow six months later
612
+ * remember which mailbox / folder / fixture file the cases originate from.
613
+ *
614
+ * Example: `"All emails in the Gmail label \"test/triage-fixtures\" — 14 messages as of 2026-05-03."`
775
615
  */
776
- advancedSection?: CredentialAdvancedSectionPresentation;
777
- supportedSourceKinds?: ReadonlyArray<CredentialMaterialSourceKind>;
778
- auth?: CredentialAuthDefinition;
779
- }>;
780
- /**
781
- * JSON-shaped credential field bag (public config, resolved secret material, etc.).
782
- */
783
- type CredentialJsonRecord = Readonly<Record<string, unknown>>;
616
+ readonly description?: string;
617
+ /**
618
+ * Resolves a human-readable label for one yielded test case (e.g. email subject). The
619
+ * orchestrator calls this once per yielded item, persists the result on the run, and the
620
+ * Tests-tab UI uses it to render the case row instead of the opaque runId. Return
621
+ * `undefined` to fall back to "Case #N".
622
+ */
623
+ caseLabel?(item: Item<TOutputJson$1>): string | undefined;
624
+ }
625
+ //#endregion
626
+ //#region ../core/src/contracts/assertionTypes.d.ts
784
627
  /**
785
- * Persisted credential instance with typed `publicConfig`.
786
- * Hosts may specialize `secretRef` with a stricter union while remaining
787
- * assignable here for session/test callbacks.
628
+ * One assertion emitted by an assertion-emitting node (a node whose config sets
629
+ * `emitsAssertions: true`). Each emitted item on `main` carries one of these as `item.json`.
630
+ *
631
+ * Pass/fail is derived from `score >= (passThreshold ?? 0.5)` — see {@link deriveAssertionPassed}.
632
+ * The `errored` marker is for cases where the assertion code itself threw (distinct from
633
+ * "the assertion was evaluated and the score was low") and is treated as a hard fail in rollups
634
+ * regardless of `score`.
788
635
  */
789
- type CredentialInstanceRecord<TPublicConfig extends CredentialJsonRecord = CredentialJsonRecord> = Readonly<{
790
- instanceId: CredentialInstanceId;
791
- typeId: CredentialTypeId;
792
- displayName: string;
793
- sourceKind: CredentialMaterialSourceKind;
794
- publicConfig: TPublicConfig;
795
- secretRef: CredentialJsonRecord;
796
- tags: ReadonlyArray<string>;
797
- setupStatus: CredentialSetupStatus;
798
- createdAt: string;
799
- updatedAt: string;
800
- }>;
636
+ interface AssertionResult {
637
+ readonly name: string;
638
+ /** 0..1 score. Source of truth for pass/fail (compared against `passThreshold`). */
639
+ readonly score: number;
640
+ /** 0..1 threshold for "passed". When omitted, consumers default to 0.5. */
641
+ readonly passThreshold?: number;
642
+ /** True when evaluating the assertion threw — treated as fail regardless of `score`. */
643
+ readonly errored?: true;
644
+ /** What the assertion expected. Free-form JSON; UIs render with a JSON viewer. */
645
+ readonly expected?: JsonValue;
646
+ /** What the workflow actually produced. */
647
+ readonly actual?: JsonValue;
648
+ /** Short human-readable explanation, especially for fails / errors. */
649
+ readonly message?: string;
650
+ /** Bag of supplemental fields (e.g. judge prompt, judge raw response, comparison method). */
651
+ readonly details?: Readonly<Record<string, JsonValue>>;
652
+ }
653
+ //#endregion
654
+ //#region ../core/src/contracts/telemetryTypes.d.ts
655
+ type TelemetryAttributePrimitive = string | number | boolean | null;
656
+ interface TelemetryAttributes {
657
+ readonly [key: string]: TelemetryAttributePrimitive | undefined;
658
+ }
659
+ interface TelemetryMetricRecord {
660
+ readonly name: string;
661
+ readonly value: number;
662
+ readonly unit?: string;
663
+ readonly attributes?: TelemetryAttributes;
664
+ }
665
+ interface TelemetrySpanEventRecord {
666
+ readonly name: string;
667
+ readonly occurredAt?: Date;
668
+ readonly attributes?: TelemetryAttributes;
669
+ }
670
+ interface TelemetryArtifactAttachment {
671
+ readonly kind: string;
672
+ readonly contentType: string;
673
+ readonly previewText?: string;
674
+ readonly previewJson?: JsonValue;
675
+ readonly payloadText?: string;
676
+ readonly payloadJson?: JsonValue;
677
+ readonly bytes?: number;
678
+ readonly truncated?: boolean;
679
+ readonly expiresAt?: Date;
680
+ }
681
+ interface TelemetryArtifactReference {
682
+ readonly artifactId: string;
683
+ readonly traceId?: string;
684
+ readonly spanId?: string;
685
+ }
686
+ interface TelemetrySpanEnd {
687
+ readonly status?: "ok" | "error";
688
+ readonly statusMessage?: string;
689
+ readonly endedAt?: Date;
690
+ readonly attributes?: TelemetryAttributes;
691
+ }
692
+ interface TelemetryChildSpanStart {
693
+ readonly name: string;
694
+ readonly kind?: "internal" | "client";
695
+ readonly startedAt?: Date;
696
+ readonly attributes?: TelemetryAttributes;
697
+ }
698
+ interface TelemetryScope {
699
+ readonly traceId?: string;
700
+ readonly spanId?: string;
701
+ readonly costTracking?: CostTrackingTelemetry;
702
+ addSpanEvent(args: TelemetrySpanEventRecord): Promise<void> | void;
703
+ recordMetric(args: TelemetryMetricRecord): Promise<void> | void;
704
+ attachArtifact(args: TelemetryArtifactAttachment): Promise<TelemetryArtifactReference> | TelemetryArtifactReference;
705
+ }
706
+ interface TelemetrySpanScope extends TelemetryScope {
707
+ readonly traceId: string;
708
+ readonly spanId: string;
709
+ end(args?: TelemetrySpanEnd): Promise<void> | void;
710
+ /**
711
+ * Lift this span into a {@link NodeExecutionTelemetry} scoped to a different (nodeId, activationId).
712
+ * Children created via the returned telemetry's `startChildSpan` get this span as their parent.
713
+ *
714
+ * Used at the sub-agent boundary so that nested runtime telemetry parents under the agent.tool.call
715
+ * span instead of the orchestrator's node-level span.
716
+ */
717
+ asNodeTelemetry(args: Readonly<{
718
+ nodeId: NodeId;
719
+ activationId: NodeActivationId;
720
+ }>): NodeExecutionTelemetry;
721
+ }
722
+ interface NodeExecutionTelemetry extends ExecutionTelemetry, TelemetrySpanScope {
723
+ startChildSpan(args: TelemetryChildSpanStart): TelemetrySpanScope;
724
+ }
725
+ interface ExecutionTelemetry extends TelemetryScope {
726
+ readonly traceId: string;
727
+ readonly spanId: string;
728
+ forNode(args: Readonly<{
729
+ nodeId: NodeId;
730
+ activationId: NodeActivationId;
731
+ }>): NodeExecutionTelemetry;
732
+ }
733
+ //#endregion
734
+ //#region ../core/src/contracts/CostTrackingTelemetryContract.d.ts
735
+ type CostTrackingComponent = "chat" | "ocr" | "rag";
736
+ interface CostTrackingUsageRecord {
737
+ readonly component: CostTrackingComponent;
738
+ readonly provider: string;
739
+ readonly operation: string;
740
+ readonly pricingKey: string;
741
+ readonly usageUnit: string;
742
+ readonly quantity: number;
743
+ readonly modelName?: string;
744
+ readonly attributes?: TelemetryAttributes;
745
+ }
746
+ interface CostTrackingPriceQuote {
747
+ readonly currency: string;
748
+ readonly currencyScale: number;
749
+ readonly estimatedAmountMinor: number;
750
+ readonly estimateKind: "catalog";
751
+ }
752
+ interface CostTrackingTelemetry {
753
+ captureUsage(args: CostTrackingUsageRecord): Promise<CostTrackingPriceQuote | undefined>;
754
+ forScope(scope: TelemetryScope): CostTrackingTelemetry;
755
+ }
756
+ //#endregion
757
+ //#region ../core/src/contracts/webhookTypes.d.ts
758
+ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
759
+ interface WebhookControlSignal {
760
+ readonly __webhookControl: true;
761
+ readonly kind: "respondNow" | "respondNowAndContinue";
762
+ readonly responseItems: Items;
763
+ readonly continueItems?: Items;
764
+ }
765
+ interface TriggerInstanceId {
766
+ workflowId: WorkflowId;
767
+ nodeId: NodeId;
768
+ }
769
+ //#endregion
770
+ //#region ../core/src/contracts/collectionTypes.d.ts
801
771
  /**
802
- * Arguments passed to `CredentialType.createSession` and `CredentialType.test`.
803
- * Declare `TPublicConfig` / `TMaterial` on `CredentialType` so implementations are checked
804
- * against your credential shapes (similar to `NodeExecutionContext.config` for nodes).
772
+ * Represents a typed store for a single collection.
773
+ * All rows include auto-managed id, created_at, and updated_at fields.
805
774
  */
806
- type CredentialSessionFactoryArgs<TPublicConfig extends CredentialJsonRecord = CredentialJsonRecord, TMaterial extends CredentialJsonRecord = CredentialJsonRecord> = Readonly<{
807
- instance: CredentialInstanceRecord<TPublicConfig>;
808
- material: TMaterial;
809
- publicConfig: TPublicConfig;
775
+ interface CollectionStore<TRow extends Record<string, unknown> = Record<string, unknown>> {
776
+ /**
777
+ * Insert a new row. id, created_at, and updated_at are auto-populated.
778
+ */
779
+ insert(row: TRow): Promise<TRow & {
780
+ id: string;
781
+ created_at: Date;
782
+ updated_at: Date;
783
+ }>;
784
+ /**
785
+ * Get a single row by id.
786
+ */
787
+ get(id: string): Promise<(TRow & {
788
+ id: string;
789
+ created_at: Date;
790
+ updated_at: Date;
791
+ }) | null>;
792
+ /**
793
+ * Find a single row matching the provided filter.
794
+ */
795
+ findOne(filter: Partial<TRow>): Promise<(TRow & {
796
+ id: string;
797
+ created_at: Date;
798
+ updated_at: Date;
799
+ }) | null>;
800
+ /**
801
+ * List rows with optional pagination and filtering.
802
+ */
803
+ list(opts?: {
804
+ limit?: number;
805
+ offset?: number;
806
+ where?: Partial<TRow>;
807
+ }): Promise<{
808
+ rows: ReadonlyArray<TRow & {
809
+ id: string;
810
+ created_at: Date;
811
+ updated_at: Date;
812
+ }>;
813
+ total: number;
814
+ }>;
815
+ /**
816
+ * Update a row by id with partial data.
817
+ */
818
+ update(id: string, patch: Partial<TRow>): Promise<TRow & {
819
+ id: string;
820
+ created_at: Date;
821
+ updated_at: Date;
822
+ }>;
823
+ /**
824
+ * Delete a row by id. Hard delete only (no soft delete).
825
+ */
826
+ delete(id: string): Promise<{
827
+ deleted: boolean;
828
+ }>;
829
+ }
830
+ /**
831
+ * Runtime collections context: keyed by collection name.
832
+ */
833
+ type CollectionsContext = Readonly<Record<string, CollectionStore>>;
834
+ //#endregion
835
+ //#region ../core/src/contracts/emitPorts.d.ts
836
+ declare const EMIT_PORTS_BRAND: unique symbol;
837
+ type PortsEmission = Readonly<{
838
+ readonly [EMIT_PORTS_BRAND]: true;
839
+ readonly ports: Readonly<Partial<Record<OutputPortKey, Items | ReadonlyArray<JsonNonArray>>>>;
810
840
  }>;
811
- type CredentialSessionFactory<TPublicConfig extends CredentialJsonRecord = CredentialJsonRecord, TMaterial extends CredentialJsonRecord = CredentialJsonRecord, TSession = unknown> = (args: CredentialSessionFactoryArgs<TPublicConfig, TMaterial>) => Promise<TSession>;
812
- type CredentialHealthTester<TPublicConfig extends CredentialJsonRecord = CredentialJsonRecord, TMaterial extends CredentialJsonRecord = CredentialJsonRecord> = (args: CredentialSessionFactoryArgs<TPublicConfig, TMaterial>) => Promise<CredentialHealth>;
841
+ //#endregion
842
+ //#region ../core/src/workflow/dsl/workflowBuilderTypes.d.ts
843
+ type AnyRunnableNodeConfig = RunnableNodeConfig<any, any>;
844
+ type AnyTriggerNodeConfig = TriggerNodeConfig<any>;
845
+ type ValidStepSequence<TCurrentJson, TSteps extends ReadonlyArray<AnyRunnableNodeConfig>> = TSteps extends readonly [] ? readonly [] : TSteps extends readonly [infer TFirst, ...infer TRest] ? TFirst extends RunnableNodeConfig<TCurrentJson, infer TNextJson> ? TRest extends ReadonlyArray<AnyRunnableNodeConfig> ? readonly [TFirst, ...ValidStepSequence<TNextJson, TRest>] : never : never : TSteps;
846
+ type StepSequenceOutput<TCurrentJson, TSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined> = TSteps extends ReadonlyArray<AnyRunnableNodeConfig> ? TSteps extends readonly [] ? TCurrentJson : TSteps extends readonly [infer TFirst, ...infer TRest] ? TFirst extends RunnableNodeConfig<TCurrentJson, infer TNextJson> ? TRest extends ReadonlyArray<AnyRunnableNodeConfig> ? StepSequenceOutput<TNextJson, TRest> : never : never : TCurrentJson : TCurrentJson;
847
+ type TypesMatch<TLeft, TRight> = [TLeft] extends [TRight] ? ([TRight] extends [TLeft] ? true : false) : false;
848
+ type BranchOutputGuard<TCurrentJson, TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined, TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined> = TypesMatch<StepSequenceOutput<TCurrentJson, TTrueSteps>, StepSequenceOutput<TCurrentJson, TFalseSteps>> extends true ? unknown : never;
849
+ type BranchStepsArg<TCurrentJson, TSteps extends ReadonlyArray<AnyRunnableNodeConfig>> = TSteps & ValidStepSequence<TCurrentJson, TSteps>;
850
+ type BranchMoreArgs<TCurrentJson, TFirstStep extends RunnableNodeConfig<TCurrentJson, any>, TRestSteps extends ReadonlyArray<AnyRunnableNodeConfig>> = TRestSteps & ValidStepSequence<RunnableNodeOutputJson<TFirstStep>, TRestSteps>;
851
+ type BooleanWhenOverloads<TCurrentJson, TReturn> = {
852
+ <TSteps extends ReadonlyArray<AnyRunnableNodeConfig>>(branch: boolean, steps: BranchStepsArg<TCurrentJson, TSteps>): TReturn;
853
+ <TFirstStep extends RunnableNodeConfig<TCurrentJson, any>, TRestSteps extends ReadonlyArray<AnyRunnableNodeConfig>>(branch: boolean, step: TFirstStep, ...more: BranchMoreArgs<TCurrentJson, TFirstStep, TRestSteps>): TReturn;
854
+ };
855
+ //#endregion
856
+ //#region ../core/src/workflow/dsl/WhenBuilder.d.ts
857
+ declare class WhenBuilder<TCurrentJson> {
858
+ private readonly wf;
859
+ private readonly from;
860
+ private readonly branchPort;
861
+ constructor(wf: WorkflowBuilder, from: NodeRef, branchPort: OutputPortKey);
862
+ addBranch<TSteps extends ReadonlyArray<AnyRunnableNodeConfig>>(steps: TSteps & ValidStepSequence<TCurrentJson, TSteps>): this;
863
+ readonly when: BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>>;
864
+ build(): WorkflowDefinition;
865
+ }
866
+ //#endregion
867
+ //#region ../core/src/workflow/dsl/ChainCursorResolver.d.ts
868
+ type ChainCursorEndpoint = Readonly<{
869
+ node: NodeRef;
870
+ output: OutputPortKey;
871
+ inputPortHint?: InputPortKey;
872
+ }>;
873
+ type ChainCursorWhenOverloads<TCurrentJson> = BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>> & {
874
+ <TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined, TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined>(branches: Readonly<{
875
+ true?: TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> ? BranchStepsArg<TCurrentJson, TTrueSteps> : never;
876
+ false?: TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig> ? BranchStepsArg<TCurrentJson, TFalseSteps> : never;
877
+ }> & BranchOutputGuard<TCurrentJson, TTrueSteps, TFalseSteps>): ChainCursor<StepSequenceOutput<TCurrentJson, TTrueSteps>>;
878
+ };
879
+ declare class ChainCursor<TCurrentJson> {
880
+ private readonly wf;
881
+ private readonly endpoints;
882
+ constructor(wf: WorkflowBuilder, endpoints: ReadonlyArray<ChainCursorEndpoint>);
883
+ then<TOutputJson$1, TConfig extends RunnableNodeConfig<TCurrentJson, TOutputJson$1>>(config: TConfig): ChainCursor<RunnableNodeOutputJson<TConfig>>;
884
+ thenIntoInputHints<TOutputJson$1, TConfig extends RunnableNodeConfig<any, TOutputJson$1>>(config: TConfig): ChainCursor<RunnableNodeOutputJson<TConfig>>;
885
+ readonly when: ChainCursorWhenOverloads<TCurrentJson>;
886
+ route<TNextJson$1>(branches: Readonly<Record<OutputPortKey, (branch: ChainCursor<TCurrentJson>) => ChainCursor<TNextJson$1> | undefined>>): ChainCursor<TNextJson$1>;
887
+ build(): WorkflowDefinition;
888
+ private resolveSharedInputPortHint;
889
+ }
890
+ //#endregion
891
+ //#region ../core/src/workflow/dsl/WorkflowBuilder.d.ts
892
+ declare class WorkflowBuilder {
893
+ private readonly meta;
894
+ private readonly options?;
895
+ private readonly nodes;
896
+ private readonly edges;
897
+ constructor(meta: {
898
+ id: WorkflowId;
899
+ name: string;
900
+ }, options?: Readonly<Record<string, never>> | undefined);
901
+ private add;
902
+ private connect;
903
+ trigger<TConfig extends AnyTriggerNodeConfig>(config: TConfig): ChainCursor<TriggerNodeOutputJson<TConfig>>;
904
+ start<TConfig extends AnyRunnableNodeConfig>(config: TConfig): ChainCursor<RunnableNodeOutputJson<TConfig>>;
905
+ build(): WorkflowDefinition;
906
+ private validateNodeIds;
907
+ }
908
+ //#endregion
909
+ //#region ../core/src/contracts/runtimeTypes.d.ts
910
+ interface WorkflowRunnerService {
911
+ runById(args: {
912
+ workflowId: WorkflowId;
913
+ startAt?: NodeId;
914
+ items: Items;
915
+ parent?: ParentExecutionRef;
916
+ }): Promise<RunResult>;
917
+ }
918
+ interface NodeResolver {
919
+ resolve<T>(token: TypeToken<T>): T;
920
+ }
921
+ interface NodeExecutionStatePublisher {
922
+ markQueued(args: {
923
+ nodeId: NodeId;
924
+ activationId?: NodeActivationId;
925
+ inputsByPort?: NodeInputsByPort;
926
+ }): Promise<void>;
927
+ markRunning(args: {
928
+ nodeId: NodeId;
929
+ activationId?: NodeActivationId;
930
+ inputsByPort?: NodeInputsByPort;
931
+ }): Promise<void>;
932
+ markCompleted(args: {
933
+ nodeId: NodeId;
934
+ activationId?: NodeActivationId;
935
+ inputsByPort?: NodeInputsByPort;
936
+ outputs?: NodeOutputs;
937
+ }): Promise<void>;
938
+ markFailed(args: {
939
+ nodeId: NodeId;
940
+ activationId?: NodeActivationId;
941
+ inputsByPort?: NodeInputsByPort;
942
+ error: Error;
943
+ }): Promise<void>;
944
+ appendConnectionInvocation(args: ConnectionInvocationAppendArgs): Promise<void>;
945
+ }
946
+ type BinaryBody = ReadableStream<Uint8Array> | AsyncIterable<Uint8Array> | Uint8Array | ArrayBuffer;
947
+ interface BinaryStorageReadResult {
948
+ body: ReadableStream<Uint8Array>;
949
+ size?: number;
950
+ }
951
+ interface BinaryAttachmentCreateRequest {
952
+ name: string;
953
+ body: BinaryBody;
954
+ mimeType: string;
955
+ filename?: string;
956
+ previewKind?: BinaryAttachment["previewKind"];
957
+ }
958
+ interface NodeBinaryAttachmentService extends ExecutionBinaryService {
959
+ attach(args: BinaryAttachmentCreateRequest): Promise<BinaryAttachment>;
960
+ withAttachment<TJson>(item: Item<TJson>, name: string, attachment: BinaryAttachment): Item<TJson>;
961
+ }
962
+ interface ExecutionBinaryService {
963
+ forNode(args: {
964
+ nodeId: NodeId;
965
+ activationId: NodeActivationId;
966
+ }): NodeBinaryAttachmentService;
967
+ openReadStream(attachment: BinaryAttachment): Promise<BinaryStorageReadResult | undefined>;
968
+ }
969
+ interface ExecutionContext {
970
+ runId: RunId;
971
+ workflowId: WorkflowId;
972
+ parent?: ParentExecutionRef;
973
+ /** This run's subworkflow depth (0 = root). */
974
+ subworkflowDepth: number;
975
+ /** Effective activation budget cap for this run (after policy merge). */
976
+ engineMaxNodeActivations: number;
977
+ /** Effective subworkflow nesting cap for this run (after policy merge). */
978
+ engineMaxSubworkflowDepth: number;
979
+ now: () => Date;
980
+ data: RunDataSnapshot;
981
+ nodeState?: NodeExecutionStatePublisher;
982
+ telemetry: ExecutionTelemetry;
983
+ binary: ExecutionBinaryService;
984
+ getCredential<TSession = unknown>(slotKey: string): Promise<TSession>;
985
+ /** Per-item iteration id, set by {@link NodeExecutor} on the ctx passed into runnable `execute`. */
986
+ iterationId?: NodeIterationId;
987
+ /** Item index (0-based) within the current activation's batch; set alongside {@link iterationId}. */
988
+ itemIndex?: number;
989
+ /** When set, this ctx is executing inside a sub-agent triggered by the named parent invocation. */
990
+ parentInvocationId?: ConnectionInvocationId;
991
+ /**
992
+ * Present iff the run was started by a TestSuiteOrchestrator. The {@link IsTestRunNode}
993
+ * branches on this; assertion-emitting nodes use it to decide whether to record results.
994
+ */
995
+ testContext?: RunTestContext;
996
+ /**
997
+ * Collections registered in the codemation config, keyed by collection name.
998
+ */
999
+ readonly collections?: CollectionsContext;
1000
+ }
1001
+ interface NodeExecutionContext<TConfig extends NodeConfigBase = NodeConfigBase> extends ExecutionContext {
1002
+ nodeId: NodeId;
1003
+ activationId: NodeActivationId;
1004
+ config: TConfig;
1005
+ telemetry: NodeExecutionTelemetry;
1006
+ binary: NodeBinaryAttachmentService;
1007
+ }
1008
+ interface PollingTriggerHandle {
1009
+ /**
1010
+ * Start the polling loop. The runtime registers its own cleanup handle so callers do not need to
1011
+ * call {@link TriggerSetupContext.registerCleanup} for the loop.
1012
+ * @returns The state returned by the first cycle (or `undefined` when the overlap guard fired).
1013
+ */
1014
+ start<TState, TItem>(args: {
1015
+ intervalMs: number;
1016
+ seedState?: TState;
1017
+ runCycle: (cycleCtx: {
1018
+ previousState: TState | undefined;
1019
+ signal: AbortSignal;
1020
+ }) => Promise<{
1021
+ items: Items<TItem>;
1022
+ nextState: TState;
1023
+ }>;
1024
+ }): Promise<TState | undefined>;
1025
+ /** Convenience dedup-window helper. */
1026
+ readonly dedup: PollingTriggerDedupWindow;
1027
+ }
1028
+ interface TriggerSetupContext<TConfig extends TriggerNodeConfig<any, any> = TriggerNodeConfig<any, any>, TSetupState$1 extends JsonValue | undefined = TriggerNodeSetupState<TConfig>> extends ExecutionContext {
1029
+ trigger: TriggerInstanceId;
1030
+ config: TConfig;
1031
+ previousState: TSetupState$1;
1032
+ registerCleanup(cleanup: TriggerCleanupHandle): void;
1033
+ emit(items: Items): Promise<void>;
1034
+ /** Generic polling-trigger surface. Pre-binds trigger id, emit, and registerCleanup. */
1035
+ readonly polling: PollingTriggerHandle;
1036
+ }
1037
+ interface TriggerTestItemsContext<TConfig extends TriggerNodeConfig<any, any> = TriggerNodeConfig<any, any>, TSetupState$1 extends JsonValue | undefined = TriggerNodeSetupState<TConfig>> extends ExecutionContext {
1038
+ trigger: TriggerInstanceId;
1039
+ nodeId: NodeId;
1040
+ config: TConfig;
1041
+ previousState: TSetupState$1;
1042
+ }
1043
+ interface TriggerCleanupHandle {
1044
+ stop(): Promise<void> | void;
1045
+ }
813
1046
  /**
814
- * Full credential type implementation: `definition` (UI/schema), `createSession`, and `test`.
815
- * Use this at registration and config boundaries; `CredentialTypeDefinition` is only the schema slice.
1047
+ * Per-item runnable node: return JSON, an array to fan-out on `main`, an explicit `Item`, or {@link emitPorts}
1048
+ * for multi-port emission. Engine applies `inputSchema.parse(item.json)` and passes the result as `args.input`
1049
+ * (wire `item.json` is unchanged). Transform helpers may opt into binary preservation, while routers and
1050
+ * pass-through nodes should return explicit items when they need to preserve full item state.
816
1051
  */
817
- type CredentialType<TPublicConfig extends CredentialJsonRecord = CredentialJsonRecord, TMaterial extends CredentialJsonRecord = CredentialJsonRecord, TSession = unknown> = Readonly<{
818
- definition: CredentialTypeDefinition;
819
- createSession: CredentialSessionFactory<TPublicConfig, TMaterial, TSession>;
820
- test: CredentialHealthTester<TPublicConfig, TMaterial>;
1052
+ interface RunnableNodeExecuteArgs<TConfig extends RunnableNodeConfig<any, any> = RunnableNodeConfig<any, any>, TInputJson$1 = unknown> {
1053
+ readonly input: TInputJson$1;
1054
+ readonly item: Item;
1055
+ readonly itemIndex: number;
1056
+ readonly items: Items;
1057
+ readonly ctx: NodeExecutionContext<TConfig>;
1058
+ }
1059
+ interface RunnableNode<TConfig extends RunnableNodeConfig<any, any> = RunnableNodeConfig<any, any>, TInputJson$1 = unknown, _TOutputJson = unknown> {
1060
+ readonly kind: "node";
1061
+ /**
1062
+ * Declared output ports (e.g. `["main"]`).
1063
+ *
1064
+ * Prefer describing dynamic router ports (Switch) and fixed multi-ports (If true/false)
1065
+ * via {@link NodeConfigBase.declaredOutputPorts}. Engine defaults to `["main"]` when omitted.
1066
+ */
1067
+ readonly outputPorts?: ReadonlyArray<OutputPortKey>;
1068
+ /** When omitted, engine uses {@link RunnableNodeConfig.inputSchema} or `z.unknown()`. */
1069
+ readonly inputSchema?: ZodType<TInputJson$1>;
1070
+ execute(args: RunnableNodeExecuteArgs<TConfig, TInputJson$1>): Promise<unknown> | unknown;
1071
+ }
1072
+ interface MultiInputNode<TConfig extends NodeConfigBase = NodeConfigBase> {
1073
+ kind: "node";
1074
+ /**
1075
+ * Declared output ports (typically `["main"]`).
1076
+ *
1077
+ * Prefer describing ports for authoring/canvas via {@link NodeConfigBase.declaredOutputPorts}.
1078
+ * Engine defaults to `["main"]` when omitted.
1079
+ */
1080
+ outputPorts?: ReadonlyArray<OutputPortKey>;
1081
+ executeMulti(inputsByPort: NodeInputsByPort, ctx: NodeExecutionContext<TConfig>): Promise<NodeOutputs>;
1082
+ }
1083
+ type TriggerSetupStateFor<TConfig extends TriggerNodeConfig<any, any>> = TriggerNodeSetupState<TConfig>;
1084
+ interface TriggerNode<TConfig extends TriggerNodeConfig<any, any> = TriggerNodeConfig<any, any>> {
1085
+ kind: "trigger";
1086
+ outputPorts: readonly ["main"];
1087
+ setup(ctx: TriggerSetupContext<TConfig>): Promise<TriggerSetupStateFor<TConfig>>;
1088
+ execute(items: Items, ctx: NodeExecutionContext<TConfig>): Promise<NodeOutputs>;
1089
+ }
1090
+ interface TestableTriggerNode<TConfig extends TriggerNodeConfig<any, any> = TriggerNodeConfig<any, any>> extends TriggerNode<TConfig> {
1091
+ getTestItems(ctx: TriggerTestItemsContext<TConfig>): Promise<Items>;
1092
+ }
1093
+ type ExecutableTriggerNode<TConfig extends TriggerNodeConfig<any, any> = TriggerNodeConfig<any, any>> = TriggerNode<TConfig>;
1094
+ //#endregion
1095
+ //#region ../core/src/contracts/itemExpr.d.ts
1096
+ declare const ITEM_EXPR_BRAND: unique symbol;
1097
+ type ItemExprResolvedContext = Readonly<{
1098
+ runId: RunId;
1099
+ workflowId: WorkflowId;
1100
+ nodeId: NodeId;
1101
+ activationId: NodeActivationId;
1102
+ data: RunDataSnapshot;
821
1103
  }>;
822
1104
  /**
823
- * Credential type with unspecified genericsused for `CodemationConfig.credentialTypes`, the host registry,
824
- * and anywhere a concrete `CredentialType<YourPublic, YourMaterial, YourSession>` is placed in a heterogeneous list.
825
- * Using `any` here avoids unsafe `as` casts while keeping typed `satisfies CredentialType<…>` definitions.
1105
+ * Context aligned with former {@link ItemInputMapperContext} use **`data`** to read any completed upstream node.
826
1106
  */
827
- type AnyCredentialType = CredentialType<any, any, unknown>;
828
- interface CredentialSessionService {
829
- getSession<TSession = unknown>(args: Readonly<{
830
- workflowId: WorkflowId;
831
- nodeId: NodeId;
832
- slotKey: string;
833
- }>): Promise<TSession>;
834
- }
1107
+ type ItemExprContext = ItemExprResolvedContext;
1108
+ type ItemExprArgs<TItemJson = unknown> = Readonly<{
1109
+ item: Item<TItemJson>;
1110
+ itemIndex: number;
1111
+ items: Items<TItemJson>;
1112
+ ctx: ItemExprContext;
1113
+ }>;
1114
+ type ItemExprCallback<T, TItemJson = unknown> = (args: ItemExprArgs<TItemJson>) => T | Promise<T>;
1115
+ type ItemExpr<T, TItemJson = unknown> = Readonly<{
1116
+ readonly [ITEM_EXPR_BRAND]: true;
1117
+ readonly fn: ItemExprCallback<T, TItemJson>;
1118
+ }>;
1119
+ //#endregion
1120
+ //#region ../core/src/contracts/params.d.ts
1121
+ type Expr<T, TItemJson = unknown> = ItemExpr<T, TItemJson>;
1122
+ type ParamDeep<T, TItemJson = unknown> = Expr<T, TItemJson> | (T extends readonly (infer U)[] ? ReadonlyArray<ParamDeep<U, TItemJson>> : never) | (T extends object ? { [K in keyof T]: ParamDeep<T[K], TItemJson> } : T);
835
1123
  //#endregion
836
1124
  //#region ../core/src/authoring/defineNode.types.d.ts
837
1125
  type ResolvableCredentialType = AnyCredentialType | CredentialTypeId;
@@ -897,6 +1185,15 @@ type ToolExecuteArgs<TConfig extends ToolConfig = ToolConfig, TInput = unknown>
897
1185
  item: Item;
898
1186
  itemIndex: number;
899
1187
  items: Items;
1188
+ /**
1189
+ * Optional sub-agent boundary hooks: when present, the live `agent.tool.call` span and the
1190
+ * planned tool-call invocationId are forwarded so node-backed runtimes can re-root their child
1191
+ * execution scope. Plain function tools may safely ignore these hooks.
1192
+ */
1193
+ hooks?: Readonly<{
1194
+ parentSpan?: TelemetrySpanScope;
1195
+ parentInvocationId?: ConnectionInvocationId;
1196
+ }>;
900
1197
  }>;
901
1198
  type AgentMessageRole = "system" | "user" | "assistant";
902
1199
  type AgentMessageBuildArgs<TInputJson$1 = unknown> = Readonly<{
@@ -1024,6 +1321,32 @@ interface AgentNodeConfig<TInputJson$1 = unknown, TOutputJson$1 = unknown> exten
1024
1321
  readonly outputSchema?: ZodType<TOutputJson$1>;
1025
1322
  }
1026
1323
  //#endregion
1324
+ //#region ../core/src/execution/ChildExecutionScopeFactory.d.ts
1325
+ /**
1326
+ * Builds a re-rooted child execution context for sub-agent (and other deeply-nested) invocations.
1327
+ *
1328
+ * At the orchestrator's `agent.tool.call` boundary the inner runtime needs a ctx whose:
1329
+ * - `nodeId` is the tool's connection node id (so inner LLM/tool connection ids derive correctly),
1330
+ * - `activationId` is fresh (so its connection-invocation rows are uniquely identifiable),
1331
+ * - `telemetry` parents children under the tool-call span (not the orchestrator's node span),
1332
+ * - `binary` is scoped to the new (nodeId, activationId),
1333
+ * - `parentInvocationId` points back to the tool-call invocation for downstream lineage.
1334
+ *
1335
+ * Registered via factory in {@link EngineRuntimeRegistrar} so constructors stay free of parameter
1336
+ * decorators (Next/SWC and coverage tooling cannot parse them on in-repo sources).
1337
+ */
1338
+ declare class ChildExecutionScopeFactory {
1339
+ private readonly activationIdFactory;
1340
+ constructor(activationIdFactory: ActivationIdFactory);
1341
+ forSubAgent<TConfig extends RunnableNodeConfig<any, any>>(args: Readonly<{
1342
+ parentCtx: NodeExecutionContext<TConfig>;
1343
+ childNodeId: NodeId;
1344
+ childConfig: TConfig;
1345
+ parentInvocationId: ConnectionInvocationId;
1346
+ parentSpan: TelemetrySpanScope;
1347
+ }>): NodeExecutionContext<TConfig>;
1348
+ }
1349
+ //#endregion
1027
1350
  //#region ../core/src/execution/ItemExprResolver.d.ts
1028
1351
  /**
1029
1352
  * Resolves {@link import("../contracts/itemExpr").ItemExpr} leaves on runnable config before {@link RunnableNode.execute}.
@@ -1055,6 +1378,325 @@ declare class NodeOutputNormalizer {
1055
1378
  private applyOutput;
1056
1379
  }
1057
1380
  //#endregion
1381
+ //#region src/http/httpRequest.types.d.ts
1382
+ /**
1383
+ * Binary reference key into `item.binary`.
1384
+ */
1385
+ type BinaryRef = string;
1386
+ /**
1387
+ * Discriminated union for the HTTP request body.
1388
+ */
1389
+ type HttpBodySpec = Readonly<{
1390
+ kind: "none";
1391
+ }> | Readonly<{
1392
+ kind: "json";
1393
+ data: unknown;
1394
+ }> | Readonly<{
1395
+ kind: "form";
1396
+ data: Readonly<Record<string, string>>;
1397
+ }> | Readonly<{
1398
+ kind: "multipart";
1399
+ fields: Readonly<Record<string, string>>;
1400
+ binaries?: Readonly<Record<string, BinaryRef>>;
1401
+ }>;
1402
+ /**
1403
+ * Session interface that credential types implement.
1404
+ * Returns header/query deltas so the executor can merge them without
1405
+ * mutating the immutable HttpRequestSpec.
1406
+ */
1407
+ interface CredentialSession {
1408
+ applyToRequest(spec: HttpRequestSpec): HttpCredentialDelta;
1409
+ }
1410
+ /**
1411
+ * Mutations the credential session wants to apply to the outgoing request.
1412
+ */
1413
+ type HttpCredentialDelta = Readonly<{
1414
+ headers?: Readonly<Record<string, string>>;
1415
+ query?: Readonly<Record<string, string>>;
1416
+ }>;
1417
+ /**
1418
+ * Full specification of one HTTP request. All URLs are fully resolved before
1419
+ * being passed here (template substitution already applied by the caller).
1420
+ */
1421
+ type HttpRequestSpec = Readonly<{
1422
+ url: string;
1423
+ method: string;
1424
+ headers?: Readonly<Record<string, string>>;
1425
+ query?: Readonly<Record<string, string | string[]>>;
1426
+ body?: HttpBodySpec;
1427
+ credential?: CredentialSession;
1428
+ download?: Readonly<{
1429
+ mode: "auto" | "always" | "never";
1430
+ binaryName: string;
1431
+ }>;
1432
+ /** Execution context — needed for binary attach. */
1433
+ ctx: NodeExecutionContext<RunnableNodeConfig<unknown, unknown>>;
1434
+ }>;
1435
+ /**
1436
+ * Result of executing an HTTP request.
1437
+ */
1438
+ type HttpRequestResult = Readonly<{
1439
+ url: string;
1440
+ method: string;
1441
+ status: number;
1442
+ ok: boolean;
1443
+ statusText: string;
1444
+ mimeType: string;
1445
+ headers: Readonly<Record<string, string>>;
1446
+ json?: unknown;
1447
+ text?: string;
1448
+ bodyBinaryName?: string;
1449
+ }>;
1450
+ //#endregion
1451
+ //#region src/credentials/ApiKeyCredentialType.d.ts
1452
+ /**
1453
+ * API key credential that injects a key either as an HTTP header or a query parameter.
1454
+ */
1455
+ declare const apiKeyCredentialType: Readonly<{
1456
+ definition: Readonly<{
1457
+ typeId: CredentialTypeId;
1458
+ displayName: string;
1459
+ description?: string;
1460
+ publicFields?: ReadonlyArray<CredentialFieldSchema>;
1461
+ secretFields?: ReadonlyArray<CredentialFieldSchema>;
1462
+ advancedSection?: CredentialAdvancedSectionPresentation;
1463
+ supportedSourceKinds?: ReadonlyArray<CredentialMaterialSourceKind>;
1464
+ auth?: CredentialAuthDefinition;
1465
+ }>;
1466
+ createSession: CredentialSessionFactory<{
1467
+ placement: unknown;
1468
+ name: unknown;
1469
+ }, {
1470
+ apiKey: unknown;
1471
+ }, CredentialSession>;
1472
+ test: CredentialHealthTester<{
1473
+ placement: unknown;
1474
+ name: unknown;
1475
+ }, {
1476
+ apiKey: unknown;
1477
+ }>;
1478
+ }> & {
1479
+ readonly key: string;
1480
+ };
1481
+ //#endregion
1482
+ //#region src/credentials/BasicAuthCredentialType.d.ts
1483
+ /**
1484
+ * HTTP Basic authentication credential.
1485
+ * Session sets `Authorization: Basic <base64(username:password)>`.
1486
+ */
1487
+ declare const basicAuthCredentialType: Readonly<{
1488
+ definition: Readonly<{
1489
+ typeId: CredentialTypeId;
1490
+ displayName: string;
1491
+ description?: string;
1492
+ publicFields?: ReadonlyArray<CredentialFieldSchema>;
1493
+ secretFields?: ReadonlyArray<CredentialFieldSchema>;
1494
+ advancedSection?: CredentialAdvancedSectionPresentation;
1495
+ supportedSourceKinds?: ReadonlyArray<CredentialMaterialSourceKind>;
1496
+ auth?: CredentialAuthDefinition;
1497
+ }>;
1498
+ createSession: CredentialSessionFactory<{
1499
+ username: unknown;
1500
+ }, {
1501
+ password: unknown;
1502
+ }, CredentialSession>;
1503
+ test: CredentialHealthTester<{
1504
+ username: unknown;
1505
+ }, {
1506
+ password: unknown;
1507
+ }>;
1508
+ }> & {
1509
+ readonly key: string;
1510
+ };
1511
+ //#endregion
1512
+ //#region src/credentials/BearerTokenCredentialType.d.ts
1513
+ /**
1514
+ * Simple Bearer token credential.
1515
+ * Session sets `Authorization: Bearer <token>` on every request.
1516
+ */
1517
+ declare const bearerTokenCredentialType: Readonly<{
1518
+ definition: Readonly<{
1519
+ typeId: CredentialTypeId;
1520
+ displayName: string;
1521
+ description?: string;
1522
+ publicFields?: ReadonlyArray<CredentialFieldSchema>;
1523
+ secretFields?: ReadonlyArray<CredentialFieldSchema>;
1524
+ advancedSection?: CredentialAdvancedSectionPresentation;
1525
+ supportedSourceKinds?: ReadonlyArray<CredentialMaterialSourceKind>;
1526
+ auth?: CredentialAuthDefinition;
1527
+ }>;
1528
+ createSession: CredentialSessionFactory<Readonly<Record<string, unknown>>, {
1529
+ token: unknown;
1530
+ }, CredentialSession>;
1531
+ test: CredentialHealthTester<Readonly<Record<string, unknown>>, {
1532
+ token: unknown;
1533
+ }>;
1534
+ }> & {
1535
+ readonly key: string;
1536
+ };
1537
+ //#endregion
1538
+ //#region src/credentials/OAuth2ClientCredentialsTypeFactory.d.ts
1539
+ /**
1540
+ * OAuth2 client-credentials flow credential.
1541
+ *
1542
+ * This is a machine-to-machine flow: no user redirect occurs. The session
1543
+ * POSTs to the configured `tokenUrl` with `client_credentials` grant, caches
1544
+ * the resulting access token for the duration of the session, and injects it
1545
+ * as `Authorization: Bearer <token>` on each request.
1546
+ *
1547
+ * Token caching is per-session only (one createSession call = one token fetch
1548
+ * at most). Cross-session caching would require host-level state and is out of
1549
+ * scope here. Because the engine creates a fresh session per execution, a new
1550
+ * token is fetched once per node activation.
1551
+ *
1552
+ * NOTE: `auth` is intentionally omitted from the definition. The OAuth2
1553
+ * `auth: { kind: "oauth2" }` shape signals an authorization-code / user-redirect
1554
+ * flow; using it here would cause the host UI to render an OAuth consent button
1555
+ * that goes nowhere. Client-credentials is a purely server-side flow.
1556
+ */
1557
+ declare const oauth2ClientCredentialsType: Readonly<{
1558
+ definition: Readonly<{
1559
+ typeId: CredentialTypeId;
1560
+ displayName: string;
1561
+ description?: string;
1562
+ publicFields?: ReadonlyArray<CredentialFieldSchema>;
1563
+ secretFields?: ReadonlyArray<CredentialFieldSchema>;
1564
+ advancedSection?: CredentialAdvancedSectionPresentation;
1565
+ supportedSourceKinds?: ReadonlyArray<CredentialMaterialSourceKind>;
1566
+ auth?: CredentialAuthDefinition;
1567
+ }>;
1568
+ createSession: CredentialSessionFactory<{
1569
+ tokenUrl: unknown;
1570
+ scopes: unknown;
1571
+ audience: unknown;
1572
+ }, {
1573
+ clientId: unknown;
1574
+ clientSecret: unknown;
1575
+ }, CredentialSession>;
1576
+ test: CredentialHealthTester<{
1577
+ tokenUrl: unknown;
1578
+ scopes: unknown;
1579
+ audience: unknown;
1580
+ }, {
1581
+ clientId: unknown;
1582
+ clientSecret: unknown;
1583
+ }>;
1584
+ }> & {
1585
+ readonly key: string;
1586
+ };
1587
+ //#endregion
1588
+ //#region src/authoring/defineRestNode.types.d.ts
1589
+ type MaybePromise<T> = T | Promise<T>;
1590
+ /**
1591
+ * API endpoint descriptor.
1592
+ */
1593
+ type RestNodeApi = Readonly<{
1594
+ /**
1595
+ * Base URL, e.g. `"https://api.slack.com"`.
1596
+ */
1597
+ baseUrl: string;
1598
+ /**
1599
+ * Path relative to `baseUrl`. May contain `{paramName}` placeholders that
1600
+ * are substituted from `input` keys before the request is made.
1601
+ * Example: `"/users/{userId}/profile"`
1602
+ */
1603
+ path: string;
1604
+ /** HTTP method (default: GET). */
1605
+ method?: string;
1606
+ }>;
1607
+ /**
1608
+ * The HTTP result shape passed into the `response` mapper.
1609
+ */
1610
+ type RestNodeResponseContext = Readonly<{
1611
+ status: number;
1612
+ ok: boolean;
1613
+ statusText: string;
1614
+ mimeType: string;
1615
+ headers: Readonly<Record<string, string>>;
1616
+ json?: unknown;
1617
+ text?: string;
1618
+ }>;
1619
+ /**
1620
+ * What the `request` callback may return to customise the request.
1621
+ */
1622
+ type RestNodeRequestShape = Readonly<{
1623
+ /** Additional path parameters to substitute (merged with `input`). */
1624
+ pathParams?: Readonly<Record<string, string>>;
1625
+ /** Extra query params. */
1626
+ query?: Readonly<Record<string, string>>;
1627
+ /** Extra headers. */
1628
+ headers?: Readonly<Record<string, string>>;
1629
+ /** Request body. */
1630
+ body?: HttpBodySpec;
1631
+ }>;
1632
+ /**
1633
+ * Error handling policy for non-2xx responses.
1634
+ * - `"throw"` (default) — throws an `Error` for non-2xx responses.
1635
+ * - `"passthrough"` — returns the result regardless of status.
1636
+ */
1637
+ type RestNodeErrorPolicy = "throw" | "passthrough";
1638
+ interface DefineRestNodeOptions<TKey$1 extends string, TCredentials extends DefinedNodeCredentialBindings | undefined, TInputJson$1, TOutputJson$1> {
1639
+ readonly key: TKey$1;
1640
+ readonly title: string;
1641
+ readonly description?: string;
1642
+ readonly icon?: string;
1643
+ readonly api: RestNodeApi;
1644
+ /**
1645
+ * Credential bindings keyed by slot. Use the built-in credential types from
1646
+ * `@codemation/core-nodes` (e.g. `bearerTokenCredentialType`) or any custom one.
1647
+ * The slot key must match what the `request` callback's context uses.
1648
+ */
1649
+ readonly credentials?: TCredentials;
1650
+ /**
1651
+ * Zod schema for per-item input. Validated before `execute`.
1652
+ */
1653
+ readonly inputSchema?: ZodType<TInputJson$1>;
1654
+ /**
1655
+ * Builds the per-request customisations from the item input.
1656
+ * Return `body`, `query`, `headers`, and/or `pathParams`.
1657
+ */
1658
+ request?(context: Readonly<{
1659
+ input: TInputJson$1;
1660
+ }>): MaybePromise<RestNodeRequestShape>;
1661
+ /**
1662
+ * Maps the HTTP response to the node's output JSON.
1663
+ * When omitted, the output is `{ status, ok, statusText, mimeType, headers, json, text }`.
1664
+ */
1665
+ response?(context: RestNodeResponseContext & Readonly<{
1666
+ input: TInputJson$1;
1667
+ }>): MaybePromise<TOutputJson$1>;
1668
+ /**
1669
+ * How to handle non-2xx responses.
1670
+ * @default "throw"
1671
+ */
1672
+ readonly errorPolicy?: RestNodeErrorPolicy;
1673
+ }
1674
+ /**
1675
+ * Declarative helper for creating thin API-wrapper nodes.
1676
+ *
1677
+ * Usage:
1678
+ * ```ts
1679
+ * export const postMessage = defineRestNode({
1680
+ * key: "slack.post-message",
1681
+ * title: "Send Slack message",
1682
+ * icon: "si:slack",
1683
+ * api: { baseUrl: "https://slack.com/api", path: "/chat.postMessage", method: "POST" },
1684
+ * credentials: { auth: bearerTokenCredentialType },
1685
+ * inputSchema: z.object({ channel: z.string(), text: z.string() }),
1686
+ * request: ({ input }) => ({
1687
+ * body: { kind: "json", data: { channel: input.channel, text: input.text } },
1688
+ * }),
1689
+ * response: ({ json }) => ({ messageTs: (json as any).ts }),
1690
+ * });
1691
+ * ```
1692
+ *
1693
+ * - `defineRestNode` is a thin wrapper over `defineNode`; it does not introduce a new runtime kind.
1694
+ * - Credential sessions are resolved via the `credentials` binding map (same as `defineNode`).
1695
+ * - Path `{placeholder}` substitution is applied from `input` keys before the request is made.
1696
+ * - Non-2xx responses throw an `Error` by default (`errorPolicy: "throw"`).
1697
+ */
1698
+ declare function defineRestNode<TKey$1 extends string, TCredentials extends DefinedNodeCredentialBindings | undefined, TInputJson$1, TOutputJson$1 = RestNodeResponseContext>(options: DefineRestNodeOptions<TKey$1, TCredentials, TInputJson$1, TOutputJson$1>): DefinedNode<TKey$1, Record<string, never>, TInputJson$1, TOutputJson$1, TCredentials>;
1699
+ //#endregion
1058
1700
  //#region src/chatModels/openAiChatModelConfig.d.ts
1059
1701
  declare class OpenAIChatModelConfig implements ChatModelConfig {
1060
1702
  readonly name: string;
@@ -1205,19 +1847,31 @@ type ResolvedTool = Readonly<{
1205
1847
  }>;
1206
1848
  /**
1207
1849
  * Per-item binding of a tool: the user config plus the resolved runtime and a snapshot of the
1208
- * original Zod `inputSchema` used to convert to AI SDK `Tool` + OpenAI-strict JSON Schema for
1209
- * repair prompts.
1850
+ * original Zod `inputSchema`.
1851
+ *
1852
+ * `execute` accepts optional `hooks` so the agent coordinator can pass the live `agent.tool.call`
1853
+ * span and the planned tool-call's `invocationId`. Node-backed sub-agent tools use these hooks
1854
+ * via {@link ChildExecutionScopeFactory} to re-root their runtime ctx under the tool-call boundary
1855
+ * (fresh activationId, telemetry parented at the tool-call span, `parentInvocationId` set).
1210
1856
  */
1211
1857
  type ItemScopedToolBinding = Readonly<{
1212
1858
  config: ToolConfig;
1213
1859
  inputSchema: ZodSchemaAny;
1214
- execute(input: unknown): Promise<unknown>;
1860
+ execute(input: unknown, hooks?: ItemScopedToolCallHooks): Promise<unknown>;
1861
+ }>;
1862
+ type ItemScopedToolCallHooks = Readonly<{
1863
+ /** Live agent.tool.call span (used to parent sub-agent telemetry). */
1864
+ parentSpan?: TelemetrySpanScope;
1865
+ /** invocationId of the parent tool call (used to thread `parentInvocationId` through ctx). */
1866
+ parentInvocationId?: ConnectionInvocationId;
1215
1867
  }>;
1216
1868
  type PlannedToolCall = Readonly<{
1217
1869
  binding: ItemScopedToolBinding;
1218
1870
  toolCall: AgentToolCall;
1219
1871
  invocationIndex: number;
1220
1872
  nodeId: string;
1873
+ /** Stable id reused across queued / running / completed connection invocation rows for this tool call. */
1874
+ invocationId: string;
1221
1875
  }>;
1222
1876
  type ExecutedToolCall = Readonly<{
1223
1877
  toolName: string;
@@ -1442,8 +2096,24 @@ declare class NodeBackedToolRuntime {
1442
2096
  private readonly itemExprResolver;
1443
2097
  private readonly outputNormalizer;
1444
2098
  private readonly outputBehaviorResolver;
1445
- constructor(nodeResolver: NodeResolver, itemExprResolver: ItemExprResolver, outputNormalizer: NodeOutputNormalizer, outputBehaviorResolver: RunnableOutputBehaviorResolver);
2099
+ private readonly childExecutionScopeFactory;
2100
+ constructor(nodeResolver: NodeResolver, itemExprResolver: ItemExprResolver, outputNormalizer: NodeOutputNormalizer, outputBehaviorResolver: RunnableOutputBehaviorResolver, childExecutionScopeFactory: ChildExecutionScopeFactory);
1446
2101
  execute(config: NodeBackedToolConfig<any, ZodSchemaAny, ZodSchemaAny>, args: ToolExecuteArgs): Promise<unknown>;
2102
+ /**
2103
+ * Returns a re-rooted child ctx for nested-agent tools (so their LLM/tool connection ids derive
2104
+ * from the tool connection node, telemetry parents under the tool-call span, and connection
2105
+ * invocations carry `parentInvocationId`). Plain runnable tools (non-agent) keep the orchestrator
2106
+ * ctx with only `config` swapped — no nesting concern.
2107
+ *
2108
+ * The caller (`AIAgentNode.createItemScopedTools`) already wraps the orchestrator ctx via
2109
+ * `ConnectionCredentialExecutionContextFactory.forConnectionNode`, so `args.ctx.nodeId` is the
2110
+ * tool's own connection node id (e.g. `AIAgentNode:2__conn__tool__searchInMail`). We pass that
2111
+ * through as the sub-agent's `nodeId`; deriving another `toolConnectionNodeId(args.ctx.nodeId,
2112
+ * config.name)` here would prepend a duplicate `__conn__tool__<name>` segment and exponentially
2113
+ * deepen ids on each invocation, which also breaks credential resolution because user-provided
2114
+ * bindings sit on the single-level connection node id.
2115
+ */
2116
+ private resolveNodeCtx;
1447
2117
  private executeResolvedNode;
1448
2118
  private isRunnableNode;
1449
2119
  private isMultiInputNode;
@@ -1510,6 +2180,14 @@ declare class AIAgentNode implements RunnableNode<AIAgent<any, any>> {
1510
2180
  private invokeStructuredTurn;
1511
2181
  private isZodSchema;
1512
2182
  private resolveCallOptions;
2183
+ /**
2184
+ * Build a no-code-friendly output payload for an LLM round.
2185
+ *
2186
+ * Always includes `content` (matching the canvas snapshot shape used elsewhere) and adds a
2187
+ * `toolCalls` array when the round produced tool calls so the execution inspector surfaces the
2188
+ * planned calls instead of just an empty `""` for tool-only rounds.
2189
+ */
2190
+ private summarizeTurnOutput;
1513
2191
  private extractTurnResult;
1514
2192
  private extractAssistantMessage;
1515
2193
  private extractUsageFromResult;
@@ -1532,6 +2210,52 @@ declare class AIAgentNode implements RunnableNode<AIAgent<any, any>> {
1532
2210
  private extractErrorDetails;
1533
2211
  }
1534
2212
  //#endregion
2213
+ //#region src/nodes/AssertionNode.d.ts
2214
+ /**
2215
+ * Runs the author's `assertions` callback for each input item and emits one workflow `Item` per
2216
+ * returned {@link AssertionResult} on `main`. Persistence is handled by a host-side subscriber
2217
+ * to `nodeCompleted` events that filters on `config.emitsAssertions === true`; this node does
2218
+ * not write to any store on its own.
2219
+ *
2220
+ * If the author callback throws, we emit a single synthetic AssertionResult with `errored: true`
2221
+ * and `score: 0`. Without this catch the whole node would fail and no assertion row would be
2222
+ * persisted — making the rollup blind to "the assertion code itself is broken." The synthetic
2223
+ * row keeps `failedAssertionsByRunId` consistent and gives the UI something to surface.
2224
+ */
2225
+ declare class AssertionNode implements RunnableNode<Assertion<any>> {
2226
+ kind: "node";
2227
+ outputPorts: readonly ["main"];
2228
+ execute(args: RunnableNodeExecuteArgs<Assertion<any>>): Promise<unknown>;
2229
+ }
2230
+ //#endregion
2231
+ //#region src/nodes/assertion.d.ts
2232
+ interface AssertionOptions<TInputJson$1> {
2233
+ readonly name?: string;
2234
+ readonly id?: string;
2235
+ readonly icon?: string;
2236
+ /**
2237
+ * Author callback. Returns one or more {@link AssertionResult}s per input item. Each becomes
2238
+ * one emitted output item — useful for per-row reporting in the Tests tab. Return `[]` to
2239
+ * emit nothing for this case (rare; usually you want at least a "no-op" pass).
2240
+ */
2241
+ assertions(item: Item<TInputJson$1>, ctx: NodeExecutionContext<Assertion<TInputJson$1>>): Promise<ReadonlyArray<AssertionResult>> | ReadonlyArray<AssertionResult>;
2242
+ }
2243
+ /**
2244
+ * Generic assertion node — the "callback" form. For declarative shorthands (StringEquals,
2245
+ * JudgeByAgent) compose this with helpers added in later phases. Sets `emitsAssertions: true`
2246
+ * so host-side persisters know to record its outputs as `TestAssertion` rows.
2247
+ */
2248
+ declare class Assertion<TInputJson$1 = unknown> implements RunnableNodeConfig<TInputJson$1, AssertionResult> {
2249
+ readonly kind: "node";
2250
+ readonly type: TypeToken<unknown>;
2251
+ readonly icon: string;
2252
+ readonly name: string;
2253
+ readonly id?: string;
2254
+ readonly emitsAssertions: true;
2255
+ readonly assertions: AssertionOptions<TInputJson$1>["assertions"];
2256
+ constructor(options: AssertionOptions<TInputJson$1>);
2257
+ }
2258
+ //#endregion
1535
2259
  //#region src/nodes/CallbackNode.d.ts
1536
2260
  declare class CallbackNode implements RunnableNode<Callback<any, any>> {
1537
2261
  kind: "node";
@@ -1576,10 +2300,12 @@ declare class HttpRequestNode implements RunnableNode<HttpRequest<any, any>> {
1576
2300
  readonly outputPorts: readonly ["main"];
1577
2301
  execute(args: RunnableNodeExecuteArgs<HttpRequest<any, any>>): Promise<unknown>;
1578
2302
  private executeItem;
2303
+ private resolveCredential;
1579
2304
  private resolveUrl;
1580
2305
  private asRecord;
1581
2306
  private readHeaders;
1582
2307
  private resolveMimeType;
2308
+ private isJsonMimeType;
1583
2309
  private shouldAttachBody;
1584
2310
  private resolveFilename;
1585
2311
  private readFilenameFromContentDisposition;
@@ -1596,15 +2322,41 @@ type HttpRequestOutputJson = Readonly<{
1596
2322
  statusText: string;
1597
2323
  mimeType: string;
1598
2324
  headers: Readonly<Record<string, string>>;
2325
+ json?: unknown;
2326
+ text?: string;
1599
2327
  bodyBinaryName?: string;
1600
2328
  }>;
2329
+ /**
2330
+ * The built-in HTTP request credential type IDs accepted by the `HttpRequest` node.
2331
+ * These match the four generic credential types shipped with `@codemation/core-nodes`.
2332
+ */
2333
+ declare const HTTP_REQUEST_ACCEPTED_CREDENTIAL_TYPES: ReadonlyArray<string>;
1601
2334
  declare class HttpRequest<TInputJson$1 = Readonly<{
1602
2335
  url?: string;
1603
2336
  }>, TOutputJson$1 = HttpRequestOutputJson> implements RunnableNodeConfig<TInputJson$1, TOutputJson$1> {
1604
2337
  readonly name: string;
1605
2338
  readonly args: Readonly<{
2339
+ /** HTTP method (default: GET). */
1606
2340
  method?: string;
2341
+ /**
2342
+ * Legacy: field name on item.json to read the URL from.
2343
+ * Use `url` for a literal/templated URL instead.
2344
+ */
1607
2345
  urlField?: string;
2346
+ /** Literal or templated URL. When present, takes precedence over `urlField`. */
2347
+ url?: string;
2348
+ /** Extra headers to add to every request. */
2349
+ headers?: Readonly<Record<string, string>>;
2350
+ /** Query parameters to append to the URL. */
2351
+ query?: Readonly<Record<string, string>>;
2352
+ /** Request body specification. For canvas use, pass a JSON string in `body.data`. */
2353
+ body?: HttpBodySpec;
2354
+ /**
2355
+ * Credential slot key. When set, the node resolves a credential via
2356
+ * `ctx.getCredential(credentialSlot)` and applies it to the request.
2357
+ * The slot must be declared in `getCredentialRequirements()`.
2358
+ */
2359
+ credentialSlot?: string;
1608
2360
  binaryName?: string;
1609
2361
  downloadMode?: HttpRequestDownloadMode;
1610
2362
  id?: string;
@@ -1617,8 +2369,27 @@ declare class HttpRequest<TInputJson$1 = Readonly<{
1617
2369
  };
1618
2370
  readonly icon: "lucide:globe";
1619
2371
  constructor(name: string, args?: Readonly<{
2372
+ /** HTTP method (default: GET). */
1620
2373
  method?: string;
2374
+ /**
2375
+ * Legacy: field name on item.json to read the URL from.
2376
+ * Use `url` for a literal/templated URL instead.
2377
+ */
1621
2378
  urlField?: string;
2379
+ /** Literal or templated URL. When present, takes precedence over `urlField`. */
2380
+ url?: string;
2381
+ /** Extra headers to add to every request. */
2382
+ headers?: Readonly<Record<string, string>>;
2383
+ /** Query parameters to append to the URL. */
2384
+ query?: Readonly<Record<string, string>>;
2385
+ /** Request body specification. For canvas use, pass a JSON string in `body.data`. */
2386
+ body?: HttpBodySpec;
2387
+ /**
2388
+ * Credential slot key. When set, the node resolves a credential via
2389
+ * `ctx.getCredential(credentialSlot)` and applies it to the request.
2390
+ * The slot must be declared in `getCredentialRequirements()`.
2391
+ */
2392
+ credentialSlot?: string;
1622
2393
  binaryName?: string;
1623
2394
  downloadMode?: HttpRequestDownloadMode;
1624
2395
  id?: string;
@@ -1628,6 +2399,7 @@ declare class HttpRequest<TInputJson$1 = Readonly<{
1628
2399
  get urlField(): string;
1629
2400
  get binaryName(): string;
1630
2401
  get downloadMode(): HttpRequestDownloadMode;
2402
+ getCredentialRequirements(): ReadonlyArray<CredentialRequirement>;
1631
2403
  }
1632
2404
  //#endregion
1633
2405
  //#region src/nodes/AggregateNode.d.ts
@@ -1694,6 +2466,38 @@ declare class If<TInputJson$1 = unknown> implements RunnableNodeConfig<TInputJso
1694
2466
  constructor(name: string, predicate: (item: Item<TInputJson$1>, index: number, items: Items<TInputJson$1>, ctx: NodeExecutionContext<If<TInputJson$1>>) => boolean, id?: string | undefined);
1695
2467
  }
1696
2468
  //#endregion
2469
+ //#region src/nodes/IsTestRunNode.d.ts
2470
+ /**
2471
+ * Routes each item to the `true` port if `ctx.testContext` is set (the run was started by the
2472
+ * TestSuiteOrchestrator), else to `false`. Lets workflow authors guard real side-effects:
2473
+ *
2474
+ * GmailTrigger / TestTrigger → ClassifyAgent → IsTestRun
2475
+ * ├── true → AssertionNode
2476
+ * └── false → SendReply
2477
+ */
2478
+ declare class IsTestRunNode implements RunnableNode<IsTestRun<unknown>> {
2479
+ kind: "node";
2480
+ execute(args: RunnableNodeExecuteArgs<IsTestRun<unknown>>): unknown;
2481
+ }
2482
+ //#endregion
2483
+ //#region src/nodes/isTestRun.d.ts
2484
+ /**
2485
+ * Branches per-item on whether the current run is a test run. Output ports: `true`, `false`.
2486
+ * The wire payload is unchanged — this is a router, not a transform.
2487
+ */
2488
+ declare class IsTestRun<TInputJson$1 = unknown> implements RunnableNodeConfig<TInputJson$1, TInputJson$1> {
2489
+ readonly kind: "node";
2490
+ readonly type: TypeToken<unknown>;
2491
+ readonly execution: {
2492
+ readonly hint: "local";
2493
+ };
2494
+ readonly icon: "lucide:flask-conical";
2495
+ readonly declaredOutputPorts: readonly ["true", "false"];
2496
+ readonly name: string;
2497
+ readonly id?: string;
2498
+ constructor(name?: string, id?: string);
2499
+ }
2500
+ //#endregion
1697
2501
  //#region src/nodes/SwitchNode.d.ts
1698
2502
  /**
1699
2503
  * Routes each item to exactly one output port. Port names must match workflow edges (see {@link Switch} config).
@@ -1754,6 +2558,45 @@ declare class Split<TIn = unknown, TElem = unknown> implements RunnableNodeConfi
1754
2558
  constructor(name: string, getElements: (item: Item<TIn>, ctx: NodeExecutionContext<Split<TIn, TElem>>) => readonly TElem[], id?: string | undefined);
1755
2559
  }
1756
2560
  //#endregion
2561
+ //#region src/nodes/CronTriggerFactory.d.ts
2562
+ type CronTickJson = {
2563
+ firedAt: string;
2564
+ scheduledFor: string;
2565
+ };
2566
+ /**
2567
+ * Schedules a workflow on a standard cron expression.
2568
+ *
2569
+ * Each tick emits one item: `{ firedAt: string, scheduledFor: string }` — both ISO-8601 timestamps.
2570
+ * `firedAt` is the wall-clock moment the callback ran; `scheduledFor` is the cron-computed
2571
+ * firing instant (these differ when the job was delayed).
2572
+ *
2573
+ * Timezone defaults to UTC when omitted — cron without an explicit TZ is a DST footgun.
2574
+ */
2575
+ declare class CronTrigger implements TriggerNodeConfig<CronTickJson> {
2576
+ readonly name: string;
2577
+ private readonly args;
2578
+ readonly kind: "trigger";
2579
+ readonly type: TypeToken<unknown>;
2580
+ readonly icon: "lucide:clock";
2581
+ readonly id?: string;
2582
+ constructor(name: string, args: Readonly<{
2583
+ schedule: string;
2584
+ timezone?: string;
2585
+ }>, id?: string);
2586
+ get schedule(): string;
2587
+ get timezone(): string | undefined;
2588
+ createJob(callback: CronCallback): Cron;
2589
+ }
2590
+ //#endregion
2591
+ //#region src/nodes/CronTriggerNode.d.ts
2592
+ declare class CronTriggerNode implements TestableTriggerNode<CronTrigger> {
2593
+ readonly kind: "trigger";
2594
+ readonly outputPorts: readonly ["main"];
2595
+ setup(ctx: TriggerSetupContext<CronTrigger>): Promise<undefined>;
2596
+ execute(items: Items, _ctx: NodeExecutionContext<CronTrigger>): Promise<NodeOutputs>;
2597
+ getTestItems(ctx: TriggerTestItemsContext<CronTrigger>): Promise<Items>;
2598
+ }
2599
+ //#endregion
1757
2600
  //#region src/nodes/ManualTriggerNode.d.ts
1758
2601
  /**
1759
2602
  * Setup is intentionally a no-op: the engine host can run workflows manually
@@ -1894,6 +2737,71 @@ declare class SubWorkflow<TInputJson$1 = unknown, TOutputJson$1 = unknown> imple
1894
2737
  } | UpstreamRefPlaceholder> | undefined, startAt?: NodeId | undefined, id?: string | undefined);
1895
2738
  }
1896
2739
  //#endregion
2740
+ //#region src/nodes/TestTriggerNode.d.ts
2741
+ /**
2742
+ * Author-defined test-fixture trigger. Live activation skips this trigger (filtered by
2743
+ * `triggerKind === "test"` in `TriggerRuntimeService`); the `TestSuiteOrchestrator` drives its
2744
+ * `generateItems` callback during a TestSuiteRun and dispatches one workflow run per yielded item.
2745
+ *
2746
+ * `setup` is intentionally a no-op for symmetry with other trigger nodes — the real work happens
2747
+ * in the orchestrator. `execute` is a passthrough so items provided to `engine.runWorkflow(...)`
2748
+ * (one per case) flow downstream unchanged on `main`.
2749
+ */
2750
+ declare class TestTriggerNode implements TriggerNode<TestTriggerNodeConfig<any>> {
2751
+ kind: "trigger";
2752
+ outputPorts: readonly ["main"];
2753
+ setup(_ctx: TriggerSetupContext<TestTriggerNodeConfig<any>>): Promise<undefined>;
2754
+ execute(items: Items, _ctx: NodeExecutionContext<TestTriggerNodeConfig<any>>): Promise<NodeOutputs>;
2755
+ }
2756
+ //#endregion
2757
+ //#region src/nodes/testTrigger.d.ts
2758
+ interface TestTriggerOptions<TOutputJson$1> {
2759
+ readonly name?: string;
2760
+ readonly id?: string;
2761
+ readonly icon?: string;
2762
+ /** Cap on simultaneous in-flight test cases for one suite run. Default: 4 (orchestrator). */
2763
+ readonly concurrency?: number;
2764
+ readonly credentialRequirements?: ReadonlyArray<CredentialRequirement>;
2765
+ /**
2766
+ * Free-form description of where the test cases come from. Shown in the node properties
2767
+ * panel and the Tests-tab suite-detail header so authors revisiting the workflow six months
2768
+ * later remember which mailbox / folder / fixture file the cases originate from.
2769
+ */
2770
+ readonly description?: string;
2771
+ /**
2772
+ * Author callback that yields one item per test case. Items are dispatched as separate
2773
+ * workflow runs by the TestSuiteOrchestrator, with `executionOptions.testContext` set.
2774
+ * The provided context exposes credential resolution and an AbortSignal for cancellation.
2775
+ */
2776
+ generateItems(ctx: TestTriggerSetupContext<TestTrigger<TOutputJson$1>>): AsyncIterable<Item<TOutputJson$1>>;
2777
+ /**
2778
+ * Optional resolver: extract a human-readable label from a yielded item. The orchestrator
2779
+ * persists this on the run, so the Tests-tab tree-table shows e.g. "RFQ for batch 14"
2780
+ * instead of an opaque runId. Typical use: `(item) => item.json.subject` for mailbox tests.
2781
+ */
2782
+ caseLabel?(item: Item<TOutputJson$1>): string | undefined;
2783
+ }
2784
+ /**
2785
+ * Trigger config for a test fixture source. Drop one (or more) of these on the canvas alongside
2786
+ * a workflow's live triggers; clicking "Run tests" on the Tests tab invokes
2787
+ * {@link TestTriggerOptions.generateItems} via the TestSuiteOrchestrator.
2788
+ */
2789
+ declare class TestTrigger<TOutputJson$1 = unknown> implements TestTriggerNodeConfig<TOutputJson$1> {
2790
+ readonly kind: "trigger";
2791
+ readonly triggerKind: "test";
2792
+ readonly type: TypeToken<unknown>;
2793
+ readonly icon: string;
2794
+ readonly name: string;
2795
+ readonly id?: string;
2796
+ readonly concurrency?: number;
2797
+ readonly description?: string;
2798
+ readonly generateItems: TestTriggerOptions<TOutputJson$1>["generateItems"];
2799
+ readonly caseLabel?: TestTriggerOptions<TOutputJson$1>["caseLabel"];
2800
+ private readonly credentialRequirements;
2801
+ constructor(options: TestTriggerOptions<TOutputJson$1>);
2802
+ getCredentialRequirements(): ReadonlyArray<CredentialRequirement>;
2803
+ }
2804
+ //#endregion
1897
2805
  //#region src/nodes/WaitDurationFactory.d.ts
1898
2806
  declare class WaitDuration {
1899
2807
  static normalize(milliseconds: number): number;
@@ -2138,5 +3046,67 @@ declare class AIAgentConnectionWorkflowExpander {
2138
3046
  private assertNoIdCollision;
2139
3047
  }
2140
3048
  //#endregion
2141
- export { AIAgent, AIAgentConnectionWorkflowExpander, AIAgentExecutionHelpersFactory, AIAgentNode, AgentItemPortMap, AgentMessageFactory, AgentOutputFactory, AgentStructuredOutputRepairPromptFactory, AgentStructuredOutputRunner, AgentToolCallPortMap, AgentToolErrorClassifier, AgentToolExecutionCoordinator, AgentToolRepairExhaustedError, AgentToolRepairPolicy, Aggregate, AggregateNode, Callback, CallbackHandler, CallbackNode, CallbackOptions, CallbackResultNormalizer, CanvasIconName, ConnectionCredentialExecutionContextFactory, ConnectionCredentialNode, ConnectionCredentialNodeConfig, ConnectionCredentialNodeConfigFactory, ExecutedToolCall, Filter, FilterNode, HttpRequest, HttpRequestDownloadMode, HttpRequestNode, HttpRequestOutputJson, If, IfNode, ItemScopedToolBinding, ManualTrigger, ManualTriggerNode, MapData, MapDataNode, MapDataOptions, Merge, MergeMode, MergeNode, NoOp, NoOpNode, OpenAIChatModelConfig, OpenAIChatModelFactory, OpenAiChatModelPresets, OpenAiCredentialSession, OpenAiStrictJsonSchemaFactory, PlannedToolCall, ResolvedTool, Split, SplitNode, SubWorkflow, SubWorkflowNode, Switch, SwitchCaseKeyResolver, SwitchNode, Wait, WaitDuration, WaitNode, WebhookRespondNowAndContinueError, WebhookRespondNowError, WebhookTrigger, WebhookTriggerNode, type WorkflowAgentMessages, type WorkflowAgentOptions, WorkflowAuthoringBuilder, WorkflowBranchBuilder, WorkflowChain, createWorkflowBuilder, openAiChatModelPresets, registerCoreNodes, workflow };
3049
+ //#region src/nodes/collections/collectionInsertNode.types.d.ts
3050
+ declare const collectionInsertNode: DefinedNode<"collection-insert", {
3051
+ collectionName: string;
3052
+ data: Record<string, unknown>;
3053
+ }, unknown, Record<string, unknown> & {
3054
+ id: string;
3055
+ created_at: Date;
3056
+ updated_at: Date;
3057
+ }, undefined>;
3058
+ //#endregion
3059
+ //#region src/nodes/collections/collectionGetNode.types.d.ts
3060
+ declare const collectionGetNode: DefinedNode<"collection-get", {
3061
+ collectionName: string;
3062
+ id: string;
3063
+ }, unknown, never[] | (Record<string, unknown> & {
3064
+ id: string;
3065
+ created_at: Date;
3066
+ updated_at: Date;
3067
+ }), undefined>;
3068
+ //#endregion
3069
+ //#region src/nodes/collections/collectionFindOneNode.types.d.ts
3070
+ declare const collectionFindOneNode: DefinedNode<"collection-find-one", {
3071
+ collectionName: string;
3072
+ where: Record<string, unknown>;
3073
+ }, unknown, never[] | (Record<string, unknown> & {
3074
+ id: string;
3075
+ created_at: Date;
3076
+ updated_at: Date;
3077
+ }), undefined>;
3078
+ //#endregion
3079
+ //#region src/nodes/collections/collectionListNode.types.d.ts
3080
+ declare const collectionListNode: DefinedNode<"collection-list", {
3081
+ collectionName: string;
3082
+ limit?: number | undefined;
3083
+ offset?: number | undefined;
3084
+ where?: Record<string, unknown> | undefined;
3085
+ }, unknown, (Record<string, unknown> & {
3086
+ id: string;
3087
+ created_at: Date;
3088
+ updated_at: Date;
3089
+ })[], undefined>;
3090
+ //#endregion
3091
+ //#region src/nodes/collections/collectionUpdateNode.types.d.ts
3092
+ declare const collectionUpdateNode: DefinedNode<"collection-update", {
3093
+ collectionName: string;
3094
+ id: string;
3095
+ patch: Record<string, unknown>;
3096
+ }, unknown, Record<string, unknown> & {
3097
+ id: string;
3098
+ created_at: Date;
3099
+ updated_at: Date;
3100
+ }, undefined>;
3101
+ //#endregion
3102
+ //#region src/nodes/collections/collectionDeleteNode.types.d.ts
3103
+ declare const collectionDeleteNode: DefinedNode<"collection-delete", {
3104
+ collectionName: string;
3105
+ id: string;
3106
+ }, unknown, {
3107
+ deleted: boolean;
3108
+ id: string;
3109
+ }, undefined>;
3110
+ //#endregion
3111
+ export { AIAgent, AIAgentConnectionWorkflowExpander, AIAgentExecutionHelpersFactory, AIAgentNode, AgentItemPortMap, AgentMessageFactory, AgentOutputFactory, AgentStructuredOutputRepairPromptFactory, AgentStructuredOutputRunner, AgentToolCallPortMap, AgentToolErrorClassifier, AgentToolExecutionCoordinator, AgentToolRepairExhaustedError, AgentToolRepairPolicy, Aggregate, AggregateNode, Assertion, AssertionNode, AssertionOptions, BinaryRef, Callback, CallbackHandler, CallbackNode, CallbackOptions, CallbackResultNormalizer, CanvasIconName, ConnectionCredentialExecutionContextFactory, ConnectionCredentialNode, ConnectionCredentialNodeConfig, ConnectionCredentialNodeConfigFactory, CredentialSession, CronTickJson, CronTrigger, CronTriggerNode, DefineRestNodeOptions, ExecutedToolCall, Filter, FilterNode, HTTP_REQUEST_ACCEPTED_CREDENTIAL_TYPES, HttpBodySpec, HttpCredentialDelta, HttpRequest, HttpRequestDownloadMode, HttpRequestNode, HttpRequestOutputJson, HttpRequestResult, HttpRequestSpec, If, IfNode, IsTestRun, IsTestRunNode, ItemScopedToolBinding, ManualTrigger, ManualTriggerNode, MapData, MapDataNode, MapDataOptions, Merge, MergeMode, MergeNode, NoOp, NoOpNode, OpenAIChatModelConfig, OpenAIChatModelFactory, OpenAiChatModelPresets, OpenAiCredentialSession, OpenAiStrictJsonSchemaFactory, PlannedToolCall, ResolvedTool, RestNodeApi, RestNodeErrorPolicy, RestNodeRequestShape, RestNodeResponseContext, Split, SplitNode, SubWorkflow, SubWorkflowNode, Switch, SwitchCaseKeyResolver, SwitchNode, TestTrigger, TestTriggerNode, TestTriggerOptions, Wait, WaitDuration, WaitNode, WebhookRespondNowAndContinueError, WebhookRespondNowError, WebhookTrigger, WebhookTriggerNode, type WorkflowAgentMessages, type WorkflowAgentOptions, WorkflowAuthoringBuilder, WorkflowBranchBuilder, WorkflowChain, apiKeyCredentialType, basicAuthCredentialType, bearerTokenCredentialType, collectionDeleteNode, collectionFindOneNode, collectionGetNode, collectionInsertNode, collectionListNode, collectionUpdateNode, createWorkflowBuilder, defineRestNode, oauth2ClientCredentialsType, openAiChatModelPresets, registerCoreNodes, workflow };
2142
3112
  //# sourceMappingURL=index.d.cts.map