@librechat/agents 3.0.0-rc9 → 3.0.0

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.
Files changed (195) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +6 -2
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +23 -2
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs +5 -5
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/instrumentation.cjs +21 -0
  8. package/dist/cjs/instrumentation.cjs.map +1 -0
  9. package/dist/cjs/llm/anthropic/index.cjs +21 -2
  10. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  11. package/dist/cjs/llm/google/index.cjs +3 -0
  12. package/dist/cjs/llm/google/index.cjs.map +1 -1
  13. package/dist/cjs/llm/google/utils/common.cjs +13 -0
  14. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  15. package/dist/cjs/llm/ollama/index.cjs +3 -0
  16. package/dist/cjs/llm/ollama/index.cjs.map +1 -1
  17. package/dist/cjs/llm/openai/index.cjs +18 -3
  18. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  19. package/dist/cjs/llm/openai/utils/index.cjs +6 -1
  20. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  21. package/dist/cjs/llm/openrouter/index.cjs +5 -1
  22. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  23. package/dist/cjs/llm/vertexai/index.cjs +1 -1
  24. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  25. package/dist/cjs/main.cjs +8 -2
  26. package/dist/cjs/main.cjs.map +1 -1
  27. package/dist/cjs/messages/cache.cjs +49 -0
  28. package/dist/cjs/messages/cache.cjs.map +1 -0
  29. package/dist/cjs/messages/content.cjs +53 -0
  30. package/dist/cjs/messages/content.cjs.map +1 -0
  31. package/dist/cjs/messages/core.cjs +5 -1
  32. package/dist/cjs/messages/core.cjs.map +1 -1
  33. package/dist/cjs/messages/format.cjs +50 -59
  34. package/dist/cjs/messages/format.cjs.map +1 -1
  35. package/dist/cjs/messages/prune.cjs +28 -0
  36. package/dist/cjs/messages/prune.cjs.map +1 -1
  37. package/dist/cjs/run.cjs +57 -5
  38. package/dist/cjs/run.cjs.map +1 -1
  39. package/dist/cjs/stream.cjs +7 -0
  40. package/dist/cjs/stream.cjs.map +1 -1
  41. package/dist/cjs/tools/ToolNode.cjs +2 -0
  42. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  43. package/dist/cjs/tools/search/firecrawl.cjs +3 -1
  44. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  45. package/dist/cjs/tools/search/rerankers.cjs +8 -6
  46. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  47. package/dist/cjs/tools/search/search.cjs +5 -5
  48. package/dist/cjs/tools/search/search.cjs.map +1 -1
  49. package/dist/cjs/tools/search/serper-scraper.cjs +132 -0
  50. package/dist/cjs/tools/search/serper-scraper.cjs.map +1 -0
  51. package/dist/cjs/tools/search/tool.cjs +46 -9
  52. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  53. package/dist/cjs/utils/handlers.cjs +70 -0
  54. package/dist/cjs/utils/handlers.cjs.map +1 -0
  55. package/dist/cjs/utils/misc.cjs +8 -1
  56. package/dist/cjs/utils/misc.cjs.map +1 -1
  57. package/dist/cjs/utils/title.cjs +54 -25
  58. package/dist/cjs/utils/title.cjs.map +1 -1
  59. package/dist/esm/agents/AgentContext.mjs +6 -2
  60. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  61. package/dist/esm/graphs/Graph.mjs +23 -2
  62. package/dist/esm/graphs/Graph.mjs.map +1 -1
  63. package/dist/esm/graphs/MultiAgentGraph.mjs +5 -5
  64. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  65. package/dist/esm/instrumentation.mjs +19 -0
  66. package/dist/esm/instrumentation.mjs.map +1 -0
  67. package/dist/esm/llm/anthropic/index.mjs +21 -2
  68. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  69. package/dist/esm/llm/google/index.mjs +3 -0
  70. package/dist/esm/llm/google/index.mjs.map +1 -1
  71. package/dist/esm/llm/google/utils/common.mjs +13 -0
  72. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  73. package/dist/esm/llm/ollama/index.mjs +3 -0
  74. package/dist/esm/llm/ollama/index.mjs.map +1 -1
  75. package/dist/esm/llm/openai/index.mjs +18 -3
  76. package/dist/esm/llm/openai/index.mjs.map +1 -1
  77. package/dist/esm/llm/openai/utils/index.mjs +6 -1
  78. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  79. package/dist/esm/llm/openrouter/index.mjs +5 -1
  80. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  81. package/dist/esm/llm/vertexai/index.mjs +1 -1
  82. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  83. package/dist/esm/main.mjs +5 -2
  84. package/dist/esm/main.mjs.map +1 -1
  85. package/dist/esm/messages/cache.mjs +47 -0
  86. package/dist/esm/messages/cache.mjs.map +1 -0
  87. package/dist/esm/messages/content.mjs +51 -0
  88. package/dist/esm/messages/content.mjs.map +1 -0
  89. package/dist/esm/messages/core.mjs +5 -1
  90. package/dist/esm/messages/core.mjs.map +1 -1
  91. package/dist/esm/messages/format.mjs +50 -58
  92. package/dist/esm/messages/format.mjs.map +1 -1
  93. package/dist/esm/messages/prune.mjs +28 -0
  94. package/dist/esm/messages/prune.mjs.map +1 -1
  95. package/dist/esm/run.mjs +57 -5
  96. package/dist/esm/run.mjs.map +1 -1
  97. package/dist/esm/stream.mjs +7 -0
  98. package/dist/esm/stream.mjs.map +1 -1
  99. package/dist/esm/tools/ToolNode.mjs +2 -0
  100. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  101. package/dist/esm/tools/search/firecrawl.mjs +3 -1
  102. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  103. package/dist/esm/tools/search/rerankers.mjs +8 -6
  104. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  105. package/dist/esm/tools/search/search.mjs +5 -5
  106. package/dist/esm/tools/search/search.mjs.map +1 -1
  107. package/dist/esm/tools/search/serper-scraper.mjs +129 -0
  108. package/dist/esm/tools/search/serper-scraper.mjs.map +1 -0
  109. package/dist/esm/tools/search/tool.mjs +46 -9
  110. package/dist/esm/tools/search/tool.mjs.map +1 -1
  111. package/dist/esm/utils/handlers.mjs +68 -0
  112. package/dist/esm/utils/handlers.mjs.map +1 -0
  113. package/dist/esm/utils/misc.mjs +8 -2
  114. package/dist/esm/utils/misc.mjs.map +1 -1
  115. package/dist/esm/utils/title.mjs +54 -25
  116. package/dist/esm/utils/title.mjs.map +1 -1
  117. package/dist/types/agents/AgentContext.d.ts +4 -1
  118. package/dist/types/instrumentation.d.ts +1 -0
  119. package/dist/types/llm/anthropic/index.d.ts +3 -0
  120. package/dist/types/llm/google/index.d.ts +1 -0
  121. package/dist/types/llm/ollama/index.d.ts +1 -0
  122. package/dist/types/llm/openai/index.d.ts +4 -0
  123. package/dist/types/llm/openrouter/index.d.ts +4 -2
  124. package/dist/types/llm/vertexai/index.d.ts +1 -1
  125. package/dist/types/messages/cache.d.ts +8 -0
  126. package/dist/types/messages/content.d.ts +7 -0
  127. package/dist/types/messages/format.d.ts +22 -25
  128. package/dist/types/messages/index.d.ts +2 -0
  129. package/dist/types/run.d.ts +2 -1
  130. package/dist/types/tools/search/firecrawl.d.ts +2 -1
  131. package/dist/types/tools/search/rerankers.d.ts +4 -1
  132. package/dist/types/tools/search/search.d.ts +1 -2
  133. package/dist/types/tools/search/serper-scraper.d.ts +59 -0
  134. package/dist/types/tools/search/tool.d.ts +25 -4
  135. package/dist/types/tools/search/types.d.ts +31 -1
  136. package/dist/types/types/graph.d.ts +3 -1
  137. package/dist/types/types/messages.d.ts +4 -0
  138. package/dist/types/utils/handlers.d.ts +34 -0
  139. package/dist/types/utils/index.d.ts +1 -0
  140. package/dist/types/utils/misc.d.ts +1 -0
  141. package/package.json +6 -2
  142. package/src/agents/AgentContext.ts +8 -0
  143. package/src/graphs/Graph.ts +31 -2
  144. package/src/graphs/MultiAgentGraph.ts +5 -5
  145. package/src/instrumentation.ts +22 -0
  146. package/src/llm/anthropic/index.ts +23 -2
  147. package/src/llm/anthropic/llm.spec.ts +1 -1
  148. package/src/llm/google/index.ts +4 -0
  149. package/src/llm/google/utils/common.ts +14 -0
  150. package/src/llm/ollama/index.ts +3 -0
  151. package/src/llm/openai/index.ts +17 -4
  152. package/src/llm/openai/utils/index.ts +7 -1
  153. package/src/llm/openrouter/index.ts +15 -6
  154. package/src/llm/vertexai/index.ts +2 -2
  155. package/src/messages/cache.test.ts +262 -0
  156. package/src/messages/cache.ts +56 -0
  157. package/src/messages/content.test.ts +362 -0
  158. package/src/messages/content.ts +63 -0
  159. package/src/messages/core.ts +5 -2
  160. package/src/messages/format.ts +65 -71
  161. package/src/messages/formatMessage.test.ts +418 -2
  162. package/src/messages/index.ts +2 -0
  163. package/src/messages/prune.ts +51 -0
  164. package/src/run.ts +82 -10
  165. package/src/scripts/ant_web_search.ts +1 -1
  166. package/src/scripts/handoff-test.ts +1 -1
  167. package/src/scripts/multi-agent-chain.ts +4 -4
  168. package/src/scripts/multi-agent-conditional.ts +4 -4
  169. package/src/scripts/multi-agent-document-review-chain.ts +4 -4
  170. package/src/scripts/multi-agent-parallel.ts +10 -8
  171. package/src/scripts/multi-agent-sequence.ts +3 -3
  172. package/src/scripts/multi-agent-supervisor.ts +5 -3
  173. package/src/scripts/multi-agent-test.ts +2 -2
  174. package/src/scripts/search.ts +5 -1
  175. package/src/scripts/simple.ts +8 -0
  176. package/src/scripts/test-custom-prompt-key.ts +4 -4
  177. package/src/scripts/test-handoff-input.ts +3 -3
  178. package/src/scripts/test-multi-agent-list-handoff.ts +2 -2
  179. package/src/scripts/tools.ts +4 -1
  180. package/src/specs/agent-handoffs.test.ts +889 -0
  181. package/src/stream.ts +9 -2
  182. package/src/tools/search/firecrawl.ts +5 -2
  183. package/src/tools/search/jina-reranker.test.ts +126 -0
  184. package/src/tools/search/rerankers.ts +11 -5
  185. package/src/tools/search/search.ts +6 -8
  186. package/src/tools/search/serper-scraper.ts +155 -0
  187. package/src/tools/search/tool.ts +49 -8
  188. package/src/tools/search/types.ts +46 -0
  189. package/src/types/graph.ts +6 -1
  190. package/src/types/messages.ts +4 -0
  191. package/src/utils/handlers.ts +107 -0
  192. package/src/utils/index.ts +2 -1
  193. package/src/utils/llmConfig.ts +35 -1
  194. package/src/utils/misc.ts +33 -21
  195. package/src/utils/title.ts +80 -40
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Multi-Agent Handler Utilities
3
+ *
4
+ * Provides a simple helper to create handlers with content aggregation for multi-agent scripts.
5
+ *
6
+ * Usage:
7
+ * ```typescript
8
+ * const { contentParts, aggregateContent, handlers } = createHandlers();
9
+ *
10
+ * // With callbacks
11
+ * const { contentParts, aggregateContent, handlers } = createHandlers({
12
+ * onRunStep: (event, data) => console.log('Step:', data),
13
+ * onRunStepCompleted: (event, data) => console.log('Completed:', data)
14
+ * });
15
+ * ```
16
+ */
17
+
18
+ import { GraphEvents } from '@/common';
19
+ import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
20
+ import { ToolEndHandler, ModelEndHandler } from '@/events';
21
+ import type * as t from '@/types';
22
+
23
+ interface HandlerCallbacks {
24
+ onRunStep?: (event: GraphEvents.ON_RUN_STEP, data: t.StreamEventData) => void;
25
+ onRunStepCompleted?: (
26
+ event: GraphEvents.ON_RUN_STEP_COMPLETED,
27
+ data: t.StreamEventData
28
+ ) => void;
29
+ onRunStepDelta?: (
30
+ event: GraphEvents.ON_RUN_STEP_DELTA,
31
+ data: t.StreamEventData
32
+ ) => void;
33
+ onMessageDelta?: (
34
+ event: GraphEvents.ON_MESSAGE_DELTA,
35
+ data: t.StreamEventData
36
+ ) => void;
37
+ }
38
+
39
+ /**
40
+ * Creates handlers with content aggregation for multi-agent scripts
41
+ */
42
+ export function createHandlers(callbacks?: HandlerCallbacks): {
43
+ contentParts: Array<t.MessageContentComplex | undefined>;
44
+ aggregateContent: ReturnType<
45
+ typeof createContentAggregator
46
+ >['aggregateContent'];
47
+ handlers: Record<string, t.EventHandler>;
48
+ } {
49
+ // Set up content aggregator
50
+ const { contentParts, aggregateContent } = createContentAggregator();
51
+
52
+ // Create the handlers object
53
+ const handlers = {
54
+ [GraphEvents.TOOL_END]: new ToolEndHandler(),
55
+ [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
56
+ [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
57
+
58
+ [GraphEvents.ON_RUN_STEP]: {
59
+ handle: (
60
+ event: GraphEvents.ON_RUN_STEP,
61
+ data: t.StreamEventData
62
+ ): void => {
63
+ aggregateContent({ event, data: data as t.RunStep });
64
+ callbacks?.onRunStep?.(event, data);
65
+ },
66
+ },
67
+
68
+ [GraphEvents.ON_RUN_STEP_COMPLETED]: {
69
+ handle: (
70
+ event: GraphEvents.ON_RUN_STEP_COMPLETED,
71
+ data: t.StreamEventData
72
+ ): void => {
73
+ aggregateContent({
74
+ event,
75
+ data: data as unknown as { result: t.ToolEndEvent },
76
+ });
77
+ callbacks?.onRunStepCompleted?.(event, data);
78
+ },
79
+ },
80
+
81
+ [GraphEvents.ON_RUN_STEP_DELTA]: {
82
+ handle: (
83
+ event: GraphEvents.ON_RUN_STEP_DELTA,
84
+ data: t.StreamEventData
85
+ ): void => {
86
+ aggregateContent({ event, data: data as t.RunStepDeltaEvent });
87
+ callbacks?.onRunStepDelta?.(event, data);
88
+ },
89
+ },
90
+
91
+ [GraphEvents.ON_MESSAGE_DELTA]: {
92
+ handle: (
93
+ event: GraphEvents.ON_MESSAGE_DELTA,
94
+ data: t.StreamEventData
95
+ ): void => {
96
+ aggregateContent({ event, data: data as t.MessageDeltaEvent });
97
+ callbacks?.onMessageDelta?.(event, data);
98
+ },
99
+ },
100
+ };
101
+
102
+ return {
103
+ contentParts,
104
+ aggregateContent,
105
+ handlers,
106
+ };
107
+ }
@@ -1,5 +1,6 @@
1
1
  export * from './graph';
2
2
  export * from './llm';
3
3
  export * from './misc';
4
+ export * from './handlers';
4
5
  export * from './run';
5
- export * from './tokens';
6
+ export * from './tokens';
@@ -12,6 +12,30 @@ export const llmConfigs: Record<string, t.LLMConfig | undefined> = {
12
12
  streamUsage: true,
13
13
  // disableStreaming: true,
14
14
  },
15
+ anthropicLITELLM: {
16
+ provider: Providers.OPENAI,
17
+ streaming: true,
18
+ streamUsage: false,
19
+ apiKey: 'sk-1234',
20
+ model: 'claude-sonnet-4',
21
+ maxTokens: 8192,
22
+ modelKwargs: {
23
+ metadata: {
24
+ user_id: 'some_user_id',
25
+ },
26
+ thinking: {
27
+ type: 'enabled',
28
+ budget_tokens: 2000,
29
+ },
30
+ },
31
+ configuration: {
32
+ baseURL: 'http://host.docker.internal:4000/v1',
33
+ defaultHeaders: {
34
+ 'anthropic-beta': 'prompt-caching-2024-07-31,context-1m-2025-08-07',
35
+ },
36
+ },
37
+ // disableStreaming: true,
38
+ },
15
39
  [Providers.XAI]: {
16
40
  provider: Providers.XAI,
17
41
  model: 'grok-2-latest',
@@ -70,6 +94,16 @@ export const llmConfigs: Record<string, t.LLMConfig | undefined> = {
70
94
  baseURL: 'http://192.168.254.183:1233/v1',
71
95
  },
72
96
  },
97
+ zhipu: {
98
+ provider: Providers.OPENAI,
99
+ streaming: true,
100
+ streamUsage: false,
101
+ model: 'glm-4.5-air',
102
+ apiKey: process.env.ZHIPU_API_KEY,
103
+ configuration: {
104
+ baseURL: 'https://open.bigmodel.cn/api/paas/v4',
105
+ },
106
+ },
73
107
  [Providers.DEEPSEEK]: {
74
108
  provider: Providers.DEEPSEEK,
75
109
  model: 'deepseek-reasoner',
@@ -78,7 +112,7 @@ export const llmConfigs: Record<string, t.LLMConfig | undefined> = {
78
112
  },
79
113
  [Providers.ANTHROPIC]: {
80
114
  provider: Providers.ANTHROPIC,
81
- model: 'claude-3-5-sonnet-20240620',
115
+ model: 'claude-sonnet-4-5',
82
116
  streaming: true,
83
117
  streamUsage: true,
84
118
  },
package/src/utils/misc.ts CHANGED
@@ -1,26 +1,31 @@
1
+ export function isPresent(value: string | null | undefined): value is string {
2
+ return value != null && value !== '';
3
+ }
4
+
1
5
  /**
2
6
  * Unescapes a c-escaped string
3
7
  * @param str The string to unescape
4
8
  * @returns The unescaped string
5
9
  */
6
- const unescapeString = (string: string): string => string.replace(/\\(.)/g, (_, char) => {
7
- switch (char) {
8
- case 'n':
9
- return '\n';
10
- case 't':
11
- return '\t';
12
- case 'r':
13
- return '\r';
14
- case '"':
15
- return '"';
16
- case '\'':
17
- return '\'';
18
- case '\\':
19
- return '\\';
20
- default:
21
- return char;
22
- }
23
- });
10
+ const unescapeString = (string: string): string =>
11
+ string.replace(/\\(.)/g, (_, char) => {
12
+ switch (char) {
13
+ case 'n':
14
+ return '\n';
15
+ case 't':
16
+ return '\t';
17
+ case 'r':
18
+ return '\r';
19
+ case '"':
20
+ return '"';
21
+ case '\'':
22
+ return '\'';
23
+ case '\\':
24
+ return '\\';
25
+ default:
26
+ return char;
27
+ }
28
+ });
24
29
 
25
30
  /**
26
31
  * Recursively unescapes all string values in an object
@@ -36,10 +41,17 @@ export function unescapeObject(obj: unknown, key?: string): unknown {
36
41
  return unescaped;
37
42
  }
38
43
  if (Array.isArray(obj)) {
39
- return obj.map((value) => unescapeObject(value, key === 'contextPaths' ? 'filePath' : ''));
44
+ return obj.map((value) =>
45
+ unescapeObject(value, key === 'contextPaths' ? 'filePath' : '')
46
+ );
40
47
  }
41
48
  if (typeof obj === 'object' && obj !== null) {
42
- return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, unescapeObject(value, key)]));
49
+ return Object.fromEntries(
50
+ Object.entries(obj).map(([key, value]) => [
51
+ key,
52
+ unescapeObject(value, key),
53
+ ])
54
+ );
43
55
  }
44
56
  return obj;
45
- }
57
+ }
@@ -1,7 +1,8 @@
1
1
  import { z } from 'zod';
2
- import { RunnableLambda } from '@langchain/core/runnables';
3
2
  import { ChatPromptTemplate } from '@langchain/core/prompts';
3
+ import { RunnableLambda, RunnableSequence } from '@langchain/core/runnables';
4
4
  import type { Runnable, RunnableConfig } from '@langchain/core/runnables';
5
+ import type { AIMessage } from '@langchain/core/messages';
5
6
  import type * as t from '@/types';
6
7
  import { ContentTypes } from '@/common';
7
8
 
@@ -42,7 +43,55 @@ export const createTitleRunnable = async (
42
43
 
43
44
  const titlePrompt = ChatPromptTemplate.fromTemplate(
44
45
  _titlePrompt ?? defaultTitlePrompt
45
- );
46
+ ).withConfig({ runName: 'TitlePrompt' });
47
+
48
+ const titleOnlyInnerChain = RunnableSequence.from([titlePrompt, titleLLM]);
49
+ const combinedInnerChain = RunnableSequence.from([titlePrompt, combinedLLM]);
50
+
51
+ /** Wrap titleOnlyChain in RunnableLambda to create parent span */
52
+ const titleOnlyChain = new RunnableLambda({
53
+ func: async (
54
+ input: { convo: string },
55
+ config?: Partial<RunnableConfig>
56
+ ): Promise<{ title: string }> => {
57
+ return await titleOnlyInnerChain.invoke(input, config);
58
+ },
59
+ }).withConfig({ runName: 'TitleOnlyChain' });
60
+
61
+ /** Wrap combinedChain in RunnableLambda to create parent span */
62
+ const combinedChain = new RunnableLambda({
63
+ func: async (
64
+ input: { convo: string },
65
+ config?: Partial<RunnableConfig>
66
+ ): Promise<{ language: string; title: string }> => {
67
+ return await combinedInnerChain.invoke(input, config);
68
+ },
69
+ }).withConfig({ runName: 'TitleLanguageChain' });
70
+
71
+ /** Runnable to add default values if needed */
72
+ const addDefaults = new RunnableLambda({
73
+ func: (
74
+ result: { language: string; title: string } | undefined
75
+ ): { language: string; title: string } => ({
76
+ language: result?.language ?? 'English',
77
+ title: result?.title ?? '',
78
+ }),
79
+ }).withConfig({ runName: 'AddDefaults' });
80
+
81
+ const combinedChainInner = RunnableSequence.from([
82
+ combinedChain,
83
+ addDefaults,
84
+ ]);
85
+
86
+ /** Wrap combinedChainWithDefaults in RunnableLambda to create parent span */
87
+ const combinedChainWithDefaults = new RunnableLambda({
88
+ func: async (
89
+ input: { convo: string },
90
+ config?: Partial<RunnableConfig>
91
+ ): Promise<{ language: string; title: string }> => {
92
+ return await combinedChainInner.invoke(input, config);
93
+ },
94
+ }).withConfig({ runName: 'CombinedChainWithDefaults' });
46
95
 
47
96
  return new RunnableLambda({
48
97
  func: async (
@@ -53,28 +102,17 @@ export const createTitleRunnable = async (
53
102
  },
54
103
  config?: Partial<RunnableConfig>
55
104
  ): Promise<{ language: string; title: string } | { title: string }> => {
105
+ const invokeInput = { convo: input.convo };
106
+
56
107
  if (input.skipLanguage) {
57
- return (await titlePrompt.pipe(titleLLM).invoke(
58
- {
59
- convo: input.convo,
60
- },
61
- config
62
- )) as { title: string };
108
+ return (await titleOnlyChain.invoke(invokeInput, config)) as {
109
+ title: string;
110
+ };
63
111
  }
64
112
 
65
- const result = (await titlePrompt.pipe(combinedLLM).invoke(
66
- {
67
- convo: input.convo,
68
- },
69
- config
70
- )) as { language: string; title: string } | undefined;
71
-
72
- return {
73
- language: result?.language ?? 'English',
74
- title: result?.title ?? '',
75
- };
113
+ return await combinedChainWithDefaults.invoke(invokeInput, config);
76
114
  },
77
- });
115
+ }).withConfig({ runName: 'TitleGenerator' });
78
116
  };
