@codemation/core-nodes 0.10.2 → 0.13.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 (39) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/dist/index.cjs +427 -102
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +205 -67
  5. package/dist/index.d.ts +206 -68
  6. package/dist/index.js +427 -99
  7. package/dist/index.js.map +1 -1
  8. package/dist/metadata.json +1 -1
  9. package/package.json +3 -2
  10. package/src/chatModels/CodemationChatModelConfig.ts +9 -21
  11. package/src/chatModels/CodemationChatModelFactory.ts +12 -9
  12. package/src/chatModels/OpenAIChatModelFactory.ts +3 -2
  13. package/src/index.ts +1 -1
  14. package/src/nodes/AIAgentConfig.ts +36 -0
  15. package/src/nodes/AIAgentNode.ts +81 -15
  16. package/src/nodes/AgentBinaryContentFactory.ts +74 -0
  17. package/src/nodes/AgentMessageFactory.ts +22 -6
  18. package/src/nodes/AgentToolResultContentFactory.ts +155 -0
  19. package/src/nodes/CallbackNodeFactory.ts +9 -6
  20. package/src/nodes/CronTriggerFactory.ts +6 -2
  21. package/src/nodes/DeferredMetaToolStrategy.ts +8 -2
  22. package/src/nodes/ManualTriggerFactory.ts +15 -11
  23. package/src/nodes/WebhookTriggerFactory.ts +9 -2
  24. package/src/nodes/aggregate.ts +9 -2
  25. package/src/nodes/assertion.ts +3 -0
  26. package/src/nodes/filter.ts +9 -2
  27. package/src/nodes/httpRequest.ts +6 -1
  28. package/src/nodes/if.ts +9 -2
  29. package/src/nodes/isTestRun.ts +6 -2
  30. package/src/nodes/mapData.ts +4 -2
  31. package/src/nodes/merge.ts +9 -2
  32. package/src/nodes/noOp.ts +9 -2
  33. package/src/nodes/nodeOptions.types.ts +12 -0
  34. package/src/nodes/split.ts +9 -2
  35. package/src/nodes/subWorkflow.ts +9 -2
  36. package/src/nodes/switch.ts +7 -1
  37. package/src/nodes/wait.ts +9 -2
  38. package/src/workflowAuthoring/WorkflowChatModelFactory.types.ts +8 -2
  39. package/src/chatModels/ManagedModelFetcher.ts +0 -23
package/dist/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  import { AgentConfigInspector, AgentConnectionNodeCollector, AgentGuardrailDefaults, AgentMessageConfigNormalizer, CallableToolConfig, ChildExecutionScopeFactory, CodemationTelemetryAttributeNames, CodemationTelemetryMetricNames, ConnectionInvocationIdFactory, ConnectionNodeIdFactory, CoreTokens, DefinedNodeRegistry, GenAiTelemetryAttributeNames, InboxChannelResolverToken, ItemExprResolver, ItemsInputNormalizer, NodeBackedToolConfig, NodeOutputNormalizer, RetryPolicy, RunnableOutputBehaviorResolver, SuspensionRequest, WorkflowBuilder, chatModel, defineCredential, defineHumanApprovalNode, defineNode, emitPorts, getOriginIndexFromItem, inject, injectable, isPortsEmission, node } from "@codemation/core";
2
2
  import dns from "node:dns/promises";
3
- import { createOpenAI } from "@ai-sdk/openai";
4
3
  import { CredentialResolverFactory } from "@codemation/core/bootstrap";
5
4
  import { createHash, createHmac, randomBytes } from "node:crypto";
6
- import { Output, generateText, jsonSchema } from "ai";
7
5
  import { Cron } from "croner";
8
6
 
9
7
  //#region src/credentials/ApiKeyCredentialType.ts
