@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.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.length > opts.maxStringLength ? `${value.slice(0, opts.maxStringLength)}\u2026` : 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
- streamedText: "",
4417
- reasoningChains: [],
4418
- generation: null,
4419
- llmCalls: [],
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.metadata?.stream_channel === "text" /* TEXT */ && event.data?.chunk?.content) {
4505
- const chunk = event.data.chunk.content;
4506
- const blocks = this.normalizeContentBlocks(chunk);
4507
- if (blocks.length > 0 && onPartial) {
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 === "on_chat_model_stream" && event.metadata?.stream_channel === "processing" /* PROCESSING */ && event.data?.chunk?.content) {
4517
- const chunk = event.data.chunk.content;
4518
- const blocks = this.normalizeContentBlocks(chunk);
4519
- for (const block of blocks) {
4520
- if (block.type === "tool_use" || block.type === "tool_call") {
4521
- if (acc.currentToolUse) {
4522
- acc.currentReasoningSteps.push(acc.currentToolUse);
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 === "on_chat_model_end") {
4561
- const output = event.data?.output;
4562
- const usageMetadata = output?.usage_metadata || output?.usageMetadata;
4563
- const modelId = event.metadata?.modelId;
4564
- if (usageMetadata && modelId) {
4565
- const llmCall = {
4566
- modelId,
4567
- promptTokens: usageMetadata.input_tokens || 0,
4568
- completionTokens: usageMetadata.output_tokens || 0,
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
- hasUsageMetadata: !!usageMetadata,
4585
- hasModelId: !!modelId,
4586
- eventName: event.name,
4587
- metadataKeys: event.metadata ? Object.keys(event.metadata) : [],
4588
- outputKeys: output ? Object.keys(output) : []
4589
- }
4607
+ type: "tool_output_chunk",
4608
+ stepId: state.currentBlock.id,
4609
+ chunk: outputString
4610
+ },
4611
+ onPartial
4590
4612
  );
4591
- }
4592
- if (event.metadata?.stream_channel === "processing" /* PROCESSING */) {
4593
- if (acc.currentToolUse) {
4594
- acc.currentReasoningSteps.push(acc.currentToolUse);
4595
- acc.currentToolUse = null;
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 === "on_chain_end" && event.metadata?.stream_channel === "text" /* TEXT */) {
4651
- const output = event.data.output;
4652
- let generation = null;
4653
- if (output?.answer?.text) {
4654
- generation = {
4655
- text: output.answer.text,
4656
- attachments: output.answer.attachments || [],
4657
- metadata: output.answer.metadata || {}
4658
- };
4659
- } else if (output?.generation?.text) {
4660
- generation = {
4661
- text: output.generation.text,
4662
- attachments: output.generation.attachments || [],
4663
- metadata: output.generation.metadata || {}
4664
- };
4665
- } else if (output?.generation?.content) {
4666
- generation = {
4667
- text: output.generation.content,
4668
- attachments: [],
4669
- metadata: {}
4670
- };
4671
- } else if (output?.text) {
4672
- generation = {
4673
- text: output.text,
4674
- attachments: output.attachments || [],
4675
- metadata: output.metadata || {}
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
- * Uses generation if available, otherwise falls back to streamed text
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 totalPromptTokens = acc.llmCalls.reduce(
4689
- (sum, call) => sum + call.promptTokens,
4690
- 0
4691
- );
4692
- const totalCompletionTokens = acc.llmCalls.reduce(
4693
- (sum, call) => sum + call.completionTokens,
4694
- 0
4695
- );
4696
- const totalTokens = acc.llmCalls.reduce(
4697
- (sum, call) => sum + call.totalTokens,
4698
- 0
4699
- );
4700
- this.logger.log("\u{1F4CA} Final metrics collected", {
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
- if (trace) {
4732
- this.logger.log("\u{1F4CA} [EventProcessor] Final trace assembled", {
4733
- totalEvents: trace.totalEvents,
4734
- eventsArrayLength: trace.events.length,
4735
- firstEventType: trace.events[0]?.type,
4736
- lastEventType: trace.events[trace.events.length - 1]?.type,
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
- text: acc.generation?.text || acc.streamedText || "",
4745
- attachments: acc.generation?.attachments || [],
4746
- metadata: acc.generation?.metadata || {},
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, metrics, trace } = this.eventProcessor.getResult(acc);
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 simplified Zod schema for LangChain
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
- if (jsonSchema.type !== "object") {
5379
- return this.mapPrimitiveSchema(jsonSchema.type, true);
5380
- }
5381
- const properties = jsonSchema.properties || {};
5382
- const required = Array.isArray(jsonSchema.required) ? jsonSchema.required : [];
5383
- const zodShape = {};
5384
- for (const [key, prop] of Object.entries(properties)) {
5385
- const propDef = prop;
5386
- const isRequired = required.includes(key);
5387
- const schemaType = propDef?.type ?? "any";
5388
- const mappedType = this.mapPrimitiveSchema(schemaType, isRequired);
5389
- zodShape[key] = mappedType;
5390
- }
5391
- const baseObject = z.object(zodShape);
5392
- const configuredObject = jsonSchema.additionalProperties === false ? baseObject.strict() : baseObject.passthrough();
5393
- return configuredObject;
5394
- }
5395
- mapPrimitiveSchema(type, required) {
5396
- const optionalize = (schema) => required ? schema : schema.optional();
5397
- switch (type) {
5398
- case "string":
5399
- return optionalize(z.string());
5400
- case "number":
5401
- case "integer":
5402
- return optionalize(z.number());
5403
- case "boolean":
5404
- return optionalize(z.boolean());
5405
- case "array":
5406
- return optionalize(z.array(z.any()));
5407
- case "object":
5408
- return optionalize(z.record(z.any()));
5409
- default:
5410
- return optionalize(z.any());
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: mcpTool.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()