@codemation/core-nodes 0.4.1 → 0.4.3
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 +23 -0
- package/dist/index.cjs +665 -85
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +194 -5
- package/dist/index.d.ts +194 -5
- package/dist/index.js +648 -87
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/chatModels/openAiChatModelConfig.ts +3 -0
- package/src/nodes/AIAgentNode.ts +294 -102
- package/src/nodes/AgentToolErrorClassifier.ts +106 -0
- package/src/nodes/AgentToolExecutionCoordinator.ts +364 -0
- package/src/nodes/AgentToolRepair.types.ts +26 -0
- package/src/nodes/AgentToolRepairExhaustedError.ts +51 -0
- package/src/nodes/AgentToolRepairPolicy.ts +21 -0
- package/src/nodes/aiAgent.ts +4 -0
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AgentConfigInspector, AgentConnectionNodeCollector, AgentGuardrailDefaults, AgentMessageConfigNormalizer, CallableToolConfig, ConnectionInvocationIdFactory, ConnectionNodeIdFactory, CoreTokens, DefinedNodeRegistry, ItemExprResolver, ItemsInputNormalizer, NodeBackedToolConfig, NodeOutputNormalizer, RetryPolicy, RunnableOutputBehaviorResolver, WorkflowBuilder, chatModel, emitPorts, getOriginIndexFromItem, inject, injectable, isPortsEmission, node } from "@codemation/core";
|
|
1
|
+
import { AgentConfigInspector, AgentConnectionNodeCollector, AgentGuardrailDefaults, AgentMessageConfigNormalizer, CallableToolConfig, CodemationTelemetryAttributeNames, CodemationTelemetryMetricNames, ConnectionInvocationIdFactory, ConnectionNodeIdFactory, CoreTokens, DefinedNodeRegistry, GenAiTelemetryAttributeNames, ItemExprResolver, ItemsInputNormalizer, NodeBackedToolConfig, NodeOutputNormalizer, RetryPolicy, RunnableOutputBehaviorResolver, WorkflowBuilder, chatModel, emitPorts, getOriginIndexFromItem, inject, injectable, isPortsEmission, node } from "@codemation/core";
|
|
2
2
|
import { ChatOpenAI } from "@langchain/openai";
|
|
3
3
|
import { AIMessage, HumanMessage, SystemMessage, ToolMessage } from "@langchain/core/messages";
|
|
4
4
|
import { isInteropZodSchema } from "@langchain/core/utils/types";
|
|
@@ -71,11 +71,14 @@ OpenAIStructuredOutputMethodFactory = _OpenAIStructuredOutputMethodFactory = __d
|
|
|
71
71
|
var OpenAIChatModelConfig = class {
|
|
72
72
|
type = OpenAIChatModelFactory;
|
|
73
73
|
presentation;
|
|
74
|
+
provider = "openai";
|
|
75
|
+
modelName;
|
|
74
76
|
constructor(name, model, credentialSlotKey = "openai", presentationIn, options) {
|
|
75
77
|
this.name = name;
|
|
76
78
|
this.model = model;
|
|
77
79
|
this.credentialSlotKey = credentialSlotKey;
|
|
78
80
|
this.options = options;
|
|
81
|
+
this.modelName = model;
|
|
79
82
|
this.presentation = presentationIn ?? {
|
|
80
83
|
icon: "builtin:openai",
|
|
81
84
|
label: name
|
|
@@ -2192,7 +2195,7 @@ function __decorateParam(paramIndex, decorator) {
|
|
|
2192
2195
|
|
|
2193
2196
|
//#endregion
|
|
2194
2197
|
//#region src/nodes/AgentStructuredOutputRepairPromptFactory.ts
|
|
2195
|
-
var _ref$
|
|
2198
|
+
var _ref$4, _AgentStructuredOutputRepairPromptFactory;
|
|
2196
2199
|
let AgentStructuredOutputRepairPromptFactory = class AgentStructuredOutputRepairPromptFactory$1 {
|
|
2197
2200
|
static {
|
|
2198
2201
|
_AgentStructuredOutputRepairPromptFactory = this;
|
|
@@ -2227,7 +2230,7 @@ let AgentStructuredOutputRepairPromptFactory = class AgentStructuredOutputRepair
|
|
|
2227
2230
|
AgentStructuredOutputRepairPromptFactory = _AgentStructuredOutputRepairPromptFactory = __decorate([
|
|
2228
2231
|
injectable(),
|
|
2229
2232
|
__decorateParam(0, inject(AIAgentExecutionHelpersFactory)),
|
|
2230
|
-
__decorateMetadata("design:paramtypes", [typeof (_ref$
|
|
2233
|
+
__decorateMetadata("design:paramtypes", [typeof (_ref$4 = typeof AIAgentExecutionHelpersFactory !== "undefined" && AIAgentExecutionHelpersFactory) === "function" ? _ref$4 : Object])
|
|
2231
2234
|
], AgentStructuredOutputRepairPromptFactory);
|
|
2232
2235
|
|
|
2233
2236
|
//#endregion
|
|
@@ -2562,7 +2565,7 @@ const meta = meta$1;
|
|
|
2562
2565
|
|
|
2563
2566
|
//#endregion
|
|
2564
2567
|
//#region src/nodes/AgentStructuredOutputRunner.ts
|
|
2565
|
-
var _ref$
|
|
2568
|
+
var _ref$3, _ref2$3, _AgentStructuredOutputRunner;
|
|
2566
2569
|
let AgentStructuredOutputRunner = class AgentStructuredOutputRunner$1 {
|
|
2567
2570
|
static {
|
|
2568
2571
|
_AgentStructuredOutputRunner = this;
|
|
@@ -2675,7 +2678,7 @@ AgentStructuredOutputRunner = _AgentStructuredOutputRunner = __decorate([
|
|
|
2675
2678
|
injectable(),
|
|
2676
2679
|
__decorateParam(0, inject(AgentStructuredOutputRepairPromptFactory)),
|
|
2677
2680
|
__decorateParam(1, inject(OpenAIStructuredOutputMethodFactory)),
|
|
2678
|
-
__decorateMetadata("design:paramtypes", [typeof (_ref$
|
|
2681
|
+
__decorateMetadata("design:paramtypes", [typeof (_ref$3 = typeof AgentStructuredOutputRepairPromptFactory !== "undefined" && AgentStructuredOutputRepairPromptFactory) === "function" ? _ref$3 : Object, typeof (_ref2$3 = typeof OpenAIStructuredOutputMethodFactory !== "undefined" && OpenAIStructuredOutputMethodFactory) === "function" ? _ref2$3 : Object])
|
|
2679
2682
|
], AgentStructuredOutputRunner);
|
|
2680
2683
|
|
|
2681
2684
|
//#endregion
|
|
@@ -2686,6 +2689,390 @@ var AgentToolCallPortMap = class {
|
|
|
2686
2689
|
}
|
|
2687
2690
|
};
|
|
2688
2691
|
|
|
2692
|
+
//#endregion
|
|
2693
|
+
//#region src/nodes/AgentToolErrorClassifier.ts
|
|
2694
|
+
let AgentToolErrorClassifier = class AgentToolErrorClassifier$1 {
|
|
2695
|
+
classify(args) {
|
|
2696
|
+
const effectiveError = this.toError(args.error);
|
|
2697
|
+
if (this.isRepairableValidationError(args.error, effectiveError)) return {
|
|
2698
|
+
kind: "repairable_validation_error",
|
|
2699
|
+
effectiveError,
|
|
2700
|
+
issues: this.extractIssues(args.error, effectiveError, args.toolName),
|
|
2701
|
+
requiredSchemaReminder: this.toJsonValue(args.schema)
|
|
2702
|
+
};
|
|
2703
|
+
if (this.isTransientExecutionError(effectiveError)) return {
|
|
2704
|
+
kind: "transient_execution_error",
|
|
2705
|
+
effectiveError
|
|
2706
|
+
};
|
|
2707
|
+
return {
|
|
2708
|
+
kind: "non_repairable_error",
|
|
2709
|
+
effectiveError
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
isRepairableValidationError(rawError, effectiveError) {
|
|
2713
|
+
if (rawError instanceof ZodError) return rawError.codemationToolValidationStage !== "output";
|
|
2714
|
+
if (effectiveError.name === "ZodError") return true;
|
|
2715
|
+
return effectiveError.message.includes("Received tool input did not match expected schema");
|
|
2716
|
+
}
|
|
2717
|
+
extractIssues(rawError, effectiveError, toolName) {
|
|
2718
|
+
if (rawError instanceof ZodError) return rawError.issues.map((issue$1) => ({
|
|
2719
|
+
path: issue$1.path.map((segment) => typeof segment === "number" ? segment : String(segment)),
|
|
2720
|
+
code: issue$1.code,
|
|
2721
|
+
message: issue$1.message,
|
|
2722
|
+
expected: this.toOptionalString("expected" in issue$1 ? issue$1.expected : void 0),
|
|
2723
|
+
received: this.toOptionalString("received" in issue$1 ? issue$1.received : void 0)
|
|
2724
|
+
}));
|
|
2725
|
+
if (effectiveError.name !== "ZodError") return;
|
|
2726
|
+
return [{
|
|
2727
|
+
path: [],
|
|
2728
|
+
code: "invalid_tool_input",
|
|
2729
|
+
message: `Tool "${toolName}" input was invalid: ${effectiveError.message}`
|
|
2730
|
+
}];
|
|
2731
|
+
}
|
|
2732
|
+
isTransientExecutionError(error) {
|
|
2733
|
+
const summary = `${error.name} ${error.message}`.toLowerCase();
|
|
2734
|
+
return summary.includes("timeout") || summary.includes("timed out") || summary.includes("rate limit") || summary.includes("too many requests") || summary.includes("temporarily unavailable") || summary.includes("econnreset") || summary.includes("etimedout") || summary.includes("503");
|
|
2735
|
+
}
|
|
2736
|
+
toError(error) {
|
|
2737
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
2738
|
+
}
|
|
2739
|
+
toJsonValue(value) {
|
|
2740
|
+
if (value === void 0) return;
|
|
2741
|
+
return JSON.parse(JSON.stringify(value));
|
|
2742
|
+
}
|
|
2743
|
+
toOptionalString(value) {
|
|
2744
|
+
if (value === void 0) return;
|
|
2745
|
+
return String(value);
|
|
2746
|
+
}
|
|
2747
|
+
};
|
|
2748
|
+
AgentToolErrorClassifier = __decorate([injectable()], AgentToolErrorClassifier);
|
|
2749
|
+
|
|
2750
|
+
//#endregion
|
|
2751
|
+
//#region src/nodes/AgentToolRepairExhaustedError.ts
|
|
2752
|
+
var AgentToolRepairExhaustedError = class extends Error {
|
|
2753
|
+
details;
|
|
2754
|
+
constructor(args) {
|
|
2755
|
+
super(`AIAgent "${args.agentName}" (${args.nodeId}) could not recover from invalid tool calls for "${args.toolName}" after ${args.maxAttempts} repair attempt(s).`);
|
|
2756
|
+
this.name = "AgentToolRepairExhaustedError";
|
|
2757
|
+
const details = {
|
|
2758
|
+
toolName: args.toolName,
|
|
2759
|
+
maxAttempts: args.maxAttempts,
|
|
2760
|
+
recommendation: "Check tool schema, tool description, or inject known values in code instead of asking the model to infer them."
|
|
2761
|
+
};
|
|
2762
|
+
if (args.lastManagedInput !== void 0) details["lastManagedInput"] = args.lastManagedInput;
|
|
2763
|
+
if (args.lastValidationIssues && args.lastValidationIssues.length > 0) details["lastValidationIssues"] = args.lastValidationIssues.map((issue$1) => this.serializeIssue(issue$1));
|
|
2764
|
+
this.details = details;
|
|
2765
|
+
}
|
|
2766
|
+
serializeIssue(issue$1) {
|
|
2767
|
+
const result = {
|
|
2768
|
+
path: [...issue$1.path],
|
|
2769
|
+
code: issue$1.code,
|
|
2770
|
+
message: issue$1.message
|
|
2771
|
+
};
|
|
2772
|
+
if (issue$1.expected !== void 0) result["expected"] = issue$1.expected;
|
|
2773
|
+
if (issue$1.received !== void 0) result["received"] = issue$1.received;
|
|
2774
|
+
return result;
|
|
2775
|
+
}
|
|
2776
|
+
};
|
|
2777
|
+
|
|
2778
|
+
//#endregion
|
|
2779
|
+
//#region src/nodes/AgentToolRepairPolicy.ts
|
|
2780
|
+
var _AgentToolRepairPolicy;
|
|
2781
|
+
let AgentToolRepairPolicy = class AgentToolRepairPolicy$1 {
|
|
2782
|
+
static {
|
|
2783
|
+
_AgentToolRepairPolicy = this;
|
|
2784
|
+
}
|
|
2785
|
+
static maxRepairAttemptsPerTool = 2;
|
|
2786
|
+
createDecision(toolName, attemptsByToolName) {
|
|
2787
|
+
const attempt = (attemptsByToolName.get(toolName) ?? 0) + 1;
|
|
2788
|
+
attemptsByToolName.set(toolName, attempt);
|
|
2789
|
+
return {
|
|
2790
|
+
attempt,
|
|
2791
|
+
maxAttempts: _AgentToolRepairPolicy.maxRepairAttemptsPerTool,
|
|
2792
|
+
nextAction: attempt < _AgentToolRepairPolicy.maxRepairAttemptsPerTool ? "model_retry_with_tool_error_message" : "fail_agent_run"
|
|
2793
|
+
};
|
|
2794
|
+
}
|
|
2795
|
+
};
|
|
2796
|
+
AgentToolRepairPolicy = _AgentToolRepairPolicy = __decorate([injectable()], AgentToolRepairPolicy);
|
|
2797
|
+
|
|
2798
|
+
//#endregion
|
|
2799
|
+
//#region src/nodes/AgentToolExecutionCoordinator.ts
|
|
2800
|
+
var _ref$2, _ref2$2;
|
|
2801
|
+
let AgentToolExecutionCoordinator = class AgentToolExecutionCoordinator$1 {
|
|
2802
|
+
constructor(errorClassifier, repairPolicy) {
|
|
2803
|
+
this.errorClassifier = errorClassifier;
|
|
2804
|
+
this.repairPolicy = repairPolicy;
|
|
2805
|
+
}
|
|
2806
|
+
async execute(args) {
|
|
2807
|
+
const results = await Promise.allSettled(args.plannedToolCalls.map(async (plannedToolCall) => await this.executePlannedToolCall({
|
|
2808
|
+
...args,
|
|
2809
|
+
plannedToolCall
|
|
2810
|
+
})));
|
|
2811
|
+
const rejected = results.find((result) => result.status === "rejected");
|
|
2812
|
+
if (rejected?.status === "rejected") throw rejected.reason instanceof Error ? rejected.reason : new Error(String(rejected.reason));
|
|
2813
|
+
return results.filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
2814
|
+
}
|
|
2815
|
+
async executePlannedToolCall(args) {
|
|
2816
|
+
const { plannedToolCall, ctx } = args;
|
|
2817
|
+
const toolCallInputsByPort = AgentToolCallPortMap.fromInput(plannedToolCall.toolCall.input ?? {});
|
|
2818
|
+
const invocationId = ConnectionInvocationIdFactory.create();
|
|
2819
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
2820
|
+
const span = ctx.telemetry.startChildSpan({
|
|
2821
|
+
name: "agent.tool.call",
|
|
2822
|
+
kind: "client",
|
|
2823
|
+
startedAt,
|
|
2824
|
+
attributes: {
|
|
2825
|
+
[CodemationTelemetryAttributeNames.connectionInvocationId]: invocationId,
|
|
2826
|
+
[CodemationTelemetryAttributeNames.toolName]: plannedToolCall.binding.config.name
|
|
2827
|
+
}
|
|
2828
|
+
});
|
|
2829
|
+
await ctx.nodeState?.markRunning({
|
|
2830
|
+
nodeId: plannedToolCall.nodeId,
|
|
2831
|
+
activationId: ctx.activationId,
|
|
2832
|
+
inputsByPort: toolCallInputsByPort
|
|
2833
|
+
});
|
|
2834
|
+
try {
|
|
2835
|
+
const serialized = await plannedToolCall.binding.langChainTool.invoke(plannedToolCall.toolCall.input ?? {});
|
|
2836
|
+
const result = this.parseToolOutput(serialized);
|
|
2837
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
2838
|
+
await ctx.nodeState?.markCompleted({
|
|
2839
|
+
nodeId: plannedToolCall.nodeId,
|
|
2840
|
+
activationId: ctx.activationId,
|
|
2841
|
+
inputsByPort: toolCallInputsByPort,
|
|
2842
|
+
outputs: AgentOutputFactory.fromUnknown(result)
|
|
2843
|
+
});
|
|
2844
|
+
await span.attachArtifact({
|
|
2845
|
+
kind: "tool.input",
|
|
2846
|
+
contentType: "application/json",
|
|
2847
|
+
previewJson: this.toJsonValue(plannedToolCall.toolCall.input)
|
|
2848
|
+
});
|
|
2849
|
+
await span.attachArtifact({
|
|
2850
|
+
kind: "tool.output",
|
|
2851
|
+
contentType: "application/json",
|
|
2852
|
+
previewJson: this.toJsonValue(result)
|
|
2853
|
+
});
|
|
2854
|
+
await span.end({
|
|
2855
|
+
status: "ok",
|
|
2856
|
+
endedAt: finishedAt
|
|
2857
|
+
});
|
|
2858
|
+
await ctx.nodeState?.appendConnectionInvocation({
|
|
2859
|
+
invocationId,
|
|
2860
|
+
connectionNodeId: plannedToolCall.nodeId,
|
|
2861
|
+
parentAgentNodeId: ctx.nodeId,
|
|
2862
|
+
parentAgentActivationId: ctx.activationId,
|
|
2863
|
+
status: "completed",
|
|
2864
|
+
managedInput: this.toJsonValue(plannedToolCall.toolCall.input),
|
|
2865
|
+
managedOutput: this.toJsonValue(result),
|
|
2866
|
+
queuedAt: startedAt.toISOString(),
|
|
2867
|
+
startedAt: startedAt.toISOString(),
|
|
2868
|
+
finishedAt: finishedAt.toISOString()
|
|
2869
|
+
});
|
|
2870
|
+
return {
|
|
2871
|
+
toolName: plannedToolCall.binding.config.name,
|
|
2872
|
+
toolCallId: plannedToolCall.toolCall.id ?? plannedToolCall.binding.config.name,
|
|
2873
|
+
serialized: typeof serialized === "string" ? serialized : JSON.stringify(serialized),
|
|
2874
|
+
result
|
|
2875
|
+
};
|
|
2876
|
+
} catch (error) {
|
|
2877
|
+
const classification = this.errorClassifier.classify({
|
|
2878
|
+
error,
|
|
2879
|
+
toolName: plannedToolCall.binding.config.name,
|
|
2880
|
+
schema: plannedToolCall.binding.langChainTool.schema
|
|
2881
|
+
});
|
|
2882
|
+
if (classification.kind !== "repairable_validation_error") {
|
|
2883
|
+
const effectiveError = classification.effectiveError;
|
|
2884
|
+
await this.recordFailedInvocation({
|
|
2885
|
+
invocationId,
|
|
2886
|
+
plannedToolCall,
|
|
2887
|
+
ctx,
|
|
2888
|
+
startedAt,
|
|
2889
|
+
inputsByPort: toolCallInputsByPort,
|
|
2890
|
+
managedInput: this.toJsonValue(plannedToolCall.toolCall.input),
|
|
2891
|
+
error: effectiveError
|
|
2892
|
+
});
|
|
2893
|
+
await span.attachArtifact({
|
|
2894
|
+
kind: "tool.input",
|
|
2895
|
+
contentType: "application/json",
|
|
2896
|
+
previewJson: this.toJsonValue(plannedToolCall.toolCall.input)
|
|
2897
|
+
});
|
|
2898
|
+
await span.end({
|
|
2899
|
+
status: "error",
|
|
2900
|
+
statusMessage: effectiveError.message,
|
|
2901
|
+
endedAt: /* @__PURE__ */ new Date()
|
|
2902
|
+
});
|
|
2903
|
+
throw effectiveError;
|
|
2904
|
+
}
|
|
2905
|
+
const repairDecision = this.repairPolicy.createDecision(plannedToolCall.binding.config.name, args.repairAttemptsByToolName);
|
|
2906
|
+
if (repairDecision.nextAction === "fail_agent_run") {
|
|
2907
|
+
const exhaustedError = new AgentToolRepairExhaustedError({
|
|
2908
|
+
agentName: args.agentName,
|
|
2909
|
+
nodeId: ctx.nodeId,
|
|
2910
|
+
toolName: plannedToolCall.binding.config.name,
|
|
2911
|
+
maxAttempts: repairDecision.maxAttempts,
|
|
2912
|
+
lastManagedInput: this.toJsonValue(plannedToolCall.toolCall.input),
|
|
2913
|
+
lastValidationIssues: classification.issues
|
|
2914
|
+
});
|
|
2915
|
+
await this.recordFailedInvocation({
|
|
2916
|
+
invocationId,
|
|
2917
|
+
plannedToolCall,
|
|
2918
|
+
ctx,
|
|
2919
|
+
startedAt,
|
|
2920
|
+
inputsByPort: toolCallInputsByPort,
|
|
2921
|
+
managedInput: this.toJsonValue(plannedToolCall.toolCall.input),
|
|
2922
|
+
error: exhaustedError,
|
|
2923
|
+
errorDetails: exhaustedError.details
|
|
2924
|
+
});
|
|
2925
|
+
await span.attachArtifact({
|
|
2926
|
+
kind: "tool.input",
|
|
2927
|
+
contentType: "application/json",
|
|
2928
|
+
previewJson: this.toJsonValue(plannedToolCall.toolCall.input)
|
|
2929
|
+
});
|
|
2930
|
+
await span.attachArtifact({
|
|
2931
|
+
kind: "tool.error",
|
|
2932
|
+
contentType: "application/json",
|
|
2933
|
+
previewJson: exhaustedError.details
|
|
2934
|
+
});
|
|
2935
|
+
await span.end({
|
|
2936
|
+
status: "error",
|
|
2937
|
+
statusMessage: exhaustedError.message,
|
|
2938
|
+
endedAt: /* @__PURE__ */ new Date()
|
|
2939
|
+
});
|
|
2940
|
+
throw exhaustedError;
|
|
2941
|
+
}
|
|
2942
|
+
const repairPayload = this.createRepairPayload({
|
|
2943
|
+
toolName: plannedToolCall.binding.config.name,
|
|
2944
|
+
issues: classification.issues,
|
|
2945
|
+
requiredSchemaReminder: classification.requiredSchemaReminder
|
|
2946
|
+
});
|
|
2947
|
+
const repairDetails = this.createRepairDetails({
|
|
2948
|
+
toolName: plannedToolCall.binding.config.name,
|
|
2949
|
+
issues: classification.issues,
|
|
2950
|
+
requiredSchemaReminder: classification.requiredSchemaReminder,
|
|
2951
|
+
repairDecision
|
|
2952
|
+
});
|
|
2953
|
+
await this.recordFailedInvocation({
|
|
2954
|
+
invocationId,
|
|
2955
|
+
plannedToolCall,
|
|
2956
|
+
ctx,
|
|
2957
|
+
startedAt,
|
|
2958
|
+
inputsByPort: toolCallInputsByPort,
|
|
2959
|
+
managedInput: this.toJsonValue(plannedToolCall.toolCall.input),
|
|
2960
|
+
error: classification.effectiveError,
|
|
2961
|
+
errorDetails: repairDetails
|
|
2962
|
+
});
|
|
2963
|
+
await span.attachArtifact({
|
|
2964
|
+
kind: "tool.input",
|
|
2965
|
+
contentType: "application/json",
|
|
2966
|
+
previewJson: this.toJsonValue(plannedToolCall.toolCall.input)
|
|
2967
|
+
});
|
|
2968
|
+
await span.attachArtifact({
|
|
2969
|
+
kind: "tool.error",
|
|
2970
|
+
contentType: "application/json",
|
|
2971
|
+
previewJson: repairPayload
|
|
2972
|
+
});
|
|
2973
|
+
await span.end({
|
|
2974
|
+
status: "error",
|
|
2975
|
+
statusMessage: classification.effectiveError.message,
|
|
2976
|
+
endedAt: /* @__PURE__ */ new Date()
|
|
2977
|
+
});
|
|
2978
|
+
return {
|
|
2979
|
+
toolName: plannedToolCall.binding.config.name,
|
|
2980
|
+
toolCallId: plannedToolCall.toolCall.id ?? plannedToolCall.binding.config.name,
|
|
2981
|
+
serialized: JSON.stringify(repairPayload),
|
|
2982
|
+
result: repairPayload
|
|
2983
|
+
};
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
async recordFailedInvocation(args) {
|
|
2987
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
2988
|
+
await args.ctx.nodeState?.markFailed({
|
|
2989
|
+
nodeId: args.plannedToolCall.nodeId,
|
|
2990
|
+
activationId: args.ctx.activationId,
|
|
2991
|
+
inputsByPort: args.inputsByPort,
|
|
2992
|
+
error: args.error
|
|
2993
|
+
});
|
|
2994
|
+
await args.ctx.nodeState?.appendConnectionInvocation({
|
|
2995
|
+
invocationId: args.invocationId,
|
|
2996
|
+
connectionNodeId: args.plannedToolCall.nodeId,
|
|
2997
|
+
parentAgentNodeId: args.ctx.nodeId,
|
|
2998
|
+
parentAgentActivationId: args.ctx.activationId,
|
|
2999
|
+
status: "failed",
|
|
3000
|
+
managedInput: args.managedInput,
|
|
3001
|
+
error: {
|
|
3002
|
+
message: args.error.message,
|
|
3003
|
+
name: args.error.name,
|
|
3004
|
+
stack: args.error.stack,
|
|
3005
|
+
details: args.errorDetails ?? this.extractErrorDetails(args.error)
|
|
3006
|
+
},
|
|
3007
|
+
queuedAt: args.startedAt.toISOString(),
|
|
3008
|
+
startedAt: args.startedAt.toISOString(),
|
|
3009
|
+
finishedAt: finishedAt.toISOString()
|
|
3010
|
+
});
|
|
3011
|
+
}
|
|
3012
|
+
createRepairPayload(args) {
|
|
3013
|
+
const payload = {
|
|
3014
|
+
status: "error",
|
|
3015
|
+
errorType: "validation",
|
|
3016
|
+
toolName: args.toolName,
|
|
3017
|
+
message: this.createValidationMessage(args.toolName, args.issues),
|
|
3018
|
+
instruction: "Call the tool again with all required fields present and correctly typed."
|
|
3019
|
+
};
|
|
3020
|
+
if (args.requiredSchemaReminder !== void 0) payload["requiredSchemaReminder"] = args.requiredSchemaReminder;
|
|
3021
|
+
return payload;
|
|
3022
|
+
}
|
|
3023
|
+
createRepairDetails(args) {
|
|
3024
|
+
const details = {
|
|
3025
|
+
errorType: "validation",
|
|
3026
|
+
toolName: args.toolName,
|
|
3027
|
+
recoveryHint: "Call the same tool again with every required field present and correctly typed.",
|
|
3028
|
+
repair: {
|
|
3029
|
+
attempt: args.repairDecision.attempt,
|
|
3030
|
+
maxAttempts: args.repairDecision.maxAttempts,
|
|
3031
|
+
nextAction: args.repairDecision.nextAction
|
|
3032
|
+
}
|
|
3033
|
+
};
|
|
3034
|
+
if (args.issues && args.issues.length > 0) details["issues"] = args.issues.map((issue$1) => this.serializeIssue(issue$1));
|
|
3035
|
+
if (args.requiredSchemaReminder !== void 0) details["requiredSchemaReminder"] = args.requiredSchemaReminder;
|
|
3036
|
+
return details;
|
|
3037
|
+
}
|
|
3038
|
+
createValidationMessage(toolName, issues) {
|
|
3039
|
+
const firstIssue = issues?.[0];
|
|
3040
|
+
if (!firstIssue) return `Your previous tool call for "${toolName}" was invalid and did not match the expected schema.`;
|
|
3041
|
+
return `Your previous tool call for "${toolName}" was invalid because field "${firstIssue.path.length > 0 ? firstIssue.path.join(".") : "<root>"}" failed validation: ${firstIssue.message}`;
|
|
3042
|
+
}
|
|
3043
|
+
parseToolOutput(serialized) {
|
|
3044
|
+
if (typeof serialized !== "string") return serialized;
|
|
3045
|
+
try {
|
|
3046
|
+
return JSON.parse(serialized);
|
|
3047
|
+
} catch {
|
|
3048
|
+
return serialized;
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
toJsonValue(value) {
|
|
3052
|
+
if (value === void 0) return;
|
|
3053
|
+
return JSON.parse(JSON.stringify(value));
|
|
3054
|
+
}
|
|
3055
|
+
extractErrorDetails(error) {
|
|
3056
|
+
return error.details;
|
|
3057
|
+
}
|
|
3058
|
+
serializeIssue(issue$1) {
|
|
3059
|
+
const result = {
|
|
3060
|
+
path: [...issue$1.path],
|
|
3061
|
+
code: issue$1.code,
|
|
3062
|
+
message: issue$1.message
|
|
3063
|
+
};
|
|
3064
|
+
if (issue$1.expected !== void 0) result["expected"] = issue$1.expected;
|
|
3065
|
+
if (issue$1.received !== void 0) result["received"] = issue$1.received;
|
|
3066
|
+
return result;
|
|
3067
|
+
}
|
|
3068
|
+
};
|
|
3069
|
+
AgentToolExecutionCoordinator = __decorate([
|
|
3070
|
+
injectable(),
|
|
3071
|
+
__decorateParam(0, inject(AgentToolErrorClassifier)),
|
|
3072
|
+
__decorateParam(1, inject(AgentToolRepairPolicy)),
|
|
3073
|
+
__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])
|
|
3074
|
+
], AgentToolExecutionCoordinator);
|
|
3075
|
+
|
|
2689
3076
|
//#endregion
|
|
2690
3077
|
//#region src/nodes/NodeBackedToolRuntime.ts
|
|
2691
3078
|
var _ref$1, _ref2$1, _ref3$1;
|
|
@@ -2776,7 +3163,7 @@ var AgentItemPortMap = class {
|
|
|
2776
3163
|
|
|
2777
3164
|
//#endregion
|
|
2778
3165
|
//#region src/nodes/AIAgentNode.ts
|
|
2779
|
-
var _ref, _ref2, _ref3;
|
|
3166
|
+
var _ref, _ref2, _ref3, _ref4;
|
|
2780
3167
|
let AIAgentNode = class AIAgentNode$1 {
|
|
2781
3168
|
kind = "node";
|
|
2782
3169
|
outputPorts = ["main"];
|
|
@@ -2789,11 +3176,12 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
2789
3176
|
connectionCredentialExecutionContextFactory;
|
|
2790
3177
|
/** One resolved model/tools bundle per activation context (same ctx across items in a batch). */
|
|
2791
3178
|
preparedByExecutionContext = /* @__PURE__ */ new WeakMap();
|
|
2792
|
-
constructor(nodeResolver, credentialSessions, nodeBackedToolRuntime, executionHelpers, structuredOutputRunner) {
|
|
3179
|
+
constructor(nodeResolver, credentialSessions, nodeBackedToolRuntime, executionHelpers, structuredOutputRunner, toolExecutionCoordinator) {
|
|
2793
3180
|
this.nodeResolver = nodeResolver;
|
|
2794
3181
|
this.nodeBackedToolRuntime = nodeBackedToolRuntime;
|
|
2795
3182
|
this.executionHelpers = executionHelpers;
|
|
2796
3183
|
this.structuredOutputRunner = structuredOutputRunner;
|
|
3184
|
+
this.toolExecutionCoordinator = toolExecutionCoordinator;
|
|
2797
3185
|
this.connectionCredentialExecutionContextFactory = this.executionHelpers.createConnectionCredentialExecutionContextFactory(credentialSessions);
|
|
2798
3186
|
}
|
|
2799
3187
|
async execute(args) {
|
|
@@ -2856,17 +3244,33 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
2856
3244
|
invokeTextModel: async (messages) => await this.invokeModel(prepared.model, prepared.languageModelConnectionNodeId, messages, ctx, itemInputsByPort, prepared.guardrails.modelInvocationOptions),
|
|
2857
3245
|
invokeStructuredModel: async (structuredModel, messages) => await this.invokeStructuredModel(structuredModel, prepared.languageModelConnectionNodeId, messages, ctx, itemInputsByPort, prepared.guardrails.modelInvocationOptions)
|
|
2858
3246
|
});
|
|
3247
|
+
await ctx.telemetry.recordMetric({
|
|
3248
|
+
name: CodemationTelemetryMetricNames.agentTurns,
|
|
3249
|
+
value: 1
|
|
3250
|
+
});
|
|
3251
|
+
await ctx.telemetry.recordMetric({
|
|
3252
|
+
name: CodemationTelemetryMetricNames.agentToolCalls,
|
|
3253
|
+
value: 0
|
|
3254
|
+
});
|
|
2859
3255
|
return this.buildOutputItem(item, structuredOutput);
|
|
2860
3256
|
}
|
|
2861
3257
|
const modelWithTools = this.bindToolsToModel(prepared.model, itemScopedTools);
|
|
2862
|
-
const
|
|
3258
|
+
const loopResult = await this.runTurnLoopUntilFinalAnswer({
|
|
2863
3259
|
prepared,
|
|
2864
3260
|
itemInputsByPort,
|
|
2865
3261
|
itemScopedTools,
|
|
2866
3262
|
conversation,
|
|
2867
3263
|
modelWithTools
|
|
2868
3264
|
});
|
|
2869
|
-
|
|
3265
|
+
await ctx.telemetry.recordMetric({
|
|
3266
|
+
name: CodemationTelemetryMetricNames.agentTurns,
|
|
3267
|
+
value: loopResult.turnCount
|
|
3268
|
+
});
|
|
3269
|
+
await ctx.telemetry.recordMetric({
|
|
3270
|
+
name: CodemationTelemetryMetricNames.agentToolCalls,
|
|
3271
|
+
value: loopResult.toolCallCount
|
|
3272
|
+
});
|
|
3273
|
+
const outputJson = await this.resolveFinalOutputJson(prepared, itemInputsByPort, conversation, loopResult.finalResponse, itemScopedTools.length > 0);
|
|
2870
3274
|
return this.buildOutputItem(item, outputJson);
|
|
2871
3275
|
}
|
|
2872
3276
|
/**
|
|
@@ -2876,7 +3280,11 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
2876
3280
|
const { prepared, itemInputsByPort, itemScopedTools, conversation, modelWithTools } = args;
|
|
2877
3281
|
const { ctx, guardrails, languageModelConnectionNodeId } = prepared;
|
|
2878
3282
|
let finalResponse;
|
|
3283
|
+
let toolCallCount = 0;
|
|
3284
|
+
let turnCount = 0;
|
|
3285
|
+
const repairAttemptsByToolName = /* @__PURE__ */ new Map();
|
|
2879
3286
|
for (let turn = 1; turn <= guardrails.maxTurns; turn++) {
|
|
3287
|
+
turnCount = turn;
|
|
2880
3288
|
const response = await this.invokeModel(modelWithTools, languageModelConnectionNodeId, conversation, ctx, itemInputsByPort, guardrails.modelInvocationOptions);
|
|
2881
3289
|
finalResponse = response;
|
|
2882
3290
|
const toolCalls = AgentMessageFactory.extractToolCalls(response);
|
|
@@ -2886,12 +3294,22 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
2886
3294
|
break;
|
|
2887
3295
|
}
|
|
2888
3296
|
const plannedToolCalls = this.planToolCalls(itemScopedTools, toolCalls, ctx.nodeId);
|
|
3297
|
+
toolCallCount += plannedToolCalls.length;
|
|
2889
3298
|
await this.markQueuedTools(plannedToolCalls, ctx);
|
|
2890
|
-
const executedToolCalls = await this.
|
|
3299
|
+
const executedToolCalls = await this.toolExecutionCoordinator.execute({
|
|
3300
|
+
plannedToolCalls,
|
|
3301
|
+
ctx,
|
|
3302
|
+
agentName: this.getAgentDisplayName(ctx),
|
|
3303
|
+
repairAttemptsByToolName
|
|
3304
|
+
});
|
|
2891
3305
|
this.appendAssistantAndToolMessages(conversation, response, executedToolCalls);
|
|
2892
3306
|
}
|
|
2893
3307
|
if (!finalResponse) throw new Error(`AIAgent "${ctx.config.name ?? ctx.nodeId}" did not produce a model response.`);
|
|
2894
|
-
return
|
|
3308
|
+
return {
|
|
3309
|
+
finalResponse,
|
|
3310
|
+
turnCount,
|
|
3311
|
+
toolCallCount
|
|
3312
|
+
};
|
|
2895
3313
|
}
|
|
2896
3314
|
cannotExecuteAnotherToolRound(turn, guardrails) {
|
|
2897
3315
|
return turn >= guardrails.maxTurns;
|
|
@@ -2950,6 +3368,10 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
2950
3368
|
});
|
|
2951
3369
|
}
|
|
2952
3370
|
async invokeModel(model, nodeId, messages, ctx, inputsByPort, options) {
|
|
3371
|
+
const invocationId = ConnectionInvocationIdFactory.create();
|
|
3372
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
3373
|
+
const summarizedInput = this.summarizeLlmMessages(messages);
|
|
3374
|
+
const span = this.createModelInvocationSpan(ctx, invocationId, startedAt);
|
|
2953
3375
|
await ctx.nodeState?.markQueued({
|
|
2954
3376
|
nodeId,
|
|
2955
3377
|
activationId: ctx.activationId,
|
|
@@ -2962,6 +3384,7 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
2962
3384
|
});
|
|
2963
3385
|
try {
|
|
2964
3386
|
const response = await model.invoke(messages, options);
|
|
3387
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
2965
3388
|
await ctx.nodeState?.markCompleted({
|
|
2966
3389
|
nodeId,
|
|
2967
3390
|
activationId: ctx.activationId,
|
|
@@ -2969,22 +3392,56 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
2969
3392
|
outputs: AgentOutputFactory.fromUnknown({ content: AgentMessageFactory.extractContent(response) })
|
|
2970
3393
|
});
|
|
2971
3394
|
const content = AgentMessageFactory.extractContent(response);
|
|
3395
|
+
await span.attachArtifact({
|
|
3396
|
+
kind: "ai.messages",
|
|
3397
|
+
contentType: "application/json",
|
|
3398
|
+
previewJson: summarizedInput
|
|
3399
|
+
});
|
|
3400
|
+
await span.attachArtifact({
|
|
3401
|
+
kind: "ai.response",
|
|
3402
|
+
contentType: "application/json",
|
|
3403
|
+
previewJson: content
|
|
3404
|
+
});
|
|
3405
|
+
await this.recordModelUsageMetrics(span, response, ctx);
|
|
3406
|
+
await span.end({
|
|
3407
|
+
status: "ok",
|
|
3408
|
+
endedAt: finishedAt
|
|
3409
|
+
});
|
|
2972
3410
|
await ctx.nodeState?.appendConnectionInvocation({
|
|
2973
|
-
invocationId
|
|
3411
|
+
invocationId,
|
|
2974
3412
|
connectionNodeId: nodeId,
|
|
2975
3413
|
parentAgentNodeId: ctx.nodeId,
|
|
2976
3414
|
parentAgentActivationId: ctx.activationId,
|
|
2977
3415
|
status: "completed",
|
|
2978
|
-
managedInput:
|
|
3416
|
+
managedInput: summarizedInput,
|
|
2979
3417
|
managedOutput: content,
|
|
2980
|
-
|
|
3418
|
+
queuedAt: startedAt.toISOString(),
|
|
3419
|
+
startedAt: startedAt.toISOString(),
|
|
3420
|
+
finishedAt: finishedAt.toISOString()
|
|
2981
3421
|
});
|
|
2982
3422
|
return response;
|
|
2983
3423
|
} catch (error) {
|
|
2984
|
-
|
|
3424
|
+
await span.end({
|
|
3425
|
+
status: "error",
|
|
3426
|
+
statusMessage: error instanceof Error ? error.message : String(error),
|
|
3427
|
+
endedAt: /* @__PURE__ */ new Date()
|
|
3428
|
+
});
|
|
3429
|
+
throw await this.failTrackedNodeInvocation({
|
|
3430
|
+
error,
|
|
3431
|
+
invocationId,
|
|
3432
|
+
startedAt,
|
|
3433
|
+
nodeId,
|
|
3434
|
+
ctx,
|
|
3435
|
+
inputsByPort,
|
|
3436
|
+
managedInput: this.summarizeLlmMessages(messages)
|
|
3437
|
+
});
|
|
2985
3438
|
}
|
|
2986
3439
|
}
|
|
2987
3440
|
async invokeStructuredModel(model, nodeId, messages, ctx, inputsByPort, options) {
|
|
3441
|
+
const invocationId = ConnectionInvocationIdFactory.create();
|
|
3442
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
3443
|
+
const summarizedInput = this.summarizeLlmMessages(messages);
|
|
3444
|
+
const span = this.createModelInvocationSpan(ctx, invocationId, startedAt);
|
|
2988
3445
|
await ctx.nodeState?.markQueued({
|
|
2989
3446
|
nodeId,
|
|
2990
3447
|
activationId: ctx.activationId,
|
|
@@ -2997,27 +3454,174 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
2997
3454
|
});
|
|
2998
3455
|
try {
|
|
2999
3456
|
const response = await model.invoke(messages, options);
|
|
3457
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
3000
3458
|
await ctx.nodeState?.markCompleted({
|
|
3001
3459
|
nodeId,
|
|
3002
3460
|
activationId: ctx.activationId,
|
|
3003
3461
|
inputsByPort,
|
|
3004
3462
|
outputs: AgentOutputFactory.fromUnknown(response)
|
|
3005
3463
|
});
|
|
3464
|
+
await span.attachArtifact({
|
|
3465
|
+
kind: "ai.messages",
|
|
3466
|
+
contentType: "application/json",
|
|
3467
|
+
previewJson: summarizedInput
|
|
3468
|
+
});
|
|
3469
|
+
await span.attachArtifact({
|
|
3470
|
+
kind: "ai.response.structured",
|
|
3471
|
+
contentType: "application/json",
|
|
3472
|
+
previewJson: this.resultToJsonValue(response)
|
|
3473
|
+
});
|
|
3474
|
+
await this.recordModelUsageMetrics(span, response, ctx);
|
|
3475
|
+
await span.end({
|
|
3476
|
+
status: "ok",
|
|
3477
|
+
endedAt: finishedAt
|
|
3478
|
+
});
|
|
3006
3479
|
await ctx.nodeState?.appendConnectionInvocation({
|
|
3007
|
-
invocationId
|
|
3480
|
+
invocationId,
|
|
3008
3481
|
connectionNodeId: nodeId,
|
|
3009
3482
|
parentAgentNodeId: ctx.nodeId,
|
|
3010
3483
|
parentAgentActivationId: ctx.activationId,
|
|
3011
3484
|
status: "completed",
|
|
3012
|
-
managedInput:
|
|
3485
|
+
managedInput: summarizedInput,
|
|
3013
3486
|
managedOutput: this.resultToJsonValue(response),
|
|
3014
|
-
|
|
3487
|
+
queuedAt: startedAt.toISOString(),
|
|
3488
|
+
startedAt: startedAt.toISOString(),
|
|
3489
|
+
finishedAt: finishedAt.toISOString()
|
|
3015
3490
|
});
|
|
3016
3491
|
return response;
|
|
3017
3492
|
} catch (error) {
|
|
3018
|
-
|
|
3493
|
+
await span.end({
|
|
3494
|
+
status: "error",
|
|
3495
|
+
statusMessage: error instanceof Error ? error.message : String(error),
|
|
3496
|
+
endedAt: /* @__PURE__ */ new Date()
|
|
3497
|
+
});
|
|
3498
|
+
throw await this.failTrackedNodeInvocation({
|
|
3499
|
+
error,
|
|
3500
|
+
invocationId,
|
|
3501
|
+
startedAt,
|
|
3502
|
+
nodeId,
|
|
3503
|
+
ctx,
|
|
3504
|
+
inputsByPort,
|
|
3505
|
+
managedInput: this.summarizeLlmMessages(messages)
|
|
3506
|
+
});
|
|
3019
3507
|
}
|
|
3020
3508
|
}
|
|
3509
|
+
createModelInvocationSpan(ctx, invocationId, startedAt) {
|
|
3510
|
+
return ctx.telemetry.startChildSpan({
|
|
3511
|
+
name: "gen_ai.chat.completion",
|
|
3512
|
+
kind: "client",
|
|
3513
|
+
startedAt,
|
|
3514
|
+
attributes: {
|
|
3515
|
+
[CodemationTelemetryAttributeNames.connectionInvocationId]: invocationId,
|
|
3516
|
+
[GenAiTelemetryAttributeNames.operationName]: "chat",
|
|
3517
|
+
[GenAiTelemetryAttributeNames.requestModel]: this.resolveChatModelName(ctx.config.chatModel)
|
|
3518
|
+
}
|
|
3519
|
+
});
|
|
3520
|
+
}
|
|
3521
|
+
async recordModelUsageMetrics(span, response, ctx) {
|
|
3522
|
+
const usage = this.extractModelUsageMetrics(response);
|
|
3523
|
+
for (const [name, value] of Object.entries(usage)) {
|
|
3524
|
+
if (value === void 0) continue;
|
|
3525
|
+
await span.recordMetric({
|
|
3526
|
+
name,
|
|
3527
|
+
value
|
|
3528
|
+
});
|
|
3529
|
+
}
|
|
3530
|
+
await this.captureCostTrackingUsage(span, ctx, usage);
|
|
3531
|
+
}
|
|
3532
|
+
async captureCostTrackingUsage(span, ctx, usage) {
|
|
3533
|
+
const costTracking = span.costTracking;
|
|
3534
|
+
if (!costTracking) return;
|
|
3535
|
+
const provider = ctx.config.chatModel.provider;
|
|
3536
|
+
const pricingKey = ctx.config.chatModel.modelName;
|
|
3537
|
+
if (!provider || !pricingKey) return;
|
|
3538
|
+
const inputTokens = usage[GenAiTelemetryAttributeNames.usageInputTokens];
|
|
3539
|
+
const outputTokens = usage[GenAiTelemetryAttributeNames.usageOutputTokens];
|
|
3540
|
+
if (inputTokens !== void 0) await costTracking.captureUsage({
|
|
3541
|
+
component: "chat",
|
|
3542
|
+
provider,
|
|
3543
|
+
operation: "completion.input",
|
|
3544
|
+
pricingKey,
|
|
3545
|
+
usageUnit: "input_tokens",
|
|
3546
|
+
quantity: inputTokens,
|
|
3547
|
+
modelName: pricingKey
|
|
3548
|
+
});
|
|
3549
|
+
if (outputTokens !== void 0) await costTracking.captureUsage({
|
|
3550
|
+
component: "chat",
|
|
3551
|
+
provider,
|
|
3552
|
+
operation: "completion.output",
|
|
3553
|
+
pricingKey,
|
|
3554
|
+
usageUnit: "output_tokens",
|
|
3555
|
+
quantity: outputTokens,
|
|
3556
|
+
modelName: pricingKey
|
|
3557
|
+
});
|
|
3558
|
+
}
|
|
3559
|
+
resolveChatModelName(chatModel$1) {
|
|
3560
|
+
return chatModel$1.modelName ?? chatModel$1.name;
|
|
3561
|
+
}
|
|
3562
|
+
extractModelUsageMetrics(response) {
|
|
3563
|
+
const usage = this.extractUsageObject(response);
|
|
3564
|
+
const inputTokens = this.readUsageNumber(usage, [
|
|
3565
|
+
"input_tokens",
|
|
3566
|
+
"inputTokens",
|
|
3567
|
+
"prompt_tokens",
|
|
3568
|
+
"promptTokens"
|
|
3569
|
+
]);
|
|
3570
|
+
const outputTokens = this.readUsageNumber(usage, [
|
|
3571
|
+
"output_tokens",
|
|
3572
|
+
"outputTokens",
|
|
3573
|
+
"completion_tokens",
|
|
3574
|
+
"completionTokens"
|
|
3575
|
+
]);
|
|
3576
|
+
const totalTokens = this.readUsageNumber(usage, ["total_tokens", "totalTokens"]) ?? (inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0);
|
|
3577
|
+
const cachedInputTokens = this.readUsageNumber(usage, [
|
|
3578
|
+
"cache_read_input_tokens",
|
|
3579
|
+
"cacheReadInputTokens",
|
|
3580
|
+
"input_token_details.cached_tokens"
|
|
3581
|
+
]);
|
|
3582
|
+
const reasoningTokens = this.readUsageNumber(usage, [
|
|
3583
|
+
"reasoning_tokens",
|
|
3584
|
+
"reasoningTokens",
|
|
3585
|
+
"output_token_details.reasoning_tokens"
|
|
3586
|
+
]);
|
|
3587
|
+
return {
|
|
3588
|
+
[GenAiTelemetryAttributeNames.usageInputTokens]: inputTokens,
|
|
3589
|
+
[GenAiTelemetryAttributeNames.usageOutputTokens]: outputTokens,
|
|
3590
|
+
[GenAiTelemetryAttributeNames.usageTotalTokens]: totalTokens,
|
|
3591
|
+
[GenAiTelemetryAttributeNames.usageCacheReadInputTokens]: cachedInputTokens,
|
|
3592
|
+
[GenAiTelemetryAttributeNames.usageReasoningTokens]: reasoningTokens
|
|
3593
|
+
};
|
|
3594
|
+
}
|
|
3595
|
+
extractUsageObject(response) {
|
|
3596
|
+
if (!this.isRecord(response)) return;
|
|
3597
|
+
const usageMetadata = response["usage_metadata"];
|
|
3598
|
+
if (this.isRecord(usageMetadata)) return usageMetadata;
|
|
3599
|
+
const responseMetadata = response["response_metadata"];
|
|
3600
|
+
if (this.isRecord(responseMetadata)) {
|
|
3601
|
+
const tokenUsage = responseMetadata["tokenUsage"];
|
|
3602
|
+
if (this.isRecord(tokenUsage)) return tokenUsage;
|
|
3603
|
+
const usage = responseMetadata["usage"];
|
|
3604
|
+
if (this.isRecord(usage)) return usage;
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
readUsageNumber(source, keys) {
|
|
3608
|
+
for (const key of keys) {
|
|
3609
|
+
const value = this.readNestedUsageValue(source, key);
|
|
3610
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
readNestedUsageValue(source, dottedKey) {
|
|
3614
|
+
if (!source) return;
|
|
3615
|
+
let current = source;
|
|
3616
|
+
for (const segment of dottedKey.split(".")) {
|
|
3617
|
+
if (!this.isRecord(current)) return;
|
|
3618
|
+
current = current[segment];
|
|
3619
|
+
}
|
|
3620
|
+
return current;
|
|
3621
|
+
}
|
|
3622
|
+
isRecord(value) {
|
|
3623
|
+
return typeof value === "object" && value !== null;
|
|
3624
|
+
}
|
|
3021
3625
|
async markQueuedTools(plannedToolCalls, ctx) {
|
|
3022
3626
|
for (const plannedToolCall of plannedToolCalls) await ctx.nodeState?.markQueued({
|
|
3023
3627
|
nodeId: plannedToolCall.nodeId,
|
|
@@ -3025,47 +3629,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
3025
3629
|
inputsByPort: AgentToolCallPortMap.fromInput(plannedToolCall.toolCall.input ?? {})
|
|
3026
3630
|
});
|
|
3027
3631
|
}
|
|
3028
|
-
async executeToolCalls(plannedToolCalls, ctx) {
|
|
3029
|
-
const results = await Promise.allSettled(plannedToolCalls.map(async (plannedToolCall) => {
|
|
3030
|
-
const toolCallInputsByPort = AgentToolCallPortMap.fromInput(plannedToolCall.toolCall.input ?? {});
|
|
3031
|
-
await ctx.nodeState?.markRunning({
|
|
3032
|
-
nodeId: plannedToolCall.nodeId,
|
|
3033
|
-
activationId: ctx.activationId,
|
|
3034
|
-
inputsByPort: toolCallInputsByPort
|
|
3035
|
-
});
|
|
3036
|
-
try {
|
|
3037
|
-
const serialized = await plannedToolCall.binding.langChainTool.invoke(plannedToolCall.toolCall.input ?? {});
|
|
3038
|
-
const result = this.parseToolOutput(serialized);
|
|
3039
|
-
await ctx.nodeState?.markCompleted({
|
|
3040
|
-
nodeId: plannedToolCall.nodeId,
|
|
3041
|
-
activationId: ctx.activationId,
|
|
3042
|
-
inputsByPort: toolCallInputsByPort,
|
|
3043
|
-
outputs: AgentOutputFactory.fromUnknown(result)
|
|
3044
|
-
});
|
|
3045
|
-
await ctx.nodeState?.appendConnectionInvocation({
|
|
3046
|
-
invocationId: ConnectionInvocationIdFactory.create(),
|
|
3047
|
-
connectionNodeId: plannedToolCall.nodeId,
|
|
3048
|
-
parentAgentNodeId: ctx.nodeId,
|
|
3049
|
-
parentAgentActivationId: ctx.activationId,
|
|
3050
|
-
status: "completed",
|
|
3051
|
-
managedInput: this.toolCallInputToJson(plannedToolCall.toolCall.input),
|
|
3052
|
-
managedOutput: this.resultToJsonValue(result),
|
|
3053
|
-
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3054
|
-
});
|
|
3055
|
-
return {
|
|
3056
|
-
toolName: plannedToolCall.binding.config.name,
|
|
3057
|
-
toolCallId: plannedToolCall.toolCall.id ?? plannedToolCall.binding.config.name,
|
|
3058
|
-
serialized,
|
|
3059
|
-
result
|
|
3060
|
-
};
|
|
3061
|
-
} catch (error) {
|
|
3062
|
-
throw await this.failTrackedNodeInvocation(error, plannedToolCall.nodeId, ctx, toolCallInputsByPort, this.toolCallInputToJson(plannedToolCall.toolCall.input));
|
|
3063
|
-
}
|
|
3064
|
-
}));
|
|
3065
|
-
const rejected = results.find((result) => result.status === "rejected");
|
|
3066
|
-
if (rejected?.status === "rejected") throw rejected.reason instanceof Error ? rejected.reason : new Error(String(rejected.reason));
|
|
3067
|
-
return results.filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
3068
|
-
}
|
|
3069
3632
|
planToolCalls(bindings, toolCalls, parentNodeId) {
|
|
3070
3633
|
const invocationCountByToolName = /* @__PURE__ */ new Map();
|
|
3071
3634
|
return toolCalls.map((toolCall) => {
|
|
@@ -3081,35 +3644,31 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
3081
3644
|
};
|
|
3082
3645
|
});
|
|
3083
3646
|
}
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
}
|
|
3092
|
-
async failTrackedNodeInvocation(error, nodeId, ctx, inputsByPort, managedInput) {
|
|
3093
|
-
const effectiveError = error instanceof Error ? error : new Error(String(error));
|
|
3094
|
-
await ctx.nodeState?.markFailed({
|
|
3095
|
-
nodeId,
|
|
3096
|
-
activationId: ctx.activationId,
|
|
3097
|
-
inputsByPort,
|
|
3647
|
+
async failTrackedNodeInvocation(args) {
|
|
3648
|
+
const effectiveError = args.error instanceof Error ? args.error : new Error(String(args.error));
|
|
3649
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
3650
|
+
await args.ctx.nodeState?.markFailed({
|
|
3651
|
+
nodeId: args.nodeId,
|
|
3652
|
+
activationId: args.ctx.activationId,
|
|
3653
|
+
inputsByPort: args.inputsByPort,
|
|
3098
3654
|
error: effectiveError
|
|
3099
3655
|
});
|
|
3100
|
-
await ctx.nodeState?.appendConnectionInvocation({
|
|
3101
|
-
invocationId:
|
|
3102
|
-
connectionNodeId: nodeId,
|
|
3103
|
-
parentAgentNodeId: ctx.nodeId,
|
|
3104
|
-
parentAgentActivationId: ctx.activationId,
|
|
3656
|
+
await args.ctx.nodeState?.appendConnectionInvocation({
|
|
3657
|
+
invocationId: args.invocationId,
|
|
3658
|
+
connectionNodeId: args.nodeId,
|
|
3659
|
+
parentAgentNodeId: args.ctx.nodeId,
|
|
3660
|
+
parentAgentActivationId: args.ctx.activationId,
|
|
3105
3661
|
status: "failed",
|
|
3106
|
-
managedInput,
|
|
3662
|
+
managedInput: args.managedInput,
|
|
3107
3663
|
error: {
|
|
3108
3664
|
message: effectiveError.message,
|
|
3109
3665
|
name: effectiveError.name,
|
|
3110
|
-
stack: effectiveError.stack
|
|
3666
|
+
stack: effectiveError.stack,
|
|
3667
|
+
details: this.extractErrorDetails(effectiveError)
|
|
3111
3668
|
},
|
|
3112
|
-
|
|
3669
|
+
queuedAt: args.startedAt.toISOString(),
|
|
3670
|
+
startedAt: args.startedAt.toISOString(),
|
|
3671
|
+
finishedAt: finishedAt.toISOString()
|
|
3113
3672
|
});
|
|
3114
3673
|
return effectiveError;
|
|
3115
3674
|
}
|
|
@@ -3121,9 +3680,6 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
3121
3680
|
lastMessagePreview: preview.slice(0, 4e3)
|
|
3122
3681
|
};
|
|
3123
3682
|
}
|
|
3124
|
-
toolCallInputToJson(input) {
|
|
3125
|
-
return this.resultToJsonValue(input);
|
|
3126
|
-
}
|
|
3127
3683
|
resultToJsonValue(value) {
|
|
3128
3684
|
if (value === void 0) return;
|
|
3129
3685
|
const json = JSON.stringify(value);
|
|
@@ -3193,6 +3749,9 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
3193
3749
|
getAgentDisplayName(ctx) {
|
|
3194
3750
|
return ctx.config.name ?? ctx.nodeId;
|
|
3195
3751
|
}
|
|
3752
|
+
extractErrorDetails(error) {
|
|
3753
|
+
return error.details;
|
|
3754
|
+
}
|
|
3196
3755
|
};
|
|
3197
3756
|
AIAgentNode = __decorate([
|
|
3198
3757
|
node({ packageName: "@codemation/core-nodes" }),
|
|
@@ -3201,12 +3760,14 @@ AIAgentNode = __decorate([
|
|
|
3201
3760
|
__decorateParam(2, inject(NodeBackedToolRuntime)),
|
|
3202
3761
|
__decorateParam(3, inject(AIAgentExecutionHelpersFactory)),
|
|
3203
3762
|
__decorateParam(4, inject(AgentStructuredOutputRunner)),
|
|
3763
|
+
__decorateParam(5, inject(AgentToolExecutionCoordinator)),
|
|
3204
3764
|
__decorateMetadata("design:paramtypes", [
|
|
3205
3765
|
Object,
|
|
3206
3766
|
Object,
|
|
3207
3767
|
typeof (_ref = typeof NodeBackedToolRuntime !== "undefined" && NodeBackedToolRuntime) === "function" ? _ref : Object,
|
|
3208
3768
|
typeof (_ref2 = typeof AIAgentExecutionHelpersFactory !== "undefined" && AIAgentExecutionHelpersFactory) === "function" ? _ref2 : Object,
|
|
3209
|
-
typeof (_ref3 = typeof AgentStructuredOutputRunner !== "undefined" && AgentStructuredOutputRunner) === "function" ? _ref3 : Object
|
|
3769
|
+
typeof (_ref3 = typeof AgentStructuredOutputRunner !== "undefined" && AgentStructuredOutputRunner) === "function" ? _ref3 : Object,
|
|
3770
|
+
typeof (_ref4 = typeof AgentToolExecutionCoordinator !== "undefined" && AgentToolExecutionCoordinator) === "function" ? _ref4 : Object
|
|
3210
3771
|
])
|
|
3211
3772
|
], AIAgentNode);
|
|
3212
3773
|
|
|
@@ -4263,5 +4824,5 @@ var ConnectionCredentialNodeConfigFactory = class {
|
|
|
4263
4824
|
};
|
|
4264
4825
|
|
|
4265
4826
|
//#endregion
|
|
4266
|
-
export { AIAgent, AIAgentConnectionWorkflowExpander, AIAgentExecutionHelpersFactory, AIAgentNode, AgentItemPortMap, AgentMessageFactory, AgentOutputFactory, AgentStructuredOutputRepairPromptFactory, AgentStructuredOutputRunner, AgentToolCallPortMap, Aggregate, AggregateNode, Callback, CallbackNode, CallbackResultNormalizer, ConnectionCredentialExecutionContextFactory, ConnectionCredentialNode, ConnectionCredentialNodeConfig, ConnectionCredentialNodeConfigFactory, Filter, FilterNode, HttpRequest, HttpRequestNode, If, IfNode, ManualTrigger, ManualTriggerNode, MapData, MapDataNode, Merge, MergeNode, NoOp, NoOpNode, OpenAIChatModelConfig, OpenAIChatModelFactory, OpenAIStructuredOutputMethodFactory, OpenAiChatModelPresets, Split, SplitNode, SubWorkflow, SubWorkflowNode, Switch, SwitchNode, Wait, WaitDuration, WaitNode, WebhookRespondNowAndContinueError, WebhookRespondNowError, WebhookTrigger, WebhookTriggerNode, WorkflowAuthoringBuilder, WorkflowBranchBuilder, WorkflowChain, createWorkflowBuilder, openAiChatModelPresets, registerCoreNodes, workflow };
|
|
4827
|
+
export { AIAgent, AIAgentConnectionWorkflowExpander, AIAgentExecutionHelpersFactory, AIAgentNode, AgentItemPortMap, AgentMessageFactory, AgentOutputFactory, AgentStructuredOutputRepairPromptFactory, AgentStructuredOutputRunner, AgentToolCallPortMap, AgentToolErrorClassifier, AgentToolExecutionCoordinator, AgentToolRepairExhaustedError, AgentToolRepairPolicy, Aggregate, AggregateNode, Callback, CallbackNode, CallbackResultNormalizer, ConnectionCredentialExecutionContextFactory, ConnectionCredentialNode, ConnectionCredentialNodeConfig, ConnectionCredentialNodeConfigFactory, Filter, FilterNode, HttpRequest, HttpRequestNode, If, IfNode, ManualTrigger, ManualTriggerNode, MapData, MapDataNode, Merge, MergeNode, NoOp, NoOpNode, OpenAIChatModelConfig, OpenAIChatModelFactory, OpenAIStructuredOutputMethodFactory, OpenAiChatModelPresets, Split, SplitNode, SubWorkflow, SubWorkflowNode, Switch, SwitchNode, Wait, WaitDuration, WaitNode, WebhookRespondNowAndContinueError, WebhookRespondNowError, WebhookTrigger, WebhookTriggerNode, WorkflowAuthoringBuilder, WorkflowBranchBuilder, WorkflowChain, createWorkflowBuilder, openAiChatModelPresets, registerCoreNodes, workflow };
|
|
4267
4828
|
//# sourceMappingURL=index.js.map
|