@@ -674,6 +672,7 @@ function __decorate(decorators, target, key, desc) {
674
672
  let OpenAIChatModelFactory = class OpenAIChatModelFactory$1 {
675
673
  async create(args) {
676
674
  const session = await args.ctx.getCredential(args.config.credentialSlotKey);
675
+ const { createOpenAI } = await import("@ai-sdk/openai");
677
676
  return {
678
677
  languageModel: createOpenAI({
679
678
  apiKey: session.apiKey,
@@ -4418,27 +4417,24 @@ function buildHmacAuthHeader(workspaceId, pairingSecret, method, url, body, over
4418
4417
  //#endregion
4419
4418
  //#region src/chatModels/CodemationChatModelFactory.ts
4420
4419
  let CodemationChatModelFactory = class CodemationChatModelFactory$1 {
4421
- create(args) {
4420
+ async create(args) {
4422
4421
  const gatewayUrl = process.env["LLM_GATEWAY_URL"];
4423
4422
  if (!gatewayUrl) throw new Error("Codemation managed AI not available in this environment (LLM_GATEWAY_URL is not set).");
4424
4423
  const workspaceId = process.env["WORKSPACE_ID"];
4425
4424
  const pairingSecret = process.env["WORKSPACE_PAIRING_SECRET"];
4426
4425
  if (!workspaceId || !pairingSecret) throw new Error("Codemation managed AI not available in this environment (workspace pairing is not configured).");
4427
4426
  const hmacFetch = managedHmacFetchFactory(workspaceId, pairingSecret);
4428
- const languageModel = createOpenAI({
4429
- baseURL: `${gatewayUrl}/v1`,
4430
- apiKey: "codemation-managed",
4431
- fetch: hmacFetch
4432
- }).chat(args.config.model);
4433
- return Promise.resolve({
4434
- languageModel,
4435
- modelName: args.config.model,
4427
+ const { createAnthropic } = await import("@ai-sdk/anthropic");
4428
+ return {
4429
+ languageModel: createAnthropic({
4430
+ baseURL: `${gatewayUrl}/v1`,
4431
+ apiKey: "codemation-managed",
4432
+ fetch: hmacFetch
4433
+ })(args.config.complexity),
4434
+ modelName: args.config.complexity,
4436
4435
  provider: "codemation-managed",
4437
- defaultCallOptions: {
4438
- maxOutputTokens: args.config.options?.maxTokens,
4439
- temperature: args.config.options?.temperature
4440
- }
4441
- });
4436
+ defaultCallOptions: { maxOutputTokens: args.config.options?.maxTokens }
4437
+ };
4442
4438
  }
4443
4439
  };
4444
4440
  CodemationChatModelFactory = __decorate([chatModel({ packageName: "@codemation/core-nodes" })], CodemationChatModelFactory);
@@ -4450,11 +4446,11 @@ var CodemationChatModelConfig = class {
4450
4446
  presentation;
4451
4447
  provider = "codemation-managed";
4452
4448
  modelName;
4453
- constructor(name, model, presentationIn, options) {
4449
+ constructor(name, complexity, presentationIn, options) {
4454
4450
  this.name = name;
4455
- this.model = model;
4451
+ this.complexity = complexity;
4456
4452
  this.options = options;
4457
- this.modelName = model;
4453
+ this.modelName = complexity;
4458
4454
  this.presentation = presentationIn ?? {
4459
4455
  icon: "lucide:bot",
4460
4456
  label: name
@@ -4463,24 +4459,151 @@ var CodemationChatModelConfig = class {
4463
4459
  };
4464
4460
 
4465
4461
  //#endregion
4466
- //#region src/chatModels/ManagedModelFetcher.ts
4462
+ //#region src/nodes/AgentToolResultContentFactory.ts
4467
4463
  /**
4468
- * Fetches the active platform-managed model allowlist from the CP.
4469
- * Reads CONTROL_PLANE_URL from the workspace process env.
4470
- * Returns an empty array if the env var is absent or the fetch fails.
4471
- * Cache the result per session — the allowlist changes infrequently.
4464
+ * Cap on raw (pre-base64) bytes inlined from a single tool result. Base64 inflates ~33% and every
4465
+ * inlined byte eats model context, so oversize binaries are replaced with a text placeholder.
4472
4466
  */
4473
- var ManagedModelFetcher = class {
4474
- async fetch() {
4475
- const cpUrl = process.env["CONTROL_PLANE_URL"];
4476
- if (!cpUrl) return [];
4477
- try {
4478
- const res = await globalThis.fetch(`${cpUrl}/api/llm/managed-models`);
4479
- if (!res.ok) return [];
4480
- return await res.json();
4481
- } catch {
4482
- return [];
4467
+ const MAX_INLINE_BYTES = 8 * 1024 * 1024;
4468
+ /** MCP content-block discriminators. At least one must appear for a result to be treated as MCP-shaped. */
4469
+ const KNOWN_MCP_BLOCK_TYPES = new Set([
4470
+ "text",
4471
+ "image",
4472
+ "audio",
4473
+ "resource",
4474
+ "resource_link"
4475
+ ]);
4476
+ /**
4477
+ * Maps a tool result that is **content-block-shaped** (an MCP `CallToolResult` with a `content`
4478
+ * array) into AI SDK `{ type: "content" }` tool-result output, so binaries reach the chat model as
4479
+ * native multimodal tool-result blocks instead of being flattened to inert JSON text.
4480
+ *
4481
+ * The `@ai-sdk/anthropic` provider maps a `content`-output part as follows:
4482
+ * `text` → text block, `image-data` → image block, `file-data` (only `application/pdf`) → document
4483
+ * block. Non-PDF `file-data` is dropped by the provider, so this factory emits `image-data` for
4484
+ * images, `file-data` only for PDFs, and a text marker for every other binary type.
4485
+ *
4486
+ * Returns `undefined` when the result is not content-block-shaped — callers keep the existing
4487
+ * `{ type: "json" }` path, so plain string/object tool results are unaffected.
4488
+ */
4489
+ var AgentToolResultContentFactory = class AgentToolResultContentFactory {
4490
+ static tryMapToContentOutput(result) {
4491
+ const blocks = AgentToolResultContentFactory.contentBlocks(result);
4492
+ if (blocks === void 0) return void 0;
4493
+ const parts = [];
4494
+ let inlinedBytes = 0;
4495
+ for (const block of blocks) {
4496
+ const mapped = AgentToolResultContentFactory.mapBlock(block, inlinedBytes);
4497
+ parts.push(mapped.part);
4498
+ inlinedBytes += mapped.bytes;
4483
4499
  }
4500
+ return parts;
4501
+ }
4502
+ /**
4503
+ * Returns the `content` array iff `result` is an object whose `content` is an array of typed
4504
+ * blocks AND at least one block carries a known MCP discriminator. A plain JSON result that merely
4505
+ * has a `content` key of some other shape (e.g. Notion/Slack rich-text blocks) is rejected,
4506
+ * preserving the `{ type: "json" }` path so its payload is never lost.
4507
+ */
4508
+ static contentBlocks(result) {
4509
+ if (result === null || typeof result !== "object") return void 0;
4510
+ const content = result.content;
4511
+ if (!Array.isArray(content) || content.length === 0) return void 0;
4512
+ if (!content.every((block) => block !== null && typeof block === "object" && typeof block.type === "string")) return void 0;
4513
+ return content.some((block) => KNOWN_MCP_BLOCK_TYPES.has(block.type)) ? content : void 0;
4514
+ }
4515
+ static mapBlock(block, inlinedBytesSoFar) {
4516
+ const type = block.type;
4517
+ if (type === "text" && typeof block.text === "string") return {
4518
+ part: {
4519
+ type: "text",
4520
+ text: block.text
4521
+ },
4522
+ bytes: 0
4523
+ };
4524
+ if (type === "image" && typeof block.data === "string" && typeof block.mimeType === "string") return AgentToolResultContentFactory.mapBinary({
4525
+ base64: block.data,
4526
+ mediaType: block.mimeType,
4527
+ inlinedBytesSoFar
4528
+ });
4529
+ if (type === "resource" && block.resource) return AgentToolResultContentFactory.mapEmbeddedResource(block.resource, inlinedBytesSoFar);
4530
+ if (type === "resource_link" && typeof block.uri === "string") {
4531
+ const mime = typeof block.mimeType === "string" ? ` (${block.mimeType})` : "";
4532
+ return {
4533
+ part: {
4534
+ type: "text",
4535
+ text: `[linked resource: ${block.uri}${mime}]`
4536
+ },
4537
+ bytes: 0
4538
+ };
4539
+ }
4540
+ return {
4541
+ part: {
4542
+ type: "text",
4543
+ text: `[unsupported tool content block: ${String(type)}]`
4544
+ },
4545
+ bytes: 0
4546
+ };
4547
+ }
4548
+ static mapEmbeddedResource(resource, inlinedBytesSoFar) {
4549
+ if (typeof resource.text === "string") return {
4550
+ part: {
4551
+ type: "text",
4552
+ text: resource.text
4553
+ },
4554
+ bytes: 0
4555
+ };
4556
+ if (typeof resource.blob === "string" && typeof resource.mimeType === "string") return AgentToolResultContentFactory.mapBinary({
4557
+ base64: resource.blob,
4558
+ mediaType: resource.mimeType,
4559
+ filename: typeof resource.name === "string" ? resource.name : void 0,
4560
+ inlinedBytesSoFar
4561
+ });
4562
+ return {
4563
+ part: {
4564
+ type: "text",
4565
+ text: `[embedded resource: ${typeof resource.uri === "string" ? resource.uri : "unknown"}]`
4566
+ },
4567
+ bytes: 0
4568
+ };
4569
+ }
4570
+ static mapBinary(args) {
4571
+ const rawBytes = Math.floor(args.base64.length * 3 / 4);
4572
+ if (args.inlinedBytesSoFar + rawBytes > MAX_INLINE_BYTES) {
4573
+ const name = args.filename ? ` "${args.filename}"` : "";
4574
+ const kb = Math.round(rawBytes / 1024);
4575
+ return {
4576
+ part: {
4577
+ type: "text",
4578
+ text: `[binary${name} (${args.mediaType}, ~${kb} KB) omitted: exceeds the per-tool-result inline limit]`
4579
+ },
4580
+ bytes: 0
4581
+ };
4582
+ }
4583
+ if (args.mediaType.startsWith("image/")) return {
4584
+ part: {
4585
+ type: "image-data",
4586
+ data: args.base64,
4587
+ mediaType: args.mediaType
4588
+ },
4589
+ bytes: rawBytes
4590
+ };
4591
+ if (args.mediaType === "application/pdf") return {
4592
+ part: {
4593
+ type: "file-data",
4594
+ data: args.base64,
4595
+ mediaType: args.mediaType,
4596
+ ...args.filename ? { filename: args.filename } : {}
4597
+ },
4598
+ bytes: rawBytes
4599
+ };
4600
+ return {
4601
+ part: {
4602
+ type: "text",
4603
+ text: `[binary${args.filename ? ` "${args.filename}"` : ""} (${args.mediaType}) not inlined: unsupported by the model]`
4604
+ },
4605
+ bytes: 0
4606
+ };
4484
4607
  }
4485
4608
  };
4486
4609
 
@@ -4520,20 +4643,35 @@ var AgentMessageFactory = class AgentMessageFactory {
4520
4643
  * Builds the `{ role: "tool", content: [{ type: "tool-result", ... }, ...] }` message returned
4521
4644
  * to the model after each tool round.
4522
4645
  */
4523
- static createToolResultsMessage(executedToolCalls) {
4646
+ static createToolResultsMessage(executedToolCalls, passToolBinariesToModel = true) {
4524
4647
  return {
4525
4648
  role: "tool",
4526
4649
  content: executedToolCalls.map((executed) => ({
4527
4650
  type: "tool-result",
4528
4651
  toolCallId: executed.toolCallId,
4529
4652
  toolName: executed.toolName,
4530
- output: {
4531
- type: "json",
4532
- value: AgentMessageFactory.toToolResultJson(executed.result)
4533
- }
4653
+ output: AgentMessageFactory.toToolResultOutput(executed.result, passToolBinariesToModel)
4534
4654
  }))
4535
4655
  };
4536
4656
  }
4657
+ /**
4658
+ * Routes a tool result to a native multimodal `{ type: "content" }` output when it is
4659
+ * content-block-shaped (an MCP `CallToolResult`) and binary passdown is enabled; otherwise keeps
4660
+ * the inert `{ type: "json" }` path.
4661
+ */
4662
+ static toToolResultOutput(result, passToolBinariesToModel) {
4663
+ if (passToolBinariesToModel) {
4664
+ const content = AgentToolResultContentFactory.tryMapToContentOutput(result);
4665
+ if (content !== void 0) return {
4666
+ type: "content",
4667
+ value: content
4668
+ };
4669
+ }
4670
+ return {
4671
+ type: "json",
4672
+ value: AgentMessageFactory.toToolResultJson(result)
4673
+ };
4674
+ }
4537
4675
  static toToolResultJson(value) {
4538
4676
  if (value === void 0) return null;
4539
4677
  try {
@@ -5852,6 +5990,63 @@ AgentToolExecutionCoordinator = __decorate([
5852
5990
  __decorateMetadata("design:paramtypes", [typeof (_ref$2 = typeof AgentToolErrorClassifier !== "undefined" && AgentToolErrorClassifier) === "function" ? _ref$2 : Object, typeof (_ref2$2 = typeof AgentToolRepairPolicy !== "undefined" && AgentToolRepairPolicy) === "function" ? _ref2$2 : Object])
5853
5991
  ], AgentToolExecutionCoordinator);
5854
5992
 
5993
+ //#endregion
5994
+ //#region src/nodes/AgentBinaryContentFactory.ts
5995
+ /**
5996
+ * Turns resolved file binaries into native AI SDK multimodal content parts and merges them into the
5997
+ * agent prompt. Images (`image/*`) become {@link ImagePart}s; every other type (PDFs, office docs,
5998
+ * CSV, JSON, …) becomes a {@link FilePart}. The provider maps these to its wire-level `image` /
5999
+ * `document` blocks; an unsupported file type surfaces as a provider error at runtime.
6000
+ *
6001
+ * Parts are appended to the LAST user message so the binary travels alongside the author's prompt
6002
+ * text (preserving any untrusted-source preamble that already wrapped that text). When no user
6003
+ * message exists, a new user message carrying only the binaries is appended.
6004
+ */
6005
+ var AgentBinaryContentFactory = class AgentBinaryContentFactory {
6006
+ static toContentPart(binary) {
6007
+ if (binary.mediaType.startsWith("image/")) return {
6008
+ type: "image",
6009
+ image: binary.base64,
6010
+ mediaType: binary.mediaType
6011
+ };
6012
+ return {
6013
+ type: "file",
6014
+ data: binary.base64,
6015
+ mediaType: binary.mediaType,
6016
+ ...binary.filename ? { filename: binary.filename } : {}
6017
+ };
6018
+ }
6019
+ static withBinaries(messages, binaries) {
6020
+ if (binaries.length === 0) return messages;
6021
+ const parts = binaries.map((binary) => AgentBinaryContentFactory.toContentPart(binary));
6022
+ const lastUserIndex = AgentBinaryContentFactory.lastUserMessageIndex(messages);
6023
+ if (lastUserIndex === -1) {
6024
+ const appended = {
6025
+ role: "user",
6026
+ content: parts
6027
+ };
6028
+ return [...messages, appended];
6029
+ }
6030
+ const next = [...messages];
6031
+ next[lastUserIndex] = AgentBinaryContentFactory.appendPartsToUserMessage(messages[lastUserIndex], parts);
6032
+ return next;
6033
+ }
6034
+ static lastUserMessageIndex(messages) {
6035
+ for (let index = messages.length - 1; index >= 0; index--) if (messages[index]?.role === "user") return index;
6036
+ return -1;
6037
+ }
6038
+ static appendPartsToUserMessage(message, parts) {
6039
+ const existing = typeof message.content === "string" ? message.content.length > 0 ? [{
6040
+ type: "text",
6041
+ text: message.content
6042
+ }] : [] : message.content;
6043
+ return {
6044
+ ...message,
6045
+ content: [...existing, ...parts]
6046
+ };
6047
+ }
6048
+ };
6049
+
5855
6050
  //#endregion
5856
6051
  //#region src/nodes/NodeBackedToolRuntime.ts
5857
6052
  var _ref$1, _ref2$1, _ref3$1, _ref4$1;
@@ -6050,11 +6245,18 @@ var DeferredMetaToolStrategy = class {
6050
6245
  mcpEntries = [];
6051
6246
  toolsByServerId = /* @__PURE__ */ new Map();
6052
6247
  foundToolIds = /* @__PURE__ */ new Set();
6248
+ /**
6249
+ * `jsonSchema` from the `ai` SDK, loaded lazily in {@link initialize} so the SDK
6250
+ * (~28MB RSS) stays off the boot path. `initialize` always runs before the sync
6251
+ * `getToolsForTurn` → `buildFindToolsDefinition` path, so this is set before use.
6252
+ */
6253
+ jsonSchema;
6053
6254
  constructor(bm25, warnFn) {
6054
6255
  this.bm25 = bm25;
6055
6256
  this.warnFn = warnFn;
6056
6257
  }
6057
6258
  async initialize(input) {
6259
+ this.jsonSchema = (await import("ai")).jsonSchema;
6058
6260
  this.nodeBackedTools = { ...input.nodeBackedTools };
6059
6261
  const pinnedIds = input.pinnedMcpTools ?? [];
6060
6262
  if (pinnedIds.length > PINNED_TOOLS_HARD_LIMIT) throw new Error(`Agent config error: pinnedMcpTools count (${pinnedIds.length}) exceeds hard limit of ${PINNED_TOOLS_HARD_LIMIT}.`);
@@ -6142,25 +6344,26 @@ var DeferredMetaToolStrategy = class {
6142
6344
  return [...this.foundToolIds];
6143
6345
  }
6144
6346
  buildFindToolsDefinition() {
6347
+ const inputSchemaRecord = {
6348
+ type: "object",
6349
+ properties: {
6350
+ query: {
6351
+ type: "string",
6352
+ description: "Natural language description of what you want to do."
6353
+ },
6354
+ limit: {
6355
+ type: "integer",
6356
+ minimum: 1,
6357
+ maximum: 10,
6358
+ description: `Maximum number of tools to return (default ${FIND_TOOLS_DEFAULT_LIMIT}).`
6359
+ }
6360
+ },
6361
+ required: ["query"],
6362
+ additionalProperties: false
6363
+ };
6145
6364
  return {
6146
6365
  description: "Search for tools available from connected MCP servers. After this call, the tools listed in the result will be callable on your very next turn. Use this when you need a capability not visible in your current tool list. Do not attempt to call a tool name you have not seen yet — use find_tools to discover it first.",
6147
- inputSchema: jsonSchema({
6148
- type: "object",
6149
- properties: {
6150
- query: {
6151
- type: "string",
6152
- description: "Natural language description of what you want to do."
6153
- },
6154
- limit: {
6155
- type: "integer",
6156
- minimum: 1,
6157
- maximum: 10,
6158
- description: `Maximum number of tools to return (default ${FIND_TOOLS_DEFAULT_LIMIT}).`
6159
- }
6160
- },
6161
- required: ["query"],
6162
- additionalProperties: false
6163
- })
6366
+ inputSchema: this.jsonSchema(inputSchemaRecord)
6164
6367
  };
6165
6368
  }
6166
6369
  };
@@ -6194,6 +6397,13 @@ let AIAgentNode = class AIAgentNode$1 {
6194
6397
  inputSchema = unknown();
6195
6398
  connectionCredentialExecutionContextFactory;
6196
6399
  preparedByExecutionContext = /* @__PURE__ */ new WeakMap();
6400
+ /**
6401
+ * The `ai` SDK, loaded lazily in {@link execute} so the SDK (~28MB RSS) stays
6402
+ * off the boot path — non-AI workflows never load it. Every path runs through
6403
+ * `execute` → `ensureAiSdk` before any sync helper touches `this.aiSdk`.
6404
+ */
6405
+ aiSdk;
6406
+ aiSdkPromise = null;
6197
6407
  constructor(nodeResolver, credentialSessions, nodeBackedToolRuntime, executionHelpers, structuredOutputRunner, toolExecutionCoordinator, toolLoadingStrategyFactory, agentMcpIntegration) {
6198
6408
  this.nodeResolver = nodeResolver;
6199
6409
  this.nodeBackedToolRuntime = nodeBackedToolRuntime;
@@ -6206,6 +6416,7 @@ let AIAgentNode = class AIAgentNode$1 {
6206
6416
  }
6207
6417
  async execute(args) {
6208
6418
  const { ctx } = args;
6419
+ await this.ensureAiSdk();
6209
6420
  if (ctx.resumeContext) return this.executeResumed(args, ctx.resumeContext);
6210
6421
  const prepared = await this.getOrPrepareExecution(ctx);
6211
6422
  const itemWithMappedJson = {
@@ -6214,6 +6425,10 @@ let AIAgentNode = class AIAgentNode$1 {
6214
6425
  };
6215
6426
  return (await this.runAgentForItem(prepared, itemWithMappedJson, args.itemIndex, args.items)).json;
6216
6427
  }
6428
+ /** Load the `ai` SDK once per node instance (cached promise guards concurrent items). */
6429
+ async ensureAiSdk() {
6430
+ this.aiSdk = await (this.aiSdkPromise ??= import("ai"));
6431
+ }
6217
6432
  /**
6218
6433
  * Resume path: re-enters the agent loop after a HITL suspension.
6219
6434
  * Reconstructs the conversation from the checkpoint, injects the human decision
@@ -6245,7 +6460,7 @@ let AIAgentNode = class AIAgentNode$1 {
6245
6460
  result: decision,
6246
6461
  serialized: JSON.stringify(decision)
6247
6462
  };
6248
- const conversation = [...checkpoint.conversation, AgentMessageFactory.createToolResultsMessage([toolResultEntry])];
6463
+ const conversation = [...checkpoint.conversation, AgentMessageFactory.createToolResultsMessage([toolResultEntry], ctx.config.passToolBinariesToModel !== false)];
6249
6464
  const loopResult = await this.runTurnLoopUntilFinalAnswer({
6250
6465
  prepared,
6251
6466
  itemInputsByPort,
@@ -6356,7 +6571,7 @@ let AIAgentNode = class AIAgentNode$1 {
6356
6571
  const { ctx } = prepared;
6357
6572
  const itemInputsByPort = AgentItemPortMap.fromItem(item);
6358
6573
  const itemScopedTools = this.createItemScopedTools(prepared.resolvedTools, ctx, item, itemIndex, items);
6359
- const conversation = [...this.createPromptMessages(item, itemIndex, items, ctx)];
6574
+ const conversation = [...await this.createPromptMessages(item, itemIndex, items, ctx)];
6360
6575
  if (ctx.config.outputSchema && itemScopedTools.length === 0) {
6361
6576
  const structuredOutput = await this.structuredOutputRunner.resolve({
6362
6577
  model: prepared.model,
@@ -6465,7 +6680,7 @@ let AIAgentNode = class AIAgentNode$1 {
6465
6680
  coordinatorExecutedCalls.push(...executed);
6466
6681
  }
6467
6682
  const allExecutedCalls = [...strategyExecutedCalls, ...coordinatorExecutedCalls];
6468
- this.appendAssistantAndToolMessages(conversation, result.assistantMessage, result.text, result.toolCalls, allExecutedCalls);
6683
+ this.appendAssistantAndToolMessages(conversation, result.assistantMessage, result.text, result.toolCalls, allExecutedCalls, ctx.config.passToolBinariesToModel !== false);
6469
6684
  }
6470
6685
  return {
6471
6686
  finalText,
@@ -6480,8 +6695,8 @@ let AIAgentNode = class AIAgentNode$1 {
6480
6695
  if (guardrails.onTurnLimitReached === "respondWithLastMessage") return;
6481
6696
  throw new Error(`AIAgent "${ctx.config.name ?? ctx.nodeId}" reached maxTurns=${guardrails.maxTurns} before producing a final response.`);
6482
6697
  }
6483
- appendAssistantAndToolMessages(conversation, assistantMessage, text, toolCalls, executedToolCalls) {
6484
- conversation.push(assistantMessage ?? AgentMessageFactory.createAssistantWithToolCalls(text, toolCalls), AgentMessageFactory.createToolResultsMessage(executedToolCalls));
6698
+ appendAssistantAndToolMessages(conversation, assistantMessage, text, toolCalls, executedToolCalls, passToolBinariesToModel) {
6699
+ conversation.push(assistantMessage ?? AgentMessageFactory.createAssistantWithToolCalls(text, toolCalls), AgentMessageFactory.createToolResultsMessage(executedToolCalls, passToolBinariesToModel));
6485
6700
  }
6486
6701
  async resolveFinalOutputJson(prepared, itemInputsByPort, conversation, finalText, wasToolEnabledRun) {
6487
6702
  if (!prepared.ctx.config.outputSchema) return AgentOutputFactory.fromAgentContent(finalText);
@@ -6600,7 +6815,7 @@ let AIAgentNode = class AIAgentNode$1 {
6600
6815
  const description = this.resolveHumanApprovalBehavior(entry.config) !== void 0 ? `${baseDescription} ${HITL_SOLO_CONSTRAINT_SENTENCE}` : baseDescription;
6601
6816
  toolSet[entry.config.name] = {
6602
6817
  description,
6603
- inputSchema: jsonSchema(schemaRecord)
6818
+ inputSchema: this.aiSdk.jsonSchema(schemaRecord)
6604
6819
  };
6605
6820
  }
6606
6821
  return toolSet;
@@ -6631,7 +6846,7 @@ let AIAgentNode = class AIAgentNode$1 {
6631
6846
  const description = entry.humanApproval !== void 0 && baseDescription !== void 0 ? `${baseDescription} ${HITL_SOLO_CONSTRAINT_SENTENCE}` : entry.humanApproval !== void 0 ? HITL_SOLO_CONSTRAINT_SENTENCE : baseDescription;
6632
6847
  toolSet[entry.config.name] = {
6633
6848
  description,
6634
- inputSchema: jsonSchema(schemaRecord)
6849
+ inputSchema: this.aiSdk.jsonSchema(schemaRecord)
6635
6850
  };
6636
6851
  }
6637
6852
  return toolSet;
@@ -6683,7 +6898,7 @@ let AIAgentNode = class AIAgentNode$1 {
6683
6898
  });
6684
6899
  try {
6685
6900
  const callOptions = this.resolveCallOptions(model, guardrails.modelInvocationOptions);
6686
- const result = await generateText({
6901
+ const result = await this.aiSdk.generateText({
6687
6902
  model: model.languageModel,
6688
6903
  messages: [...messages],
6689
6904
  tools,
@@ -6802,8 +7017,8 @@ let AIAgentNode = class AIAgentNode$1 {
6802
7017
  schemaName: structuredOptions?.schemaName ?? "structured_output",
6803
7018
  requireObjectRoot: true
6804
7019
  }) : schema;
6805
- const outputSchema = Output.object({ schema: jsonSchema(schemaRecord) });
6806
- const result = await generateText({
7020
+ const outputSchema = this.aiSdk.Output.object({ schema: this.aiSdk.jsonSchema(schemaRecord) });
7021
+ const result = await this.aiSdk.generateText({
6807
7022
  model: model.languageModel,
6808
7023
  messages: [...messages],
6809
7024
  experimental_output: outputSchema,
@@ -7074,7 +7289,7 @@ let AIAgentNode = class AIAgentNode$1 {
7074
7289
  const json = JSON.stringify(value);
7075
7290
  return JSON.parse(json);
7076
7291
  }
7077
- createPromptMessages(item, itemIndex, items, ctx) {
7292
+ async createPromptMessages(item, itemIndex, items, ctx) {
7078
7293
  const messages = AgentMessageConfigNormalizer.resolveFromInputOrConfig(item.json, ctx.config, {
7079
7294
  item,
7080
7295
  itemIndex,
@@ -7082,7 +7297,47 @@ let AIAgentNode = class AIAgentNode$1 {
7082
7297
  ctx
7083
7298
  });
7084
7299
  const wrapped = this.wrapUntrustedSourceMessages(messages, item, ctx.config);
7085
- return AgentMessageFactory.createPromptMessages(wrapped);
7300
+ const promptMessages = AgentMessageFactory.createPromptMessages(wrapped);
7301
+ if (ctx.config.passBinariesToModel === false) return promptMessages;
7302
+ const attachments = this.selectBinaryAttachments(item, itemIndex, items, ctx);
7303
+ const binaries = await this.resolveInlineBinaries(attachments, ctx);
7304
+ return AgentBinaryContentFactory.withBinaries(promptMessages, binaries);
7305
+ }
7306
+ /**
7307
+ * Picks which attachments feed the passdown. When the author supplies `config.binaries`
7308
+ * (a static array or a per-item function — e.g. to forward binaries from an earlier node),
7309
+ * those replace the current item's attachments; otherwise the current item's `item.binary`
7310
+ * is used.
7311
+ */
7312
+ selectBinaryAttachments(item, itemIndex, items, ctx) {
7313
+ const manual = ctx.config.binaries;
7314
+ if (manual !== void 0) return typeof manual === "function" ? manual({
7315
+ item,
7316
+ itemIndex,
7317
+ items,
7318
+ ctx
7319
+ }) : manual;
7320
+ return item.binary ? Object.values(item.binary) : [];
7321
+ }
7322
+ /**
7323
+ * Reads every attachment through `ctx.binary` (storage-backed, by reference — never base64 on
7324
+ * `item.json`) and resolves it to inline base64 so the agent can pass it to the chat model as a
7325
+ * native multimodal block. Images become image blocks; every other type (PDF, office docs, CSV,
7326
+ * JSON, …) becomes a file block — we don't filter by media type, so any binary can be fed to the
7327
+ * model. If the provider rejects an unsupported type the error surfaces at runtime, and the
7328
+ * workflow can filter the binary upstream.
7329
+ */
7330
+ async resolveInlineBinaries(attachments, ctx) {
7331
+ const resolved = [];
7332
+ for (const attachment of attachments) {
7333
+ const bytes = await ctx.binary.getBytes(attachment);
7334
+ resolved.push({
7335
+ mediaType: attachment.mimeType,
7336
+ base64: Buffer.from(bytes).toString("base64"),
7337
+ ...attachment.filename ? { filename: attachment.filename } : {}
7338
+ });
7339
+ }
7340
+ return resolved;
7086
7341
  }
7087
7342
  /**
7088
7343
  * When `item.json.__source` matches an entry in `config.untrustedSources`
@@ -7196,6 +7451,7 @@ var AIAgent = class {
7196
7451
  chatModel;
7197
7452
  tools;
7198
7453
  id;
7454
+ description;
7199
7455
  retryPolicy;
7200
7456
  guardrails;
7201
7457
  inputSchema;
@@ -7203,12 +7459,16 @@ var AIAgent = class {
7203
7459
  mcpServers;
7204
7460
  pinnedMcpTools;
7205
7461
  untrustedSources;
7462
+ passBinariesToModel;
7463
+ passToolBinariesToModel;
7464
+ binaries;
7206
7465
  constructor(options) {
7207
7466
  this.name = options.name;
7208
7467
  this.messages = options.messages;
7209
7468
  this.chatModel = options.chatModel;
7210
7469
  this.tools = options.tools ?? [];
7211
7470
  this.id = options.id;
7471
+ this.description = options.description;
7212
7472
  this.retryPolicy = options.retryPolicy ?? RetryPolicy.defaultForAiAgent;
7213
7473
  this.guardrails = options.guardrails;
7214
7474
  this.inputSchema = options.inputSchema;
@@ -7216,6 +7476,9 @@ var AIAgent = class {
7216
7476
  this.mcpServers = options.mcpServers;
7217
7477
  this.pinnedMcpTools = options.pinnedMcpTools;
7218
7478
  this.untrustedSources = options.untrustedSources;
7479
+ this.passBinariesToModel = options.passBinariesToModel;
7480
+ this.passToolBinariesToModel = options.passToolBinariesToModel;
7481
+ this.binaries = options.binaries;
7219
7482
  }
7220
7483
  inspectorSummary() {
7221
7484
  const rows = [];
@@ -7286,12 +7549,14 @@ var Assertion = class {
7286
7549
  icon;
7287
7550
  name;
7288
7551
  id;
7552
+ description;
7289
7553
  emitsAssertions = true;
7290
7554
  assertions;
7291
7555
  constructor(options) {
7292
7556
  this.name = options.name ?? "Assertion";
7293
7557
  this.id = options.id;
7294
7558
  this.icon = options.icon ?? "lucide:check-circle";
7559
+ this.description = options.description;
7295
7560
  this.assertions = options.assertions;
7296
7561
  }
7297
7562
  inspectorSummary() {
@@ -7343,6 +7608,7 @@ var Callback = class Callback {
7343
7608
  icon = "lucide:braces";
7344
7609
  emptyBatchExecution = "runOnce";
7345
7610
  id;
7611
+ description;
7346
7612
  retryPolicy;
7347
7613
  nodeErrorHandler;
7348
7614
  declaredOutputPorts;
@@ -7354,6 +7620,7 @@ var Callback = class Callback {
7354
7620
  id: idOrOptions
7355
7621
  } : idOrOptions;
7356
7622
  this.id = resolvedOptions?.id;
7623
+ this.description = resolvedOptions?.description;
7357
7624
  this.retryPolicy = resolvedOptions?.retryPolicy;
7358
7625
  this.nodeErrorHandler = resolvedOptions?.nodeErrorHandler;
7359
7626
  this.declaredOutputPorts = resolvedOptions?.declaredOutputPorts;
@@ -7555,10 +7822,12 @@ var HttpRequest = class {
7555
7822
  type = HttpRequestNode;
7556
7823
  execution = { hint: "local" };
7557
7824
  icon = "lucide:globe";
7825
+ description;
7558
7826
  constructor(name, args = {}, retryPolicy = RetryPolicy.defaultForHttp) {
7559
7827
  this.name = name;
7560
7828
  this.args = args;
7561
7829
  this.retryPolicy = retryPolicy;
7830
+ this.description = args.description;
7562
7831
  }
7563
7832
  get id() {
7564
7833
  return this.args.id;
@@ -7653,10 +7922,14 @@ var Aggregate = class {
7653
7922
  execution = { hint: "local" };
7654
7923
  keepBinaries = true;
7655
7924
  icon = "builtin:aggregate-rows";
7656
- constructor(name, aggregate, id) {
7925
+ id;
7926
+ description;
7927
+ constructor(name, aggregate, idOrOptions) {
7657
7928
  this.name = name;
7658
7929
  this.aggregate = aggregate;
7659
- this.id = id;
7930
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
7931
+ this.id = options?.id;
7932
+ this.description = options?.description;
7660
7933
  }
7661
7934
  inspectorSummary() {
7662
7935
  const fnName = this.aggregate.name;
@@ -7687,10 +7960,14 @@ var Filter = class {
7687
7960
  type = FilterNode;
7688
7961
  execution = { hint: "local" };
7689
7962
  icon = "lucide:filter";
7690
- constructor(name, predicate, id) {
7963
+ id;
7964
+ description;
7965
+ constructor(name, predicate, idOrOptions) {
7691
7966
  this.name = name;
7692
7967
  this.predicate = predicate;
7693
- this.id = id;
7968
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
7969
+ this.id = options?.id;
7970
+ this.description = options?.description;
7694
7971
  }
7695
7972
  inspectorSummary() {
7696
7973
  const fnName = this.predicate.name;
@@ -7765,10 +8042,14 @@ var If = class {
7765
8042
  execution = { hint: "local" };
7766
8043
  icon = "lucide:split@rot=90";
7767
8044
  declaredOutputPorts = ["true", "false"];
7768
- constructor(name, predicate, id) {
8045
+ id;
8046
+ description;
8047
+ constructor(name, predicate, idOrOptions) {
7769
8048
  this.name = name;
7770
8049
  this.predicate = predicate;
7771
- this.id = id;
8050
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
8051
+ this.id = options?.id;
8052
+ this.description = options?.description;
7772
8053
  }
7773
8054
  inspectorSummary() {
7774
8055
  const fnName = this.predicate.name;
@@ -7808,9 +8089,12 @@ var IsTestRun = class {
7808
8089
  declaredOutputPorts = ["true", "false"];
7809
8090
  name;
7810
8091
  id;
7811
- constructor(name = "Is test run?", id) {
8092
+ description;
8093
+ constructor(name = "Is test run?", idOrOptions) {
7812
8094
  this.name = name;
7813
- this.id = id;
8095
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
8096
+ this.id = options?.id;
8097
+ this.description = options?.description;
7814
8098
  }
7815
8099
  };
7816
8100
 
@@ -7839,11 +8123,15 @@ var Switch = class {
7839
8123
  execution = { hint: "local" };
7840
8124
  icon = "lucide:git-branch-plus";
7841
8125
  declaredOutputPorts;
7842
- constructor(name, cfg, id) {
8126
+ id;
8127
+ description;
8128
+ constructor(name, cfg, idOrOptions) {
7843
8129
  this.name = name;
7844
8130
  this.cfg = cfg;
7845
- this.id = id;
7846
8131
  this.declaredOutputPorts = [...new Set([...cfg.cases, cfg.defaultCase])].sort();
8132
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
8133
+ this.id = options?.id;
8134
+ this.description = options?.description;
7847
8135
  }
7848
8136
  inspectorSummary() {
7849
8137
  const rows = [{
@@ -7882,10 +8170,14 @@ var Split = class {
7882
8170
  */
7883
8171
  continueWhenEmptyOutput = true;
7884
8172
  icon = "builtin:split-rows";
7885
- constructor(name, getElements, id) {
8173
+ id;
8174
+ description;
8175
+ constructor(name, getElements, idOrOptions) {
7886
8176
  this.name = name;
7887
8177
  this.getElements = getElements;
7888
- this.id = id;
8178
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
8179
+ this.id = options?.id;
8180
+ this.description = options?.description;
7889
8181
  }
7890
8182
  inspectorSummary() {
7891
8183
  const fnName = this.getElements.name;
@@ -7943,14 +8235,17 @@ var CronTrigger = class {
7943
8235
  type = CronTriggerNode;
7944
8236
  icon = "lucide:clock";
7945
8237
  id;
7946
- constructor(name, args, id) {
8238
+ description;
8239
+ constructor(name, args, idOrOptions) {
7947
8240
  this.name = name;
7948
8241
  this.args = args;
7949
8242
  new Cron(args.schedule, {
7950
8243
  paused: true,
7951
8244
  timezone: args.timezone
7952
8245
  });
7953
- this.id = id;
8246
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
8247
+ this.id = options?.id;
8248
+ this.description = options?.description;
7954
8249
  }
7955
8250
  get schedule() {
7956
8251
  return this.args.schedule;
@@ -8004,20 +8299,21 @@ var ManualTrigger = class ManualTrigger {
8004
8299
  icon = "lucide:play";
8005
8300
  defaultItems;
8006
8301
  id;
8302
+ description;
8007
8303
  /** Manual runs often emit an empty batch; still schedule downstream by default. */
8008
8304
  continueWhenEmptyOutput = true;
8009
- constructor(name = "Manual trigger", defaultItemsOrId, id) {
8305
+ constructor(name = "Manual trigger", defaultItemsOrId, idOrOptions) {
8010
8306
  this.name = name;
8011
8307
  this.defaultItems = ManualTrigger.resolveDefaultItems(defaultItemsOrId);
8012
- this.id = ManualTrigger.resolveId(defaultItemsOrId, id);
8308
+ const trailing = idOrOptions ?? (typeof defaultItemsOrId === "string" ? defaultItemsOrId : void 0);
8309
+ const options = typeof trailing === "string" ? { id: trailing } : trailing ?? {};
8310
+ this.id = options.id;
8311
+ this.description = options.description;
8013
8312
  }
8014
8313
  static resolveDefaultItems(value) {
8015
8314
  if (typeof value === "string" || value === void 0) return;
8016
8315
  return this.itemsInputNormalizer.normalize(value);
8017
8316
  }
8018
- static resolveId(value, id) {
8019
- return typeof value === "string" ? value : id;
8020
- }
8021
8317
  inspectorSummary() {
8022
8318
  const rows = [{
8023
8319
  label: "Trigger",
@@ -8063,11 +8359,13 @@ var MapData = class {
8063
8359
  continueWhenEmptyOutput = true;
8064
8360
  icon = "lucide:square-pen";
8065
8361
  keepBinaries;
8362
+ description;
8066
8363
  constructor(name, map, options = {}) {
8067
8364
  this.name = name;
8068
8365
  this.map = map;
8069
8366
  this.options = options;
8070
8367
  this.keepBinaries = options.keepBinaries ?? true;
8368
+ this.description = options.description;
8071
8369
  }
8072
8370
  get id() {
8073
8371
  return this.options.id;
@@ -8140,10 +8438,14 @@ var Merge = class {
8140
8438
  kind = "node";
8141
8439
  type = MergeNode;
8142
8440
  icon = "lucide:merge@rot=90";
8143
- constructor(name, cfg = { mode: "passThrough" }, id) {
8441
+ id;
8442
+ description;
8443
+ constructor(name, cfg = { mode: "passThrough" }, idOrOptions) {
8144
8444
  this.name = name;
8145
8445
  this.cfg = cfg;
8146
- this.id = id;
8446
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
8447
+ this.id = options?.id;
8448
+ this.description = options?.description;
8147
8449
  }
8148
8450
  inspectorSummary() {
8149
8451
  const rows = [{
@@ -8176,9 +8478,13 @@ var NoOp = class {
8176
8478
  type = NoOpNode;
8177
8479
  execution = { hint: "local" };
8178
8480
  icon = "lucide:circle-dashed";
8179
- constructor(name = "NoOp", id) {
8481
+ id;
8482
+ description;
8483
+ constructor(name = "NoOp", idOrOptions) {
8180
8484
  this.name = name;
8181
- this.id = id;
8485
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
8486
+ this.id = options?.id;
8487
+ this.description = options?.description;
8182
8488
  }
8183
8489
  };
8184
8490
 
@@ -8244,12 +8550,16 @@ var SubWorkflow = class {
8244
8550
  kind = "node";
8245
8551
  type = SubWorkflowNode;
8246
8552
  icon = "lucide:workflow";
8247
- constructor(name, workflowId, upstreamRefs, startAt, id) {
8553
+ id;
8554
+ description;
8555
+ constructor(name, workflowId, upstreamRefs, startAt, idOrOptions) {
8248
8556
  this.name = name;
8249
8557
  this.workflowId = workflowId;
8250
8558
  this.upstreamRefs = upstreamRefs;
8251
8559
  this.startAt = startAt;
8252
- this.id = id;
8560
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
8561
+ this.id = options?.id;
8562
+ this.description = options?.description;
8253
8563
  }
8254
8564
  inspectorSummary() {
8255
8565
  const rows = [{
@@ -8359,10 +8669,14 @@ var Wait = class {
8359
8669
  /** Pass-through empty batches should still advance to downstream nodes. */
8360
8670
  continueWhenEmptyOutput = true;
8361
8671
  icon = "lucide:hourglass";
8362
- constructor(name, milliseconds, id) {
8672
+ id;
8673
+ description;
8674
+ constructor(name, milliseconds, idOrOptions) {
8363
8675
  this.name = name;
8364
8676
  this.milliseconds = milliseconds;
8365
- this.id = id;
8677
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
8678
+ this.id = options?.id;
8679
+ this.description = options?.description;
8366
8680
  }
8367
8681
  inspectorSummary() {
8368
8682
  const seconds = this.milliseconds / 1e3;
@@ -8417,11 +8731,15 @@ var WebhookTrigger = class WebhookTrigger {
8417
8731
  kind = "trigger";
8418
8732
  type = WebhookTriggerNode;
8419
8733
  icon = "lucide:globe";
8420
- constructor(name, args, handler = WebhookTrigger.defaultHandler, id) {
8734
+ id;
8735
+ description;
8736
+ constructor(name, args, handler = WebhookTrigger.defaultHandler, idOrOptions) {
8421
8737
  this.name = name;
8422
8738
  this.args = args;
8423
8739
  this.handler = handler;
8424
- this.id = id;
8740
+ const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
8741
+ this.id = options?.id;
8742
+ this.description = options?.description;
8425
8743
  }
8426
8744
  get endpointKey() {
8427
8745
  return this.args.endpointKey;
@@ -8478,11 +8796,21 @@ function createWorkflowBuilder(meta$2) {
8478
8796
 
8479
8797
  //#endregion
8480
8798
  //#region src/workflowAuthoring/WorkflowChatModelFactory.types.ts
8799
+ const VALID_COMPLEXITY = new Set([
8800
+ "low",
8801
+ "medium",
8802
+ "high",
8803
+ "xhigh"
8804
+ ]);
8481
8805
  var WorkflowChatModelFactory = class {
8482
8806
  static create(model) {
8483
8807
  if (typeof model !== "string") return model;
8484
8808
  const [provider, resolvedModel] = model.includes(":") ? model.split(":", 2) : ["openai", model];
8485
- if (provider === "codemation-managed") return new CodemationChatModelConfig("Codemation Managed", resolvedModel ?? "");
8809
+ if (provider === "codemation-managed") {
8810
+ const complexity = resolvedModel ?? "medium";
8811
+ if (!VALID_COMPLEXITY.has(complexity)) throw new Error(`Invalid managed complexity "${complexity}". Must be one of: low, medium, high, xhigh.`);
8812
+ return new CodemationChatModelConfig("Codemation Managed", complexity);
8813
+ }
8486
8814
  if (provider !== "openai") throw new Error(`Unsupported workflow().agent() model provider "${provider}".`);
8487
8815
  return new OpenAIChatModelConfig("OpenAI", resolvedModel);
8488
8816
  }
@@ -9119,5 +9447,5 @@ const codemationDocumentScannerNode = defineNode({
9119
9447
  });
9120
9448
 
9121
9449
  //#endregion
9122
- export { AIAgent, AIAgentConnectionWorkflowExpander, AIAgentExecutionHelpersFactory, AIAgentNode, AgentItemPortMap, AgentMessageFactory, AgentOutputFactory, AgentStructuredOutputRepairPromptFactory, AgentStructuredOutputRunner, AgentToolCallPortMap, AgentToolErrorClassifier, AgentToolExecutionCoordinator, AgentToolRepairExhaustedError, AgentToolRepairPolicy, Aggregate, AggregateNode, Assertion, AssertionNode, BM25Index, Callback, CallbackNode, CallbackResultNormalizer, CodemationChatModelConfig, CodemationChatModelFactory, ConnectionCredentialExecutionContextFactory, ConnectionCredentialNode, ConnectionCredentialNodeConfig, ConnectionCredentialNodeConfigFactory, CronTrigger, CronTriggerNode, DeferredMetaToolStrategy, DeferredMetaToolStrategyFactory, Filter, FilterNode, HTTP_REQUEST_ACCEPTED_CREDENTIAL_TYPES, HttpRequest, HttpRequestNode, If, IfNode, IsTestRun, IsTestRunNode, ManagedModelFetcher, ManualTrigger, ManualTriggerNode, MapData, MapDataNode, Merge, MergeNode, NoOp, NoOpNode, OpenAIChatModelConfig, OpenAIChatModelFactory, OpenAiChatModelPresets, OpenAiStrictJsonSchemaFactory, SSRFBlockedError, Split, SplitNode, SsrfGuard, SubWorkflow, SubWorkflowNode, Switch, SwitchNode, TestTrigger, TestTriggerNode, Wait, WaitDuration, WaitNode, WebhookRespondNowAndContinueError, WebhookRespondNowError, WebhookTrigger, WebhookTriggerNode, WorkflowAuthoringBuilder, WorkflowBranchBuilder, WorkflowChain, apiKeyCredentialType, basicAuthCredentialType, bearerTokenCredentialType, codemationDocumentScannerNode, collectionDeleteNode, collectionFindOneNode, collectionGetNode, collectionInsertNode, collectionListNode, collectionUpdateNode, createWorkflowBuilder, defineRestNode, inboxApproval, oauth2ClientCredentialsType, openAiChatModelPresets, registerCoreNodes, workflow };
9450
+ export { AIAgent, AIAgentConnectionWorkflowExpander, AIAgentExecutionHelpersFactory, AIAgentNode, AgentItemPortMap, AgentMessageFactory, AgentOutputFactory, AgentStructuredOutputRepairPromptFactory, AgentStructuredOutputRunner, AgentToolCallPortMap, AgentToolErrorClassifier, AgentToolExecutionCoordinator, AgentToolRepairExhaustedError, AgentToolRepairPolicy, Aggregate, AggregateNode, Assertion, AssertionNode, BM25Index, Callback, CallbackNode, CallbackResultNormalizer, CodemationChatModelConfig, CodemationChatModelFactory, ConnectionCredentialExecutionContextFactory, ConnectionCredentialNode, ConnectionCredentialNodeConfig, ConnectionCredentialNodeConfigFactory, CronTrigger, CronTriggerNode, DeferredMetaToolStrategy, DeferredMetaToolStrategyFactory, Filter, FilterNode, HTTP_REQUEST_ACCEPTED_CREDENTIAL_TYPES, HttpRequest, HttpRequestNode, If, IfNode, IsTestRun, IsTestRunNode, ManualTrigger, ManualTriggerNode, MapData, MapDataNode, Merge, MergeNode, NoOp, NoOpNode, OpenAIChatModelConfig, OpenAIChatModelFactory, OpenAiChatModelPresets, OpenAiStrictJsonSchemaFactory, SSRFBlockedError, Split, SplitNode, SsrfGuard, SubWorkflow, SubWorkflowNode, Switch, SwitchNode, TestTrigger, TestTriggerNode, Wait, WaitDuration, WaitNode, WebhookRespondNowAndContinueError, WebhookRespondNowError, WebhookTrigger, WebhookTriggerNode, WorkflowAuthoringBuilder, WorkflowBranchBuilder, WorkflowChain, apiKeyCredentialType, basicAuthCredentialType, bearerTokenCredentialType, codemationDocumentScannerNode, collectionDeleteNode, collectionFindOneNode, collectionGetNode, collectionInsertNode, collectionListNode, collectionUpdateNode, createWorkflowBuilder, defineRestNode, inboxApproval, oauth2ClientCredentialsType, openAiChatModelPresets, registerCoreNodes, workflow };
9123
9451
  //# sourceMappingURL=index.js.map