@flutchai/flutch-sdk 0.1.7 → 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');
@@ -3076,9 +3077,6 @@ var _AbstractGraphBuilder = class _AbstractGraphBuilder {
3076
3077
  if (this.manifest?.companySlug && this.manifest?.name) {
3077
3078
  return `${this.manifest.companySlug}.${this.manifest.name}::${this.version}`;
3078
3079
  }
3079
- console.log(
3080
- `DEBUG graphType: manifest=${!!this.manifest}, companySlug=${this.manifest?.companySlug}, name=${this.manifest?.name}, version=${this.version}`
3081
- );
3082
3080
  return `unknown::${this.version}`;
3083
3081
  }
3084
3082
  /**
@@ -3410,6 +3408,9 @@ exports.UniversalGraphService = class UniversalGraphService {
3410
3408
  this.engine = engine;
3411
3409
  this.endpointRegistry = endpointRegistry;
3412
3410
  this.logger.log("UniversalGraphService initialized");
3411
+ if (!this.engine) {
3412
+ this.logger.error("GRAPH_ENGINE is not properly injected!");
3413
+ }
3413
3414
  }
3414
3415
  logger = new common.Logger(exports.UniversalGraphService.name);
3415
3416
  /**
@@ -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;
@@ -4405,11 +4406,11 @@ function sanitizeTraceError(error, options) {
4405
4406
  raw: sanitizeTraceData(error, 0, /* @__PURE__ */ new WeakSet(), options)
4406
4407
  };
4407
4408
  }
