@flutchai/flutch-sdk 0.1.8 → 0.1.9

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');
@@ -4330,7 +4331,7 @@ function sanitizeTraceData(value, depth = 0, seen = /* @__PURE__ */ new WeakSet(
4330
4331
  return null;
4331
4332
  }
4332
4333
  if (typeof value === "string") {
4333
- return value.length > opts.maxStringLength ? `${value.slice(0, opts.maxStringLength)}\u2026` : value;
4334
+ return value;
4334
4335
  }
4335
4336
  if (typeof value === "number" || typeof value === "boolean") {
4336
4337
  return value;
@@ -4586,6 +4587,31 @@ exports.EventProcessor = class EventProcessor {
4586
4587
  }
4587
4588
  return;
4588
4589
  }
4590
+ if (event.event === "on_tool_start") {
4591
+ this.logger.log("\u{1F527} Tool execution started", {
4592
+ toolName: event.name,
4593
+ input: event.data?.input,
4594
+ runId: event.run_id,
4595
+ metadata: event.metadata
4596
+ });
4597
+ return;
4598
+ }
4599
+ if (event.event === "on_tool_end") {
4600
+ this.logger.log("\u2705 Tool execution completed", {
4601
+ toolName: event.name,
4602
+ output: typeof event.data?.output === "string" ? event.data.output.substring(0, 200) + (event.data.output.length > 200 ? "..." : "") : event.data?.output,
4603
+ runId: event.run_id
4604
+ });
4605
+ return;
4606
+ }
4607
+ if (event.event === "on_tool_error") {
4608
+ this.logger.error("\u274C Tool execution failed", {
4609
+ toolName: event.name,
4610
+ error: event.data?.error,
4611
+ runId: event.run_id
4612
+ });
4613
+ return;
4614
+ }
4589
4615
  if (event.event === "on_chat_model_end") {
4590
4616
  const output = event.data?.output;
4591
4617
  const usageMetadata = output?.usage_metadata || output?.usageMetadata;
@@ -4711,42 +4737,9 @@ exports.EventProcessor = class EventProcessor {
4711
4737
  /**
4712
4738
  * Build final result from accumulator
4713
4739
  * Uses generation if available, otherwise falls back to streamed text
4714
- * Returns content and metrics separately (metrics should NOT be stored in message.metadata)
4740
+ * Returns content and trace events (metrics should be extracted from trace on backend)
4715
4741
  */
4716
4742
  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;
4750
4743
  const startedAt = acc.traceStartedAt ?? Date.now();
4751
4744
  const completedAt = acc.traceCompletedAt ?? startedAt;
4752
4745
  const trace = acc.traceEvents.length > 0 ? {
@@ -4775,7 +4768,6 @@ exports.EventProcessor = class EventProcessor {
4775
4768
  metadata: acc.generation?.metadata || {},
4776
4769
  reasoningChains: acc.reasoningChains.length > 0 ? acc.reasoningChains : void 0
4777
4770
  },
4778
- metrics,
4779
4771
  trace
4780
4772
  };
4781
4773
  }
@@ -4890,33 +4882,14 @@ exports.LangGraphEngine = class LangGraphEngine {
4890
4882
  );
4891
4883
  }
4892
4884
  }
