mcp-use 1.3.0-canary.0 → 1.3.0-canary.1

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.
@@ -1319,11 +1319,11 @@ Raw error: ${result}`
1319
1319
 
1320
1320
  // src/agents/mcp_agent.ts
1321
1321
  import {
1322
+ AIMessage,
1322
1323
  createAgent,
1324
+ HumanMessage,
1323
1325
  modelCallLimitMiddleware,
1324
1326
  SystemMessage as SystemMessage2,
1325
- AIMessage,
1326
- HumanMessage,
1327
1327
  ToolMessage
1328
1328
  } from "langchain";
1329
1329
  import { zodToJsonSchema as zodToJsonSchema2 } from "zod-to-json-schema";
@@ -1880,6 +1880,185 @@ var MCPAgent = class {
1880
1880
  return String(value);
1881
1881
  }
1882
1882
  }
1883
+ /**
1884
+ * Check if a message is AI/assistant-like regardless of whether it's a class instance.
1885
+ * Handles version mismatches, serialization boundaries, and different message formats.
1886
+ *
1887
+ * This method solves the issue where messages from LangChain agents may be plain JavaScript
1888
+ * objects (e.g., `{ type: 'ai', content: '...' }`) instead of AIMessage instances due to
1889
+ * serialization/deserialization across module boundaries or version mismatches.
1890
+ *
1891
+ * @example
1892
+ * // Real AIMessage instance (standard case)
1893
+ * _isAIMessageLike(new AIMessage("hello")) // => true
1894
+ *
1895
+ * @example
1896
+ * // Plain object after serialization (fixes issue #446)
1897
+ * _isAIMessageLike({ type: "ai", content: "hello" }) // => true
1898
+ *
1899
+ * @example
1900
+ * // OpenAI-style format with role
1901
+ * _isAIMessageLike({ role: "assistant", content: "hello" }) // => true
1902
+ *
1903
+ * @example
1904
+ * // Object with getType() method
1905
+ * _isAIMessageLike({ getType: () => "ai", content: "hello" }) // => true
1906
+ *
1907
+ * @param message - The message object to check
1908
+ * @returns true if the message represents an AI/assistant message
1909
+ */
1910
+ _isAIMessageLike(message) {
1911
+ if (message instanceof AIMessage) {
1912
+ return true;
1913
+ }
1914
+ if (typeof message !== "object" || message === null) {
1915
+ return false;
1916
+ }
1917
+ const msg = message;
1918
+ if (typeof msg.getType === "function") {
1919
+ try {
1920
+ const type = msg.getType();
1921
+ if (type === "ai" || type === "assistant") {
1922
+ return true;
1923
+ }
1924
+ } catch (error) {
1925
+ }
1926
+ }
1927
+ if (typeof msg._getType === "function") {
1928
+ try {
1929
+ const type = msg._getType();
1930
+ if (type === "ai" || type === "assistant") {
1931
+ return true;
1932
+ }
1933
+ } catch (error) {
1934
+ }
1935
+ }
1936
+ if ("type" in msg) {
1937
+ return msg.type === "ai" || msg.type === "assistant";
1938
+ }
1939
+ if ("role" in msg) {
1940
+ return msg.role === "ai" || msg.role === "assistant";
1941
+ }
1942
+ return false;
1943
+ }
1944
+ /**
1945
+ * Check if a message has tool calls, handling both class instances and plain objects.
1946
+ * Safely checks for tool_calls array presence.
1947
+ *
1948
+ * @example
1949
+ * // AIMessage with tool calls
1950
+ * const msg = new AIMessage({ content: "", tool_calls: [{ name: "add", args: {} }] });
1951
+ * _messageHasToolCalls(msg) // => true
1952
+ *
1953
+ * @example
1954
+ * // Plain object with tool calls
1955
+ * _messageHasToolCalls({ type: "ai", tool_calls: [{ name: "add" }] }) // => true
1956
+ *
1957
+ * @example
1958
+ * // Message without tool calls
1959
+ * _messageHasToolCalls({ type: "ai", content: "hello" }) // => false
1960
+ *
1961
+ * @param message - The message object to check
1962
+ * @returns true if the message has non-empty tool_calls array
1963
+ */
1964
+ _messageHasToolCalls(message) {
1965
+ if (typeof message === "object" && message !== null && "tool_calls" in message && Array.isArray(message.tool_calls)) {
1966
+ return message.tool_calls.length > 0;
1967
+ }
1968
+ return false;
1969
+ }
1970
+ /**
1971
+ * Check if a message is a HumanMessage-like object.
1972
+ * Handles both class instances and plain objects from serialization.
1973
+ *
1974
+ * @example
1975
+ * _isHumanMessageLike(new HumanMessage("hello")) // => true
1976
+ * _isHumanMessageLike({ type: "human", content: "hello" }) // => true
1977
+ *
1978
+ * @param message - The message object to check
1979
+ * @returns true if the message represents a human message
1980
+ */
1981
+ _isHumanMessageLike(message) {
1982
+ if (message instanceof HumanMessage) {
1983
+ return true;
1984
+ }
1985
+ if (typeof message !== "object" || message === null) {
1986
+ return false;
1987
+ }
1988
+ const msg = message;
1989
+ if (typeof msg.getType === "function") {
1990
+ try {
1991
+ const type = msg.getType();
1992
+ if (type === "human" || type === "user") {
1993
+ return true;
1994
+ }
1995
+ } catch (error) {
1996
+ }
1997
+ }
1998
+ if ("type" in msg && (msg.type === "human" || msg.type === "user")) {
1999
+ return true;
2000
+ }
2001
+ if ("role" in msg && (msg.role === "human" || msg.role === "user")) {
2002
+ return true;
2003
+ }
2004
+ return false;
2005
+ }
2006
+ /**
2007
+ * Check if a message is a ToolMessage-like object.
2008
+ * Handles both class instances and plain objects from serialization.
2009
+ *
2010
+ * @example
2011
+ * _isToolMessageLike(new ToolMessage({ content: "result", tool_call_id: "123" })) // => true
2012
+ * _isToolMessageLike({ type: "tool", content: "result" }) // => true
2013
+ *
2014
+ * @param message - The message object to check
2015
+ * @returns true if the message represents a tool message
2016
+ */
2017
+ _isToolMessageLike(message) {
2018
+ if (message instanceof ToolMessage) {
2019
+ return true;
2020
+ }
2021
+ if (typeof message !== "object" || message === null) {
2022
+ return false;
2023
+ }
2024
+ const msg = message;
2025
+ if (typeof msg.getType === "function") {
2026
+ try {
2027
+ const type = msg.getType();
2028
+ if (type === "tool") {
2029
+ return true;
2030
+ }
2031
+ } catch (error) {
2032
+ }
2033
+ }
2034
+ if ("type" in msg && msg.type === "tool") {
2035
+ return true;
2036
+ }
2037
+ return false;
2038
+ }
2039
+ /**
2040
+ * Extract content from a message, handling both AIMessage instances and plain objects.
2041
+ *
2042
+ * @example
2043
+ * // From AIMessage instance
2044
+ * _getMessageContent(new AIMessage("hello")) // => "hello"
2045
+ *
2046
+ * @example
2047
+ * // From plain object
2048
+ * _getMessageContent({ type: "ai", content: "hello" }) // => "hello"
2049
+ *
2050
+ * @param message - The message object to extract content from
2051
+ * @returns The content of the message, or undefined if not present
2052
+ */
2053
+ _getMessageContent(message) {
2054
+ if (message instanceof AIMessage) {
2055
+ return message.content;
2056
+ }
2057
+ if (message && typeof message === "object" && "content" in message) {
2058
+ return message.content;
2059
+ }
2060
+ return void 0;
2061
+ }
1883
2062
  async _consumeAndReturn(generator) {
1884
2063
  while (true) {
1885
2064
  const { done, value } = await generator.next();
@@ -1951,7 +2130,7 @@ var MCPAgent = class {
1951
2130
  const historyToUse = externalHistory ?? this.conversationHistory;
1952
2131
  const langchainHistory = [];
1953
2132
  for (const msg of historyToUse) {
1954
- if (msg instanceof HumanMessage || msg instanceof AIMessage) {
2133
+ if (this._isHumanMessageLike(msg) || this._isAIMessageLike(msg)) {
1955
2134
  langchainHistory.push(msg);
1956
2135
  }
1957
2136
  }
@@ -2020,7 +2199,7 @@ var MCPAgent = class {
2020
2199
  };
2021
2200
  }
2022
2201
  }
2023
- if (message instanceof ToolMessage || message && "type" in message && message.type === "tool") {
2202
+ if (this._isToolMessageLike(message)) {
2024
2203
  const observation = message.content;
2025
2204
  let observationStr = String(observation);
2026
2205
  if (observationStr.length > 100) {
@@ -2055,8 +2234,10 @@ var MCPAgent = class {
2055
2234
  }
2056
2235
  }
2057
2236
  }
2058
- if (message instanceof AIMessage && !("tool_calls" in message && Array.isArray(message.tool_calls) && message.tool_calls.length > 0)) {
2059
- finalOutput = this._normalizeOutput(message.content);
2237
+ if (this._isAIMessageLike(message) && !this._messageHasToolCalls(message)) {
2238
+ finalOutput = this._normalizeOutput(
2239
+ this._getMessageContent(message)
2240
+ );
2060
2241
  logger.info("\u2705 Agent finished with output");
2061
2242
  }
2062
2243
  }
@@ -2239,10 +2420,12 @@ var MCPAgent = class {
2239
2420
  const historyToUse = externalHistory ?? this.conversationHistory;
2240
2421
  const langchainHistory = [];
2241
2422
  for (const msg of historyToUse) {
2242
- if (msg instanceof HumanMessage || msg instanceof AIMessage || msg instanceof ToolMessage) {
2423
+ if (this._isHumanMessageLike(msg) || this._isAIMessageLike(msg) || this._isToolMessageLike(msg)) {
2243
2424
  langchainHistory.push(msg);
2244
2425
  } else {
2245
- logger.info(`\u26A0\uFE0F Skipped message of type: ${msg.constructor.name}`);
2426
+ logger.info(
2427
+ `\u26A0\uFE0F Skipped message of type: ${msg.constructor?.name || typeof msg}`
2428
+ );
2246
2429
  }
2247
2430
  }
2248
2431
  const inputs = [
package/dist/index.cjs CHANGED
@@ -2488,6 +2488,185 @@ var MCPAgent = class {
2488
2488
  return String(value);
2489
2489
  }
2490
2490
  }
2491
+ /**
2492
+ * Check if a message is AI/assistant-like regardless of whether it's a class instance.
2493
+ * Handles version mismatches, serialization boundaries, and different message formats.
2494
+ *
2495
+ * This method solves the issue where messages from LangChain agents may be plain JavaScript
2496
+ * objects (e.g., `{ type: 'ai', content: '...' }`) instead of AIMessage instances due to
2497
+ * serialization/deserialization across module boundaries or version mismatches.
2498
+ *
2499
+ * @example
2500
+ * // Real AIMessage instance (standard case)
2501
+ * _isAIMessageLike(new AIMessage("hello")) // => true
2502
+ *
2503
+ * @example
2504
+ * // Plain object after serialization (fixes issue #446)
2505
+ * _isAIMessageLike({ type: "ai", content: "hello" }) // => true
2506
+ *
2507
+ * @example
2508
+ * // OpenAI-style format with role
2509
+ * _isAIMessageLike({ role: "assistant", content: "hello" }) // => true
2510
+ *
2511
+ * @example
2512
+ * // Object with getType() method
2513
+ * _isAIMessageLike({ getType: () => "ai", content: "hello" }) // => true
2514
+ *
2515
+ * @param message - The message object to check
2516
+ * @returns true if the message represents an AI/assistant message
2517
+ */
2518
+ _isAIMessageLike(message) {
2519
+ if (message instanceof import_langchain2.AIMessage) {
2520
+ return true;
2521
+ }
2522
+ if (typeof message !== "object" || message === null) {
2523
+ return false;
2524
+ }
2525
+ const msg = message;
2526
+ if (typeof msg.getType === "function") {
2527
+ try {
2528
+ const type = msg.getType();
2529
+ if (type === "ai" || type === "assistant") {
2530
+ return true;
2531
+ }
2532
+ } catch (error) {
2533
+ }
2534
+ }
2535
+ if (typeof msg._getType === "function") {
2536
+ try {
2537
+ const type = msg._getType();
2538
+ if (type === "ai" || type === "assistant") {
2539
+ return true;
2540
+ }
2541
+ } catch (error) {
2542
+ }
2543
+ }
2544
+ if ("type" in msg) {
2545
+ return msg.type === "ai" || msg.type === "assistant";
2546
+ }
2547
+ if ("role" in msg) {
2548
+ return msg.role === "ai" || msg.role === "assistant";
2549
+ }
2550
+ return false;
2551
+ }
2552
+ /**
2553
+ * Check if a message has tool calls, handling both class instances and plain objects.
2554
+ * Safely checks for tool_calls array presence.
2555
+ *
2556
+ * @example
2557
+ * // AIMessage with tool calls
2558
+ * const msg = new AIMessage({ content: "", tool_calls: [{ name: "add", args: {} }] });
2559
+ * _messageHasToolCalls(msg) // => true
2560
+ *
2561
+ * @example
2562
+ * // Plain object with tool calls
2563
+ * _messageHasToolCalls({ type: "ai", tool_calls: [{ name: "add" }] }) // => true
2564
+ *
2565
+ * @example
2566
+ * // Message without tool calls
2567
+ * _messageHasToolCalls({ type: "ai", content: "hello" }) // => false
2568
+ *
2569
+ * @param message - The message object to check
2570
+ * @returns true if the message has non-empty tool_calls array
2571
+ */
2572
+ _messageHasToolCalls(message) {
2573
+ if (typeof message === "object" && message !== null && "tool_calls" in message && Array.isArray(message.tool_calls)) {
2574
+ return message.tool_calls.length > 0;
2575
+ }
2576
+ return false;
2577
+ }
2578
+ /**
2579
+ * Check if a message is a HumanMessage-like object.
2580
+ * Handles both class instances and plain objects from serialization.
2581
+ *
2582
+ * @example
2583
+ * _isHumanMessageLike(new HumanMessage("hello")) // => true
2584
+ * _isHumanMessageLike({ type: "human", content: "hello" }) // => true
2585
+ *
2586
+ * @param message - The message object to check
2587
+ * @returns true if the message represents a human message
2588
+ */
2589
+ _isHumanMessageLike(message) {
2590
+ if (message instanceof import_langchain2.HumanMessage) {
2591
+ return true;
2592
+ }
2593
+ if (typeof message !== "object" || message === null) {
2594
+ return false;
2595
+ }
2596
+ const msg = message;
2597
+ if (typeof msg.getType === "function") {
2598
+ try {
2599
+ const type = msg.getType();
2600
+ if (type === "human" || type === "user") {
2601
+ return true;
2602
+ }
2603
+ } catch (error) {
2604
+ }
2605
+ }
2606
+ if ("type" in msg && (msg.type === "human" || msg.type === "user")) {
2607
+ return true;
2608
+ }
2609
+ if ("role" in msg && (msg.role === "human" || msg.role === "user")) {
2610
+ return true;
2611
+ }
2612
+ return false;
2613
+ }
2614
+ /**
2615
+ * Check if a message is a ToolMessage-like object.
2616
+ * Handles both class instances and plain objects from serialization.
2617
+ *
2618
+ * @example
2619
+ * _isToolMessageLike(new ToolMessage({ content: "result", tool_call_id: "123" })) // => true
2620
+ * _isToolMessageLike({ type: "tool", content: "result" }) // => true
2621
+ *
2622
+ * @param message - The message object to check
2623
+ * @returns true if the message represents a tool message
2624
+ */
2625
+ _isToolMessageLike(message) {
2626
+ if (message instanceof import_langchain2.ToolMessage) {
2627
+ return true;
2628
+ }
2629
+ if (typeof message !== "object" || message === null) {
2630
+ return false;
2631
+ }
2632
+ const msg = message;
2633
+ if (typeof msg.getType === "function") {
2634
+ try {
2635
+ const type = msg.getType();
2636
+ if (type === "tool") {
2637
+ return true;
2638
+ }
2639
+ } catch (error) {
2640
+ }
2641
+ }
2642
+ if ("type" in msg && msg.type === "tool") {
2643
+ return true;
2644
+ }
2645
+ return false;
2646
+ }
2647
+ /**
2648
+ * Extract content from a message, handling both AIMessage instances and plain objects.
2649
+ *
2650
+ * @example
2651
+ * // From AIMessage instance
2652
+ * _getMessageContent(new AIMessage("hello")) // => "hello"
2653
+ *
2654
+ * @example
2655
+ * // From plain object
2656
+ * _getMessageContent({ type: "ai", content: "hello" }) // => "hello"
2657
+ *
2658
+ * @param message - The message object to extract content from
2659
+ * @returns The content of the message, or undefined if not present
2660
+ */
2661
+ _getMessageContent(message) {
2662
+ if (message instanceof import_langchain2.AIMessage) {
2663
+ return message.content;
2664
+ }
2665
+ if (message && typeof message === "object" && "content" in message) {
2666
+ return message.content;
2667
+ }
2668
+ return void 0;
2669
+ }
2491
2670
  async _consumeAndReturn(generator) {
2492
2671
  while (true) {
2493
2672
  const { done, value } = await generator.next();
@@ -2559,7 +2738,7 @@ var MCPAgent = class {
2559
2738
  const historyToUse = externalHistory ?? this.conversationHistory;
2560
2739
  const langchainHistory = [];
2561
2740
  for (const msg of historyToUse) {
2562
- if (msg instanceof import_langchain2.HumanMessage || msg instanceof import_langchain2.AIMessage) {
2741
+ if (this._isHumanMessageLike(msg) || this._isAIMessageLike(msg)) {
2563
2742
  langchainHistory.push(msg);
2564
2743
  }
2565
2744
  }
@@ -2628,7 +2807,7 @@ var MCPAgent = class {
2628
2807
  };
2629
2808
  }
2630
2809
  }
2631
- if (message instanceof import_langchain2.ToolMessage || message && "type" in message && message.type === "tool") {
2810
+ if (this._isToolMessageLike(message)) {
2632
2811
  const observation = message.content;
2633
2812
  let observationStr = String(observation);
2634
2813
  if (observationStr.length > 100) {
@@ -2663,8 +2842,10 @@ var MCPAgent = class {
2663
2842
  }
2664
2843
  }
2665
2844
  }
2666
- if (message instanceof import_langchain2.AIMessage && !("tool_calls" in message && Array.isArray(message.tool_calls) && message.tool_calls.length > 0)) {
2667
- finalOutput = this._normalizeOutput(message.content);
2845
+ if (this._isAIMessageLike(message) && !this._messageHasToolCalls(message)) {
2846
+ finalOutput = this._normalizeOutput(
2847
+ this._getMessageContent(message)
2848
+ );
2668
2849
  logger.info("\u2705 Agent finished with output");
2669
2850
  }
2670
2851
  }
@@ -2847,10 +3028,12 @@ var MCPAgent = class {
2847
3028
  const historyToUse = externalHistory ?? this.conversationHistory;
2848
3029
  const langchainHistory = [];
2849
3030
  for (const msg of historyToUse) {
2850
- if (msg instanceof import_langchain2.HumanMessage || msg instanceof import_langchain2.AIMessage || msg instanceof import_langchain2.ToolMessage) {
3031
+ if (this._isHumanMessageLike(msg) || this._isAIMessageLike(msg) || this._isToolMessageLike(msg)) {
2851
3032
  langchainHistory.push(msg);
2852
3033
  } else {
2853
- logger.info(`\u26A0\uFE0F Skipped message of type: ${msg.constructor.name}`);
3034
+ logger.info(
3035
+ `\u26A0\uFE0F Skipped message of type: ${msg.constructor?.name || typeof msg}`
3036
+ );
2854
3037
  }
2855
3038
  }
2856
3039
  const inputs = [
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  ServerManager,
18
18
  Telemetry,
19
19
  setTelemetrySource
20
- } from "./chunk-73SH52J2.js";
20
+ } from "./chunk-6EHM3S3M.js";
21
21
  import {
22
22
  useMcp,
23
23
  useWidget,