4408
- var GraphEngineType = /* @__PURE__ */ ((GraphEngineType2) => {
4409
- GraphEngineType2["LANGGRAPH"] = "langgraph";
4410
- GraphEngineType2["LANGFLOW"] = "langflow";
4411
- GraphEngineType2["FLOWISE"] = "flowise";
4412
- return GraphEngineType2;
4409
+ var GraphEngineType = /* @__PURE__ */ ((GraphEngineType3) => {
4410
+ GraphEngineType3["LANGGRAPH"] = "langgraph";
4411
+ GraphEngineType3["LANGFLOW"] = "langflow";
4412
+ GraphEngineType3["FLOWISE"] = "flowise";
4413
+ return GraphEngineType3;
4413
4414
  })(GraphEngineType || {});
4414
4415
  exports.GraphEngineFactory = class GraphEngineFactory {
4415
4416
  constructor(langgraph) {
@@ -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
  }
@@ -4855,6 +4847,9 @@ exports.LangGraphEngine = class LangGraphEngine {
4855
4847
  constructor(eventProcessor, configService) {
4856
4848
  this.eventProcessor = eventProcessor;
4857
4849
  this.configService = configService;
4850
+ if (!eventProcessor) {
4851
+ this.logger.error("EventProcessor is undefined/null!");
4852
+ }
4858
4853
  }
4859
4854
  logger = new common.Logger(exports.LangGraphEngine.name);
4860
4855
  /**
@@ -4887,33 +4882,14 @@ exports.LangGraphEngine = class LangGraphEngine {
4887
4882
  );
4888
4883
  }
4889
4884
  }
4890
- const { content, metrics, trace } = this.eventProcessor.getResult(acc);
4885
+ const { content, trace } = this.eventProcessor.getResult(acc);
4891
4886
  this.logger.debug("[STREAM-RESULT] Got result from EventProcessor", {
4892
4887
  hasContent: !!content,
4893
- hasMetrics: !!metrics,
4894
- modelCallsCount: metrics?.modelCalls?.length || 0,
4895
- apiCallsCount: metrics?.apiCalls?.length || 0,
4896
4888
  hasContext: !!config.configurable?.context,
4897
4889
  hasTrace: !!trace,
4898
- traceEvents: trace?.events?.length || 0
4890
+ traceEvents: trace?.events?.length || 0,
4891
+ totalModelCalls: trace?.totalModelCalls || 0
4899
4892
  });
4900
- if (metrics && metrics.modelCalls?.length > 0 && config.configurable?.context) {
4901
- const context = config.configurable.context;
4902
- await this.sendMetricsWebhook({
4903
- messageId: context.messageId || "unknown",
4904
- threadId: context.threadId || "unknown",
4905
- userId: context.userId || "unknown",
4906
- agentId: context.agentId || "unknown",
4907
- companyId: context.companyId || "unknown",
4908
- metrics
4909
- });
4910
- } else {
4911
- this.logger.debug("[METRICS-WEBHOOK] Skipping webhook", {
4912
- hasMetrics: !!metrics,
4913
- modelCallsCount: metrics?.modelCalls?.length || 0,
4914
- hasContext: !!config.configurable?.context
4915
- });
4916
- }
4917
4893
  if (trace && trace.events.length > 0 && config.configurable?.context) {
4918
4894
  const context = config.configurable.context;
4919
4895
  this.logger.debug("[TRACE-WEBHOOK] Sending trace events batch", {
@@ -4957,8 +4933,8 @@ exports.LangGraphEngine = class LangGraphEngine {
4957
4933
  */
4958
4934
  async sendMetricsWebhook(payload) {
4959
4935
  try {
4960
- const backendUrl = this.configService.get("API_URL") || "http://amelie-service";
4961
- const internalToken = this.configService.get("INTERNAL_API_TOKEN");
4936
+ const backendUrl = this.configService?.get("API_URL") || "http://amelie-service";
4937
+ const internalToken = this.configService?.get("INTERNAL_API_TOKEN");
4962
4938
  if (!internalToken) {
4963
4939
  this.logger.warn(
4964
4940
  "[METRICS-WEBHOOK] INTERNAL_API_TOKEN not configured, skipping webhook"
@@ -4997,8 +4973,8 @@ exports.LangGraphEngine = class LangGraphEngine {
4997
4973
  }
4998
4974
  async sendTraceEventsBatch(payload) {
4999
4975
  try {
5000
- const backendUrl = this.configService.get("API_URL") || "http://amelie-service";
5001
- const internalToken = this.configService.get("INTERNAL_API_TOKEN");
4976
+ const backendUrl = this.configService?.get("API_URL") || "http://amelie-service";
4977
+ const internalToken = this.configService?.get("INTERNAL_API_TOKEN");
5002
4978
  if (!internalToken) {
5003
4979
  this.logger.warn(
5004
4980
  "[TRACE-EVENTS-BATCH] INTERNAL_API_TOKEN not configured, skipping batch webhook"
@@ -5080,7 +5056,8 @@ exports.LangGraphEngine = class LangGraphEngine {
5080
5056
  }
5081
5057
  };
5082
5058
  exports.LangGraphEngine = __decorateClass([
5083
- common.Injectable()
5059
+ common.Injectable(),
5060
+ __decorateParam(1, common.Optional())
5084
5061
  ], exports.LangGraphEngine);
5085
5062
 
5086
5063
  // src/core/universal-graph.module.ts
@@ -5156,9 +5133,16 @@ exports.UniversalGraphModule = class UniversalGraphModule {
5156
5133
  // Discovery services from @nestjs/core
5157
5134
  core.MetadataScanner,
5158
5135
  // Event processor for stream handling
5159
- exports.EventProcessor,
5136
+ {
5137
+ provide: exports.EventProcessor,
5138
+ useFactory: () => new exports.EventProcessor()
5139
+ },
5160
5140
  // Graph engines
5161
- exports.LangGraphEngine,
5141
+ {
5142
+ provide: exports.LangGraphEngine,
5143
+ useFactory: (eventProcessor) => new exports.LangGraphEngine(eventProcessor, void 0),
5144
+ inject: [exports.EventProcessor]
5145
+ },
5162
5146
  exports.BuilderRegistryService,
5163
5147
  exports.GraphEngineFactory,
5164
5148
  exports.VersionedGraphService,
@@ -5264,12 +5248,8 @@ exports.UniversalGraphModule = class UniversalGraphModule {
5264
5248
  },
5265
5249
  {
5266
5250
  provide: "GRAPH_ENGINE",
5267
- useFactory: (factory) => {
5268
- return factory.getEngine(
5269
- options.engineType || "langgraph" /* LANGGRAPH */
5270
- );
5271
- },
5272
- inject: [exports.GraphEngineFactory]
5251
+ useFactory: (langGraphEngine) => langGraphEngine,
5252
+ inject: [exports.LangGraphEngine]
5273
5253
  },
5274
5254
  {
5275
5255
  provide: "GRAPH_BUILDERS",
@@ -5389,47 +5369,65 @@ var McpConverter = class _McpConverter {
5389
5369
  mcpRuntimeUrl;
5390
5370
  constructor(mcpRuntimeUrl = "http://localhost:3004") {
5391
5371
  this.mcpRuntimeUrl = mcpRuntimeUrl;
5372
+ this.logger.log(
5373
+ `\u{1F527} McpConverter initialized with SDK version 0.1.8 (manual jsonSchemaToZod)`
5374
+ );
5392
5375
  }
5393
5376
  /**
5394
- * 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
5395
5379
  */
5396
5380
  jsonSchemaToZod(jsonSchema) {
5397
5381
  if (!jsonSchema || typeof jsonSchema !== "object") {
5398
5382
  return zod.z.any();
5399
5383
  }
5400
- if (jsonSchema.type !== "object") {
5401
- return this.mapPrimitiveSchema(jsonSchema.type, true);
5402
- }
5403
- const properties = jsonSchema.properties || {};
5404
- const required = Array.isArray(jsonSchema.required) ? jsonSchema.required : [];
5405
- const zodShape = {};
5406
- for (const [key, prop] of Object.entries(properties)) {
5407
- const propDef = prop;
5408
- const isRequired = required.includes(key);
5409
- const schemaType = propDef?.type ?? "any";
5410
- const mappedType = this.mapPrimitiveSchema(schemaType, isRequired);
5411
- zodShape[key] = mappedType;
5412
- }
5413
- const baseObject = zod.z.object(zodShape);
5414
- const configuredObject = jsonSchema.additionalProperties === false ? baseObject.strict() : baseObject.passthrough();
5415
- return configuredObject;
5416
- }
5417
- mapPrimitiveSchema(type, required) {
5418
- const optionalize = (schema) => required ? schema : schema.optional();
5419
- switch (type) {
5420
- case "string":
5421
- return optionalize(zod.z.string());
5422
- case "number":
5423
- case "integer":
5424
- return optionalize(zod.z.number());
5425
- case "boolean":
5426
- return optionalize(zod.z.boolean());
5427
- case "array":
5428
- return optionalize(zod.z.array(zod.z.any()));
5429
- case "object":
5430
- return optionalize(zod.z.record(zod.z.any()));
5431
- default:
5432
- 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();
5433
5431
  }
5434
5432
  }
5435
5433
  /**
@@ -5438,6 +5436,27 @@ var McpConverter = class _McpConverter {
5438
5436
  convertTool(mcpTool) {
5439
5437
  const logger2 = this.logger;
5440
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
+ }
5441
5460
  const schema = this.jsonSchemaToZod(mcpTool.inputSchema);
5442
5461
  logger2.debug(
5443
5462
  `\u{1F527} [${mcpTool.name}] Original schema:`,
@@ -5446,9 +5465,48 @@ var McpConverter = class _McpConverter {
5446
5465
  logger2.debug(
5447
5466
  `\u{1F527} [${mcpTool.name}] Using schema type: ${schema?._def?.typeName ?? "unknown"}`
5448
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
+ }
5449
5507
  return new tools.DynamicStructuredTool({
5450
5508
  name: mcpTool.name,
5451
- description: mcpTool.description,
5509
+ description: enhancedDescription,
5452
5510
  schema,
5453
5511
  func: async (input) => {
5454
5512
  logger2.log(`\u{1F527} [${mcpTool.name}] LLM INPUT: ${JSON.stringify(input)}`);
@@ -5765,6 +5823,58 @@ exports.McpRuntimeHttpClient = class McpRuntimeHttpClient {
5765
5823
  return false;
5766
5824
  }
5767
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
+ }
5768
5878
  };
5769
5879
  exports.McpRuntimeHttpClient = __decorateClass([
5770
5880
  common.Injectable()