4893
- const { content, metrics, trace } = this.eventProcessor.getResult(acc);
4885
+ const { content, trace } = this.eventProcessor.getResult(acc);
4894
4886
  this.logger.debug("[STREAM-RESULT] Got result from EventProcessor", {
4895
4887
  hasContent: !!content,
4896
- hasMetrics: !!metrics,
4897
- modelCallsCount: metrics?.modelCalls?.length || 0,
4898
- apiCallsCount: metrics?.apiCalls?.length || 0,
4899
4888
  hasContext: !!config.configurable?.context,
4900
4889
  hasTrace: !!trace,
4901
- traceEvents: trace?.events?.length || 0
4890
+ traceEvents: trace?.events?.length || 0,
4891
+ totalModelCalls: trace?.totalModelCalls || 0
4902
4892
  });
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
4893
  if (trace && trace.events.length > 0 && config.configurable?.context) {
4921
4894
  const context = config.configurable.context;
4922
4895
  this.logger.debug("[TRACE-WEBHOOK] Sending trace events batch", {
@@ -5396,47 +5369,65 @@ var McpConverter = class _McpConverter {
5396
5369
  mcpRuntimeUrl;
5397
5370
  constructor(mcpRuntimeUrl = "http://localhost:3004") {
5398
5371
  this.mcpRuntimeUrl = mcpRuntimeUrl;
5372
+ this.logger.log(
5373
+ `\u{1F527} McpConverter initialized with SDK version 0.1.8 (manual jsonSchemaToZod)`
5374
+ );
5399
5375
  }
5400
5376
  /**
5401
- * Convert JSON Schema to simplified Zod schema for LangChain
5377
+ * Convert JSON Schema to Zod schema manually
5378
+ * This creates a standard Zod schema that zodToJsonSchema can convert back properly
5402
5379
  */
5403
5380
  jsonSchemaToZod(jsonSchema) {
5404
5381
  if (!jsonSchema || typeof jsonSchema !== "object") {
5405
5382
  return zod.z.any();
5406
5383
  }
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());
5384
+ try {
5385
+ if (jsonSchema.type === "object" && jsonSchema.properties) {
5386
+ const shape = {};
5387
+ for (const [key, propSchema] of Object.entries(jsonSchema.properties)) {
5388
+ const prop = propSchema;
5389
+ let zodProp;
5390
+ switch (prop.type) {
5391
+ case "string":
5392
+ zodProp = zod.z.string();
5393
+ break;
5394
+ case "number":
5395
+ zodProp = zod.z.number();
5396
+ break;
5397
+ case "boolean":
5398
+ zodProp = zod.z.boolean();
5399
+ break;
5400
+ case "integer":
5401
+ zodProp = zod.z.number().int();
5402
+ break;
5403
+ case "array":
5404
+ zodProp = zod.z.array(zod.z.any());
5405
+ break;
5406
+ case "object":
5407
+ zodProp = zod.z.record(zod.z.any());
5408
+ break;
5409
+ default:
5410
+ zodProp = zod.z.any();
5411
+ }
5412
+ if (prop.description) {
5413
+ zodProp = zodProp.describe(prop.description);
5414
+ }
5415
+ if (!jsonSchema.required?.includes(key)) {
5416
+ zodProp = zodProp.optional();
5417
+ }
5418
+ shape[key] = zodProp;
5419
+ }
5420
+ return zod.z.object(shape);
5421
+ }
5422
+ this.logger.warn(
5423
+ `Unsupported JSON Schema structure, falling back to z.any()`
5424
+ );
5425
+ return zod.z.any();
5426
+ } catch (error) {
5427
+ this.logger.warn(
5428
+ `Failed to convert JSON Schema, falling back to z.any(): ${error}`
5429
+ );
5430
+ return zod.z.any();
5440
5431
  }
5441
5432
  }
5442
5433
  /**
@@ -5445,6 +5436,27 @@ var McpConverter = class _McpConverter {
5445
5436
  convertTool(mcpTool) {
5446
5437
  const logger2 = this.logger;
5447
5438
  const mcpRuntimeUrl = this.mcpRuntimeUrl;
5439
+ let enhancedDescription = mcpTool.description;
5440
+ if (mcpTool.inputSchema?.properties) {
5441
+ const paramDescriptions = [];
5442
+ for (const [key, propSchema] of Object.entries(
5443
+ mcpTool.inputSchema.properties
5444
+ )) {
5445
+ const prop = propSchema;
5446
+ if (prop.description) {
5447
+ const isRequired = mcpTool.inputSchema.required?.includes(key);
5448
+ paramDescriptions.push(
5449
+ `- ${key}${isRequired ? " (required)" : ""}: ${prop.description}`
5450
+ );
5451
+ }
5452
+ }
5453
+ if (paramDescriptions.length > 0) {
5454
+ enhancedDescription = `${mcpTool.description}
5455
+
5456
+ Parameters:
5457
+ ${paramDescriptions.join("\n")}`;
5458
+ }
5459
+ }
5448
5460
  const schema = this.jsonSchemaToZod(mcpTool.inputSchema);
5449
5461
  logger2.debug(
5450
5462
  `\u{1F527} [${mcpTool.name}] Original schema:`,
@@ -5453,9 +5465,48 @@ var McpConverter = class _McpConverter {
5453
5465
  logger2.debug(
5454
5466
  `\u{1F527} [${mcpTool.name}] Using schema type: ${schema?._def?.typeName ?? "unknown"}`
5455
5467
  );
5468
+ if (schema?._def?.shape && typeof schema._def.shape === "function") {
5469
+ try {
5470
+ const shape = schema._def.shape();
5471
+ logger2.debug(
5472
+ `\u{1F527} [${mcpTool.name}] Converted Zod schema shape:`,
5473
+ JSON.stringify(
5474
+ Object.entries(shape).reduce(
5475
+ (acc, [key, val]) => {
5476
+ acc[key] = {
5477
+ type: val?._def?.typeName,
5478
+ description: val?._def?.description,
5479
+ optional: val?._def?.typeName === "ZodOptional"
5480
+ };
5481
+ return acc;
5482
+ },
5483
+ {}
5484
+ ),
5485
+ null,
5486
+ 2
5487
+ )
5488
+ );
5489
+ } catch (error) {
5490
+ logger2.debug(
5491
+ `\u{1F527} [${mcpTool.name}] Could not extract Zod schema shape: ${error}`
5492
+ );
5493
+ }
5494
+ }
5495
+ try {
5496
+ const { zodToJsonSchema } = __require("zod-to-json-schema");
5497
+ const convertedJsonSchema = zodToJsonSchema(schema);
5498
+ logger2.warn(
5499
+ `\u{1F527} [${mcpTool.name}] JSON Schema that LangChain will use:`,
5500
+ JSON.stringify(convertedJsonSchema, null, 2)
5501
+ );
5502
+ } catch (error) {
5503
+ logger2.warn(
5504
+ `\u{1F527} [${mcpTool.name}] Could not convert Zod to JSON Schema: ${error}`
5505
+ );
5506
+ }
5456
5507
  return new tools.DynamicStructuredTool({
5457
5508
  name: mcpTool.name,
5458
- description: mcpTool.description,
5509
+ description: enhancedDescription,
5459
5510
  schema,
5460
5511
  func: async (input) => {
5461
5512
  logger2.log(`\u{1F527} [${mcpTool.name}] LLM INPUT: ${JSON.stringify(input)}`);
@@ -5772,6 +5823,58 @@ exports.McpRuntimeHttpClient = class McpRuntimeHttpClient {
5772
5823
  return false;
5773
5824
  }
5774
5825
  }
5826
+ /**
5827
+ * Execute tool with LangChain event emission
5828
+ * @param toolCallId - Tool call ID from LLM
5829
+ * @param toolName - Tool name
5830
+ * @param enrichedArgs - Merged arguments (toolConfig + LLM args)
5831
+ * @param executionContext - Execution context (userId, agentId, etc.)
5832
+ * @param config - RunnableConfig with callbacks
5833
+ * @returns Tool execution result with content
5834
+ */
5835
+ async executeToolWithEvents(toolCallId, toolName, enrichedArgs, executionContext, config) {
5836
+ const parsedConfig = manager.parseCallbackConfigArg(config);
5837
+ const callbackManager = manager.CallbackManager.configure(parsedConfig.callbacks);
5838
+ let runManager;
5839
+ try {
5840
+ runManager = await callbackManager?.handleToolStart(
5841
+ {
5842
+ name: toolName,
5843
+ lc: 1,
5844
+ type: "not_implemented",
5845
+ id: ["langchain", "tools", "mcp", toolName]
5846
+ },
5847
+ JSON.stringify(enrichedArgs),
5848
+ parsedConfig.runId,
5849
+ void 0,
5850
+ parsedConfig.tags,
5851
+ parsedConfig.metadata,
5852
+ toolName
5853
+ );
5854
+ const result = await this.executeTool(
5855
+ toolName,
5856
+ enrichedArgs,
5857
+ executionContext
5858
+ );
5859
+ const content = result.success ? JSON.stringify(result) : result.error || JSON.stringify(result);
5860
+ await runManager?.handleToolEnd(content);
5861
+ return {
5862
+ content,
5863
+ success: result.success
5864
+ };
5865
+ } catch (error) {
5866
+ this.logger.error(`Error executing tool ${toolName}:`, error);
5867
+ await runManager?.handleToolError(error);
5868
+ const errorContent = JSON.stringify({
5869
+ success: false,
5870
+ error: error instanceof Error ? error.message : "Tool execution failed"
5871
+ });
5872
+ return {
5873
+ content: errorContent,
5874
+ success: false
5875
+ };
5876
+ }
5877
+ }
5775
5878
  };
5776
5879
  exports.McpRuntimeHttpClient = __decorateClass([
5777
5880
  common.Injectable()