@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 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.length > opts.maxStringLength ? `${value.slice(0, opts.maxStringLength)}\u2026` : 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
- streamedText: "",
4446
- reasoningChains: [],
4447
- generation: null,
4448
- llmCalls: [],
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.metadata?.stream_channel === "text" /* TEXT */ && event.data?.chunk?.content) {
4534
- const chunk = event.data.chunk.content;
4535
- const blocks = this.normalizeContentBlocks(chunk);
4536
- if (blocks.length > 0 && onPartial) {
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 === "on_chat_model_stream" && event.metadata?.stream_channel === "processing" /* PROCESSING */ && event.data?.chunk?.content) {
4546
- const chunk = event.data.chunk.content;
4547
- const blocks = this.normalizeContentBlocks(chunk);
4548
- for (const block of blocks) {
4549
- if (block.type === "tool_use" || block.type === "tool_call") {
4550
- if (acc.currentToolUse) {
4551
- acc.currentReasoningSteps.push(acc.currentToolUse);
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 === "on_chat_model_end") {
4590
- const output = event.data?.output;
4591
- const usageMetadata = output?.usage_metadata || output?.usageMetadata;
4592
- const modelId = event.metadata?.modelId;
4593
- if (usageMetadata && modelId) {
4594
- const llmCall = {
4595
- modelId,
4596
- promptTokens: usageMetadata.input_tokens || 0,
4597
- completionTokens: usageMetadata.output_tokens || 0,
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
- hasUsageMetadata: !!usageMetadata,
4614
- hasModelId: !!modelId,
4615
- eventName: event.name,
4616
- metadataKeys: event.metadata ? Object.keys(event.metadata) : [],
4617
- outputKeys: output ? Object.keys(output) : []
4618
- }
4636
+ type: "tool_output_chunk",
4637
+ stepId: state.currentBlock.id,
4638
+ chunk: outputString
4639
+ },
4640
+ onPartial
4619
4641
  );
4620
- }
4621
- if (event.metadata?.stream_channel === "processing" /* PROCESSING */) {
4622
- if (acc.currentToolUse) {
4623
- acc.currentReasoningSteps.push(acc.currentToolUse);
4624
- acc.currentToolUse = null;
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 === "on_chain_end" && event.metadata?.stream_channel === "text" /* TEXT */) {
4680
- const output = event.data.output;
4681
- let generation = null;
4682
- if (output?.answer?.text) {
4683
- generation = {
4684
- text: output.answer.text,
4685
- attachments: output.answer.attachments || [],
4686
- metadata: output.answer.metadata || {}
4687
- };
4688
- } else if (output?.generation?.text) {
4689
- generation = {
4690
- text: output.generation.text,
4691
- attachments: output.generation.attachments || [],
4692
- metadata: output.generation.metadata || {}
4693
- };
4694
- } else if (output?.generation?.content) {
4695
- generation = {
4696
- text: output.generation.content,
4697
- attachments: [],
4698
- metadata: {}
4699
- };
4700
- } else if (output?.text) {
4701
- generation = {
4702
- text: output.text,
4703
- attachments: output.attachments || [],
4704
- metadata: output.metadata || {}
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
- * Uses generation if available, otherwise falls back to streamed text
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 totalPromptTokens = acc.llmCalls.reduce(
4718
- (sum, call) => sum + call.promptTokens,
4719
- 0
4720
- );
4721
- const totalCompletionTokens = acc.llmCalls.reduce(
4722
- (sum, call) => sum + call.completionTokens,
4723
- 0
4724
- );
4725
- const totalTokens = acc.llmCalls.reduce(
4726
- (sum, call) => sum + call.totalTokens,
4727
- 0
4728
- );
4729
- this.logger.log("\u{1F4CA} Final metrics collected", {
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
- if (trace) {
4761
- this.logger.log("\u{1F4CA} [EventProcessor] Final trace assembled", {
4762
- totalEvents: trace.totalEvents,
4763
- eventsArrayLength: trace.events.length,
4764
- firstEventType: trace.events[0]?.type,
4765
- lastEventType: trace.events[trace.events.length - 1]?.type,
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
- text: acc.generation?.text || acc.streamedText || "",
4774
- attachments: acc.generation?.attachments || [],
4775
- metadata: acc.generation?.metadata || {},
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, metrics, trace } = this.eventProcessor.getResult(acc);
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 simplified Zod schema for LangChain
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
- if (jsonSchema.type !== "object") {
5408
- return this.mapPrimitiveSchema(jsonSchema.type, true);
5409
- }
5410
- const properties = jsonSchema.properties || {};
5411
- const required = Array.isArray(jsonSchema.required) ? jsonSchema.required : [];
5412
- const zodShape = {};
5413
- for (const [key, prop] of Object.entries(properties)) {
5414
- const propDef = prop;
5415
- const isRequired = required.includes(key);
5416
- const schemaType = propDef?.type ?? "any";
5417
- const mappedType = this.mapPrimitiveSchema(schemaType, isRequired);
5418
- zodShape[key] = mappedType;
5419
- }
5420
- const baseObject = zod.z.object(zodShape);
5421
- const configuredObject = jsonSchema.additionalProperties === false ? baseObject.strict() : baseObject.passthrough();
5422
- return configuredObject;
5423
- }
5424
- mapPrimitiveSchema(type, required) {
5425
- const optionalize = (schema) => required ? schema : schema.optional();
5426
- switch (type) {
5427
- case "string":
5428
- return optionalize(zod.z.string());
5429
- case "number":
5430
- case "integer":
5431
- return optionalize(zod.z.number());
5432
- case "boolean":
5433
- return optionalize(zod.z.boolean());
5434
- case "array":
5435
- return optionalize(zod.z.array(zod.z.any()));
5436
- case "object":
5437
- return optionalize(zod.z.record(zod.z.any()));
5438
- default:
5439
- return optionalize(zod.z.any());
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: mcpTool.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()