@flutchai/flutch-sdk 0.1.8 → 0.1.10
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/dist/index.cjs +336 -285
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -28
- package/dist/index.d.ts +25 -28
- package/dist/index.js +336 -285
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -15,6 +15,7 @@ var LangGraph = require('@langchain/langgraph');
|
|
|
15
15
|
var tools = require('@langchain/core/tools');
|
|
16
16
|
var zod = require('zod');
|
|
17
17
|
var axios2 = require('axios');
|
|
18
|
+
var manager = require('@langchain/core/callbacks/manager');
|
|
18
19
|
var openai = require('@langchain/openai');
|
|
19
20
|
var azureOpenai = require('@langchain/azure-openai');
|
|
20
21
|
var anthropic = require('@langchain/anthropic');
|
|
@@ -3899,7 +3900,6 @@ var AttachmentType = /* @__PURE__ */ ((AttachmentType2) => {
|
|
|
3899
3900
|
var StreamChannel = /* @__PURE__ */ ((StreamChannel2) => {
|
|
3900
3901
|
StreamChannel2["TEXT"] = "text";
|
|
3901
3902
|
StreamChannel2["PROCESSING"] = "processing";
|
|
3902
|
-
StreamChannel2["TOOLS"] = "tools";
|
|
3903
3903
|
return StreamChannel2;
|
|
3904
3904
|
})(StreamChannel || {});
|
|
3905
3905
|
|
|
@@ -4330,7 +4330,7 @@ function sanitizeTraceData(value, depth = 0, seen = /* @__PURE__ */ new WeakSet(
|
|
|
4330
4330
|
return null;
|
|
4331
4331
|
}
|
|
4332
4332
|
if (typeof value === "string") {
|
|
4333
|
-
return value
|
|
4333
|
+
return value;
|
|
4334
4334
|
}
|
|
4335
4335
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
4336
4336
|
return value;
|
|
@@ -4442,15 +4442,15 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4442
4442
|
*/
|
|
4443
4443
|
createAccumulator() {
|
|
4444
4444
|
return {
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4445
|
+
channels: /* @__PURE__ */ new Map([
|
|
4446
|
+
["text" /* TEXT */, { contentChain: [], currentBlock: null }],
|
|
4447
|
+
["processing" /* PROCESSING */, { contentChain: [], currentBlock: null }]
|
|
4448
|
+
]),
|
|
4449
|
+
attachments: [],
|
|
4450
|
+
metadata: {},
|
|
4449
4451
|
traceEvents: [],
|
|
4450
4452
|
traceStartedAt: null,
|
|
4451
|
-
traceCompletedAt: null
|
|
4452
|
-
currentReasoningSteps: [],
|
|
4453
|
-
currentToolUse: null
|
|
4453
|
+
traceCompletedAt: null
|
|
4454
4454
|
};
|
|
4455
4455
|
}
|
|
4456
4456
|
/**
|
|
@@ -4478,10 +4478,88 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4478
4478
|
}
|
|
4479
4479
|
return [];
|
|
4480
4480
|
}
|
|
4481
|
+
/**
|
|
4482
|
+
* Send delta to UI (unified format)
|
|
4483
|
+
*/
|
|
4484
|
+
sendDelta(channel, delta, onPartial) {
|
|
4485
|
+
if (!onPartial) return;
|
|
4486
|
+
onPartial(
|
|
4487
|
+
JSON.stringify({
|
|
4488
|
+
channel,
|
|
4489
|
+
delta
|
|
4490
|
+
})
|
|
4491
|
+
);
|
|
4492
|
+
}
|
|
4493
|
+
/**
|
|
4494
|
+
* Process content stream blocks (universal for all channels)
|
|
4495
|
+
*/
|
|
4496
|
+
processContentStream(acc, channel, blocks, onPartial) {
|
|
4497
|
+
const state = acc.channels.get(channel);
|
|
4498
|
+
for (const block of blocks) {
|
|
4499
|
+
if (block.type === "tool_use" || block.type === "tool_call") {
|
|
4500
|
+
if (state.currentBlock) {
|
|
4501
|
+
state.contentChain.push(state.currentBlock);
|
|
4502
|
+
}
|
|
4503
|
+
state.currentBlock = {
|
|
4504
|
+
index: state.contentChain.length,
|
|
4505
|
+
type: "tool_use",
|
|
4506
|
+
name: block.name,
|
|
4507
|
+
id: block.id,
|
|
4508
|
+
input: block.input || "",
|
|
4509
|
+
output: ""
|
|
4510
|
+
};
|
|
4511
|
+
this.sendDelta(
|
|
4512
|
+
channel,
|
|
4513
|
+
{
|
|
4514
|
+
type: "step_started",
|
|
4515
|
+
step: state.currentBlock
|
|
4516
|
+
},
|
|
4517
|
+
onPartial
|
|
4518
|
+
);
|
|
4519
|
+
} else if (block.type === "input_json_delta") {
|
|
4520
|
+
if (state.currentBlock && state.currentBlock.type === "tool_use") {
|
|
4521
|
+
const chunk = block.input || "";
|
|
4522
|
+
state.currentBlock.input += chunk;
|
|
4523
|
+
this.sendDelta(
|
|
4524
|
+
channel,
|
|
4525
|
+
{
|
|
4526
|
+
type: "tool_input_chunk",
|
|
4527
|
+
stepId: state.currentBlock.id,
|
|
4528
|
+
chunk
|
|
4529
|
+
},
|
|
4530
|
+
onPartial
|
|
4531
|
+
);
|
|
4532
|
+
}
|
|
4533
|
+
} else if (block.type === "text") {
|
|
4534
|
+
const textChunk = block.text || "";
|
|
4535
|
+
if (state.currentBlock && state.currentBlock.type === "text") {
|
|
4536
|
+
state.currentBlock.text = (state.currentBlock.text || "") + textChunk;
|
|
4537
|
+
} else {
|
|
4538
|
+
if (state.currentBlock) {
|
|
4539
|
+
state.contentChain.push(state.currentBlock);
|
|
4540
|
+
}
|
|
4541
|
+
state.currentBlock = {
|
|
4542
|
+
index: state.contentChain.length,
|
|
4543
|
+
type: "text",
|
|
4544
|
+
text: textChunk
|
|
4545
|
+
};
|
|
4546
|
+
}
|
|
4547
|
+
this.sendDelta(
|
|
4548
|
+
channel,
|
|
4549
|
+
{
|
|
4550
|
+
type: "text_chunk",
|
|
4551
|
+
text: textChunk
|
|
4552
|
+
},
|
|
4553
|
+
onPartial
|
|
4554
|
+
);
|
|
4555
|
+
}
|
|
4556
|
+
}
|
|
4557
|
+
}
|
|
4481
4558
|
/**
|
|
4482
4559
|
* Groups tool_use and input_json_delta into proper structure
|
|
4483
4560
|
* tool_use.input → output (tool execution result)
|
|
4484
4561
|
* input_json_delta.input → output (tool execution result, accumulated)
|
|
4562
|
+
* @deprecated This method is for legacy fallback only
|
|
4485
4563
|
*/
|
|
4486
4564
|
mapReasoningSteps(rawSteps) {
|
|
4487
4565
|
const steps = [];
|
|
@@ -4530,223 +4608,96 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4530
4608
|
*/
|
|
4531
4609
|
processEvent(acc, event, onPartial) {
|
|
4532
4610
|
this.captureTraceEvent(acc, event);
|
|
4533
|
-
if (event.event === "on_chat_model_stream" && event.
|
|
4534
|
-
const
|
|
4535
|
-
const blocks = this.normalizeContentBlocks(chunk);
|
|
4536
|
-
|
|
4537
|
-
onPartial(JSON.stringify({ text: blocks }));
|
|
4538
|
-
}
|
|
4539
|
-
const textOnly = blocks.filter((block) => block?.type === "text").map((block) => block.text || "").join("");
|
|
4540
|
-
if (textOnly) {
|
|
4541
|
-
acc.streamedText += textOnly;
|
|
4542
|
-
}
|
|
4611
|
+
if (event.event === "on_chat_model_stream" && event.data?.chunk?.content) {
|
|
4612
|
+
const channel = event.metadata?.stream_channel ?? "text" /* TEXT */;
|
|
4613
|
+
const blocks = this.normalizeContentBlocks(event.data.chunk.content);
|
|
4614
|
+
this.processContentStream(acc, channel, blocks, onPartial);
|
|
4543
4615
|
return;
|
|
4544
4616
|
}
|
|
4545
|
-
if (event.event === "
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
}
|
|
4553
|
-
acc.currentToolUse = {
|
|
4554
|
-
index: acc.currentReasoningSteps.length,
|
|
4555
|
-
type: "tool_use",
|
|
4556
|
-
name: block.name,
|
|
4557
|
-
id: block.id,
|
|
4558
|
-
input: block.input || "",
|
|
4559
|
-
output: ""
|
|
4560
|
-
};
|
|
4561
|
-
if (onPartial) {
|
|
4562
|
-
onPartial(
|
|
4563
|
-
JSON.stringify({
|
|
4564
|
-
processing_delta: {
|
|
4565
|
-
type: "step_started",
|
|
4566
|
-
step: acc.currentToolUse
|
|
4567
|
-
}
|
|
4568
|
-
})
|
|
4569
|
-
);
|
|
4570
|
-
}
|
|
4571
|
-
} else if (block.type === "input_json_delta") {
|
|
4572
|
-
if (acc.currentToolUse && onPartial) {
|
|
4573
|
-
const chunk2 = block.input || "";
|
|
4574
|
-
acc.currentToolUse.output += chunk2;
|
|
4575
|
-
onPartial(
|
|
4576
|
-
JSON.stringify({
|
|
4577
|
-
processing_delta: {
|
|
4578
|
-
type: "output_chunk",
|
|
4579
|
-
stepId: acc.currentToolUse.id,
|
|
4580
|
-
chunk: chunk2
|
|
4581
|
-
}
|
|
4582
|
-
})
|
|
4583
|
-
);
|
|
4584
|
-
}
|
|
4585
|
-
}
|
|
4586
|
-
}
|
|
4617
|
+
if (event.event === "on_tool_start") {
|
|
4618
|
+
this.logger.log("\u{1F527} Tool execution started", {
|
|
4619
|
+
toolName: event.name,
|
|
4620
|
+
input: event.data?.input,
|
|
4621
|
+
runId: event.run_id,
|
|
4622
|
+
metadata: event.metadata
|
|
4623
|
+
});
|
|
4587
4624
|
return;
|
|
4588
4625
|
}
|
|
4589
|
-
if (event.event === "
|
|
4590
|
-
const
|
|
4591
|
-
const
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
const
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
totalTokens: usageMetadata.total_tokens || 0,
|
|
4599
|
-
timestamp: Date.now(),
|
|
4600
|
-
nodeName: event.metadata?.langgraph_node || event.name
|
|
4601
|
-
};
|
|
4602
|
-
acc.llmCalls.push(llmCall);
|
|
4603
|
-
this.logger.log("\u2705 LLM call recorded", {
|
|
4604
|
-
modelId,
|
|
4605
|
-
tokens: llmCall.totalTokens,
|
|
4606
|
-
nodeName: llmCall.nodeName,
|
|
4607
|
-
totalRecorded: acc.llmCalls.length
|
|
4608
|
-
});
|
|
4609
|
-
} else {
|
|
4610
|
-
this.logger.warn(
|
|
4611
|
-
"\u26A0\uFE0F Missing usage metadata or modelId in on_chat_model_end",
|
|
4626
|
+
if (event.event === "on_tool_end") {
|
|
4627
|
+
const channel = event.metadata?.stream_channel ?? "text" /* TEXT */;
|
|
4628
|
+
const state = acc.channels.get(channel);
|
|
4629
|
+
if (state?.currentBlock && state.currentBlock.type === "tool_use") {
|
|
4630
|
+
const output = event.data?.output;
|
|
4631
|
+
const outputString = typeof output === "string" ? output : JSON.stringify(output, null, 2);
|
|
4632
|
+
state.currentBlock.output = outputString;
|
|
4633
|
+
this.sendDelta(
|
|
4634
|
+
channel,
|
|
4612
4635
|
{
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
}
|
|
4636
|
+
type: "tool_output_chunk",
|
|
4637
|
+
stepId: state.currentBlock.id,
|
|
4638
|
+
chunk: outputString
|
|
4639
|
+
},
|
|
4640
|
+
onPartial
|
|
4619
4641
|
);
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
}
|
|
4626
|
-
if (acc.currentReasoningSteps.length > 0) {
|
|
4627
|
-
acc.reasoningChains.push({
|
|
4628
|
-
steps: acc.currentReasoningSteps,
|
|
4629
|
-
isComplete: true
|
|
4630
|
-
});
|
|
4631
|
-
if (onPartial) {
|
|
4632
|
-
onPartial(
|
|
4633
|
-
JSON.stringify({
|
|
4634
|
-
processing_delta: {
|
|
4635
|
-
type: "chain_completed"
|
|
4636
|
-
}
|
|
4637
|
-
})
|
|
4638
|
-
);
|
|
4639
|
-
}
|
|
4640
|
-
acc.currentReasoningSteps = [];
|
|
4641
|
-
} else {
|
|
4642
|
-
const stepsRaw = output?.content || // AIMessageChunk object (direct)
|
|
4643
|
-
output?.kwargs?.content || // Serialized LangChain format
|
|
4644
|
-
event.data?.chunk?.content || // Older version
|
|
4645
|
-
[];
|
|
4646
|
-
let steps;
|
|
4647
|
-
if (Array.isArray(stepsRaw)) {
|
|
4648
|
-
steps = this.mapReasoningSteps(stepsRaw);
|
|
4649
|
-
} else if (typeof stepsRaw === "string" && stepsRaw.trim().length > 0) {
|
|
4650
|
-
steps = [
|
|
4651
|
-
{
|
|
4652
|
-
index: 0,
|
|
4653
|
-
type: "text",
|
|
4654
|
-
text: stepsRaw.trim()
|
|
4655
|
-
}
|
|
4656
|
-
];
|
|
4657
|
-
} else {
|
|
4658
|
-
steps = [];
|
|
4659
|
-
}
|
|
4660
|
-
if (steps.length > 0) {
|
|
4661
|
-
acc.reasoningChains.push({
|
|
4662
|
-
steps,
|
|
4663
|
-
isComplete: true
|
|
4664
|
-
});
|
|
4665
|
-
if (onPartial) {
|
|
4666
|
-
onPartial(
|
|
4667
|
-
JSON.stringify({
|
|
4668
|
-
processing_delta: {
|
|
4669
|
-
type: "chain_completed"
|
|
4670
|
-
}
|
|
4671
|
-
})
|
|
4672
|
-
);
|
|
4673
|
-
}
|
|
4674
|
-
}
|
|
4675
|
-
}
|
|
4642
|
+
this.logger.log("\u2705 Tool execution completed", {
|
|
4643
|
+
toolName: event.name,
|
|
4644
|
+
outputPreview: outputString.substring(0, 200) + (outputString.length > 200 ? "..." : ""),
|
|
4645
|
+
runId: event.run_id
|
|
4646
|
+
});
|
|
4676
4647
|
}
|
|
4677
4648
|
return;
|
|
4678
4649
|
}
|
|
4679
|
-
if (event.event === "
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
generation
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4650
|
+
if (event.event === "on_tool_error") {
|
|
4651
|
+
this.logger.error("\u274C Tool execution failed", {
|
|
4652
|
+
toolName: event.name,
|
|
4653
|
+
error: event.data?.error,
|
|
4654
|
+
runId: event.run_id
|
|
4655
|
+
});
|
|
4656
|
+
return;
|
|
4657
|
+
}
|
|
4658
|
+
if (event.event === "on_chat_model_end") {
|
|
4659
|
+
this.logger.debug("\u2705 LLM call completed", {
|
|
4660
|
+
nodeName: event.metadata?.langgraph_node || event.name,
|
|
4661
|
+
channel: event.metadata?.stream_channel
|
|
4662
|
+
});
|
|
4663
|
+
return;
|
|
4664
|
+
}
|
|
4665
|
+
if (event.event === "on_chain_end") {
|
|
4666
|
+
const channel = event.metadata?.stream_channel ?? "text" /* TEXT */;
|
|
4667
|
+
if (channel === "text" /* TEXT */) {
|
|
4668
|
+
const output = event.data.output;
|
|
4669
|
+
if (output?.answer) {
|
|
4670
|
+
acc.attachments = output.answer.attachments || [];
|
|
4671
|
+
acc.metadata = output.answer.metadata || {};
|
|
4672
|
+
} else if (output?.generation) {
|
|
4673
|
+
acc.attachments = output.generation.attachments || [];
|
|
4674
|
+
acc.metadata = output.generation.metadata || {};
|
|
4675
|
+
} else if (output) {
|
|
4676
|
+
acc.attachments = output.attachments || [];
|
|
4677
|
+
acc.metadata = output.metadata || {};
|
|
4678
|
+
}
|
|
4706
4679
|
}
|
|
4707
|
-
acc.generation = generation;
|
|
4708
4680
|
return;
|
|
4709
4681
|
}
|
|
4710
4682
|
}
|
|
4711
4683
|
/**
|
|
4712
4684
|
* Build final result from accumulator
|
|
4713
|
-
*
|
|
4714
|
-
* Returns content and metrics separately (metrics should NOT be stored in message.metadata)
|
|
4685
|
+
* Returns unified content chains from all channels
|
|
4715
4686
|
*/
|
|
4716
4687
|
getResult(acc) {
|
|
4717
|
-
const
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
(
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
llmCallsCount: acc.llmCalls.length,
|
|
4731
|
-
totalPromptTokens,
|
|
4732
|
-
totalCompletionTokens,
|
|
4733
|
-
totalTokens,
|
|
4734
|
-
modelIds: acc.llmCalls.map((c) => c.modelId)
|
|
4735
|
-
});
|
|
4736
|
-
const metrics = acc.llmCalls.length > 0 ? {
|
|
4737
|
-
modelCalls: acc.llmCalls.map((call) => ({
|
|
4738
|
-
nodeName: call.nodeName || "unknown",
|
|
4739
|
-
timestamp: call.timestamp,
|
|
4740
|
-
modelId: call.modelId,
|
|
4741
|
-
promptTokens: call.promptTokens,
|
|
4742
|
-
completionTokens: call.completionTokens,
|
|
4743
|
-
totalTokens: call.totalTokens,
|
|
4744
|
-
latencyMs: 0
|
|
4745
|
-
// Not calculated from events
|
|
4746
|
-
})),
|
|
4747
|
-
apiCalls: []
|
|
4748
|
-
// TODO: Add API calls tracking (rerank, embeddings) via custom events
|
|
4749
|
-
} : null;
|
|
4688
|
+
const allChains = [];
|
|
4689
|
+
for (const [channel, state] of acc.channels.entries()) {
|
|
4690
|
+
if (state.currentBlock) {
|
|
4691
|
+
state.contentChain.push(state.currentBlock);
|
|
4692
|
+
}
|
|
4693
|
+
if (state.contentChain.length > 0) {
|
|
4694
|
+
allChains.push({
|
|
4695
|
+
channel,
|
|
4696
|
+
steps: state.contentChain,
|
|
4697
|
+
isComplete: true
|
|
4698
|
+
});
|
|
4699
|
+
}
|
|
4700
|
+
}
|
|
4750
4701
|
const startedAt = acc.traceStartedAt ?? Date.now();
|
|
4751
4702
|
const completedAt = acc.traceCompletedAt ?? startedAt;
|
|
4752
4703
|
const trace = acc.traceEvents.length > 0 ? {
|
|
@@ -4754,28 +4705,20 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4754
4705
|
startedAt,
|
|
4755
4706
|
completedAt,
|
|
4756
4707
|
durationMs: Math.max(0, completedAt - startedAt),
|
|
4757
|
-
totalEvents: acc.traceEvents.length
|
|
4758
|
-
totalModelCalls: acc.llmCalls.length
|
|
4708
|
+
totalEvents: acc.traceEvents.length
|
|
4759
4709
|
} : null;
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
firstEventSample: trace.events[0] ? JSON.stringify(trace.events[0]).substring(0, 150) : null,
|
|
4767
|
-
allEventsNull: trace.events.every((e) => e === null),
|
|
4768
|
-
someEventsNull: trace.events.some((e) => e === null)
|
|
4769
|
-
});
|
|
4770
|
-
}
|
|
4710
|
+
this.logger.log("\u{1F4CA} [EventProcessor] Final result assembled", {
|
|
4711
|
+
totalChains: allChains.length,
|
|
4712
|
+
textChains: allChains.filter((c) => c.channel === "text").length,
|
|
4713
|
+
processingChains: allChains.filter((c) => c.channel === "processing").length,
|
|
4714
|
+
totalSteps: allChains.reduce((sum, c) => sum + c.steps.length, 0)
|
|
4715
|
+
});
|
|
4771
4716
|
return {
|
|
4772
4717
|
content: {
|
|
4773
|
-
|
|
4774
|
-
attachments: acc.
|
|
4775
|
-
metadata: acc.
|
|
4776
|
-
reasoningChains: acc.reasoningChains.length > 0 ? acc.reasoningChains : void 0
|
|
4718
|
+
contentChains: allChains.length > 0 ? allChains : void 0,
|
|
4719
|
+
attachments: acc.attachments,
|
|
4720
|
+
metadata: acc.metadata
|
|
4777
4721
|
},
|
|
4778
|
-
metrics,
|
|
4779
4722
|
trace
|
|
4780
4723
|
};
|
|
4781
4724
|
}
|
|
@@ -4890,33 +4833,13 @@ exports.LangGraphEngine = class LangGraphEngine {
|
|
|
4890
4833
|
);
|
|
4891
4834
|
}
|
|
4892
4835
|
}
|
|
4893
|
-
const { content,
|
|
4836
|
+
const { content, trace } = this.eventProcessor.getResult(acc);
|
|
4894
4837
|
this.logger.debug("[STREAM-RESULT] Got result from EventProcessor", {
|
|
4895
4838
|
hasContent: !!content,
|
|
4896
|
-
hasMetrics: !!metrics,
|
|
4897
|
-
modelCallsCount: metrics?.modelCalls?.length || 0,
|
|
4898
|
-
apiCallsCount: metrics?.apiCalls?.length || 0,
|
|
4899
4839
|
hasContext: !!config.configurable?.context,
|
|
4900
4840
|
hasTrace: !!trace,
|
|
4901
4841
|
traceEvents: trace?.events?.length || 0
|
|
4902
4842
|
});
|
|
4903
|
-
if (metrics && metrics.modelCalls?.length > 0 && config.configurable?.context) {
|
|
4904
|
-
const context = config.configurable.context;
|
|
4905
|
-
await this.sendMetricsWebhook({
|
|
4906
|
-
messageId: context.messageId || "unknown",
|
|
4907
|
-
threadId: context.threadId || "unknown",
|
|
4908
|
-
userId: context.userId || "unknown",
|
|
4909
|
-
agentId: context.agentId || "unknown",
|
|
4910
|
-
companyId: context.companyId || "unknown",
|
|
4911
|
-
metrics
|
|
4912
|
-
});
|
|
4913
|
-
} else {
|
|
4914
|
-
this.logger.debug("[METRICS-WEBHOOK] Skipping webhook", {
|
|
4915
|
-
hasMetrics: !!metrics,
|
|
4916
|
-
modelCallsCount: metrics?.modelCalls?.length || 0,
|
|
4917
|
-
hasContext: !!config.configurable?.context
|
|
4918
|
-
});
|
|
4919
|
-
}
|
|
4920
4843
|
if (trace && trace.events.length > 0 && config.configurable?.context) {
|
|
4921
4844
|
const context = config.configurable.context;
|
|
4922
4845
|
this.logger.debug("[TRACE-WEBHOOK] Sending trace events batch", {
|
|
@@ -4933,7 +4856,6 @@ exports.LangGraphEngine = class LangGraphEngine {
|
|
|
4933
4856
|
companyId: context.companyId || "unknown",
|
|
4934
4857
|
events: trace.events,
|
|
4935
4858
|
totalEvents: trace.totalEvents,
|
|
4936
|
-
totalModelCalls: trace.totalModelCalls,
|
|
4937
4859
|
startedAt: trace.startedAt,
|
|
4938
4860
|
completedAt: trace.completedAt,
|
|
4939
4861
|
durationMs: trace.durationMs
|
|
@@ -5016,7 +4938,6 @@ exports.LangGraphEngine = class LangGraphEngine {
|
|
|
5016
4938
|
agentId: payload.agentId,
|
|
5017
4939
|
companyId: payload.companyId,
|
|
5018
4940
|
totalEvents: payload.totalEvents,
|
|
5019
|
-
totalModelCalls: payload.totalModelCalls,
|
|
5020
4941
|
startedAt: payload.startedAt,
|
|
5021
4942
|
completedAt: payload.completedAt,
|
|
5022
4943
|
durationMs: payload.durationMs,
|
|
@@ -5396,47 +5317,65 @@ var McpConverter = class _McpConverter {
|
|
|
5396
5317
|
mcpRuntimeUrl;
|
|
5397
5318
|
constructor(mcpRuntimeUrl = "http://localhost:3004") {
|
|
5398
5319
|
this.mcpRuntimeUrl = mcpRuntimeUrl;
|
|
5320
|
+
this.logger.log(
|
|
5321
|
+
`\u{1F527} McpConverter initialized with SDK version 0.1.8 (manual jsonSchemaToZod)`
|
|
5322
|
+
);
|
|
5399
5323
|
}
|
|
5400
5324
|
/**
|
|
5401
|
-
* Convert JSON Schema to
|
|
5325
|
+
* Convert JSON Schema to Zod schema manually
|
|
5326
|
+
* This creates a standard Zod schema that zodToJsonSchema can convert back properly
|
|
5402
5327
|
*/
|
|
5403
5328
|
jsonSchemaToZod(jsonSchema) {
|
|
5404
5329
|
if (!jsonSchema || typeof jsonSchema !== "object") {
|
|
5405
5330
|
return zod.z.any();
|
|
5406
5331
|
}
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5332
|
+
try {
|
|
5333
|
+
if (jsonSchema.type === "object" && jsonSchema.properties) {
|
|
5334
|
+
const shape = {};
|
|
5335
|
+
for (const [key, propSchema] of Object.entries(jsonSchema.properties)) {
|
|
5336
|
+
const prop = propSchema;
|
|
5337
|
+
let zodProp;
|
|
5338
|
+
switch (prop.type) {
|
|
5339
|
+
case "string":
|
|
5340
|
+
zodProp = zod.z.string();
|
|
5341
|
+
break;
|
|
5342
|
+
case "number":
|
|
5343
|
+
zodProp = zod.z.number();
|
|
5344
|
+
break;
|
|
5345
|
+
case "boolean":
|
|
5346
|
+
zodProp = zod.z.boolean();
|
|
5347
|
+
break;
|
|
5348
|
+
case "integer":
|
|
5349
|
+
zodProp = zod.z.number().int();
|
|
5350
|
+
break;
|
|
5351
|
+
case "array":
|
|
5352
|
+
zodProp = zod.z.array(zod.z.any());
|
|
5353
|
+
break;
|
|
5354
|
+
case "object":
|
|
5355
|
+
zodProp = zod.z.record(zod.z.any());
|
|
5356
|
+
break;
|
|
5357
|
+
default:
|
|
5358
|
+
zodProp = zod.z.any();
|
|
5359
|
+
}
|
|
5360
|
+
if (prop.description) {
|
|
5361
|
+
zodProp = zodProp.describe(prop.description);
|
|
5362
|
+
}
|
|
5363
|
+
if (!jsonSchema.required?.includes(key)) {
|
|
5364
|
+
zodProp = zodProp.optional();
|
|
5365
|
+
}
|
|
5366
|
+
shape[key] = zodProp;
|
|
5367
|
+
}
|
|
5368
|
+
return zod.z.object(shape);
|
|
5369
|
+
}
|
|
5370
|
+
this.logger.warn(
|
|
5371
|
+
`Unsupported JSON Schema structure, falling back to z.any()`
|
|
5372
|
+
);
|
|
5373
|
+
return zod.z.any();
|
|
5374
|
+
} catch (error) {
|
|
5375
|
+
this.logger.warn(
|
|
5376
|
+
`Failed to convert JSON Schema, falling back to z.any(): ${error}`
|
|
5377
|
+
);
|
|
5378
|
+
return zod.z.any();
|
|
5440
5379
|
}
|
|
5441
5380
|
}
|
|
5442
5381
|
/**
|
|
@@ -5445,6 +5384,27 @@ var McpConverter = class _McpConverter {
|
|
|
5445
5384
|
convertTool(mcpTool) {
|
|
5446
5385
|
const logger2 = this.logger;
|
|
5447
5386
|
const mcpRuntimeUrl = this.mcpRuntimeUrl;
|
|
5387
|
+
let enhancedDescription = mcpTool.description;
|
|
5388
|
+
if (mcpTool.inputSchema?.properties) {
|
|
5389
|
+
const paramDescriptions = [];
|
|
5390
|
+
for (const [key, propSchema] of Object.entries(
|
|
5391
|
+
mcpTool.inputSchema.properties
|
|
5392
|
+
)) {
|
|
5393
|
+
const prop = propSchema;
|
|
5394
|
+
if (prop.description) {
|
|
5395
|
+
const isRequired = mcpTool.inputSchema.required?.includes(key);
|
|
5396
|
+
paramDescriptions.push(
|
|
5397
|
+
`- ${key}${isRequired ? " (required)" : ""}: ${prop.description}`
|
|
5398
|
+
);
|
|
5399
|
+
}
|
|
5400
|
+
}
|
|
5401
|
+
if (paramDescriptions.length > 0) {
|
|
5402
|
+
enhancedDescription = `${mcpTool.description}
|
|
5403
|
+
|
|
5404
|
+
Parameters:
|
|
5405
|
+
${paramDescriptions.join("\n")}`;
|
|
5406
|
+
}
|
|
5407
|
+
}
|
|
5448
5408
|
const schema = this.jsonSchemaToZod(mcpTool.inputSchema);
|
|
5449
5409
|
logger2.debug(
|
|
5450
5410
|
`\u{1F527} [${mcpTool.name}] Original schema:`,
|
|
@@ -5453,9 +5413,48 @@ var McpConverter = class _McpConverter {
|
|
|
5453
5413
|
logger2.debug(
|
|
5454
5414
|
`\u{1F527} [${mcpTool.name}] Using schema type: ${schema?._def?.typeName ?? "unknown"}`
|
|
5455
5415
|
);
|
|
5416
|
+
if (schema?._def?.shape && typeof schema._def.shape === "function") {
|
|
5417
|
+
try {
|
|
5418
|
+
const shape = schema._def.shape();
|
|
5419
|
+
logger2.debug(
|
|
5420
|
+
`\u{1F527} [${mcpTool.name}] Converted Zod schema shape:`,
|
|
5421
|
+
JSON.stringify(
|
|
5422
|
+
Object.entries(shape).reduce(
|
|
5423
|
+
(acc, [key, val]) => {
|
|
5424
|
+
acc[key] = {
|
|
5425
|
+
type: val?._def?.typeName,
|
|
5426
|
+
description: val?._def?.description,
|
|
5427
|
+
optional: val?._def?.typeName === "ZodOptional"
|
|
5428
|
+
};
|
|
5429
|
+
return acc;
|
|
5430
|
+
},
|
|
5431
|
+
{}
|
|
5432
|
+
),
|
|
5433
|
+
null,
|
|
5434
|
+
2
|
|
5435
|
+
)
|
|
5436
|
+
);
|
|
5437
|
+
} catch (error) {
|
|
5438
|
+
logger2.debug(
|
|
5439
|
+
`\u{1F527} [${mcpTool.name}] Could not extract Zod schema shape: ${error}`
|
|
5440
|
+
);
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5443
|
+
try {
|
|
5444
|
+
const { zodToJsonSchema } = __require("zod-to-json-schema");
|
|
5445
|
+
const convertedJsonSchema = zodToJsonSchema(schema);
|
|
5446
|
+
logger2.warn(
|
|
5447
|
+
`\u{1F527} [${mcpTool.name}] JSON Schema that LangChain will use:`,
|
|
5448
|
+
JSON.stringify(convertedJsonSchema, null, 2)
|
|
5449
|
+
);
|
|
5450
|
+
} catch (error) {
|
|
5451
|
+
logger2.warn(
|
|
5452
|
+
`\u{1F527} [${mcpTool.name}] Could not convert Zod to JSON Schema: ${error}`
|
|
5453
|
+
);
|
|
5454
|
+
}
|
|
5456
5455
|
return new tools.DynamicStructuredTool({
|
|
5457
5456
|
name: mcpTool.name,
|
|
5458
|
-
description:
|
|
5457
|
+
description: enhancedDescription,
|
|
5459
5458
|
schema,
|
|
5460
5459
|
func: async (input) => {
|
|
5461
5460
|
logger2.log(`\u{1F527} [${mcpTool.name}] LLM INPUT: ${JSON.stringify(input)}`);
|
|
@@ -5772,6 +5771,58 @@ exports.McpRuntimeHttpClient = class McpRuntimeHttpClient {
|
|
|
5772
5771
|
return false;
|
|
5773
5772
|
}
|
|
5774
5773
|
}
|
|
5774
|
+
/**
|
|
5775
|
+
* Execute tool with LangChain event emission
|
|
5776
|
+
* @param toolCallId - Tool call ID from LLM
|
|
5777
|
+
* @param toolName - Tool name
|
|
5778
|
+
* @param enrichedArgs - Merged arguments (toolConfig + LLM args)
|
|
5779
|
+
* @param executionContext - Execution context (userId, agentId, etc.)
|
|
5780
|
+
* @param config - RunnableConfig with callbacks
|
|
5781
|
+
* @returns Tool execution result with content
|
|
5782
|
+
*/
|
|
5783
|
+
async executeToolWithEvents(toolCallId, toolName, enrichedArgs, executionContext, config) {
|
|
5784
|
+
const parsedConfig = manager.parseCallbackConfigArg(config);
|
|
5785
|
+
const callbackManager = manager.CallbackManager.configure(parsedConfig.callbacks);
|
|
5786
|
+
let runManager;
|
|
5787
|
+
try {
|
|
5788
|
+
runManager = await callbackManager?.handleToolStart(
|
|
5789
|
+
{
|
|
5790
|
+
name: toolName,
|
|
5791
|
+
lc: 1,
|
|
5792
|
+
type: "not_implemented",
|
|
5793
|
+
id: ["langchain", "tools", "mcp", toolName]
|
|
5794
|
+
},
|
|
5795
|
+
JSON.stringify(enrichedArgs),
|
|
5796
|
+
parsedConfig.runId,
|
|
5797
|
+
void 0,
|
|
5798
|
+
parsedConfig.tags,
|
|
5799
|
+
parsedConfig.metadata,
|
|
5800
|
+
toolName
|
|
5801
|
+
);
|
|
5802
|
+
const result = await this.executeTool(
|
|
5803
|
+
toolName,
|
|
5804
|
+
enrichedArgs,
|
|
5805
|
+
executionContext
|
|
5806
|
+
);
|
|
5807
|
+
const content = result.success ? JSON.stringify(result) : result.error || JSON.stringify(result);
|
|
5808
|
+
await runManager?.handleToolEnd(content);
|
|
5809
|
+
return {
|
|
5810
|
+
content,
|
|
5811
|
+
success: result.success
|
|
5812
|
+
};
|
|
5813
|
+
} catch (error) {
|
|
5814
|
+
this.logger.error(`Error executing tool ${toolName}:`, error);
|
|
5815
|
+
await runManager?.handleToolError(error);
|
|
5816
|
+
const errorContent = JSON.stringify({
|
|
5817
|
+
success: false,
|
|
5818
|
+
error: error instanceof Error ? error.message : "Tool execution failed"
|
|
5819
|
+
});
|
|
5820
|
+
return {
|
|
5821
|
+
content: errorContent,
|
|
5822
|
+
success: false
|
|
5823
|
+
};
|
|
5824
|
+
}
|
|
5825
|
+
}
|
|
5775
5826
|
};
|
|
5776
5827
|
exports.McpRuntimeHttpClient = __decorateClass([
|
|
5777
5828
|
common.Injectable()
|