@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.js
CHANGED
|
@@ -13,6 +13,7 @@ import * as LangGraph from '@langchain/langgraph';
|
|
|
13
13
|
import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
14
14
|
import { z } from 'zod';
|
|
15
15
|
import axios2 from 'axios';
|
|
16
|
+
import { parseCallbackConfigArg, CallbackManager } from '@langchain/core/callbacks/manager';
|
|
16
17
|
import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';
|
|
17
18
|
import { AzureChatOpenAI } from '@langchain/azure-openai';
|
|
18
19
|
import { ChatAnthropic } from '@langchain/anthropic';
|
|
@@ -3870,7 +3871,6 @@ var AttachmentType = /* @__PURE__ */ ((AttachmentType2) => {
|
|
|
3870
3871
|
var StreamChannel = /* @__PURE__ */ ((StreamChannel2) => {
|
|
3871
3872
|
StreamChannel2["TEXT"] = "text";
|
|
3872
3873
|
StreamChannel2["PROCESSING"] = "processing";
|
|
3873
|
-
StreamChannel2["TOOLS"] = "tools";
|
|
3874
3874
|
return StreamChannel2;
|
|
3875
3875
|
})(StreamChannel || {});
|
|
3876
3876
|
|
|
@@ -4301,7 +4301,7 @@ function sanitizeTraceData(value, depth = 0, seen = /* @__PURE__ */ new WeakSet(
|
|
|
4301
4301
|
return null;
|
|
4302
4302
|
}
|
|
4303
4303
|
if (typeof value === "string") {
|
|
4304
|
-
return value
|
|
4304
|
+
return value;
|
|
4305
4305
|
}
|
|
4306
4306
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
4307
4307
|
return value;
|
|
@@ -4413,15 +4413,15 @@ var EventProcessor = class {
|
|
|
4413
4413
|
*/
|
|
4414
4414
|
createAccumulator() {
|
|
4415
4415
|
return {
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4416
|
+
channels: /* @__PURE__ */ new Map([
|
|
4417
|
+
["text" /* TEXT */, { contentChain: [], currentBlock: null }],
|
|
4418
|
+
["processing" /* PROCESSING */, { contentChain: [], currentBlock: null }]
|
|
4419
|
+
]),
|
|
4420
|
+
attachments: [],
|
|
4421
|
+
metadata: {},
|
|
4420
4422
|
traceEvents: [],
|
|
4421
4423
|
traceStartedAt: null,
|
|
4422
|
-
traceCompletedAt: null
|
|
4423
|
-
currentReasoningSteps: [],
|
|
4424
|
-
currentToolUse: null
|
|
4424
|
+
traceCompletedAt: null
|
|
4425
4425
|
};
|
|
4426
4426
|
}
|
|
4427
4427
|
/**
|
|
@@ -4449,10 +4449,88 @@ var EventProcessor = class {
|
|
|
4449
4449
|
}
|
|
4450
4450
|
return [];
|
|
4451
4451
|
}
|
|
4452
|
+
/**
|
|
4453
|
+
* Send delta to UI (unified format)
|
|
4454
|
+
*/
|
|
4455
|
+
sendDelta(channel, delta, onPartial) {
|
|
4456
|
+
if (!onPartial) return;
|
|
4457
|
+
onPartial(
|
|
4458
|
+
JSON.stringify({
|
|
4459
|
+
channel,
|
|
4460
|
+
delta
|
|
4461
|
+
})
|
|
4462
|
+
);
|
|
4463
|
+
}
|
|
4464
|
+
/**
|
|
4465
|
+
* Process content stream blocks (universal for all channels)
|
|
4466
|
+
*/
|
|
4467
|
+
processContentStream(acc, channel, blocks, onPartial) {
|
|
4468
|
+
const state = acc.channels.get(channel);
|
|
4469
|
+
for (const block of blocks) {
|
|
4470
|
+
if (block.type === "tool_use" || block.type === "tool_call") {
|
|
4471
|
+
if (state.currentBlock) {
|
|
4472
|
+
state.contentChain.push(state.currentBlock);
|
|
4473
|
+
}
|
|
4474
|
+
state.currentBlock = {
|
|
4475
|
+
index: state.contentChain.length,
|
|
4476
|
+
type: "tool_use",
|
|
4477
|
+
name: block.name,
|
|
4478
|
+
id: block.id,
|
|
4479
|
+
input: block.input || "",
|
|
4480
|
+
output: ""
|
|
4481
|
+
};
|
|
4482
|
+
this.sendDelta(
|
|
4483
|
+
channel,
|
|
4484
|
+
{
|
|
4485
|
+
type: "step_started",
|
|
4486
|
+
step: state.currentBlock
|
|
4487
|
+
},
|
|
4488
|
+
onPartial
|
|
4489
|
+
);
|
|
4490
|
+
} else if (block.type === "input_json_delta") {
|
|
4491
|
+
if (state.currentBlock && state.currentBlock.type === "tool_use") {
|
|
4492
|
+
const chunk = block.input || "";
|
|
4493
|
+
state.currentBlock.input += chunk;
|
|
4494
|
+
this.sendDelta(
|
|
4495
|
+
channel,
|
|
4496
|
+
{
|
|
4497
|
+
type: "tool_input_chunk",
|
|
4498
|
+
stepId: state.currentBlock.id,
|
|
4499
|
+
chunk
|
|
4500
|
+
},
|
|
4501
|
+
onPartial
|
|
4502
|
+
);
|
|
4503
|
+
}
|
|
4504
|
+
} else if (block.type === "text") {
|
|
4505
|
+
const textChunk = block.text || "";
|
|
4506
|
+
if (state.currentBlock && state.currentBlock.type === "text") {
|
|
4507
|
+
state.currentBlock.text = (state.currentBlock.text || "") + textChunk;
|
|
4508
|
+
} else {
|
|
4509
|
+
if (state.currentBlock) {
|
|
4510
|
+
state.contentChain.push(state.currentBlock);
|
|
4511
|
+
}
|
|
4512
|
+
state.currentBlock = {
|
|
4513
|
+
index: state.contentChain.length,
|
|
4514
|
+
type: "text",
|
|
4515
|
+
text: textChunk
|
|
4516
|
+
};
|
|
4517
|
+
}
|
|
4518
|
+
this.sendDelta(
|
|
4519
|
+
channel,
|
|
4520
|
+
{
|
|
4521
|
+
type: "text_chunk",
|
|
4522
|
+
text: textChunk
|
|
4523
|
+
},
|
|
4524
|
+
onPartial
|
|
4525
|
+
);
|
|
4526
|
+
}
|
|
4527
|
+
}
|
|
4528
|
+
}
|
|
4452
4529
|
/**
|
|
4453
4530
|
* Groups tool_use and input_json_delta into proper structure
|
|
4454
4531
|
* tool_use.input → output (tool execution result)
|
|
4455
4532
|
* input_json_delta.input → output (tool execution result, accumulated)
|
|
4533
|
+
* @deprecated This method is for legacy fallback only
|
|
4456
4534
|
*/
|
|
4457
4535
|
mapReasoningSteps(rawSteps) {
|
|
4458
4536
|
const steps = [];
|
|
@@ -4501,223 +4579,96 @@ var EventProcessor = class {
|
|
|
4501
4579
|
*/
|
|
4502
4580
|
processEvent(acc, event, onPartial) {
|
|
4503
4581
|
this.captureTraceEvent(acc, event);
|
|
4504
|
-
if (event.event === "on_chat_model_stream" && event.
|
|
4505
|
-
const
|
|
4506
|
-
const blocks = this.normalizeContentBlocks(chunk);
|
|
4507
|
-
|
|
4508
|
-
onPartial(JSON.stringify({ text: blocks }));
|
|
4509
|
-
}
|
|
4510
|
-
const textOnly = blocks.filter((block) => block?.type === "text").map((block) => block.text || "").join("");
|
|
4511
|
-
if (textOnly) {
|
|
4512
|
-
acc.streamedText += textOnly;
|
|
4513
|
-
}
|
|
4582
|
+
if (event.event === "on_chat_model_stream" && event.data?.chunk?.content) {
|
|
4583
|
+
const channel = event.metadata?.stream_channel ?? "text" /* TEXT */;
|
|
4584
|
+
const blocks = this.normalizeContentBlocks(event.data.chunk.content);
|
|
4585
|
+
this.processContentStream(acc, channel, blocks, onPartial);
|
|
4514
4586
|
return;
|
|
4515
4587
|
}
|
|
4516
|
-
if (event.event === "
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
}
|
|
4524
|
-
acc.currentToolUse = {
|
|
4525
|
-
index: acc.currentReasoningSteps.length,
|
|
4526
|
-
type: "tool_use",
|
|
4527
|
-
name: block.name,
|
|
4528
|
-
id: block.id,
|
|
4529
|
-
input: block.input || "",
|
|
4530
|
-
output: ""
|
|
4531
|
-
};
|
|
4532
|
-
if (onPartial) {
|
|
4533
|
-
onPartial(
|
|
4534
|
-
JSON.stringify({
|
|
4535
|
-
processing_delta: {
|
|
4536
|
-
type: "step_started",
|
|
4537
|
-
step: acc.currentToolUse
|
|
4538
|
-
}
|
|
4539
|
-
})
|
|
4540
|
-
);
|
|
4541
|
-
}
|
|
4542
|
-
} else if (block.type === "input_json_delta") {
|
|
4543
|
-
if (acc.currentToolUse && onPartial) {
|
|
4544
|
-
const chunk2 = block.input || "";
|
|
4545
|
-
acc.currentToolUse.output += chunk2;
|
|
4546
|
-
onPartial(
|
|
4547
|
-
JSON.stringify({
|
|
4548
|
-
processing_delta: {
|
|
4549
|
-
type: "output_chunk",
|
|
4550
|
-
stepId: acc.currentToolUse.id,
|
|
4551
|
-
chunk: chunk2
|
|
4552
|
-
}
|
|
4553
|
-
})
|
|
4554
|
-
);
|
|
4555
|
-
}
|
|
4556
|
-
}
|
|
4557
|
-
}
|
|
4588
|
+
if (event.event === "on_tool_start") {
|
|
4589
|
+
this.logger.log("\u{1F527} Tool execution started", {
|
|
4590
|
+
toolName: event.name,
|
|
4591
|
+
input: event.data?.input,
|
|
4592
|
+
runId: event.run_id,
|
|
4593
|
+
metadata: event.metadata
|
|
4594
|
+
});
|
|
4558
4595
|
return;
|
|
4559
4596
|
}
|
|
4560
|
-
if (event.event === "
|
|
4561
|
-
const
|
|
4562
|
-
const
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
const
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
totalTokens: usageMetadata.total_tokens || 0,
|
|
4570
|
-
timestamp: Date.now(),
|
|
4571
|
-
nodeName: event.metadata?.langgraph_node || event.name
|
|
4572
|
-
};
|
|
4573
|
-
acc.llmCalls.push(llmCall);
|
|
4574
|
-
this.logger.log("\u2705 LLM call recorded", {
|
|
4575
|
-
modelId,
|
|
4576
|
-
tokens: llmCall.totalTokens,
|
|
4577
|
-
nodeName: llmCall.nodeName,
|
|
4578
|
-
totalRecorded: acc.llmCalls.length
|
|
4579
|
-
});
|
|
4580
|
-
} else {
|
|
4581
|
-
this.logger.warn(
|
|
4582
|
-
"\u26A0\uFE0F Missing usage metadata or modelId in on_chat_model_end",
|
|
4597
|
+
if (event.event === "on_tool_end") {
|
|
4598
|
+
const channel = event.metadata?.stream_channel ?? "text" /* TEXT */;
|
|
4599
|
+
const state = acc.channels.get(channel);
|
|
4600
|
+
if (state?.currentBlock && state.currentBlock.type === "tool_use") {
|
|
4601
|
+
const output = event.data?.output;
|
|
4602
|
+
const outputString = typeof output === "string" ? output : JSON.stringify(output, null, 2);
|
|
4603
|
+
state.currentBlock.output = outputString;
|
|
4604
|
+
this.sendDelta(
|
|
4605
|
+
channel,
|
|
4583
4606
|
{
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
}
|
|
4607
|
+
type: "tool_output_chunk",
|
|
4608
|
+
stepId: state.currentBlock.id,
|
|
4609
|
+
chunk: outputString
|
|
4610
|
+
},
|
|
4611
|
+
onPartial
|
|
4590
4612
|
);
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
}
|
|
4597
|
-
if (acc.currentReasoningSteps.length > 0) {
|
|
4598
|
-
acc.reasoningChains.push({
|
|
4599
|
-
steps: acc.currentReasoningSteps,
|
|
4600
|
-
isComplete: true
|
|
4601
|
-
});
|
|
4602
|
-
if (onPartial) {
|
|
4603
|
-
onPartial(
|
|
4604
|
-
JSON.stringify({
|
|
4605
|
-
processing_delta: {
|
|
4606
|
-
type: "chain_completed"
|
|
4607
|
-
}
|
|
4608
|
-
})
|
|
4609
|
-
);
|
|
4610
|
-
}
|
|
4611
|
-
acc.currentReasoningSteps = [];
|
|
4612
|
-
} else {
|
|
4613
|
-
const stepsRaw = output?.content || // AIMessageChunk object (direct)
|
|
4614
|
-
output?.kwargs?.content || // Serialized LangChain format
|
|
4615
|
-
event.data?.chunk?.content || // Older version
|
|
4616
|
-
[];
|
|
4617
|
-
let steps;
|
|
4618
|
-
if (Array.isArray(stepsRaw)) {
|
|
4619
|
-
steps = this.mapReasoningSteps(stepsRaw);
|
|
4620
|
-
} else if (typeof stepsRaw === "string" && stepsRaw.trim().length > 0) {
|
|
4621
|
-
steps = [
|
|
4622
|
-
{
|
|
4623
|
-
index: 0,
|
|
4624
|
-
type: "text",
|
|
4625
|
-
text: stepsRaw.trim()
|
|
4626
|
-
}
|
|
4627
|
-
];
|
|
4628
|
-
} else {
|
|
4629
|
-
steps = [];
|
|
4630
|
-
}
|
|
4631
|
-
if (steps.length > 0) {
|
|
4632
|
-
acc.reasoningChains.push({
|
|
4633
|
-
steps,
|
|
4634
|
-
isComplete: true
|
|
4635
|
-
});
|
|
4636
|
-
if (onPartial) {
|
|
4637
|
-
onPartial(
|
|
4638
|
-
JSON.stringify({
|
|
4639
|
-
processing_delta: {
|
|
4640
|
-
type: "chain_completed"
|
|
4641
|
-
}
|
|
4642
|
-
})
|
|
4643
|
-
);
|
|
4644
|
-
}
|
|
4645
|
-
}
|
|
4646
|
-
}
|
|
4613
|
+
this.logger.log("\u2705 Tool execution completed", {
|
|
4614
|
+
toolName: event.name,
|
|
4615
|
+
outputPreview: outputString.substring(0, 200) + (outputString.length > 200 ? "..." : ""),
|
|
4616
|
+
runId: event.run_id
|
|
4617
|
+
});
|
|
4647
4618
|
}
|
|
4648
4619
|
return;
|
|
4649
4620
|
}
|
|
4650
|
-
if (event.event === "
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
generation
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4621
|
+
if (event.event === "on_tool_error") {
|
|
4622
|
+
this.logger.error("\u274C Tool execution failed", {
|
|
4623
|
+
toolName: event.name,
|
|
4624
|
+
error: event.data?.error,
|
|
4625
|
+
runId: event.run_id
|
|
4626
|
+
});
|
|
4627
|
+
return;
|
|
4628
|
+
}
|
|
4629
|
+
if (event.event === "on_chat_model_end") {
|
|
4630
|
+
this.logger.debug("\u2705 LLM call completed", {
|
|
4631
|
+
nodeName: event.metadata?.langgraph_node || event.name,
|
|
4632
|
+
channel: event.metadata?.stream_channel
|
|
4633
|
+
});
|
|
4634
|
+
return;
|
|
4635
|
+
}
|
|
4636
|
+
if (event.event === "on_chain_end") {
|
|
4637
|
+
const channel = event.metadata?.stream_channel ?? "text" /* TEXT */;
|
|
4638
|
+
if (channel === "text" /* TEXT */) {
|
|
4639
|
+
const output = event.data.output;
|
|
4640
|
+
if (output?.answer) {
|
|
4641
|
+
acc.attachments = output.answer.attachments || [];
|
|
4642
|
+
acc.metadata = output.answer.metadata || {};
|
|
4643
|
+
} else if (output?.generation) {
|
|
4644
|
+
acc.attachments = output.generation.attachments || [];
|
|
4645
|
+
acc.metadata = output.generation.metadata || {};
|
|
4646
|
+
} else if (output) {
|
|
4647
|
+
acc.attachments = output.attachments || [];
|
|
4648
|
+
acc.metadata = output.metadata || {};
|
|
4649
|
+
}
|
|
4677
4650
|
}
|
|
4678
|
-
acc.generation = generation;
|
|
4679
4651
|
return;
|
|
4680
4652
|
}
|
|
4681
4653
|
}
|
|
4682
4654
|
/**
|
|
4683
4655
|
* Build final result from accumulator
|
|
4684
|
-
*
|
|
4685
|
-
* Returns content and metrics separately (metrics should NOT be stored in message.metadata)
|
|
4656
|
+
* Returns unified content chains from all channels
|
|
4686
4657
|
*/
|
|
4687
4658
|
getResult(acc) {
|
|
4688
|
-
const
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
(
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
llmCallsCount: acc.llmCalls.length,
|
|
4702
|
-
totalPromptTokens,
|
|
4703
|
-
totalCompletionTokens,
|
|
4704
|
-
totalTokens,
|
|
4705
|
-
modelIds: acc.llmCalls.map((c) => c.modelId)
|
|
4706
|
-
});
|
|
4707
|
-
const metrics = acc.llmCalls.length > 0 ? {
|
|
4708
|
-
modelCalls: acc.llmCalls.map((call) => ({
|
|
4709
|
-
nodeName: call.nodeName || "unknown",
|
|
4710
|
-
timestamp: call.timestamp,
|
|
4711
|
-
modelId: call.modelId,
|
|
4712
|
-
promptTokens: call.promptTokens,
|
|
4713
|
-
completionTokens: call.completionTokens,
|
|
4714
|
-
totalTokens: call.totalTokens,
|
|
4715
|
-
latencyMs: 0
|
|
4716
|
-
// Not calculated from events
|
|
4717
|
-
})),
|
|
4718
|
-
apiCalls: []
|
|
4719
|
-
// TODO: Add API calls tracking (rerank, embeddings) via custom events
|
|
4720
|
-
} : null;
|
|
4659
|
+
const allChains = [];
|
|
4660
|
+
for (const [channel, state] of acc.channels.entries()) {
|
|
4661
|
+
if (state.currentBlock) {
|
|
4662
|
+
state.contentChain.push(state.currentBlock);
|
|
4663
|
+
}
|
|
4664
|
+
if (state.contentChain.length > 0) {
|
|
4665
|
+
allChains.push({
|
|
4666
|
+
channel,
|
|
4667
|
+
steps: state.contentChain,
|
|
4668
|
+
isComplete: true
|
|
4669
|
+
});
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4721
4672
|
const startedAt = acc.traceStartedAt ?? Date.now();
|
|
4722
4673
|
const completedAt = acc.traceCompletedAt ?? startedAt;
|
|
4723
4674
|
const trace = acc.traceEvents.length > 0 ? {
|
|
@@ -4725,28 +4676,20 @@ var EventProcessor = class {
|
|
|
4725
4676
|
startedAt,
|
|
4726
4677
|
completedAt,
|
|
4727
4678
|
durationMs: Math.max(0, completedAt - startedAt),
|
|
4728
|
-
totalEvents: acc.traceEvents.length
|
|
4729
|
-
totalModelCalls: acc.llmCalls.length
|
|
4679
|
+
totalEvents: acc.traceEvents.length
|
|
4730
4680
|
} : null;
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
firstEventSample: trace.events[0] ? JSON.stringify(trace.events[0]).substring(0, 150) : null,
|
|
4738
|
-
allEventsNull: trace.events.every((e) => e === null),
|
|
4739
|
-
someEventsNull: trace.events.some((e) => e === null)
|
|
4740
|
-
});
|
|
4741
|
-
}
|
|
4681
|
+
this.logger.log("\u{1F4CA} [EventProcessor] Final result assembled", {
|
|
4682
|
+
totalChains: allChains.length,
|
|
4683
|
+
textChains: allChains.filter((c) => c.channel === "text").length,
|
|
4684
|
+
processingChains: allChains.filter((c) => c.channel === "processing").length,
|
|
4685
|
+
totalSteps: allChains.reduce((sum, c) => sum + c.steps.length, 0)
|
|
4686
|
+
});
|
|
4742
4687
|
return {
|
|
4743
4688
|
content: {
|
|
4744
|
-
|
|
4745
|
-
attachments: acc.
|
|
4746
|
-
metadata: acc.
|
|
4747
|
-
reasoningChains: acc.reasoningChains.length > 0 ? acc.reasoningChains : void 0
|
|
4689
|
+
contentChains: allChains.length > 0 ? allChains : void 0,
|
|
4690
|
+
attachments: acc.attachments,
|
|
4691
|
+
metadata: acc.metadata
|
|
4748
4692
|
},
|
|
4749
|
-
metrics,
|
|
4750
4693
|
trace
|
|
4751
4694
|
};
|
|
4752
4695
|
}
|
|
@@ -4861,33 +4804,13 @@ var LangGraphEngine = class {
|
|
|
4861
4804
|
);
|
|
4862
4805
|
}
|
|
4863
4806
|
}
|
|
4864
|
-
const { content,
|
|
4807
|
+
const { content, trace } = this.eventProcessor.getResult(acc);
|
|
4865
4808
|
this.logger.debug("[STREAM-RESULT] Got result from EventProcessor", {
|
|
4866
4809
|
hasContent: !!content,
|
|
4867
|
-
hasMetrics: !!metrics,
|
|
4868
|
-
modelCallsCount: metrics?.modelCalls?.length || 0,
|
|
4869
|
-
apiCallsCount: metrics?.apiCalls?.length || 0,
|
|
4870
4810
|
hasContext: !!config.configurable?.context,
|
|
4871
4811
|
hasTrace: !!trace,
|
|
4872
4812
|
traceEvents: trace?.events?.length || 0
|
|
4873
4813
|
});
|
|
4874
|
-
if (metrics && metrics.modelCalls?.length > 0 && config.configurable?.context) {
|
|
4875
|
-
const context = config.configurable.context;
|
|
4876
|
-
await this.sendMetricsWebhook({
|
|
4877
|
-
messageId: context.messageId || "unknown",
|
|
4878
|
-
threadId: context.threadId || "unknown",
|
|
4879
|
-
userId: context.userId || "unknown",
|
|
4880
|
-
agentId: context.agentId || "unknown",
|
|
4881
|
-
companyId: context.companyId || "unknown",
|
|
4882
|
-
metrics
|
|
4883
|
-
});
|
|
4884
|
-
} else {
|
|
4885
|
-
this.logger.debug("[METRICS-WEBHOOK] Skipping webhook", {
|
|
4886
|
-
hasMetrics: !!metrics,
|
|
4887
|
-
modelCallsCount: metrics?.modelCalls?.length || 0,
|
|
4888
|
-
hasContext: !!config.configurable?.context
|
|
4889
|
-
});
|
|
4890
|
-
}
|
|
4891
4814
|
if (trace && trace.events.length > 0 && config.configurable?.context) {
|
|
4892
4815
|
const context = config.configurable.context;
|
|
4893
4816
|
this.logger.debug("[TRACE-WEBHOOK] Sending trace events batch", {
|
|
@@ -4904,7 +4827,6 @@ var LangGraphEngine = class {
|
|
|
4904
4827
|
companyId: context.companyId || "unknown",
|
|
4905
4828
|
events: trace.events,
|
|
4906
4829
|
totalEvents: trace.totalEvents,
|
|
4907
|
-
totalModelCalls: trace.totalModelCalls,
|
|
4908
4830
|
startedAt: trace.startedAt,
|
|
4909
4831
|
completedAt: trace.completedAt,
|
|
4910
4832
|
durationMs: trace.durationMs
|
|
@@ -4987,7 +4909,6 @@ var LangGraphEngine = class {
|
|
|
4987
4909
|
agentId: payload.agentId,
|
|
4988
4910
|
companyId: payload.companyId,
|
|
4989
4911
|
totalEvents: payload.totalEvents,
|
|
4990
|
-
totalModelCalls: payload.totalModelCalls,
|
|
4991
4912
|
startedAt: payload.startedAt,
|
|
4992
4913
|
completedAt: payload.completedAt,
|
|
4993
4914
|
durationMs: payload.durationMs,
|
|
@@ -5367,47 +5288,65 @@ var McpConverter = class _McpConverter {
|
|
|
5367
5288
|
mcpRuntimeUrl;
|
|
5368
5289
|
constructor(mcpRuntimeUrl = "http://localhost:3004") {
|
|
5369
5290
|
this.mcpRuntimeUrl = mcpRuntimeUrl;
|
|
5291
|
+
this.logger.log(
|
|
5292
|
+
`\u{1F527} McpConverter initialized with SDK version 0.1.8 (manual jsonSchemaToZod)`
|
|
5293
|
+
);
|
|
5370
5294
|
}
|
|
5371
5295
|
/**
|
|
5372
|
-
* Convert JSON Schema to
|
|
5296
|
+
* Convert JSON Schema to Zod schema manually
|
|
5297
|
+
* This creates a standard Zod schema that zodToJsonSchema can convert back properly
|
|
5373
5298
|
*/
|
|
5374
5299
|
jsonSchemaToZod(jsonSchema) {
|
|
5375
5300
|
if (!jsonSchema || typeof jsonSchema !== "object") {
|
|
5376
5301
|
return z.any();
|
|
5377
5302
|
}
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5303
|
+
try {
|
|
5304
|
+
if (jsonSchema.type === "object" && jsonSchema.properties) {
|
|
5305
|
+
const shape = {};
|
|
5306
|
+
for (const [key, propSchema] of Object.entries(jsonSchema.properties)) {
|
|
5307
|
+
const prop = propSchema;
|
|
5308
|
+
let zodProp;
|
|
5309
|
+
switch (prop.type) {
|
|
5310
|
+
case "string":
|
|
5311
|
+
zodProp = z.string();
|
|
5312
|
+
break;
|
|
5313
|
+
case "number":
|
|
5314
|
+
zodProp = z.number();
|
|
5315
|
+
break;
|
|
5316
|
+
case "boolean":
|
|
5317
|
+
zodProp = z.boolean();
|
|
5318
|
+
break;
|
|
5319
|
+
case "integer":
|
|
5320
|
+
zodProp = z.number().int();
|
|
5321
|
+
break;
|
|
5322
|
+
case "array":
|
|
5323
|
+
zodProp = z.array(z.any());
|
|
5324
|
+
break;
|
|
5325
|
+
case "object":
|
|
5326
|
+
zodProp = z.record(z.any());
|
|
5327
|
+
break;
|
|
5328
|
+
default:
|
|
5329
|
+
zodProp = z.any();
|
|
5330
|
+
}
|
|
5331
|
+
if (prop.description) {
|
|
5332
|
+
zodProp = zodProp.describe(prop.description);
|
|
5333
|
+
}
|
|
5334
|
+
if (!jsonSchema.required?.includes(key)) {
|
|
5335
|
+
zodProp = zodProp.optional();
|
|
5336
|
+
}
|
|
5337
|
+
shape[key] = zodProp;
|
|
5338
|
+
}
|
|
5339
|
+
return z.object(shape);
|
|
5340
|
+
}
|
|
5341
|
+
this.logger.warn(
|
|
5342
|
+
`Unsupported JSON Schema structure, falling back to z.any()`
|
|
5343
|
+
);
|
|
5344
|
+
return z.any();
|
|
5345
|
+
} catch (error) {
|
|
5346
|
+
this.logger.warn(
|
|
5347
|
+
`Failed to convert JSON Schema, falling back to z.any(): ${error}`
|
|
5348
|
+
);
|
|
5349
|
+
return z.any();
|
|
5411
5350
|
}
|
|
5412
5351
|
}
|
|
5413
5352
|
/**
|
|
@@ -5416,6 +5355,27 @@ var McpConverter = class _McpConverter {
|
|
|
5416
5355
|
convertTool(mcpTool) {
|
|
5417
5356
|
const logger2 = this.logger;
|
|
5418
5357
|
const mcpRuntimeUrl = this.mcpRuntimeUrl;
|
|
5358
|
+
let enhancedDescription = mcpTool.description;
|
|
5359
|
+
if (mcpTool.inputSchema?.properties) {
|
|
5360
|
+
const paramDescriptions = [];
|
|
5361
|
+
for (const [key, propSchema] of Object.entries(
|
|
5362
|
+
mcpTool.inputSchema.properties
|
|
5363
|
+
)) {
|
|
5364
|
+
const prop = propSchema;
|
|
5365
|
+
if (prop.description) {
|
|
5366
|
+
const isRequired = mcpTool.inputSchema.required?.includes(key);
|
|
5367
|
+
paramDescriptions.push(
|
|
5368
|
+
`- ${key}${isRequired ? " (required)" : ""}: ${prop.description}`
|
|
5369
|
+
);
|
|
5370
|
+
}
|
|
5371
|
+
}
|
|
5372
|
+
if (paramDescriptions.length > 0) {
|
|
5373
|
+
enhancedDescription = `${mcpTool.description}
|
|
5374
|
+
|
|
5375
|
+
Parameters:
|
|
5376
|
+
${paramDescriptions.join("\n")}`;
|
|
5377
|
+
}
|
|
5378
|
+
}
|
|
5419
5379
|
const schema = this.jsonSchemaToZod(mcpTool.inputSchema);
|
|
5420
5380
|
logger2.debug(
|
|
5421
5381
|
`\u{1F527} [${mcpTool.name}] Original schema:`,
|
|
@@ -5424,9 +5384,48 @@ var McpConverter = class _McpConverter {
|
|
|
5424
5384
|
logger2.debug(
|
|
5425
5385
|
`\u{1F527} [${mcpTool.name}] Using schema type: ${schema?._def?.typeName ?? "unknown"}`
|
|
5426
5386
|
);
|
|
5387
|
+
if (schema?._def?.shape && typeof schema._def.shape === "function") {
|
|
5388
|
+
try {
|
|
5389
|
+
const shape = schema._def.shape();
|
|
5390
|
+
logger2.debug(
|
|
5391
|
+
`\u{1F527} [${mcpTool.name}] Converted Zod schema shape:`,
|
|
5392
|
+
JSON.stringify(
|
|
5393
|
+
Object.entries(shape).reduce(
|
|
5394
|
+
(acc, [key, val]) => {
|
|
5395
|
+
acc[key] = {
|
|
5396
|
+
type: val?._def?.typeName,
|
|
5397
|
+
description: val?._def?.description,
|
|
5398
|
+
optional: val?._def?.typeName === "ZodOptional"
|
|
5399
|
+
};
|
|
5400
|
+
return acc;
|
|
5401
|
+
},
|
|
5402
|
+
{}
|
|
5403
|
+
),
|
|
5404
|
+
null,
|
|
5405
|
+
2
|
|
5406
|
+
)
|
|
5407
|
+
);
|
|
5408
|
+
} catch (error) {
|
|
5409
|
+
logger2.debug(
|
|
5410
|
+
`\u{1F527} [${mcpTool.name}] Could not extract Zod schema shape: ${error}`
|
|
5411
|
+
);
|
|
5412
|
+
}
|
|
5413
|
+
}
|
|
5414
|
+
try {
|
|
5415
|
+
const { zodToJsonSchema } = __require("zod-to-json-schema");
|
|
5416
|
+
const convertedJsonSchema = zodToJsonSchema(schema);
|
|
5417
|
+
logger2.warn(
|
|
5418
|
+
`\u{1F527} [${mcpTool.name}] JSON Schema that LangChain will use:`,
|
|
5419
|
+
JSON.stringify(convertedJsonSchema, null, 2)
|
|
5420
|
+
);
|
|
5421
|
+
} catch (error) {
|
|
5422
|
+
logger2.warn(
|
|
5423
|
+
`\u{1F527} [${mcpTool.name}] Could not convert Zod to JSON Schema: ${error}`
|
|
5424
|
+
);
|
|
5425
|
+
}
|
|
5427
5426
|
return new DynamicStructuredTool({
|
|
5428
5427
|
name: mcpTool.name,
|
|
5429
|
-
description:
|
|
5428
|
+
description: enhancedDescription,
|
|
5430
5429
|
schema,
|
|
5431
5430
|
func: async (input) => {
|
|
5432
5431
|
logger2.log(`\u{1F527} [${mcpTool.name}] LLM INPUT: ${JSON.stringify(input)}`);
|
|
@@ -5743,6 +5742,58 @@ var McpRuntimeHttpClient = class {
|
|
|
5743
5742
|
return false;
|
|
5744
5743
|
}
|
|
5745
5744
|
}
|
|
5745
|
+
/**
|
|
5746
|
+
* Execute tool with LangChain event emission
|
|
5747
|
+
* @param toolCallId - Tool call ID from LLM
|
|
5748
|
+
* @param toolName - Tool name
|
|
5749
|
+
* @param enrichedArgs - Merged arguments (toolConfig + LLM args)
|
|
5750
|
+
* @param executionContext - Execution context (userId, agentId, etc.)
|
|
5751
|
+
* @param config - RunnableConfig with callbacks
|
|
5752
|
+
* @returns Tool execution result with content
|
|
5753
|
+
*/
|
|
5754
|
+
async executeToolWithEvents(toolCallId, toolName, enrichedArgs, executionContext, config) {
|
|
5755
|
+
const parsedConfig = parseCallbackConfigArg(config);
|
|
5756
|
+
const callbackManager = CallbackManager.configure(parsedConfig.callbacks);
|
|
5757
|
+
let runManager;
|
|
5758
|
+
try {
|
|
5759
|
+
runManager = await callbackManager?.handleToolStart(
|
|
5760
|
+
{
|
|
5761
|
+
name: toolName,
|
|
5762
|
+
lc: 1,
|
|
5763
|
+
type: "not_implemented",
|
|
5764
|
+
id: ["langchain", "tools", "mcp", toolName]
|
|
5765
|
+
},
|
|
5766
|
+
JSON.stringify(enrichedArgs),
|
|
5767
|
+
parsedConfig.runId,
|
|
5768
|
+
void 0,
|
|
5769
|
+
parsedConfig.tags,
|
|
5770
|
+
parsedConfig.metadata,
|
|
5771
|
+
toolName
|
|
5772
|
+
);
|
|
5773
|
+
const result = await this.executeTool(
|
|
5774
|
+
toolName,
|
|
5775
|
+
enrichedArgs,
|
|
5776
|
+
executionContext
|
|
5777
|
+
);
|
|
5778
|
+
const content = result.success ? JSON.stringify(result) : result.error || JSON.stringify(result);
|
|
5779
|
+
await runManager?.handleToolEnd(content);
|
|
5780
|
+
return {
|
|
5781
|
+
content,
|
|
5782
|
+
success: result.success
|
|
5783
|
+
};
|
|
5784
|
+
} catch (error) {
|
|
5785
|
+
this.logger.error(`Error executing tool ${toolName}:`, error);
|
|
5786
|
+
await runManager?.handleToolError(error);
|
|
5787
|
+
const errorContent = JSON.stringify({
|
|
5788
|
+
success: false,
|
|
5789
|
+
error: error instanceof Error ? error.message : "Tool execution failed"
|
|
5790
|
+
});
|
|
5791
|
+
return {
|
|
5792
|
+
content: errorContent,
|
|
5793
|
+
success: false
|
|
5794
|
+
};
|
|
5795
|
+
}
|
|
5796
|
+
}
|
|
5746
5797
|
};
|
|
5747
5798
|
McpRuntimeHttpClient = __decorateClass([
|
|
5748
5799
|
Injectable()
|