@codemation/core-nodes 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/index.cjs +34 -433
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +95 -1312
- package/dist/index.d.ts +95 -1312
- package/dist/index.js +35 -435
- package/dist/index.js.map +1 -1
- package/dist/metadata.json +1 -1
- package/package.json +2 -2
- package/src/authoring/defineRestNode.types.ts +0 -84
- package/src/canvasIconName.ts +0 -7
- package/src/chatModels/CodemationChatModelConfig.ts +0 -10
- package/src/chatModels/CodemationChatModelFactory.ts +0 -7
- package/src/chatModels/ManagedHmacSignerFactory.types.ts +0 -35
- package/src/chatModels/OpenAIChatModelFactory.ts +0 -2
- package/src/chatModels/OpenAiChatModelPresetsFactory.ts +0 -5
- package/src/chatModels/OpenAiCredentialSession.ts +0 -1
- package/src/chatModels/OpenAiStrictJsonSchemaFactory.ts +0 -21
- package/src/credentials/ApiKeyCredentialType.ts +0 -3
- package/src/credentials/BasicAuthCredentialType.ts +0 -4
- package/src/credentials/BearerTokenCredentialType.ts +0 -4
- package/src/credentials/OAuth2ClientCredentialsTypeFactory.ts +0 -19
- package/src/credentials/OAuth2TokenExchangeFactory.ts +0 -7
- package/src/http/HttpBodyBuilder.ts +0 -16
- package/src/http/HttpRequestExecutor.ts +0 -35
- package/src/http/HttpUrlBuilder.ts +0 -4
- package/src/http/SSRFBlockedError.ts +0 -4
- package/src/http/SsrfGuard.ts +10 -50
- package/src/http/httpRequest.types.ts +0 -49
- package/src/index.ts +1 -0
- package/src/nodes/AIAgentConfig.ts +0 -44
- package/src/nodes/AIAgentExecutionHelpersFactory.ts +0 -37
- package/src/nodes/AIAgentNode.ts +0 -132
- package/src/nodes/AgentBinaryContentFactory.ts +0 -12
- package/src/nodes/AgentLoopCheckpoint.types.ts +0 -13
- package/src/nodes/AgentMessageFactory.ts +0 -18
- package/src/nodes/AgentStructuredOutputRunner.ts +0 -17
- package/src/nodes/AgentToolExecutionCoordinator.ts +0 -12
- package/src/nodes/AgentToolResultContentFactory.ts +0 -29
- package/src/nodes/AssertionNode.ts +0 -14
- package/src/nodes/BM25Index.ts +0 -14
- package/src/nodes/ConnectionCredentialExecutionContextFactory.ts +0 -5
- package/src/nodes/ConnectionCredentialNode.ts +0 -4
- package/src/nodes/CronTriggerFactory.ts +0 -9
- package/src/nodes/DeferredMetaToolStrategy.ts +0 -18
- package/src/nodes/DeferredMetaToolStrategyFactory.ts +0 -5
- package/src/nodes/HttpRequestNodeFactory.ts +0 -14
- package/src/nodes/InboxApprovalNode.types.ts +0 -16
- package/src/nodes/IsTestRunNode.ts +0 -8
- package/src/nodes/ManualTriggerFactory.ts +0 -3
- package/src/nodes/ManualTriggerNode.ts +0 -4
- package/src/nodes/MergeNode.ts +0 -1
- package/src/nodes/NodeBackedToolRuntime.ts +0 -14
- package/src/nodes/SubWorkflowNode.ts +0 -3
- package/src/nodes/SwitchNode.ts +0 -3
- package/src/nodes/TestTriggerNode.ts +0 -9
- package/src/nodes/aiAgentSupport.types.ts +0 -16
- package/src/nodes/assertion.ts +0 -10
- package/src/nodes/codemationDocumentScannerNode.ts +0 -18
- package/src/nodes/collections/collectionListNode.types.ts +0 -1
- package/src/nodes/httpRequest.ts +0 -68
- package/src/nodes/isTestRun.ts +0 -4
- package/src/nodes/mapData.ts +0 -1
- package/src/nodes/merge.ts +0 -4
- package/src/nodes/mergeExecutionUtils.types.ts +0 -3
- package/src/nodes/nodeOptions.types.ts +0 -8
- package/src/nodes/schedulePollingTrigger.ts +37 -0
- package/src/nodes/split.ts +0 -4
- package/src/nodes/testTrigger.ts +0 -21
- package/src/nodes/wait.ts +0 -1
- package/src/nodes/webhookTriggerNode.ts +0 -5
- package/src/register.types.ts +0 -10
- package/src/workflows/AIAgentConnectionWorkflowExpander.ts +0 -3
package/dist/index.cjs
CHANGED
|
@@ -33,9 +33,6 @@ let croner = require("croner");
|
|
|
33
33
|
croner = __toESM(croner);
|
|
34
34
|
|
|
35
35
|
//#region src/credentials/ApiKeyCredentialType.ts
|
|
36
|
-
/**
|
|
37
|
-
* API key credential that injects a key either as an HTTP header or a query parameter.
|
|
38
|
-
*/
|
|
39
36
|
const apiKeyCredentialType = (0, __codemation_core.defineCredential)({
|
|
40
37
|
key: "core-nodes.api-key",
|
|
41
38
|
label: "API Key",
|
|
@@ -83,10 +80,6 @@ const apiKeyCredentialType = (0, __codemation_core.defineCredential)({
|
|
|
83
80
|
|
|
84
81
|
//#endregion
|
|
85
82
|
//#region src/credentials/BasicAuthCredentialType.ts
|
|
86
|
-
/**
|
|
87
|
-
* HTTP Basic authentication credential.
|
|
88
|
-
* Session sets `Authorization: Basic <base64(username:password)>`.
|
|
89
|
-
*/
|
|
90
83
|
const basicAuthCredentialType = (0, __codemation_core.defineCredential)({
|
|
91
84
|
key: "core-nodes.basic-auth",
|
|
92
85
|
label: "Basic Auth",
|
|
@@ -124,10 +117,6 @@ const basicAuthCredentialType = (0, __codemation_core.defineCredential)({
|
|
|
124
117
|
|
|
125
118
|
//#endregion
|
|
126
119
|
//#region src/credentials/BearerTokenCredentialType.ts
|
|
127
|
-
/**
|
|
128
|
-
* Simple Bearer token credential.
|
|
129
|
-
* Session sets `Authorization: Bearer <token>` on every request.
|
|
130
|
-
*/
|
|
131
120
|
const bearerTokenCredentialType = (0, __codemation_core.defineCredential)({
|
|
132
121
|
key: "core-nodes.bearer-token",
|
|
133
122
|
label: "Bearer Token",
|
|
@@ -186,24 +175,6 @@ var OAuth2TokenExchangeFactory = class {
|
|
|
186
175
|
|
|
187
176
|
//#endregion
|
|
188
177
|
//#region src/credentials/OAuth2ClientCredentialsTypeFactory.ts
|
|
189
|
-
/**
|
|
190
|
-
* OAuth2 client-credentials flow credential.
|
|
191
|
-
*
|
|
192
|
-
* This is a machine-to-machine flow: no user redirect occurs. The session
|
|
193
|
-
* POSTs to the configured `tokenUrl` with `client_credentials` grant, caches
|
|
194
|
-
* the resulting access token for the duration of the session, and injects it
|
|
195
|
-
* as `Authorization: Bearer <token>` on each request.
|
|
196
|
-
*
|
|
197
|
-
* Token caching is per-session only (one createSession call = one token fetch
|
|
198
|
-
* at most). Cross-session caching would require host-level state and is out of
|
|
199
|
-
* scope here. Because the engine creates a fresh session per execution, a new
|
|
200
|
-
* token is fetched once per node activation.
|
|
201
|
-
*
|
|
202
|
-
* NOTE: `auth` is intentionally omitted from the definition. The OAuth2
|
|
203
|
-
* `auth: { kind: "oauth2" }` shape signals an authorization-code / user-redirect
|
|
204
|
-
* flow; using it here would cause the host UI to render an OAuth consent button
|
|
205
|
-
* that goes nowhere. Client-credentials is a purely server-side flow.
|
|
206
|
-
*/
|
|
207
178
|
const oauth2ClientCredentialsType = (0, __codemation_core.defineCredential)({
|
|
208
179
|
key: "core-nodes.oauth2-client-credentials",
|
|
209
180
|
label: "OAuth2 Client Credentials",
|
|
@@ -287,10 +258,6 @@ const oauth2ClientCredentialsType = (0, __codemation_core.defineCredential)({
|
|
|
287
258
|
|
|
288
259
|
//#endregion
|
|
289
260
|
//#region src/http/SSRFBlockedError.ts
|
|
290
|
-
/**
|
|
291
|
-
* Thrown when an HTTP request target resolves to a private, link-local, or
|
|
292
|
-
* loopback address and `allowPrivateNetworkTargets` is not set.
|
|
293
|
-
*/
|
|
294
261
|
var SSRFBlockedError = class extends Error {
|
|
295
262
|
resolvedIp;
|
|
296
263
|
constructor(host, resolvedIp) {
|
|
@@ -302,26 +269,7 @@ var SSRFBlockedError = class extends Error {
|
|
|
302
269
|
|
|
303
270
|
//#endregion
|
|
304
271
|
//#region src/http/SsrfGuard.ts
|
|
305
|
-
/** Emitted once per process when NODE_ENV=production and no allowedOutboundHosts is set. */
|
|
306
272
|
let _productionNoAllowlistWarned = false;
|
|
307
|
-
/**
|
|
308
|
-
* Guards HTTP requests against Server-Side Request Forgery (SSRF) by
|
|
309
|
-
* DNS-resolving the target host and rejecting private/link-local/loopback
|
|
310
|
-
* addresses.
|
|
311
|
-
*
|
|
312
|
-
* Blocked ranges:
|
|
313
|
-
* - RFC-1918: 10/8, 172.16/12, 192.168/16
|
|
314
|
-
* - Link-local: 169.254/16
|
|
315
|
-
* - Loopback: 127/8, ::1
|
|
316
|
-
*
|
|
317
|
-
* When `allowedOutboundHosts` is set, every resolved DNS target must match
|
|
318
|
-
* at least one entry in the list (exact hostname or `*.example.com` wildcard).
|
|
319
|
-
* When unset, existing behaviour applies: private ranges blocked, public allowed.
|
|
320
|
-
*
|
|
321
|
-
* Call {@link check} before making any outbound HTTP request.
|
|
322
|
-
* Pass `allowPrivate: true` to bypass the private-network guard for trusted workflows
|
|
323
|
-
* (allowedOutboundHosts allowlist is still applied when set).
|
|
324
|
-
*/
|
|
325
273
|
var SsrfGuard = class {
|
|
326
274
|
constructor(allowedOutboundHosts) {
|
|
327
275
|
this.allowedOutboundHosts = allowedOutboundHosts;
|
|
@@ -330,15 +278,6 @@ var SsrfGuard = class {
|
|
|
330
278
|
console.warn("[SsrfGuard] WARNING: NODE_ENV=production but no allowedOutboundHosts is configured for HttpRequest. All public destinations are permitted. Set allowedOutboundHosts to restrict outbound traffic.");
|
|
331
279
|
}
|
|
332
280
|
}
|
|
333
|
-
/**
|
|
334
|
-
* Resolves the host of `url` via DNS and throws {@link SSRFBlockedError}
|
|
335
|
-
* if any resolved address falls in a blocked range, or if the host does not
|
|
336
|
-
* match the operator-configured allowlist (when set).
|
|
337
|
-
*
|
|
338
|
-
* @param url - Fully-qualified URL of the intended request target.
|
|
339
|
-
* @param allowPrivate - When `true`, the private-network check is skipped.
|
|
340
|
-
* The allowedOutboundHosts check is still applied when set.
|
|
341
|
-
*/
|
|
342
281
|
async check(url, allowPrivate) {
|
|
343
282
|
if (allowPrivate && !this.allowedOutboundHosts?.length) return;
|
|
344
283
|
let host;
|
|
@@ -362,10 +301,6 @@ var SsrfGuard = class {
|
|
|
362
301
|
}
|
|
363
302
|
for (const { address } of addresses) if (this.isPrivateAddress(address)) throw new SSRFBlockedError(host, address);
|
|
364
303
|
}
|
|
365
|
-
/**
|
|
366
|
-
* Returns true when `host` matches at least one entry in `allowedOutboundHosts`.
|
|
367
|
-
* Supports exact hostnames (`api.example.com`) and wildcard prefixes (`*.example.com`).
|
|
368
|
-
*/
|
|
369
304
|
isHostAllowed(host) {
|
|
370
305
|
for (const allowed of this.allowedOutboundHosts ?? []) if (allowed.startsWith("*.")) {
|
|
371
306
|
const suffix = allowed.slice(1);
|
|
@@ -399,21 +334,6 @@ var SsrfGuard = class {
|
|
|
399
334
|
|
|
400
335
|
//#endregion
|
|
401
336
|
//#region src/http/HttpRequestExecutor.ts
|
|
402
|
-
/**
|
|
403
|
-
* Executes a single HTTP request described by {@link HttpRequestSpec}.
|
|
404
|
-
*
|
|
405
|
-
* - Credential sessions provide header/query deltas via `applyToRequest`.
|
|
406
|
-
* - Body encoding is delegated to {@link HttpBodyBuilder}.
|
|
407
|
-
* - URL query merging is delegated to {@link HttpUrlBuilder}.
|
|
408
|
-
* - SSRF protection is delegated to {@link SsrfGuard} (injected).
|
|
409
|
-
* - Binary response bodies: when `download.mode` triggers binary attach, the
|
|
410
|
-
* `bodyBinaryName` field is set in the result but the body is NOT read here.
|
|
411
|
-
* Callers that need binary attachment should use `buildRequest` to get the
|
|
412
|
-
* resolved URL + init and make the fetch + binary attach themselves.
|
|
413
|
-
*
|
|
414
|
-
* Collaborators (`fetch`, body builder, url builder, ssrfGuard) are injected so
|
|
415
|
-
* callers own construction at composition roots and tests can supply deterministic stubs.
|
|
416
|
-
*/
|
|
417
337
|
var HttpRequestExecutor = class {
|
|
418
338
|
constructor(fetchFn, bodyBuilder, urlBuilder, ssrfGuard) {
|
|
419
339
|
this.fetchFn = fetchFn;
|
|
@@ -421,14 +341,6 @@ var HttpRequestExecutor = class {
|
|
|
421
341
|
this.urlBuilder = urlBuilder;
|
|
422
342
|
this.ssrfGuard = ssrfGuard;
|
|
423
343
|
}
|
|
424
|
-
/**
|
|
425
|
-
* Builds the fetch init (headers, query, body) from the spec + credential delta,
|
|
426
|
-
* returning both the resolved URL and the RequestInit so callers can make the
|
|
427
|
-
* actual fetch call themselves (useful for streaming / binary attach).
|
|
428
|
-
*
|
|
429
|
-
* Also performs SSRF protection via the injected {@link SsrfGuard} before
|
|
430
|
-
* returning — throws {@link SSRFBlockedError} if the target is a private address.
|
|
431
|
-
*/
|
|
432
344
|
async buildRequest(spec, item) {
|
|
433
345
|
await this.ssrfGuard.check(spec.url, spec.allowPrivateNetworkTargets ?? false);
|
|
434
346
|
const credentialDelta = spec.credential?.applyToRequest(spec) ?? {};
|
|
@@ -452,12 +364,6 @@ var HttpRequestExecutor = class {
|
|
|
452
364
|
}
|
|
453
365
|
};
|
|
454
366
|
}
|
|
455
|
-
/**
|
|
456
|
-
* Executes an HTTP request and returns parsed result.
|
|
457
|
-
* For binary downloads (when `shouldAttachBody` is true), the body is NOT consumed
|
|
458
|
-
* and callers must call `ctx.binary.attach` directly using the resolved URL + init
|
|
459
|
-
* (available via `buildRequest`).
|
|
460
|
-
*/
|
|
461
367
|
async execute(spec, item) {
|
|
462
368
|
const { url: resolvedUrl, init } = await this.buildRequest(spec, item);
|
|
463
369
|
const response = await this.fetchFn(resolvedUrl, init);
|
|
@@ -514,10 +420,6 @@ var HttpRequestExecutor = class {
|
|
|
514
420
|
|
|
515
421
|
//#endregion
|
|
516
422
|
//#region src/http/HttpBodyBuilder.ts
|
|
517
|
-
/**
|
|
518
|
-
* Builds a fetch-compatible `BodyInit` + Content-Type pair from an {@link HttpBodySpec}.
|
|
519
|
-
* Multipart binaries are read from `item.binary` via `ctx.binary.openReadStream`.
|
|
520
|
-
*/
|
|
521
423
|
var HttpBodyBuilder = class {
|
|
522
424
|
async build(spec, item, ctx) {
|
|
523
425
|
if (!spec || spec.kind === "none") return;
|
|
@@ -588,10 +490,6 @@ var HttpBodyBuilder = class {
|
|
|
588
490
|
|
|
589
491
|
//#endregion
|
|
590
492
|
//#region src/http/HttpUrlBuilder.ts
|
|
591
|
-
/**
|
|
592
|
-
* Merges query parameters into a base URL.
|
|
593
|
-
* Handles both scalar and array values, and preserves any existing params.
|
|
594
|
-
*/
|
|
595
493
|
var HttpUrlBuilder = class {
|
|
596
494
|
build(baseUrl, query) {
|
|
597
495
|
if (!query || Object.keys(query).length === 0) return baseUrl;
|
|
@@ -604,39 +502,12 @@ var HttpUrlBuilder = class {
|
|
|
604
502
|
|
|
605
503
|
//#endregion
|
|
606
504
|
//#region src/authoring/defineRestNode.types.ts
|
|
607
|
-
/**
|
|
608
|
-
* Substitutes `{name}` placeholders in a path template using values from `params`.
|
|
609
|
-
*/
|
|
610
505
|
function substitutePath(template, params) {
|
|
611
506
|
return template.replace(/\{([^}]+)}/g, (_match, key) => {
|
|
612
507
|
const value = params[key];
|
|
613
508
|
return value !== void 0 ? String(value) : `{${key}}`;
|
|
614
509
|
});
|
|
615
510
|
}
|
|
616
|
-
/**
|
|
617
|
-
* Declarative helper for creating thin API-wrapper nodes.
|
|
618
|
-
*
|
|
619
|
-
* Usage:
|
|
620
|
-
* ```ts
|
|
621
|
-
* export const postMessage = defineRestNode({
|
|
622
|
-
* key: "slack.post-message",
|
|
623
|
-
* title: "Send Slack message",
|
|
624
|
-
* icon: "si:slack",
|
|
625
|
-
* api: { baseUrl: "https://slack.com/api", path: "/chat.postMessage", method: "POST" },
|
|
626
|
-
* credentials: { auth: bearerTokenCredentialType },
|
|
627
|
-
* inputSchema: z.object({ channel: z.string(), text: z.string() }),
|
|
628
|
-
* request: ({ input }) => ({
|
|
629
|
-
* body: { kind: "json", data: { channel: input.channel, text: input.text } },
|
|
630
|
-
* }),
|
|
631
|
-
* response: ({ json }) => ({ messageTs: (json as any).ts }),
|
|
632
|
-
* });
|
|
633
|
-
* ```
|
|
634
|
-
*
|
|
635
|
-
* - `defineRestNode` is a thin wrapper over `defineNode`; it does not introduce a new runtime kind.
|
|
636
|
-
* - Credential sessions are resolved via the `credentials` binding map (same as `defineNode`).
|
|
637
|
-
* - Path `{placeholder}` substitution is applied from `input` keys before the request is made.
|
|
638
|
-
* - Non-2xx responses throw an `Error` by default (`errorPolicy: "throw"`).
|
|
639
|
-
*/
|
|
640
511
|
function defineRestNode(options) {
|
|
641
512
|
const errorPolicy = options.errorPolicy ?? "throw";
|
|
642
513
|
return (0, __codemation_core.defineNode)({
|
|
@@ -4174,11 +4045,6 @@ function toJSONSchema(input, params) {
|
|
|
4174
4045
|
|
|
4175
4046
|
//#endregion
|
|
4176
4047
|
//#region src/nodes/ConnectionCredentialExecutionContextFactory.ts
|
|
4177
|
-
/**
|
|
4178
|
-
* Builds a {@link NodeExecutionContext} whose identity for credential binding and `getCredential`
|
|
4179
|
-
* is a **connection-owned** workflow node id (`ConnectionNodeIdFactory` in `@codemation/core`),
|
|
4180
|
-
* not the executing parent node. Use for LLM slots, tool slots, or any connection-scoped owner.
|
|
4181
|
-
*/
|
|
4182
4048
|
var ConnectionCredentialExecutionContextFactory = class {
|
|
4183
4049
|
credentialResolverFactory;
|
|
4184
4050
|
constructor(credentialSessions) {
|
|
@@ -4201,15 +4067,6 @@ let AIAgentExecutionHelpersFactory = class AIAgentExecutionHelpersFactory$1 {
|
|
|
4201
4067
|
createConnectionCredentialExecutionContextFactory(credentialSessions) {
|
|
4202
4068
|
return new ConnectionCredentialExecutionContextFactory(credentialSessions);
|
|
4203
4069
|
}
|
|
4204
|
-
/**
|
|
4205
|
-
* Produces a plain JSON Schema object (`draft-07`) from a Zod schema, as needed by
|
|
4206
|
-
* OpenAI tool-parameter schemas and the structured-output repair prompt.
|
|
4207
|
-
* - Prefers the schema's **instance** `toJSONSchema(...)` method so we stay inside the Zod
|
|
4208
|
-
* instance that created the schema (works across consumer/framework tsx namespaces — see
|
|
4209
|
-
* {@link ZodInstanceToJsonSchema}). Falls back to the framework-imported module function.
|
|
4210
|
-
* - Strips root `$schema` (OpenAI ignores it).
|
|
4211
|
-
* - Sanitizes `required` for cfworker json-schema compatibility (must be a string array or absent).
|
|
4212
|
-
*/
|
|
4213
4070
|
createJsonSchemaRecord(inputSchema, options) {
|
|
4214
4071
|
const { $schema: _draftSchemaOmitted,...rest } = this.convertZodSchemaToJsonSchema(inputSchema, { target: "draft-07" });
|
|
4215
4072
|
if (options.requireObjectRoot && rest.type !== "object") throw new Error(`Cannot create tool "${options.schemaName}": tool input schema must be a JSON Schema object type (got type=${String(rest.type)}).`);
|
|
@@ -4218,20 +4075,11 @@ let AIAgentExecutionHelpersFactory = class AIAgentExecutionHelpersFactory$1 {
|
|
|
4218
4075
|
this.sanitizeJsonSchemaRequiredKeywordsForCfworker(rest);
|
|
4219
4076
|
return rest;
|
|
4220
4077
|
}
|
|
4221
|
-
/**
|
|
4222
|
-
* Runs Zod's `toJSONSchema` via the schema's own instance method when available, so consumer
|
|
4223
|
-
* schemas loaded under a different tsx namespace still convert correctly. If the caller handed us
|
|
4224
|
-
* a payload that lacks that method (e.g. a plain JSON Schema record or a Zod instance whose
|
|
4225
|
-
* prototype was stripped), we fall back to the framework-bundled module function.
|
|
4226
|
-
*/
|
|
4227
4078
|
convertZodSchemaToJsonSchema(inputSchema, params) {
|
|
4228
4079
|
const candidate = inputSchema.toJSONSchema;
|
|
4229
4080
|
if (typeof candidate === "function") return candidate.call(inputSchema, params);
|
|
4230
4081
|
return toJSONSchema(inputSchema, params);
|
|
4231
4082
|
}
|
|
4232
|
-
/**
|
|
4233
|
-
* `@cfworker/json-schema` iterates `schema.required` with `for...of`; it must be a string array or absent.
|
|
4234
|
-
*/
|
|
4235
4083
|
sanitizeJsonSchemaRequiredKeywordsForCfworker(node$20) {
|
|
4236
4084
|
if (!node$20 || typeof node$20 !== "object" || Array.isArray(node$20)) return;
|
|
4237
4085
|
const o = node$20;
|
|
@@ -4378,11 +4226,6 @@ var OpenAIChatModelConfig = class {
|
|
|
4378
4226
|
|
|
4379
4227
|
//#endregion
|
|
4380
4228
|
//#region src/chatModels/OpenAiChatModelPresetsFactory.ts
|
|
4381
|
-
/**
|
|
4382
|
-
* Default OpenAI chat model configs for scaffolds and demos (icon + label match {@link OpenAIChatModelConfig} defaults).
|
|
4383
|
-
* Prefer importing {@link openAiChatModelPresets} from here or from the consumer template re-export
|
|
4384
|
-
* instead of repeating {@link OpenAIChatModelConfig} construction in app workflows.
|
|
4385
|
-
*/
|
|
4386
4229
|
var OpenAiChatModelPresets = class {
|
|
4387
4230
|
demoGpt4oMini = new OpenAIChatModelConfig("OpenAI", "gpt-4o-mini");
|
|
4388
4231
|
demoGpt41 = new OpenAIChatModelConfig("OpenAI", "gpt-4.1");
|
|
@@ -4391,19 +4234,6 @@ const openAiChatModelPresets = new OpenAiChatModelPresets();
|
|
|
4391
4234
|
|
|
4392
4235
|
//#endregion
|
|
4393
4236
|
//#region src/chatModels/ManagedHmacSignerFactory.types.ts
|
|
4394
|
-
/**
|
|
4395
|
-
* Creates an HMAC-signing fetch wrapper that authenticates requests to
|
|
4396
|
-
* Codemation managed services (LLM broker, doc-scanner) with the
|
|
4397
|
-
* Codemation-Hmac v=1 scheme.
|
|
4398
|
-
*
|
|
4399
|
-
* Mirrors HmacRequestSigner from @codemation/host/pairing without importing
|
|
4400
|
-
* that package (which would create a circular dependency since @codemation/host
|
|
4401
|
-
* depends on @codemation/core-nodes).
|
|
4402
|
-
*
|
|
4403
|
-
* @param workspaceId - Workspace identifier injected by the CP provisioner.
|
|
4404
|
-
* @param pairingSecret - Base64-encoded 32-byte HMAC key injected by the provisioner.
|
|
4405
|
-
* @param options - Optional behaviour flags and test seams.
|
|
4406
|
-
*/
|
|
4407
4237
|
function managedHmacFetchFactory(workspaceId, pairingSecret, options) {
|
|
4408
4238
|
const signBody = options?.signBody ?? true;
|
|
4409
4239
|
return async (input, init) => {
|
|
@@ -4422,10 +4252,6 @@ function managedHmacFetchFactory(workspaceId, pairingSecret, options) {
|
|
|
4422
4252
|
});
|
|
4423
4253
|
};
|
|
4424
4254
|
}
|
|
4425
|
-
/**
|
|
4426
|
-
* Produces a Codemation-Hmac v=1 Authorization header value.
|
|
4427
|
-
* Algorithm must match HmacVerifier.computeSignature() in the control-plane.
|
|
4428
|
-
*/
|
|
4429
4255
|
function buildHmacAuthHeader(workspaceId, pairingSecret, method, url, body, overrides) {
|
|
4430
4256
|
const ts = overrides?.now ? overrides.now() : Math.floor(Date.now() / 1e3);
|
|
4431
4257
|
const nonce = overrides?.nonce ? overrides.nonce() : (0, node_crypto.randomBytes)(16).toString("base64");
|
|
@@ -4488,12 +4314,7 @@ var CodemationChatModelConfig = class {
|
|
|
4488
4314
|
|
|
4489
4315
|
//#endregion
|
|
4490
4316
|
//#region src/nodes/AgentToolResultContentFactory.ts
|
|
4491
|
-
/**
|
|
4492
|
-
* Cap on raw (pre-base64) bytes inlined from a single tool result. Base64 inflates ~33% and every
|
|
4493
|
-
* inlined byte eats model context, so oversize binaries are replaced with a text placeholder.
|
|
4494
|
-
*/
|
|
4495
4317
|
const MAX_INLINE_BYTES = 8 * 1024 * 1024;
|
|
4496
|
-
/** MCP content-block discriminators. At least one must appear for a result to be treated as MCP-shaped. */
|
|
4497
4318
|
const KNOWN_MCP_BLOCK_TYPES = new Set([
|
|
4498
4319
|
"text",
|
|
4499
4320
|
"image",
|
|
@@ -4501,19 +4322,6 @@ const KNOWN_MCP_BLOCK_TYPES = new Set([
|
|
|
4501
4322
|
"resource",
|
|
4502
4323
|
"resource_link"
|
|
4503
4324
|
]);
|
|
4504
|
-
/**
|
|
4505
|
-
* Maps a tool result that is **content-block-shaped** (an MCP `CallToolResult` with a `content`
|
|
4506
|
-
* array) into AI SDK `{ type: "content" }` tool-result output, so binaries reach the chat model as
|
|
4507
|
-
* native multimodal tool-result blocks instead of being flattened to inert JSON text.
|
|
4508
|
-
*
|
|
4509
|
-
* The `@ai-sdk/anthropic` provider maps a `content`-output part as follows:
|
|
4510
|
-
* `text` → text block, `image-data` → image block, `file-data` (only `application/pdf`) → document
|
|
4511
|
-
* block. Non-PDF `file-data` is dropped by the provider, so this factory emits `image-data` for
|
|
4512
|
-
* images, `file-data` only for PDFs, and a text marker for every other binary type.
|
|
4513
|
-
*
|
|
4514
|
-
* Returns `undefined` when the result is not content-block-shaped — callers keep the existing
|
|
4515
|
-
* `{ type: "json" }` path, so plain string/object tool results are unaffected.
|
|
4516
|
-
*/
|
|
4517
4325
|
var AgentToolResultContentFactory = class AgentToolResultContentFactory {
|
|
4518
4326
|
static tryMapToContentOutput(result) {
|
|
4519
4327
|
const blocks = AgentToolResultContentFactory.contentBlocks(result);
|
|
@@ -4527,12 +4335,6 @@ var AgentToolResultContentFactory = class AgentToolResultContentFactory {
|
|
|
4527
4335
|
}
|
|
4528
4336
|
return parts;
|
|
4529
4337
|
}
|
|
4530
|
-
/**
|
|
4531
|
-
* Returns the `content` array iff `result` is an object whose `content` is an array of typed
|
|
4532
|
-
* blocks AND at least one block carries a known MCP discriminator. A plain JSON result that merely
|
|
4533
|
-
* has a `content` key of some other shape (e.g. Notion/Slack rich-text blocks) is rejected,
|
|
4534
|
-
* preserving the `{ type: "json" }` path so its payload is never lost.
|
|
4535
|
-
*/
|
|
4536
4338
|
static contentBlocks(result) {
|
|
4537
4339
|
if (result === null || typeof result !== "object") return void 0;
|
|
4538
4340
|
const content = result.content;
|
|
@@ -4637,19 +4439,10 @@ var AgentToolResultContentFactory = class AgentToolResultContentFactory {
|
|
|
4637
4439
|
|
|
4638
4440
|
//#endregion
|
|
4639
4441
|
//#region src/nodes/AgentMessageFactory.ts
|
|
4640
|
-
/**
|
|
4641
|
-
* AI-SDK-shaped message construction for the AIAgent stack. Emits plain `ModelMessage[]`
|
|
4642
|
-
* ( `{ role: 'system' | 'user' | 'assistant' | 'tool', content: ... }` ) as consumed by
|
|
4643
|
-
* `generateText({ messages })` from the `ai` package.
|
|
4644
|
-
*/
|
|
4645
4442
|
var AgentMessageFactory = class AgentMessageFactory {
|
|
4646
4443
|
static createPromptMessages(messages) {
|
|
4647
4444
|
return messages.map((message) => this.createPromptMessage(message));
|
|
4648
4445
|
}
|
|
4649
|
-
/**
|
|
4650
|
-
* Builds the assistant message that contains optional text plus one or more tool-call parts,
|
|
4651
|
-
* matching the shape AI SDK emits between steps.
|
|
4652
|
-
*/
|
|
4653
4446
|
static createAssistantWithToolCalls(text, toolCalls) {
|
|
4654
4447
|
const content = [];
|
|
4655
4448
|
if (text && text.length > 0) content.push({
|
|
@@ -4667,10 +4460,6 @@ var AgentMessageFactory = class AgentMessageFactory {
|
|
|
4667
4460
|
content
|
|
4668
4461
|
};
|
|
4669
4462
|
}
|
|
4670
|
-
/**
|
|
4671
|
-
* Builds the `{ role: "tool", content: [{ type: "tool-result", ... }, ...] }` message returned
|
|
4672
|
-
* to the model after each tool round.
|
|
4673
|
-
*/
|
|
4674
4463
|
static createToolResultsMessage(executedToolCalls, passToolBinariesToModel = true) {
|
|
4675
4464
|
return {
|
|
4676
4465
|
role: "tool",
|
|
@@ -4682,11 +4471,6 @@ var AgentMessageFactory = class AgentMessageFactory {
|
|
|
4682
4471
|
}))
|
|
4683
4472
|
};
|
|
4684
4473
|
}
|
|
4685
|
-
/**
|
|
4686
|
-
* Routes a tool result to a native multimodal `{ type: "content" }` output when it is
|
|
4687
|
-
* content-block-shaped (an MCP `CallToolResult`) and binary passdown is enabled; otherwise keeps
|
|
4688
|
-
* the inert `{ type: "json" }` path.
|
|
4689
|
-
*/
|
|
4690
4474
|
static toToolResultOutput(result, passToolBinariesToModel) {
|
|
4691
4475
|
if (passToolBinariesToModel) {
|
|
4692
4476
|
const content = AgentToolResultContentFactory.tryMapToContentOutput(result);
|
|
@@ -5496,10 +5280,6 @@ let AgentStructuredOutputRunner = class AgentStructuredOutputRunner$1 {
|
|
|
5496
5280
|
}
|
|
5497
5281
|
throw new Error(`Structured output required for AIAgent "${args.agentName}" (${args.nodeId}) but validation still failed after ${_AgentStructuredOutputRunner.repairAttemptCount} repair attempts: ${failure.validationError}`);
|
|
5498
5282
|
}
|
|
5499
|
-
/**
|
|
5500
|
-
* Chooses strict mode for OpenAI chat-model configs, off otherwise. Extendable in future for
|
|
5501
|
-
* other providers that adopt the same "supply a JSON Schema record directly" contract.
|
|
5502
|
-
*/
|
|
5503
5283
|
resolveStructuredOutputOptions(chatModelConfig) {
|
|
5504
5284
|
if (chatModelConfig.type !== OpenAIChatModelFactory) return;
|
|
5505
5285
|
return {
|
|
@@ -5982,10 +5762,6 @@ let AgentToolExecutionCoordinator = class AgentToolExecutionCoordinator$1 {
|
|
|
5982
5762
|
extractErrorDetails(error) {
|
|
5983
5763
|
return error.details;
|
|
5984
5764
|
}
|
|
5985
|
-
/**
|
|
5986
|
-
* Extracts the text content from the last assistant message in the conversation snapshot.
|
|
5987
|
-
* Used to populate `agentReasoning` in the HITL suspension metadata.
|
|
5988
|
-
*/
|
|
5989
5765
|
extractLastAssistantText(conversation) {
|
|
5990
5766
|
for (let i = conversation.length - 1; i >= 0; i--) {
|
|
5991
5767
|
const msg = conversation[i];
|
|
@@ -6020,16 +5796,6 @@ AgentToolExecutionCoordinator = __decorate([
|
|
|
6020
5796
|
|
|
6021
5797
|
//#endregion
|
|
6022
5798
|
//#region src/nodes/AgentBinaryContentFactory.ts
|
|
6023
|
-
/**
|
|
6024
|
-
* Turns resolved file binaries into native AI SDK multimodal content parts and merges them into the
|
|
6025
|
-
* agent prompt. Images (`image/*`) become {@link ImagePart}s; every other type (PDFs, office docs,
|
|
6026
|
-
* CSV, JSON, …) becomes a {@link FilePart}. The provider maps these to its wire-level `image` /
|
|
6027
|
-
* `document` blocks; an unsupported file type surfaces as a provider error at runtime.
|
|
6028
|
-
*
|
|
6029
|
-
* Parts are appended to the LAST user message so the binary travels alongside the author's prompt
|
|
6030
|
-
* text (preserving any untrusted-source preamble that already wrapped that text). When no user
|
|
6031
|
-
* message exists, a new user message carrying only the binaries is appended.
|
|
6032
|
-
*/
|
|
6033
5799
|
var AgentBinaryContentFactory = class AgentBinaryContentFactory {
|
|
6034
5800
|
static toContentPart(binary) {
|
|
6035
5801
|
if (binary.mediaType.startsWith("image/")) return {
|
|
@@ -6108,20 +5874,6 @@ let NodeBackedToolRuntime = class NodeBackedToolRuntime$1 {
|
|
|
6108
5874
|
outputs
|
|
6109
5875
|
});
|
|
6110
5876
|
}
|
|
6111
|
-
/**
|
|
6112
|
-
* Returns a re-rooted child ctx for nested-agent tools (so their LLM/tool connection ids derive
|
|
6113
|
-
* from the tool connection node, telemetry parents under the tool-call span, and connection
|
|
6114
|
-
* invocations carry `parentInvocationId`). Plain runnable tools (non-agent) keep the orchestrator
|
|
6115
|
-
* ctx with only `config` swapped — no nesting concern.
|
|
6116
|
-
*
|
|
6117
|
-
* The caller (`AIAgentNode.createItemScopedTools`) already wraps the orchestrator ctx via
|
|
6118
|
-
* `ConnectionCredentialExecutionContextFactory.forConnectionNode`, so `args.ctx.nodeId` is the
|
|
6119
|
-
* tool's own connection node id (e.g. `AIAgentNode:2__conn__tool__searchInMail`). We pass that
|
|
6120
|
-
* through as the sub-agent's `nodeId`; deriving another `toolConnectionNodeId(args.ctx.nodeId,
|
|
6121
|
-
* config.name)` here would prepend a duplicate `__conn__tool__<name>` segment and exponentially
|
|
6122
|
-
* deepen ids on each invocation, which also breaks credential resolution because user-provided
|
|
6123
|
-
* bindings sit on the single-level connection node id.
|
|
6124
|
-
*/
|
|
6125
5877
|
resolveNodeCtx(config$1, args) {
|
|
6126
5878
|
const isNestedAgent = __codemation_core.AgentConfigInspector.isAgentNodeConfig(config$1.node);
|
|
6127
5879
|
const hooks = args.hooks;
|
|
@@ -6186,22 +5938,12 @@ NodeBackedToolRuntime = __decorate([
|
|
|
6186
5938
|
|
|
6187
5939
|
//#endregion
|
|
6188
5940
|
//#region src/nodes/BM25Index.ts
|
|
6189
|
-
/**
|
|
6190
|
-
* Minimal BM25 (Okapi BM25) implementation for indexing MCP tool descriptions.
|
|
6191
|
-
*
|
|
6192
|
-
* Parameters: k1=1.5, b=0.75 (standard defaults).
|
|
6193
|
-
* Tokenisation: lowercase, split on non-alphanumerics, filter empties.
|
|
6194
|
-
*/
|
|
6195
5941
|
var BM25Index = class {
|
|
6196
5942
|
k1 = 1.5;
|
|
6197
5943
|
b = .75;
|
|
6198
5944
|
tf = [];
|
|
6199
5945
|
df = /* @__PURE__ */ new Map();
|
|
6200
5946
|
avgDocLen = 0;
|
|
6201
|
-
/**
|
|
6202
|
-
* Add all documents at once. After calling this, search is available.
|
|
6203
|
-
* Documents are indexed in insertion order; search returns their indices.
|
|
6204
|
-
*/
|
|
6205
5947
|
add(docs) {
|
|
6206
5948
|
const docTerms = docs.map((d) => this.tokenize(d));
|
|
6207
5949
|
let totalLen = 0;
|
|
@@ -6214,10 +5956,6 @@ var BM25Index = class {
|
|
|
6214
5956
|
}
|
|
6215
5957
|
this.avgDocLen = docTerms.length > 0 ? totalLen / docTerms.length : 0;
|
|
6216
5958
|
}
|
|
6217
|
-
/**
|
|
6218
|
-
* Returns up to `limit` document indices ranked by BM25 score (highest first).
|
|
6219
|
-
* Returns an empty array if the index is empty or the query matches nothing.
|
|
6220
|
-
*/
|
|
6221
5959
|
search(query, limit) {
|
|
6222
5960
|
const n = this.tf.length;
|
|
6223
5961
|
if (n === 0) return [];
|
|
@@ -6258,26 +5996,12 @@ const PINNED_TOOLS_SOFT_LIMIT = 8;
|
|
|
6258
5996
|
const PINNED_TOOLS_HARD_LIMIT = 16;
|
|
6259
5997
|
const FIND_TOOLS_NAME = "find_tools";
|
|
6260
5998
|
const FIND_TOOLS_DEFAULT_LIMIT = 5;
|
|
6261
|
-
/**
|
|
6262
|
-
* Default tool-loading strategy: BM25-indexed MCP tool deferral via a `find_tools` meta-tool.
|
|
6263
|
-
*
|
|
6264
|
-
* - Node-backed tools and pinned MCP tools are always included in every turn.
|
|
6265
|
-
* - `find_tools(query, limit?)` is added to the tool set when MCP tools are indexed.
|
|
6266
|
-
* - Tools surfaced by `find_tools` are included in subsequent turns.
|
|
6267
|
-
*
|
|
6268
|
-
* Not DI-managed; instantiated per agent execution by DeferredMetaToolStrategyFactory.
|
|
6269
|
-
*/
|
|
6270
5999
|
var DeferredMetaToolStrategy = class {
|
|
6271
6000
|
nodeBackedTools = {};
|
|
6272
6001
|
pinnedTools = {};
|
|
6273
6002
|
mcpEntries = [];
|
|
6274
6003
|
toolsByServerId = /* @__PURE__ */ new Map();
|
|
6275
6004
|
foundToolIds = /* @__PURE__ */ new Set();
|
|
6276
|
-
/**
|
|
6277
|
-
* `jsonSchema` from the `ai` SDK, loaded lazily in {@link initialize} so the SDK
|
|
6278
|
-
* (~28MB RSS) stays off the boot path. `initialize` always runs before the sync
|
|
6279
|
-
* `getToolsForTurn` → `buildFindToolsDefinition` path, so this is set before use.
|
|
6280
|
-
*/
|
|
6281
6005
|
jsonSchema;
|
|
6282
6006
|
constructor(bm25, warnFn) {
|
|
6283
6007
|
this.bm25 = bm25;
|
|
@@ -6425,11 +6149,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6425
6149
|
inputSchema = unknown();
|
|
6426
6150
|
connectionCredentialExecutionContextFactory;
|
|
6427
6151
|
preparedByExecutionContext = /* @__PURE__ */ new WeakMap();
|
|
6428
|
-
/**
|
|
6429
|
-
* The `ai` SDK, loaded lazily in {@link execute} so the SDK (~28MB RSS) stays
|
|
6430
|
-
* off the boot path — non-AI workflows never load it. Every path runs through
|
|
6431
|
-
* `execute` → `ensureAiSdk` before any sync helper touches `this.aiSdk`.
|
|
6432
|
-
*/
|
|
6433
6152
|
aiSdk;
|
|
6434
6153
|
aiSdkPromise = null;
|
|
6435
6154
|
constructor(nodeResolver, credentialSessions, nodeBackedToolRuntime, executionHelpers, structuredOutputRunner, toolExecutionCoordinator, toolLoadingStrategyFactory, agentMcpIntegration) {
|
|
@@ -6453,15 +6172,9 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6453
6172
|
};
|
|
6454
6173
|
return (await this.runAgentForItem(prepared, itemWithMappedJson, args.itemIndex, args.items)).json;
|
|
6455
6174
|
}
|
|
6456
|
-
/** Load the `ai` SDK once per node instance (cached promise guards concurrent items). */
|
|
6457
6175
|
async ensureAiSdk() {
|
|
6458
6176
|
this.aiSdk = await (this.aiSdkPromise ??= import("ai"));
|
|
6459
6177
|
}
|
|
6460
|
-
/**
|
|
6461
|
-
* Resume path: re-enters the agent loop after a HITL suspension.
|
|
6462
|
-
* Reconstructs the conversation from the checkpoint, injects the human decision
|
|
6463
|
-
* as a tool_result, and continues the loop from where it suspended.
|
|
6464
|
-
*/
|
|
6465
6178
|
async executeResumed(args, resumeContext) {
|
|
6466
6179
|
const { ctx } = args;
|
|
6467
6180
|
const taskMetadata = resumeContext.task.metadata ?? {};
|
|
@@ -6508,10 +6221,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6508
6221
|
const outputJson = await this.resolveFinalOutputJson(prepared, itemInputsByPort, conversation, loopResult.finalText, itemScopedTools.length > 0);
|
|
6509
6222
|
return this.buildOutputItem(item, outputJson).json;
|
|
6510
6223
|
}
|
|
6511
|
-
/**
|
|
6512
|
-
* Normalizes a {@link ResumeContext} decision into a flat JSON-serializable shape
|
|
6513
|
-
* suitable for injection as a tool_result content.
|
|
6514
|
-
*/
|
|
6515
6224
|
normalizeDecision(resumeContext) {
|
|
6516
6225
|
const { decision } = resumeContext;
|
|
6517
6226
|
if (decision.kind === "decided") {
|
|
@@ -6638,16 +6347,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6638
6347
|
const outputJson = await this.resolveFinalOutputJson(prepared, itemInputsByPort, conversation, loopResult.finalText, itemScopedTools.length > 0);
|
|
6639
6348
|
return this.buildOutputItem(item, outputJson);
|
|
6640
6349
|
}
|
|
6641
|
-
/**
|
|
6642
|
-
* Multi-turn loop:
|
|
6643
|
-
* - Each turn is a single `generateText` call with tools exposed but **not auto-executed**
|
|
6644
|
-
* (we control tool dispatch so that {@link AgentToolExecutionCoordinator} drives repair /
|
|
6645
|
-
* connection-invocation recording / transient-error handling exactly like before).
|
|
6646
|
-
* - When the model returns no tool calls the loop ends with the model's text as the final answer.
|
|
6647
|
-
* - Respects `guardrails.maxTurns` and `guardrails.onTurnLimitReached`.
|
|
6648
|
-
* - Strategy-owned tool calls (e.g. `find_tools`) are dispatched via the strategy, not the
|
|
6649
|
-
* coordinator; their results are tracked so subsequent turns receive the discovered tools.
|
|
6650
|
-
*/
|
|
6651
6350
|
async runTurnLoopUntilFinalAnswer(args) {
|
|
6652
6351
|
const { prepared, itemInputsByPort, itemScopedTools, conversation } = args;
|
|
6653
6352
|
const { ctx, guardrails, toolLoadingStrategy } = prepared;
|
|
@@ -6655,7 +6354,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6655
6354
|
let toolCallCount = args.resumedToolCallCount ?? 0;
|
|
6656
6355
|
let turnCount = 0;
|
|
6657
6356
|
const repairAttemptsByToolName = /* @__PURE__ */ new Map();
|
|
6658
|
-
/** Tool IDs surfaced by find_tools across all prior turns in this item run. */
|
|
6659
6357
|
let previousFoundToolIds = [];
|
|
6660
6358
|
for (let turn = 1; turn <= guardrails.maxTurns; turn++) {
|
|
6661
6359
|
turnCount = turn;
|
|
@@ -6785,12 +6483,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6785
6483
|
};
|
|
6786
6484
|
});
|
|
6787
6485
|
}
|
|
6788
|
-
/**
|
|
6789
|
-
* Resolves the HITL behavior for a tool binding, or `undefined` when it is not a HITL tool.
|
|
6790
|
-
* A binding is HITL if either the backing node carries a `defineHumanApprovalNode` marker or the
|
|
6791
|
-
* binding sets a per-binding `onRejected` via `asTool(..., { onRejected })`. The per-binding value
|
|
6792
|
-
* wins over the node marker, so two tools backed by the same node can reject differently.
|
|
6793
|
-
*/
|
|
6794
6486
|
resolveHumanApprovalBehavior(config$1) {
|
|
6795
6487
|
if (!this.isNodeBackedToolConfig(config$1)) return void 0;
|
|
6796
6488
|
const marker = config$1.node.humanApprovalToolBehavior;
|
|
@@ -6798,11 +6490,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6798
6490
|
if (marker === void 0 && perBinding === void 0) return void 0;
|
|
6799
6491
|
return { onRejected: perBinding ?? marker?.onRejected ?? "return" };
|
|
6800
6492
|
}
|
|
6801
|
-
/**
|
|
6802
|
-
* Invoke a text turn using the merged tool set from item-scoped tools (coordinator-managed)
|
|
6803
|
-
* and strategy tools (find_tools + discovered MCP tools).
|
|
6804
|
-
* Strategy tools take precedence for names that overlap.
|
|
6805
|
-
*/
|
|
6806
6493
|
async invokeTextTurnWithStrategyTools(prepared, itemInputsByPort, messages, itemScopedTools, strategyTools) {
|
|
6807
6494
|
const itemToolSet = this.buildToolSet(itemScopedTools);
|
|
6808
6495
|
const strategyHasTools = Object.keys(strategyTools).length > 0;
|
|
@@ -6813,10 +6500,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6813
6500
|
} : void 0;
|
|
6814
6501
|
return this.invokeTextTurnWithToolSet(prepared, itemInputsByPort, messages, mergedTools);
|
|
6815
6502
|
}
|
|
6816
|
-
/**
|
|
6817
|
-
* Removes `execute` properties from ToolSet entries so the AI SDK does not
|
|
6818
|
-
* auto-execute them within `generateText`. Codemation owns all tool dispatch.
|
|
6819
|
-
*/
|
|
6820
6503
|
stripExecuteCallbacks(tools) {
|
|
6821
6504
|
const stripped = {};
|
|
6822
6505
|
for (const [name, def] of Object.entries(tools)) {
|
|
@@ -6825,12 +6508,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6825
6508
|
}
|
|
6826
6509
|
return stripped;
|
|
6827
6510
|
}
|
|
6828
|
-
/**
|
|
6829
|
-
* Builds a ToolSet from resolved tools for strategy initialization.
|
|
6830
|
-
* The strategy uses this for its "always-included" node-backed tool descriptions.
|
|
6831
|
-
* HITL tools (detected via the `humanApprovalToolBehavior` field set by `defineHumanApprovalNode`) get the solo-constraint sentence
|
|
6832
|
-
* appended to their description.
|
|
6833
|
-
*/
|
|
6834
6511
|
buildToolSetFromResolved(resolvedTools) {
|
|
6835
6512
|
if (resolvedTools.length === 0) return {};
|
|
6836
6513
|
const toolSet = {};
|
|
@@ -6848,20 +6525,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6848
6525
|
}
|
|
6849
6526
|
return toolSet;
|
|
6850
6527
|
}
|
|
6851
|
-
/**
|
|
6852
|
-
* Builds an AI SDK {@link ToolSet} where every tool ships a pre-converted JSON Schema (via
|
|
6853
|
-
* {@link jsonSchema}) — not the raw Zod schema — and carries **no** `execute`. Two reasons:
|
|
6854
|
-
*
|
|
6855
|
-
* 1. Codemation owns tool dispatch + the per-tool repair loop (see {@link AgentToolExecutionCoordinator}),
|
|
6856
|
-
* so the AI SDK must surface tool calls back to us instead of auto-running them.
|
|
6857
|
-
* 2. The AI SDK's `asSchema` helper discriminates between Zod v3 / Zod v4 / Standard Schema via
|
|
6858
|
-
* runtime feature-detection (`~standard`, `_zod`, etc.). Handing it a pre-built
|
|
6859
|
-
* {@link jsonSchema} record — which is tagged with `Symbol.for('vercel.ai.schema')` — skips all
|
|
6860
|
-
* of that detection and guarantees the provider receives a draft-07 JSON Schema with
|
|
6861
|
-
* `additionalProperties: false` at every object depth (see {@link OpenAiStrictJsonSchemaFactory}
|
|
6862
|
-
* for the same logic applied to structured-output schemas). Codemation still runs its own Zod
|
|
6863
|
-
* validation on tool inputs before execute — the schema handed to the model is advisory.
|
|
6864
|
-
*/
|
|
6865
6528
|
buildToolSet(itemScopedTools) {
|
|
6866
6529
|
if (itemScopedTools.length === 0) return void 0;
|
|
6867
6530
|
const toolSet = {};
|
|
@@ -6879,10 +6542,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6879
6542
|
}
|
|
6880
6543
|
return toolSet;
|
|
6881
6544
|
}
|
|
6882
|
-
/**
|
|
6883
|
-
* One `generateText` turn (no auto tool execution) with Codemation-owned child-span telemetry
|
|
6884
|
-
* and connection-invocation state recording. Accepts a pre-built ToolSet.
|
|
6885
|
-
*/
|
|
6886
6545
|
async invokeTextTurnWithToolSet(prepared, itemInputsByPort, messages, tools) {
|
|
6887
6546
|
const invocationId = __codemation_core.ConnectionInvocationIdFactory.create();
|
|
6888
6547
|
const startedAt = /* @__PURE__ */ new Date();
|
|
@@ -6993,11 +6652,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6993
6652
|
});
|
|
6994
6653
|
}
|
|
6995
6654
|
}
|
|
6996
|
-
/**
|
|
6997
|
-
* Structured-output turn: runs `generateText({ output: Output.object({ schema }) })` via the
|
|
6998
|
-
* structured-output runner. We keep this as a separate helper because the runner needs the raw
|
|
6999
|
-
* validated value (not just text) back, and must be able to retry on Zod failures.
|
|
7000
|
-
*/
|
|
7001
6655
|
async invokeStructuredTurn(prepared, itemInputsByPort, schema, messages, structuredOptions) {
|
|
7002
6656
|
const invocationId = __codemation_core.ConnectionInvocationIdFactory.create();
|
|
7003
6657
|
const startedAt = /* @__PURE__ */ new Date();
|
|
@@ -7122,13 +6776,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
7122
6776
|
providerOptions: overrides?.providerOptions ?? defaults.providerOptions
|
|
7123
6777
|
};
|
|
7124
6778
|
}
|
|
7125
|
-
/**
|
|
7126
|
-
* Build a no-code-friendly output payload for an LLM round.
|
|
7127
|
-
*
|
|
7128
|
-
* Always includes `content` (matching the canvas snapshot shape used elsewhere) and adds a
|
|
7129
|
-
* `toolCalls` array when the round produced tool calls so the execution inspector surfaces the
|
|
7130
|
-
* planned calls instead of just an empty `""` for tool-only rounds.
|
|
7131
|
-
*/
|
|
7132
6779
|
summarizeTurnOutput(turnResult) {
|
|
7133
6780
|
if (turnResult.toolCalls.length === 0) return { content: turnResult.text };
|
|
7134
6781
|
const toolCalls = turnResult.toolCalls.map((toolCall) => ({
|
|
@@ -7331,12 +6978,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
7331
6978
|
const binaries = await this.resolveInlineBinaries(attachments, ctx);
|
|
7332
6979
|
return AgentBinaryContentFactory.withBinaries(promptMessages, binaries);
|
|
7333
6980
|
}
|
|
7334
|
-
/**
|
|
7335
|
-
* Picks which attachments feed the passdown. When the author supplies `config.binaries`
|
|
7336
|
-
* (a static array or a per-item function — e.g. to forward binaries from an earlier node),
|
|
7337
|
-
* those replace the current item's attachments; otherwise the current item's `item.binary`
|
|
7338
|
-
* is used.
|
|
7339
|
-
*/
|
|
7340
6981
|
selectBinaryAttachments(item, itemIndex, items, ctx) {
|
|
7341
6982
|
const manual = ctx.config.binaries;
|
|
7342
6983
|
if (manual !== void 0) return typeof manual === "function" ? manual({
|
|
@@ -7347,14 +6988,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
7347
6988
|
}) : manual;
|
|
7348
6989
|
return item.binary ? Object.values(item.binary) : [];
|
|
7349
6990
|
}
|
|
7350
|
-
/**
|
|
7351
|
-
* Reads every attachment through `ctx.binary` (storage-backed, by reference — never base64 on
|
|
7352
|
-
* `item.json`) and resolves it to inline base64 so the agent can pass it to the chat model as a
|
|
7353
|
-
* native multimodal block. Images become image blocks; every other type (PDF, office docs, CSV,
|
|
7354
|
-
* JSON, …) becomes a file block — we don't filter by media type, so any binary can be fed to the
|
|
7355
|
-
* model. If the provider rejects an unsupported type the error surfaces at runtime, and the
|
|
7356
|
-
* workflow can filter the binary upstream.
|
|
7357
|
-
*/
|
|
7358
6991
|
async resolveInlineBinaries(attachments, ctx) {
|
|
7359
6992
|
const resolved = [];
|
|
7360
6993
|
for (const attachment of attachments) {
|
|
@@ -7367,12 +7000,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
7367
7000
|
}
|
|
7368
7001
|
return resolved;
|
|
7369
7002
|
}
|
|
7370
|
-
/**
|
|
7371
|
-
* When `item.json.__source` matches an entry in `config.untrustedSources`
|
|
7372
|
-
* (default: `["gmail", "ocr", "webhook"]`), wraps every user-role message
|
|
7373
|
-
* content with an untrusted-external-source preamble so the LLM treats the
|
|
7374
|
-
* content as data, not instructions.
|
|
7375
|
-
*/
|
|
7376
7003
|
wrapUntrustedSourceMessages(messages, item, config$1) {
|
|
7377
7004
|
const source = item.json !== null && typeof item.json === "object" ? item.json.__source : void 0;
|
|
7378
7005
|
if (typeof source !== "string") return messages;
|
|
@@ -7465,10 +7092,6 @@ AIAgentNode = __decorate([
|
|
|
7465
7092
|
|
|
7466
7093
|
//#endregion
|
|
7467
7094
|
//#region src/nodes/AIAgentConfig.ts
|
|
7468
|
-
/**
|
|
7469
|
-
* AI agent: credential bindings are keyed to connection-owned LLM/tool node ids (ConnectionNodeIdFactory),
|
|
7470
|
-
* not to the agent workflow node id.
|
|
7471
|
-
*/
|
|
7472
7095
|
var AIAgent = class {
|
|
7473
7096
|
kind = "node";
|
|
7474
7097
|
type = AIAgentNode;
|
|
@@ -7566,11 +7189,6 @@ AssertionNode = __decorate([(0, __codemation_core.node)({ packageName: "@codemat
|
|
|
7566
7189
|
|
|
7567
7190
|
//#endregion
|
|
7568
7191
|
//#region src/nodes/assertion.ts
|
|
7569
|
-
/**
|
|
7570
|
-
* Generic assertion node — the "callback" form. For declarative shorthands (StringEquals,
|
|
7571
|
-
* JudgeByAgent) compose this with helpers added in later phases. Sets `emitsAssertions: true`
|
|
7572
|
-
* so host-side persisters know to record its outputs as `TestAssertion` rows.
|
|
7573
|
-
*/
|
|
7574
7192
|
var Assertion = class {
|
|
7575
7193
|
kind = "node";
|
|
7576
7194
|
type = AssertionNode;
|
|
@@ -7833,17 +7451,12 @@ HttpRequestNode = __decorate([(0, __codemation_core.node)({ packageName: "@codem
|
|
|
7833
7451
|
|
|
7834
7452
|
//#endregion
|
|
7835
7453
|
//#region src/nodes/httpRequest.ts
|
|
7836
|
-
/**
|
|
7837
|
-
* The built-in HTTP request credential type IDs accepted by the `HttpRequest` node.
|
|
7838
|
-
* These match the four generic credential types shipped with `@codemation/core-nodes`.
|
|
7839
|
-
*/
|
|
7840
7454
|
const HTTP_REQUEST_ACCEPTED_CREDENTIAL_TYPES = [
|
|
7841
7455
|
bearerTokenCredentialType.definition.typeId,
|
|
7842
7456
|
apiKeyCredentialType.definition.typeId,
|
|
7843
7457
|
basicAuthCredentialType.definition.typeId,
|
|
7844
7458
|
oauth2ClientCredentialsType.definition.typeId
|
|
7845
7459
|
];
|
|
7846
|
-
/** Default maximum response size for binary mode: 100 MiB. */
|
|
7847
7460
|
const DEFAULT_RESPONSE_SIZE_CAP_BYTES = 100 * 1024 * 1024;
|
|
7848
7461
|
var HttpRequest = class {
|
|
7849
7462
|
kind = "node";
|
|
@@ -8012,9 +7625,6 @@ var Filter = class {
|
|
|
8012
7625
|
function getOriginIndex(item) {
|
|
8013
7626
|
return (0, __codemation_core.getOriginIndexFromItem)(item);
|
|
8014
7627
|
}
|
|
8015
|
-
/**
|
|
8016
|
-
* Tags items routed to fan-in merge-by-origin (same contract as {@link IfNode} / {@link SwitchNode}).
|
|
8017
|
-
*/
|
|
8018
7628
|
function tagItemForRouterFanIn(args) {
|
|
8019
7629
|
const { item, itemIndex, nodeId, inputPortLabel = "$in" } = args;
|
|
8020
7630
|
const metaBase = item.meta && typeof item.meta === "object" ? item.meta : {};
|
|
@@ -8105,10 +7715,6 @@ IsTestRunNode = __decorate([(0, __codemation_core.node)({ packageName: "@codemat
|
|
|
8105
7715
|
|
|
8106
7716
|
//#endregion
|
|
8107
7717
|
//#region src/nodes/isTestRun.ts
|
|
8108
|
-
/**
|
|
8109
|
-
* Branches per-item on whether the current run is a test run. Output ports: `true`, `false`.
|
|
8110
|
-
* The wire payload is unchanged — this is a router, not a transform.
|
|
8111
|
-
*/
|
|
8112
7718
|
var IsTestRun = class {
|
|
8113
7719
|
kind = "node";
|
|
8114
7720
|
type = IsTestRunNode;
|
|
@@ -8192,10 +7798,6 @@ var Split = class {
|
|
|
8192
7798
|
type = SplitNode;
|
|
8193
7799
|
execution = { hint: "local" };
|
|
8194
7800
|
keepBinaries = true;
|
|
8195
|
-
/**
|
|
8196
|
-
* When splitting yields zero items for a batch, downstream single-input nodes still run once with an empty batch.
|
|
8197
|
-
* Mirrors {@link MapData}'s empty-output behavior.
|
|
8198
|
-
*/
|
|
8199
7801
|
continueWhenEmptyOutput = true;
|
|
8200
7802
|
icon = "builtin:split-rows";
|
|
8201
7803
|
id;
|
|
@@ -8249,15 +7851,6 @@ CronTriggerNode = __decorate([(0, __codemation_core.node)({ packageName: "@codem
|
|
|
8249
7851
|
|
|
8250
7852
|
//#endregion
|
|
8251
7853
|
//#region src/nodes/CronTriggerFactory.ts
|
|
8252
|
-
/**
|
|
8253
|
-
* Schedules a workflow on a standard cron expression.
|
|
8254
|
-
*
|
|
8255
|
-
* Each tick emits one item: `{ firedAt: string, scheduledFor: string }` — both ISO-8601 timestamps.
|
|
8256
|
-
* `firedAt` is the wall-clock moment the callback ran; `scheduledFor` is the cron-computed
|
|
8257
|
-
* firing instant (these differ when the job was delayed).
|
|
8258
|
-
*
|
|
8259
|
-
* Timezone defaults to UTC when omitted — cron without an explicit TZ is a DST footgun.
|
|
8260
|
-
*/
|
|
8261
7854
|
var CronTrigger = class {
|
|
8262
7855
|
kind = "trigger";
|
|
8263
7856
|
type = CronTriggerNode;
|
|
@@ -8328,7 +7921,6 @@ var ManualTrigger = class ManualTrigger {
|
|
|
8328
7921
|
defaultItems;
|
|
8329
7922
|
id;
|
|
8330
7923
|
description;
|
|
8331
|
-
/** Manual runs often emit an empty batch; still schedule downstream by default. */
|
|
8332
7924
|
continueWhenEmptyOutput = true;
|
|
8333
7925
|
constructor(name = "Manual trigger", defaultItemsOrId, idOrOptions) {
|
|
8334
7926
|
this.name = name;
|
|
@@ -8383,7 +7975,6 @@ var MapData = class {
|
|
|
8383
7975
|
kind = "node";
|
|
8384
7976
|
type = MapDataNode;
|
|
8385
7977
|
execution = { hint: "local" };
|
|
8386
|
-
/** Zero mapped items should still allow downstream nodes to run. */
|
|
8387
7978
|
continueWhenEmptyOutput = true;
|
|
8388
7979
|
icon = "lucide:square-pen";
|
|
8389
7980
|
keepBinaries;
|
|
@@ -8616,11 +8207,6 @@ TestTriggerNode = __decorate([(0, __codemation_core.node)({ packageName: "@codem
|
|
|
8616
8207
|
|
|
8617
8208
|
//#endregion
|
|
8618
8209
|
//#region src/nodes/testTrigger.ts
|
|
8619
|
-
/**
|
|
8620
|
-
* Trigger config for a test fixture source. Drop one (or more) of these on the canvas alongside
|
|
8621
|
-
* a workflow's live triggers; clicking "Run tests" on the Tests tab invokes
|
|
8622
|
-
* {@link TestTriggerOptions.generateItems} via the TestSuiteOrchestrator.
|
|
8623
|
-
*/
|
|
8624
8210
|
var TestTrigger = class {
|
|
8625
8211
|
kind = "trigger";
|
|
8626
8212
|
triggerKind = "test";
|
|
@@ -8694,7 +8280,6 @@ var Wait = class {
|
|
|
8694
8280
|
kind = "node";
|
|
8695
8281
|
type = WaitNode;
|
|
8696
8282
|
execution = { hint: "local" };
|
|
8697
|
-
/** Pass-through empty batches should still advance to downstream nodes. */
|
|
8698
8283
|
continueWhenEmptyOutput = true;
|
|
8699
8284
|
icon = "lucide:hourglass";
|
|
8700
8285
|
id;
|
|
@@ -8796,6 +8381,39 @@ var WebhookTrigger = class WebhookTrigger {
|
|
|
8796
8381
|
}
|
|
8797
8382
|
};
|
|
8798
8383
|
|
|
8384
|
+
//#endregion
|
|
8385
|
+
//#region src/nodes/schedulePollingTrigger.ts
|
|
8386
|
+
const schedulePollingTrigger = (0, __codemation_core.definePollingTrigger)({
|
|
8387
|
+
key: "schedule.interval",
|
|
8388
|
+
packageName: "@codemation/core-nodes",
|
|
8389
|
+
title: "Run on schedule",
|
|
8390
|
+
description: "Emit one tick item on every poll cycle.",
|
|
8391
|
+
icon: "lucide:clock",
|
|
8392
|
+
pollIntervalMs: 6e4,
|
|
8393
|
+
initialState() {
|
|
8394
|
+
return { tick: 0 };
|
|
8395
|
+
},
|
|
8396
|
+
poll({ state }) {
|
|
8397
|
+
const tick = (state ?? { tick: 0 }).tick + 1;
|
|
8398
|
+
return {
|
|
8399
|
+
items: [{ json: {
|
|
8400
|
+
firedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8401
|
+
tick
|
|
8402
|
+
} }],
|
|
8403
|
+
nextState: { tick }
|
|
8404
|
+
};
|
|
8405
|
+
},
|
|
8406
|
+
execute(items) {
|
|
8407
|
+
return { main: items };
|
|
8408
|
+
},
|
|
8409
|
+
testItems() {
|
|
8410
|
+
return [{ json: {
|
|
8411
|
+
firedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8412
|
+
tick: 0
|
|
8413
|
+
} }];
|
|
8414
|
+
}
|
|
8415
|
+
});
|
|
8416
|
+
|
|
8799
8417
|
//#endregion
|
|
8800
8418
|
//#region src/nodes/ConnectionCredentialNode.ts
|
|
8801
8419
|
let ConnectionCredentialNode = class ConnectionCredentialNode$1 {
|
|
@@ -8809,11 +8427,6 @@ ConnectionCredentialNode = __decorate([(0, __codemation_core.node)({ packageName
|
|
|
8809
8427
|
|
|
8810
8428
|
//#endregion
|
|
8811
8429
|
//#region src/register.types.ts
|
|
8812
|
-
/**
|
|
8813
|
-
* Registrar for built-in nodes. In a real project, this would use tsyringe's
|
|
8814
|
-
* container.registerSingleton(...). For the skeleton we keep it token-based:
|
|
8815
|
-
* the engine resolves node implementations by class token.
|
|
8816
|
-
*/
|
|
8817
8430
|
function registerCoreNodes(container) {}
|
|
8818
8431
|
|
|
8819
8432
|
//#endregion
|
|
@@ -9042,9 +8655,6 @@ function workflow(id) {
|
|
|
9042
8655
|
|
|
9043
8656
|
//#endregion
|
|
9044
8657
|
//#region src/workflows/AIAgentConnectionWorkflowExpander.ts
|
|
9045
|
-
/**
|
|
9046
|
-
* Materializes connection-owned child nodes and {@link WorkflowDefinition.connections} for AI agent nodes.
|
|
9047
|
-
*/
|
|
9048
8658
|
var AIAgentConnectionWorkflowExpander = class {
|
|
9049
8659
|
constructor(connectionCredentialNodeConfigFactory, mcpServerResolver) {
|
|
9050
8660
|
this.connectionCredentialNodeConfigFactory = connectionCredentialNodeConfigFactory;
|
|
@@ -9312,16 +8922,6 @@ const collectionDeleteNode = (0, __codemation_core.defineNode)({
|
|
|
9312
8922
|
function resolveSubjectField(field, item) {
|
|
9313
8923
|
return typeof field === "function" ? field({ item }) : field;
|
|
9314
8924
|
}
|
|
9315
|
-
/**
|
|
9316
|
-
* Auto-detecting inbox approval node.
|
|
9317
|
-
*
|
|
9318
|
-
* Uses `ctx.resolve(InboxChannelResolverToken)` to pick the right inbox channel
|
|
9319
|
-
* at runtime:
|
|
9320
|
-
* - In managed mode (PairingConfig present): routes to the control-plane inbox.
|
|
9321
|
-
* - Otherwise: routes to the local inbox.
|
|
9322
|
-
*
|
|
9323
|
-
* Authors use this node directly; no extra wiring needed per deployment mode.
|
|
9324
|
-
*/
|
|
9325
8925
|
const inboxApproval = (0, __codemation_core.defineHumanApprovalNode)({
|
|
9326
8926
|
key: "inbox.approval",
|
|
9327
8927
|
title: "Inbox Approval",
|
|
@@ -9714,5 +9314,6 @@ exports.inboxApproval = inboxApproval;
|
|
|
9714
9314
|
exports.oauth2ClientCredentialsType = oauth2ClientCredentialsType;
|
|
9715
9315
|
exports.openAiChatModelPresets = openAiChatModelPresets;
|
|
9716
9316
|
exports.registerCoreNodes = registerCoreNodes;
|
|
9317
|
+
exports.schedulePollingTrigger = schedulePollingTrigger;
|
|
9717
9318
|
exports.workflow = workflow;
|
|
9718
9319
|
//# sourceMappingURL=index.cjs.map
|