@codemation/core-nodes 0.10.2 → 0.12.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 +105 -0
- package/dist/index.cjs +259 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +191 -66
- package/dist/index.d.ts +192 -67
- package/dist/index.js +259 -97
- package/dist/index.js.map +1 -1
- package/dist/metadata.json +1 -1
- package/package.json +3 -2
- package/src/chatModels/CodemationChatModelConfig.ts +9 -21
- package/src/chatModels/CodemationChatModelFactory.ts +12 -9
- package/src/chatModels/OpenAIChatModelFactory.ts +3 -2
- package/src/index.ts +1 -1
- package/src/nodes/AIAgentConfig.ts +28 -0
- package/src/nodes/AIAgentNode.ts +77 -13
- package/src/nodes/AgentBinaryContentFactory.ts +74 -0
- package/src/nodes/CallbackNodeFactory.ts +9 -6
- package/src/nodes/CronTriggerFactory.ts +6 -2
- package/src/nodes/DeferredMetaToolStrategy.ts +8 -2
- package/src/nodes/ManualTriggerFactory.ts +15 -11
- package/src/nodes/WebhookTriggerFactory.ts +9 -2
- package/src/nodes/aggregate.ts +9 -2
- package/src/nodes/assertion.ts +3 -0
- package/src/nodes/filter.ts +9 -2
- package/src/nodes/httpRequest.ts +6 -1
- package/src/nodes/if.ts +9 -2
- package/src/nodes/isTestRun.ts +6 -2
- package/src/nodes/mapData.ts +4 -2
- package/src/nodes/merge.ts +9 -2
- package/src/nodes/noOp.ts +9 -2
- package/src/nodes/nodeOptions.types.ts +12 -0
- package/src/nodes/split.ts +9 -2
- package/src/nodes/subWorkflow.ts +9 -2
- package/src/nodes/switch.ts +7 -1
- package/src/nodes/wait.ts +9 -2
- package/src/workflowAuthoring/WorkflowChatModelFactory.types.ts +8 -2
- package/src/chatModels/ManagedModelFetcher.ts +0 -23
package/dist/index.cjs
CHANGED
|
@@ -25,14 +25,10 @@ let __codemation_core = require("@codemation/core");
|
|
|
25
25
|
__codemation_core = __toESM(__codemation_core);
|
|
26
26
|
let node_dns_promises = require("node:dns/promises");
|
|
27
27
|
node_dns_promises = __toESM(node_dns_promises);
|
|
28
|
-
let __ai_sdk_openai = require("@ai-sdk/openai");
|
|
29
|
-
__ai_sdk_openai = __toESM(__ai_sdk_openai);
|
|
30
28
|
let __codemation_core_bootstrap = require("@codemation/core/bootstrap");
|
|
31
29
|
__codemation_core_bootstrap = __toESM(__codemation_core_bootstrap);
|
|
32
30
|
let node_crypto = require("node:crypto");
|
|
33
31
|
node_crypto = __toESM(node_crypto);
|
|
34
|
-
let ai = require("ai");
|
|
35
|
-
ai = __toESM(ai);
|
|
36
32
|
let croner = require("croner");
|
|
37
33
|
croner = __toESM(croner);
|
|
38
34
|
|
|
@@ -704,8 +700,9 @@ function __decorate(decorators, target, key, desc) {
|
|
|
704
700
|
let OpenAIChatModelFactory = class OpenAIChatModelFactory$1 {
|
|
705
701
|
async create(args) {
|
|
706
702
|
const session = await args.ctx.getCredential(args.config.credentialSlotKey);
|
|
703
|
+
const { createOpenAI } = await import("@ai-sdk/openai");
|
|
707
704
|
return {
|
|
708
|
-
languageModel:
|
|
705
|
+
languageModel: createOpenAI({
|
|
709
706
|
apiKey: session.apiKey,
|
|
710
707
|
baseURL: session.baseUrl
|
|
711
708
|
}).chat(args.config.model),
|
|
@@ -4448,27 +4445,24 @@ function buildHmacAuthHeader(workspaceId, pairingSecret, method, url, body, over
|
|
|
4448
4445
|
//#endregion
|
|
4449
4446
|
//#region src/chatModels/CodemationChatModelFactory.ts
|
|
4450
4447
|
let CodemationChatModelFactory = class CodemationChatModelFactory$1 {
|
|
4451
|
-
create(args) {
|
|
4448
|
+
async create(args) {
|
|
4452
4449
|
const gatewayUrl = process.env["LLM_GATEWAY_URL"];
|
|
4453
4450
|
if (!gatewayUrl) throw new Error("Codemation managed AI not available in this environment (LLM_GATEWAY_URL is not set).");
|
|
4454
4451
|
const workspaceId = process.env["WORKSPACE_ID"];
|
|
4455
4452
|
const pairingSecret = process.env["WORKSPACE_PAIRING_SECRET"];
|
|
4456
4453
|
if (!workspaceId || !pairingSecret) throw new Error("Codemation managed AI not available in this environment (workspace pairing is not configured).");
|
|
4457
4454
|
const hmacFetch = managedHmacFetchFactory(workspaceId, pairingSecret);
|
|
4458
|
-
const
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
modelName: args.config.
|
|
4455
|
+
const { createAnthropic } = await import("@ai-sdk/anthropic");
|
|
4456
|
+
return {
|
|
4457
|
+
languageModel: createAnthropic({
|
|
4458
|
+
baseURL: `${gatewayUrl}/v1`,
|
|
4459
|
+
apiKey: "codemation-managed",
|
|
4460
|
+
fetch: hmacFetch
|
|
4461
|
+
})(args.config.complexity),
|
|
4462
|
+
modelName: args.config.complexity,
|
|
4466
4463
|
provider: "codemation-managed",
|
|
4467
|
-
defaultCallOptions: {
|
|
4468
|
-
|
|
4469
|
-
temperature: args.config.options?.temperature
|
|
4470
|
-
}
|
|
4471
|
-
});
|
|
4464
|
+
defaultCallOptions: { maxOutputTokens: args.config.options?.maxTokens }
|
|
4465
|
+
};
|
|
4472
4466
|
}
|
|
4473
4467
|
};
|
|
4474
4468
|
CodemationChatModelFactory = __decorate([(0, __codemation_core.chatModel)({ packageName: "@codemation/core-nodes" })], CodemationChatModelFactory);
|
|
@@ -4480,11 +4474,11 @@ var CodemationChatModelConfig = class {
|
|
|
4480
4474
|
presentation;
|
|
4481
4475
|
provider = "codemation-managed";
|
|
4482
4476
|
modelName;
|
|
4483
|
-
constructor(name,
|
|
4477
|
+
constructor(name, complexity, presentationIn, options) {
|
|
4484
4478
|
this.name = name;
|
|
4485
|
-
this.
|
|
4479
|
+
this.complexity = complexity;
|
|
4486
4480
|
this.options = options;
|
|
4487
|
-
this.modelName =
|
|
4481
|
+
this.modelName = complexity;
|
|
4488
4482
|
this.presentation = presentationIn ?? {
|
|
4489
4483
|
icon: "lucide:bot",
|
|
4490
4484
|
label: name
|
|
@@ -4492,28 +4486,6 @@ var CodemationChatModelConfig = class {
|
|
|
4492
4486
|
}
|
|
4493
4487
|
};
|
|
4494
4488
|
|
|
4495
|
-
//#endregion
|
|
4496
|
-
//#region src/chatModels/ManagedModelFetcher.ts
|
|
4497
|
-
/**
|
|
4498
|
-
* Fetches the active platform-managed model allowlist from the CP.
|
|
4499
|
-
* Reads CONTROL_PLANE_URL from the workspace process env.
|
|
4500
|
-
* Returns an empty array if the env var is absent or the fetch fails.
|
|
4501
|
-
* Cache the result per session — the allowlist changes infrequently.
|
|
4502
|
-
*/
|
|
4503
|
-
var ManagedModelFetcher = class {
|
|
4504
|
-
async fetch() {
|
|
4505
|
-
const cpUrl = process.env["CONTROL_PLANE_URL"];
|
|
4506
|
-
if (!cpUrl) return [];
|
|
4507
|
-
try {
|
|
4508
|
-
const res = await globalThis.fetch(`${cpUrl}/api/llm/managed-models`);
|
|
4509
|
-
if (!res.ok) return [];
|
|
4510
|
-
return await res.json();
|
|
4511
|
-
} catch {
|
|
4512
|
-
return [];
|
|
4513
|
-
}
|
|
4514
|
-
}
|
|
4515
|
-
};
|
|
4516
|
-
|
|
4517
4489
|
//#endregion
|
|
4518
4490
|
//#region src/nodes/AgentMessageFactory.ts
|
|
4519
4491
|
/**
|
|
@@ -5882,6 +5854,63 @@ AgentToolExecutionCoordinator = __decorate([
|
|
|
5882
5854
|
__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])
|
|
5883
5855
|
], AgentToolExecutionCoordinator);
|
|
5884
5856
|
|
|
5857
|
+
//#endregion
|
|
5858
|
+
//#region src/nodes/AgentBinaryContentFactory.ts
|
|
5859
|
+
/**
|
|
5860
|
+
* Turns resolved file binaries into native AI SDK multimodal content parts and merges them into the
|
|
5861
|
+
* agent prompt. Images (`image/*`) become {@link ImagePart}s; every other type (PDFs, office docs,
|
|
5862
|
+
* CSV, JSON, …) becomes a {@link FilePart}. The provider maps these to its wire-level `image` /
|
|
5863
|
+
* `document` blocks; an unsupported file type surfaces as a provider error at runtime.
|
|
5864
|
+
*
|
|
5865
|
+
* Parts are appended to the LAST user message so the binary travels alongside the author's prompt
|
|
5866
|
+
* text (preserving any untrusted-source preamble that already wrapped that text). When no user
|
|
5867
|
+
* message exists, a new user message carrying only the binaries is appended.
|
|
5868
|
+
*/
|
|
5869
|
+
var AgentBinaryContentFactory = class AgentBinaryContentFactory {
|
|
5870
|
+
static toContentPart(binary) {
|
|
5871
|
+
if (binary.mediaType.startsWith("image/")) return {
|
|
5872
|
+
type: "image",
|
|
5873
|
+
image: binary.base64,
|
|
5874
|
+
mediaType: binary.mediaType
|
|
5875
|
+
};
|
|
5876
|
+
return {
|
|
5877
|
+
type: "file",
|
|
5878
|
+
data: binary.base64,
|
|
5879
|
+
mediaType: binary.mediaType,
|
|
5880
|
+
...binary.filename ? { filename: binary.filename } : {}
|
|
5881
|
+
};
|
|
5882
|
+
}
|
|
5883
|
+
static withBinaries(messages, binaries) {
|
|
5884
|
+
if (binaries.length === 0) return messages;
|
|
5885
|
+
const parts = binaries.map((binary) => AgentBinaryContentFactory.toContentPart(binary));
|
|
5886
|
+
const lastUserIndex = AgentBinaryContentFactory.lastUserMessageIndex(messages);
|
|
5887
|
+
if (lastUserIndex === -1) {
|
|
5888
|
+
const appended = {
|
|
5889
|
+
role: "user",
|
|
5890
|
+
content: parts
|
|
5891
|
+
};
|
|
5892
|
+
return [...messages, appended];
|
|
5893
|
+
}
|
|
5894
|
+
const next = [...messages];
|
|
5895
|
+
next[lastUserIndex] = AgentBinaryContentFactory.appendPartsToUserMessage(messages[lastUserIndex], parts);
|
|
5896
|
+
return next;
|
|
5897
|
+
}
|
|
5898
|
+
static lastUserMessageIndex(messages) {
|
|
5899
|
+
for (let index = messages.length - 1; index >= 0; index--) if (messages[index]?.role === "user") return index;
|
|
5900
|
+
return -1;
|
|
5901
|
+
}
|
|
5902
|
+
static appendPartsToUserMessage(message, parts) {
|
|
5903
|
+
const existing = typeof message.content === "string" ? message.content.length > 0 ? [{
|
|
5904
|
+
type: "text",
|
|
5905
|
+
text: message.content
|
|
5906
|
+
}] : [] : message.content;
|
|
5907
|
+
return {
|
|
5908
|
+
...message,
|
|
5909
|
+
content: [...existing, ...parts]
|
|
5910
|
+
};
|
|
5911
|
+
}
|
|
5912
|
+
};
|
|
5913
|
+
|
|
5885
5914
|
//#endregion
|
|
5886
5915
|
//#region src/nodes/NodeBackedToolRuntime.ts
|
|
5887
5916
|
var _ref$1, _ref2$1, _ref3$1, _ref4$1;
|
|
@@ -6080,11 +6109,18 @@ var DeferredMetaToolStrategy = class {
|
|
|
6080
6109
|
mcpEntries = [];
|
|
6081
6110
|
toolsByServerId = /* @__PURE__ */ new Map();
|
|
6082
6111
|
foundToolIds = /* @__PURE__ */ new Set();
|
|
6112
|
+
/**
|
|
6113
|
+
* `jsonSchema` from the `ai` SDK, loaded lazily in {@link initialize} so the SDK
|
|
6114
|
+
* (~28MB RSS) stays off the boot path. `initialize` always runs before the sync
|
|
6115
|
+
* `getToolsForTurn` → `buildFindToolsDefinition` path, so this is set before use.
|
|
6116
|
+
*/
|
|
6117
|
+
jsonSchema;
|
|
6083
6118
|
constructor(bm25, warnFn) {
|
|
6084
6119
|
this.bm25 = bm25;
|
|
6085
6120
|
this.warnFn = warnFn;
|
|
6086
6121
|
}
|
|
6087
6122
|
async initialize(input) {
|
|
6123
|
+
this.jsonSchema = (await import("ai")).jsonSchema;
|
|
6088
6124
|
this.nodeBackedTools = { ...input.nodeBackedTools };
|
|
6089
6125
|
const pinnedIds = input.pinnedMcpTools ?? [];
|
|
6090
6126
|
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}.`);
|
|
@@ -6172,25 +6208,26 @@ var DeferredMetaToolStrategy = class {
|
|
|
6172
6208
|
return [...this.foundToolIds];
|
|
6173
6209
|
}
|
|
6174
6210
|
buildFindToolsDefinition() {
|
|
6211
|
+
const inputSchemaRecord = {
|
|
6212
|
+
type: "object",
|
|
6213
|
+
properties: {
|
|
6214
|
+
query: {
|
|
6215
|
+
type: "string",
|
|
6216
|
+
description: "Natural language description of what you want to do."
|
|
6217
|
+
},
|
|
6218
|
+
limit: {
|
|
6219
|
+
type: "integer",
|
|
6220
|
+
minimum: 1,
|
|
6221
|
+
maximum: 10,
|
|
6222
|
+
description: `Maximum number of tools to return (default ${FIND_TOOLS_DEFAULT_LIMIT}).`
|
|
6223
|
+
}
|
|
6224
|
+
},
|
|
6225
|
+
required: ["query"],
|
|
6226
|
+
additionalProperties: false
|
|
6227
|
+
};
|
|
6175
6228
|
return {
|
|
6176
6229
|
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.",
|
|
6177
|
-
inputSchema:
|
|
6178
|
-
type: "object",
|
|
6179
|
-
properties: {
|
|
6180
|
-
query: {
|
|
6181
|
-
type: "string",
|
|
6182
|
-
description: "Natural language description of what you want to do."
|
|
6183
|
-
},
|
|
6184
|
-
limit: {
|
|
6185
|
-
type: "integer",
|
|
6186
|
-
minimum: 1,
|
|
6187
|
-
maximum: 10,
|
|
6188
|
-
description: `Maximum number of tools to return (default ${FIND_TOOLS_DEFAULT_LIMIT}).`
|
|
6189
|
-
}
|
|
6190
|
-
},
|
|
6191
|
-
required: ["query"],
|
|
6192
|
-
additionalProperties: false
|
|
6193
|
-
})
|
|
6230
|
+
inputSchema: this.jsonSchema(inputSchemaRecord)
|
|
6194
6231
|
};
|
|
6195
6232
|
}
|
|
6196
6233
|
};
|
|
@@ -6224,6 +6261,13 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6224
6261
|
inputSchema = unknown();
|
|
6225
6262
|
connectionCredentialExecutionContextFactory;
|
|
6226
6263
|
preparedByExecutionContext = /* @__PURE__ */ new WeakMap();
|
|
6264
|
+
/**
|
|
6265
|
+
* The `ai` SDK, loaded lazily in {@link execute} so the SDK (~28MB RSS) stays
|
|
6266
|
+
* off the boot path — non-AI workflows never load it. Every path runs through
|
|
6267
|
+
* `execute` → `ensureAiSdk` before any sync helper touches `this.aiSdk`.
|
|
6268
|
+
*/
|
|
6269
|
+
aiSdk;
|
|
6270
|
+
aiSdkPromise = null;
|
|
6227
6271
|
constructor(nodeResolver, credentialSessions, nodeBackedToolRuntime, executionHelpers, structuredOutputRunner, toolExecutionCoordinator, toolLoadingStrategyFactory, agentMcpIntegration) {
|
|
6228
6272
|
this.nodeResolver = nodeResolver;
|
|
6229
6273
|
this.nodeBackedToolRuntime = nodeBackedToolRuntime;
|
|
@@ -6236,6 +6280,7 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6236
6280
|
}
|
|
6237
6281
|
async execute(args) {
|
|
6238
6282
|
const { ctx } = args;
|
|
6283
|
+
await this.ensureAiSdk();
|
|
6239
6284
|
if (ctx.resumeContext) return this.executeResumed(args, ctx.resumeContext);
|
|
6240
6285
|
const prepared = await this.getOrPrepareExecution(ctx);
|
|
6241
6286
|
const itemWithMappedJson = {
|
|
@@ -6244,6 +6289,10 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6244
6289
|
};
|
|
6245
6290
|
return (await this.runAgentForItem(prepared, itemWithMappedJson, args.itemIndex, args.items)).json;
|
|
6246
6291
|
}
|
|
6292
|
+
/** Load the `ai` SDK once per node instance (cached promise guards concurrent items). */
|
|
6293
|
+
async ensureAiSdk() {
|
|
6294
|
+
this.aiSdk = await (this.aiSdkPromise ??= import("ai"));
|
|
6295
|
+
}
|
|
6247
6296
|
/**
|
|
6248
6297
|
* Resume path: re-enters the agent loop after a HITL suspension.
|
|
6249
6298
|
* Reconstructs the conversation from the checkpoint, injects the human decision
|
|
@@ -6386,7 +6435,7 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6386
6435
|
const { ctx } = prepared;
|
|
6387
6436
|
const itemInputsByPort = AgentItemPortMap.fromItem(item);
|
|
6388
6437
|
const itemScopedTools = this.createItemScopedTools(prepared.resolvedTools, ctx, item, itemIndex, items);
|
|
6389
|
-
const conversation = [...this.createPromptMessages(item, itemIndex, items, ctx)];
|
|
6438
|
+
const conversation = [...await this.createPromptMessages(item, itemIndex, items, ctx)];
|
|
6390
6439
|
if (ctx.config.outputSchema && itemScopedTools.length === 0) {
|
|
6391
6440
|
const structuredOutput = await this.structuredOutputRunner.resolve({
|
|
6392
6441
|
model: prepared.model,
|
|
@@ -6630,7 +6679,7 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6630
6679
|
const description = this.resolveHumanApprovalBehavior(entry.config) !== void 0 ? `${baseDescription} ${HITL_SOLO_CONSTRAINT_SENTENCE}` : baseDescription;
|
|
6631
6680
|
toolSet[entry.config.name] = {
|
|
6632
6681
|
description,
|
|
6633
|
-
inputSchema:
|
|
6682
|
+
inputSchema: this.aiSdk.jsonSchema(schemaRecord)
|
|
6634
6683
|
};
|
|
6635
6684
|
}
|
|
6636
6685
|
return toolSet;
|
|
@@ -6661,7 +6710,7 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6661
6710
|
const description = entry.humanApproval !== void 0 && baseDescription !== void 0 ? `${baseDescription} ${HITL_SOLO_CONSTRAINT_SENTENCE}` : entry.humanApproval !== void 0 ? HITL_SOLO_CONSTRAINT_SENTENCE : baseDescription;
|
|
6662
6711
|
toolSet[entry.config.name] = {
|
|
6663
6712
|
description,
|
|
6664
|
-
inputSchema:
|
|
6713
|
+
inputSchema: this.aiSdk.jsonSchema(schemaRecord)
|
|
6665
6714
|
};
|
|
6666
6715
|
}
|
|
6667
6716
|
return toolSet;
|
|
@@ -6713,7 +6762,7 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6713
6762
|
});
|
|
6714
6763
|
try {
|
|
6715
6764
|
const callOptions = this.resolveCallOptions(model, guardrails.modelInvocationOptions);
|
|
6716
|
-
const result = await
|
|
6765
|
+
const result = await this.aiSdk.generateText({
|
|
6717
6766
|
model: model.languageModel,
|
|
6718
6767
|
messages: [...messages],
|
|
6719
6768
|
tools,
|
|
@@ -6832,8 +6881,8 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
6832
6881
|
schemaName: structuredOptions?.schemaName ?? "structured_output",
|
|
6833
6882
|
requireObjectRoot: true
|
|
6834
6883
|
}) : schema;
|
|
6835
|
-
const outputSchema =
|
|
6836
|
-
const result = await
|
|
6884
|
+
const outputSchema = this.aiSdk.Output.object({ schema: this.aiSdk.jsonSchema(schemaRecord) });
|
|
6885
|
+
const result = await this.aiSdk.generateText({
|
|
6837
6886
|
model: model.languageModel,
|
|
6838
6887
|
messages: [...messages],
|
|
6839
6888
|
experimental_output: outputSchema,
|
|
@@ -7104,7 +7153,7 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
7104
7153
|
const json = JSON.stringify(value);
|
|
7105
7154
|
return JSON.parse(json);
|
|
7106
7155
|
}
|
|
7107
|
-
createPromptMessages(item, itemIndex, items, ctx) {
|
|
7156
|
+
async createPromptMessages(item, itemIndex, items, ctx) {
|
|
7108
7157
|
const messages = __codemation_core.AgentMessageConfigNormalizer.resolveFromInputOrConfig(item.json, ctx.config, {
|
|
7109
7158
|
item,
|
|
7110
7159
|
itemIndex,
|
|
@@ -7112,7 +7161,47 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
7112
7161
|
ctx
|
|
7113
7162
|
});
|
|
7114
7163
|
const wrapped = this.wrapUntrustedSourceMessages(messages, item, ctx.config);
|
|
7115
|
-
|
|
7164
|
+
const promptMessages = AgentMessageFactory.createPromptMessages(wrapped);
|
|
7165
|
+
if (ctx.config.passBinariesToModel === false) return promptMessages;
|
|
7166
|
+
const attachments = this.selectBinaryAttachments(item, itemIndex, items, ctx);
|
|
7167
|
+
const binaries = await this.resolveInlineBinaries(attachments, ctx);
|
|
7168
|
+
return AgentBinaryContentFactory.withBinaries(promptMessages, binaries);
|
|
7169
|
+
}
|
|
7170
|
+
/**
|
|
7171
|
+
* Picks which attachments feed the passdown. When the author supplies `config.binaries`
|
|
7172
|
+
* (a static array or a per-item function — e.g. to forward binaries from an earlier node),
|
|
7173
|
+
* those replace the current item's attachments; otherwise the current item's `item.binary`
|
|
7174
|
+
* is used.
|
|
7175
|
+
*/
|
|
7176
|
+
selectBinaryAttachments(item, itemIndex, items, ctx) {
|
|
7177
|
+
const manual = ctx.config.binaries;
|
|
7178
|
+
if (manual !== void 0) return typeof manual === "function" ? manual({
|
|
7179
|
+
item,
|
|
7180
|
+
itemIndex,
|
|
7181
|
+
items,
|
|
7182
|
+
ctx
|
|
7183
|
+
}) : manual;
|
|
7184
|
+
return item.binary ? Object.values(item.binary) : [];
|
|
7185
|
+
}
|
|
7186
|
+
/**
|
|
7187
|
+
* Reads every attachment through `ctx.binary` (storage-backed, by reference — never base64 on
|
|
7188
|
+
* `item.json`) and resolves it to inline base64 so the agent can pass it to the chat model as a
|
|
7189
|
+
* native multimodal block. Images become image blocks; every other type (PDF, office docs, CSV,
|
|
7190
|
+
* JSON, …) becomes a file block — we don't filter by media type, so any binary can be fed to the
|
|
7191
|
+
* model. If the provider rejects an unsupported type the error surfaces at runtime, and the
|
|
7192
|
+
* workflow can filter the binary upstream.
|
|
7193
|
+
*/
|
|
7194
|
+
async resolveInlineBinaries(attachments, ctx) {
|
|
7195
|
+
const resolved = [];
|
|
7196
|
+
for (const attachment of attachments) {
|
|
7197
|
+
const bytes = await ctx.binary.getBytes(attachment);
|
|
7198
|
+
resolved.push({
|
|
7199
|
+
mediaType: attachment.mimeType,
|
|
7200
|
+
base64: Buffer.from(bytes).toString("base64"),
|
|
7201
|
+
...attachment.filename ? { filename: attachment.filename } : {}
|
|
7202
|
+
});
|
|
7203
|
+
}
|
|
7204
|
+
return resolved;
|
|
7116
7205
|
}
|
|
7117
7206
|
/**
|
|
7118
7207
|
* When `item.json.__source` matches an entry in `config.untrustedSources`
|
|
@@ -7226,6 +7315,7 @@ var AIAgent = class {
|
|
|
7226
7315
|
chatModel;
|
|
7227
7316
|
tools;
|
|
7228
7317
|
id;
|
|
7318
|
+
description;
|
|
7229
7319
|
retryPolicy;
|
|
7230
7320
|
guardrails;
|
|
7231
7321
|
inputSchema;
|
|
@@ -7233,12 +7323,15 @@ var AIAgent = class {
|
|
|
7233
7323
|
mcpServers;
|
|
7234
7324
|
pinnedMcpTools;
|
|
7235
7325
|
untrustedSources;
|
|
7326
|
+
passBinariesToModel;
|
|
7327
|
+
binaries;
|
|
7236
7328
|
constructor(options) {
|
|
7237
7329
|
this.name = options.name;
|
|
7238
7330
|
this.messages = options.messages;
|
|
7239
7331
|
this.chatModel = options.chatModel;
|
|
7240
7332
|
this.tools = options.tools ?? [];
|
|
7241
7333
|
this.id = options.id;
|
|
7334
|
+
this.description = options.description;
|
|
7242
7335
|
this.retryPolicy = options.retryPolicy ?? __codemation_core.RetryPolicy.defaultForAiAgent;
|
|
7243
7336
|
this.guardrails = options.guardrails;
|
|
7244
7337
|
this.inputSchema = options.inputSchema;
|
|
@@ -7246,6 +7339,8 @@ var AIAgent = class {
|
|
|
7246
7339
|
this.mcpServers = options.mcpServers;
|
|
7247
7340
|
this.pinnedMcpTools = options.pinnedMcpTools;
|
|
7248
7341
|
this.untrustedSources = options.untrustedSources;
|
|
7342
|
+
this.passBinariesToModel = options.passBinariesToModel;
|
|
7343
|
+
this.binaries = options.binaries;
|
|
7249
7344
|
}
|
|
7250
7345
|
inspectorSummary() {
|
|
7251
7346
|
const rows = [];
|
|
@@ -7316,12 +7411,14 @@ var Assertion = class {
|
|
|
7316
7411
|
icon;
|
|
7317
7412
|
name;
|
|
7318
7413
|
id;
|
|
7414
|
+
description;
|
|
7319
7415
|
emitsAssertions = true;
|
|
7320
7416
|
assertions;
|
|
7321
7417
|
constructor(options) {
|
|
7322
7418
|
this.name = options.name ?? "Assertion";
|
|
7323
7419
|
this.id = options.id;
|
|
7324
7420
|
this.icon = options.icon ?? "lucide:check-circle";
|
|
7421
|
+
this.description = options.description;
|
|
7325
7422
|
this.assertions = options.assertions;
|
|
7326
7423
|
}
|
|
7327
7424
|
inspectorSummary() {
|
|
@@ -7373,6 +7470,7 @@ var Callback = class Callback {
|
|
|
7373
7470
|
icon = "lucide:braces";
|
|
7374
7471
|
emptyBatchExecution = "runOnce";
|
|
7375
7472
|
id;
|
|
7473
|
+
description;
|
|
7376
7474
|
retryPolicy;
|
|
7377
7475
|
nodeErrorHandler;
|
|
7378
7476
|
declaredOutputPorts;
|
|
@@ -7384,6 +7482,7 @@ var Callback = class Callback {
|
|
|
7384
7482
|
id: idOrOptions
|
|
7385
7483
|
} : idOrOptions;
|
|
7386
7484
|
this.id = resolvedOptions?.id;
|
|
7485
|
+
this.description = resolvedOptions?.description;
|
|
7387
7486
|
this.retryPolicy = resolvedOptions?.retryPolicy;
|
|
7388
7487
|
this.nodeErrorHandler = resolvedOptions?.nodeErrorHandler;
|
|
7389
7488
|
this.declaredOutputPorts = resolvedOptions?.declaredOutputPorts;
|
|
@@ -7585,10 +7684,12 @@ var HttpRequest = class {
|
|
|
7585
7684
|
type = HttpRequestNode;
|
|
7586
7685
|
execution = { hint: "local" };
|
|
7587
7686
|
icon = "lucide:globe";
|
|
7687
|
+
description;
|
|
7588
7688
|
constructor(name, args = {}, retryPolicy = __codemation_core.RetryPolicy.defaultForHttp) {
|
|
7589
7689
|
this.name = name;
|
|
7590
7690
|
this.args = args;
|
|
7591
7691
|
this.retryPolicy = retryPolicy;
|
|
7692
|
+
this.description = args.description;
|
|
7592
7693
|
}
|
|
7593
7694
|
get id() {
|
|
7594
7695
|
return this.args.id;
|
|
@@ -7683,10 +7784,14 @@ var Aggregate = class {
|
|
|
7683
7784
|
execution = { hint: "local" };
|
|
7684
7785
|
keepBinaries = true;
|
|
7685
7786
|
icon = "builtin:aggregate-rows";
|
|
7686
|
-
|
|
7787
|
+
id;
|
|
7788
|
+
description;
|
|
7789
|
+
constructor(name, aggregate, idOrOptions) {
|
|
7687
7790
|
this.name = name;
|
|
7688
7791
|
this.aggregate = aggregate;
|
|
7689
|
-
|
|
7792
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
7793
|
+
this.id = options?.id;
|
|
7794
|
+
this.description = options?.description;
|
|
7690
7795
|
}
|
|
7691
7796
|
inspectorSummary() {
|
|
7692
7797
|
const fnName = this.aggregate.name;
|
|
@@ -7717,10 +7822,14 @@ var Filter = class {
|
|
|
7717
7822
|
type = FilterNode;
|
|
7718
7823
|
execution = { hint: "local" };
|
|
7719
7824
|
icon = "lucide:filter";
|
|
7720
|
-
|
|
7825
|
+
id;
|
|
7826
|
+
description;
|
|
7827
|
+
constructor(name, predicate, idOrOptions) {
|
|
7721
7828
|
this.name = name;
|
|
7722
7829
|
this.predicate = predicate;
|
|
7723
|
-
|
|
7830
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
7831
|
+
this.id = options?.id;
|
|
7832
|
+
this.description = options?.description;
|
|
7724
7833
|
}
|
|
7725
7834
|
inspectorSummary() {
|
|
7726
7835
|
const fnName = this.predicate.name;
|
|
@@ -7795,10 +7904,14 @@ var If = class {
|
|
|
7795
7904
|
execution = { hint: "local" };
|
|
7796
7905
|
icon = "lucide:split@rot=90";
|
|
7797
7906
|
declaredOutputPorts = ["true", "false"];
|
|
7798
|
-
|
|
7907
|
+
id;
|
|
7908
|
+
description;
|
|
7909
|
+
constructor(name, predicate, idOrOptions) {
|
|
7799
7910
|
this.name = name;
|
|
7800
7911
|
this.predicate = predicate;
|
|
7801
|
-
|
|
7912
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
7913
|
+
this.id = options?.id;
|
|
7914
|
+
this.description = options?.description;
|
|
7802
7915
|
}
|
|
7803
7916
|
inspectorSummary() {
|
|
7804
7917
|
const fnName = this.predicate.name;
|
|
@@ -7838,9 +7951,12 @@ var IsTestRun = class {
|
|
|
7838
7951
|
declaredOutputPorts = ["true", "false"];
|
|
7839
7952
|
name;
|
|
7840
7953
|
id;
|
|
7841
|
-
|
|
7954
|
+
description;
|
|
7955
|
+
constructor(name = "Is test run?", idOrOptions) {
|
|
7842
7956
|
this.name = name;
|
|
7843
|
-
|
|
7957
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
7958
|
+
this.id = options?.id;
|
|
7959
|
+
this.description = options?.description;
|
|
7844
7960
|
}
|
|
7845
7961
|
};
|
|
7846
7962
|
|
|
@@ -7869,11 +7985,15 @@ var Switch = class {
|
|
|
7869
7985
|
execution = { hint: "local" };
|
|
7870
7986
|
icon = "lucide:git-branch-plus";
|
|
7871
7987
|
declaredOutputPorts;
|
|
7872
|
-
|
|
7988
|
+
id;
|
|
7989
|
+
description;
|
|
7990
|
+
constructor(name, cfg, idOrOptions) {
|
|
7873
7991
|
this.name = name;
|
|
7874
7992
|
this.cfg = cfg;
|
|
7875
|
-
this.id = id;
|
|
7876
7993
|
this.declaredOutputPorts = [...new Set([...cfg.cases, cfg.defaultCase])].sort();
|
|
7994
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
7995
|
+
this.id = options?.id;
|
|
7996
|
+
this.description = options?.description;
|
|
7877
7997
|
}
|
|
7878
7998
|
inspectorSummary() {
|
|
7879
7999
|
const rows = [{
|
|
@@ -7912,10 +8032,14 @@ var Split = class {
|
|
|
7912
8032
|
*/
|
|
7913
8033
|
continueWhenEmptyOutput = true;
|
|
7914
8034
|
icon = "builtin:split-rows";
|
|
7915
|
-
|
|
8035
|
+
id;
|
|
8036
|
+
description;
|
|
8037
|
+
constructor(name, getElements, idOrOptions) {
|
|
7916
8038
|
this.name = name;
|
|
7917
8039
|
this.getElements = getElements;
|
|
7918
|
-
|
|
8040
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
8041
|
+
this.id = options?.id;
|
|
8042
|
+
this.description = options?.description;
|
|
7919
8043
|
}
|
|
7920
8044
|
inspectorSummary() {
|
|
7921
8045
|
const fnName = this.getElements.name;
|
|
@@ -7973,14 +8097,17 @@ var CronTrigger = class {
|
|
|
7973
8097
|
type = CronTriggerNode;
|
|
7974
8098
|
icon = "lucide:clock";
|
|
7975
8099
|
id;
|
|
7976
|
-
|
|
8100
|
+
description;
|
|
8101
|
+
constructor(name, args, idOrOptions) {
|
|
7977
8102
|
this.name = name;
|
|
7978
8103
|
this.args = args;
|
|
7979
8104
|
new croner.Cron(args.schedule, {
|
|
7980
8105
|
paused: true,
|
|
7981
8106
|
timezone: args.timezone
|
|
7982
8107
|
});
|
|
7983
|
-
|
|
8108
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
8109
|
+
this.id = options?.id;
|
|
8110
|
+
this.description = options?.description;
|
|
7984
8111
|
}
|
|
7985
8112
|
get schedule() {
|
|
7986
8113
|
return this.args.schedule;
|
|
@@ -8034,20 +8161,21 @@ var ManualTrigger = class ManualTrigger {
|
|
|
8034
8161
|
icon = "lucide:play";
|
|
8035
8162
|
defaultItems;
|
|
8036
8163
|
id;
|
|
8164
|
+
description;
|
|
8037
8165
|
/** Manual runs often emit an empty batch; still schedule downstream by default. */
|
|
8038
8166
|
continueWhenEmptyOutput = true;
|
|
8039
|
-
constructor(name = "Manual trigger", defaultItemsOrId,
|
|
8167
|
+
constructor(name = "Manual trigger", defaultItemsOrId, idOrOptions) {
|
|
8040
8168
|
this.name = name;
|
|
8041
8169
|
this.defaultItems = ManualTrigger.resolveDefaultItems(defaultItemsOrId);
|
|
8042
|
-
|
|
8170
|
+
const trailing = idOrOptions ?? (typeof defaultItemsOrId === "string" ? defaultItemsOrId : void 0);
|
|
8171
|
+
const options = typeof trailing === "string" ? { id: trailing } : trailing ?? {};
|
|
8172
|
+
this.id = options.id;
|
|
8173
|
+
this.description = options.description;
|
|
8043
8174
|
}
|
|
8044
8175
|
static resolveDefaultItems(value) {
|
|
8045
8176
|
if (typeof value === "string" || value === void 0) return;
|
|
8046
8177
|
return this.itemsInputNormalizer.normalize(value);
|
|
8047
8178
|
}
|
|
8048
|
-
static resolveId(value, id) {
|
|
8049
|
-
return typeof value === "string" ? value : id;
|
|
8050
|
-
}
|
|
8051
8179
|
inspectorSummary() {
|
|
8052
8180
|
const rows = [{
|
|
8053
8181
|
label: "Trigger",
|
|
@@ -8093,11 +8221,13 @@ var MapData = class {
|
|
|
8093
8221
|
continueWhenEmptyOutput = true;
|
|
8094
8222
|
icon = "lucide:square-pen";
|
|
8095
8223
|
keepBinaries;
|
|
8224
|
+
description;
|
|
8096
8225
|
constructor(name, map, options = {}) {
|
|
8097
8226
|
this.name = name;
|
|
8098
8227
|
this.map = map;
|
|
8099
8228
|
this.options = options;
|
|
8100
8229
|
this.keepBinaries = options.keepBinaries ?? true;
|
|
8230
|
+
this.description = options.description;
|
|
8101
8231
|
}
|
|
8102
8232
|
get id() {
|
|
8103
8233
|
return this.options.id;
|
|
@@ -8170,10 +8300,14 @@ var Merge = class {
|
|
|
8170
8300
|
kind = "node";
|
|
8171
8301
|
type = MergeNode;
|
|
8172
8302
|
icon = "lucide:merge@rot=90";
|
|
8173
|
-
|
|
8303
|
+
id;
|
|
8304
|
+
description;
|
|
8305
|
+
constructor(name, cfg = { mode: "passThrough" }, idOrOptions) {
|
|
8174
8306
|
this.name = name;
|
|
8175
8307
|
this.cfg = cfg;
|
|
8176
|
-
|
|
8308
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
8309
|
+
this.id = options?.id;
|
|
8310
|
+
this.description = options?.description;
|
|
8177
8311
|
}
|
|
8178
8312
|
inspectorSummary() {
|
|
8179
8313
|
const rows = [{
|
|
@@ -8206,9 +8340,13 @@ var NoOp = class {
|
|
|
8206
8340
|
type = NoOpNode;
|
|
8207
8341
|
execution = { hint: "local" };
|
|
8208
8342
|
icon = "lucide:circle-dashed";
|
|
8209
|
-
|
|
8343
|
+
id;
|
|
8344
|
+
description;
|
|
8345
|
+
constructor(name = "NoOp", idOrOptions) {
|
|
8210
8346
|
this.name = name;
|
|
8211
|
-
|
|
8347
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
8348
|
+
this.id = options?.id;
|
|
8349
|
+
this.description = options?.description;
|
|
8212
8350
|
}
|
|
8213
8351
|
};
|
|
8214
8352
|
|
|
@@ -8274,12 +8412,16 @@ var SubWorkflow = class {
|
|
|
8274
8412
|
kind = "node";
|
|
8275
8413
|
type = SubWorkflowNode;
|
|
8276
8414
|
icon = "lucide:workflow";
|
|
8277
|
-
|
|
8415
|
+
id;
|
|
8416
|
+
description;
|
|
8417
|
+
constructor(name, workflowId, upstreamRefs, startAt, idOrOptions) {
|
|
8278
8418
|
this.name = name;
|
|
8279
8419
|
this.workflowId = workflowId;
|
|
8280
8420
|
this.upstreamRefs = upstreamRefs;
|
|
8281
8421
|
this.startAt = startAt;
|
|
8282
|
-
|
|
8422
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
8423
|
+
this.id = options?.id;
|
|
8424
|
+
this.description = options?.description;
|
|
8283
8425
|
}
|
|
8284
8426
|
inspectorSummary() {
|
|
8285
8427
|
const rows = [{
|
|
@@ -8389,10 +8531,14 @@ var Wait = class {
|
|
|
8389
8531
|
/** Pass-through empty batches should still advance to downstream nodes. */
|
|
8390
8532
|
continueWhenEmptyOutput = true;
|
|
8391
8533
|
icon = "lucide:hourglass";
|
|
8392
|
-
|
|
8534
|
+
id;
|
|
8535
|
+
description;
|
|
8536
|
+
constructor(name, milliseconds, idOrOptions) {
|
|
8393
8537
|
this.name = name;
|
|
8394
8538
|
this.milliseconds = milliseconds;
|
|
8395
|
-
|
|
8539
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
8540
|
+
this.id = options?.id;
|
|
8541
|
+
this.description = options?.description;
|
|
8396
8542
|
}
|
|
8397
8543
|
inspectorSummary() {
|
|
8398
8544
|
const seconds = this.milliseconds / 1e3;
|
|
@@ -8447,11 +8593,15 @@ var WebhookTrigger = class WebhookTrigger {
|
|
|
8447
8593
|
kind = "trigger";
|
|
8448
8594
|
type = WebhookTriggerNode;
|
|
8449
8595
|
icon = "lucide:globe";
|
|
8450
|
-
|
|
8596
|
+
id;
|
|
8597
|
+
description;
|
|
8598
|
+
constructor(name, args, handler = WebhookTrigger.defaultHandler, idOrOptions) {
|
|
8451
8599
|
this.name = name;
|
|
8452
8600
|
this.args = args;
|
|
8453
8601
|
this.handler = handler;
|
|
8454
|
-
|
|
8602
|
+
const options = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
8603
|
+
this.id = options?.id;
|
|
8604
|
+
this.description = options?.description;
|
|
8455
8605
|
}
|
|
8456
8606
|
get endpointKey() {
|
|
8457
8607
|
return this.args.endpointKey;
|
|
@@ -8508,11 +8658,21 @@ function createWorkflowBuilder(meta$2) {
|
|
|
8508
8658
|
|
|
8509
8659
|
//#endregion
|
|
8510
8660
|
//#region src/workflowAuthoring/WorkflowChatModelFactory.types.ts
|
|
8661
|
+
const VALID_COMPLEXITY = new Set([
|
|
8662
|
+
"low",
|
|
8663
|
+
"medium",
|
|
8664
|
+
"high",
|
|
8665
|
+
"xhigh"
|
|
8666
|
+
]);
|
|
8511
8667
|
var WorkflowChatModelFactory = class {
|
|
8512
8668
|
static create(model) {
|
|
8513
8669
|
if (typeof model !== "string") return model;
|
|
8514
8670
|
const [provider, resolvedModel] = model.includes(":") ? model.split(":", 2) : ["openai", model];
|
|
8515
|
-
if (provider === "codemation-managed")
|
|
8671
|
+
if (provider === "codemation-managed") {
|
|
8672
|
+
const complexity = resolvedModel ?? "medium";
|
|
8673
|
+
if (!VALID_COMPLEXITY.has(complexity)) throw new Error(`Invalid managed complexity "${complexity}". Must be one of: low, medium, high, xhigh.`);
|
|
8674
|
+
return new CodemationChatModelConfig("Codemation Managed", complexity);
|
|
8675
|
+
}
|
|
8516
8676
|
if (provider !== "openai") throw new Error(`Unsupported workflow().agent() model provider "${provider}".`);
|
|
8517
8677
|
return new OpenAIChatModelConfig("OpenAI", resolvedModel);
|
|
8518
8678
|
}
|
|
@@ -9280,7 +9440,6 @@ Object.defineProperty(exports, 'IsTestRunNode', {
|
|
|
9280
9440
|
return IsTestRunNode;
|
|
9281
9441
|
}
|
|
9282
9442
|
});
|
|
9283
|
-
exports.ManagedModelFetcher = ManagedModelFetcher;
|
|
9284
9443
|
exports.ManualTrigger = ManualTrigger;
|
|
9285
9444
|
Object.defineProperty(exports, 'ManualTriggerNode', {
|
|
9286
9445
|
enumerable: true,
|