79
117
 
80
118
  const defaultCompletionPrompt = `Provide a concise, 5-word-or-less title for the conversation, using title case conventions. Only return the title itself.
@@ -88,22 +126,11 @@ export const createCompletionTitleRunnable = async (
88
126
  ): Promise<Runnable> => {
89
127
  const completionPrompt = ChatPromptTemplate.fromTemplate(
90
128
  titlePrompt ?? defaultCompletionPrompt
91
- );
129
+ ).withConfig({ runName: 'CompletionTitlePrompt' });
92
130
 
93
- return new RunnableLambda({
94
- func: async (
95
- input: {
96
- convo: string;
97
- inputText: string;
98
- skipLanguage: boolean;
99
- },
100
- config?: Partial<RunnableConfig>
101
- ): Promise<{ title: string }> => {
102
- const promptOutput = await completionPrompt.invoke({
103
- convo: input.convo,
104
- });
105
-
106
- const response = await model.invoke(promptOutput, config);
131
+ /** Runnable to extract content from model response */
132
+ const extractContent = new RunnableLambda({
133
+ func: (response: AIMessage): { title: string } => {
107
134
  let content = '';
108
135
  if (typeof response.content === 'string') {
109
136
  content = response.content;
@@ -116,10 +143,23 @@ export const createCompletionTitleRunnable = async (
116
143
  .map((part) => part.text)
117
144
  .join('');
118
145
  }
119
- const title = content.trim();
120
- return {
121
- title,
122
- };
146
+ return { title: content.trim() };
147
+ },
148
+ }).withConfig({ runName: 'ExtractTitle' });
149
+
150
+ const innerChain = RunnableSequence.from([
151
+ completionPrompt,
152
+ model,
153
+ extractContent,
154
+ ]);
155
+
156
+ /** Wrap in RunnableLambda to create a parent span for LangFuse */
157
+ return new RunnableLambda({
158
+ func: async (
159
+ input: { convo: string },
160
+ config?: Partial<RunnableConfig>
161
+ ): Promise<{ title: string }> => {
162
+ return await innerChain.invoke(input, config);
123
163
  },
124
- });
164
+ }).withConfig({ runName: 'CompletionTitleChain' });
125
165
  };