@librechat/agents 3.1.0 → 3.1.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.
Files changed (75) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +2 -5
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +1 -0
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs +26 -17
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/llm/openai/index.cjs +1 -0
  8. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  9. package/dist/cjs/main.cjs +3 -0
  10. package/dist/cjs/main.cjs.map +1 -1
  11. package/dist/cjs/tools/CodeExecutor.cjs +37 -27
  12. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  13. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +21 -17
  14. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  15. package/dist/cjs/tools/ToolNode.cjs +1 -0
  16. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  17. package/dist/cjs/tools/ToolSearch.cjs +37 -30
  18. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  19. package/dist/cjs/tools/search/schema.cjs +25 -23
  20. package/dist/cjs/tools/search/schema.cjs.map +1 -1
  21. package/dist/cjs/tools/search/tool.cjs +9 -33
  22. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  23. package/dist/cjs/utils/schema.cjs +27 -0
  24. package/dist/cjs/utils/schema.cjs.map +1 -0
  25. package/dist/cjs/utils/title.cjs +28 -14
  26. package/dist/cjs/utils/title.cjs.map +1 -1
  27. package/dist/esm/agents/AgentContext.mjs +2 -5
  28. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  29. package/dist/esm/graphs/Graph.mjs +1 -0
  30. package/dist/esm/graphs/Graph.mjs.map +1 -1
  31. package/dist/esm/graphs/MultiAgentGraph.mjs +26 -17
  32. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  33. package/dist/esm/llm/openai/index.mjs +1 -0
  34. package/dist/esm/llm/openai/index.mjs.map +1 -1
  35. package/dist/esm/main.mjs +1 -0
  36. package/dist/esm/main.mjs.map +1 -1
  37. package/dist/esm/tools/CodeExecutor.mjs +37 -27
  38. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  39. package/dist/esm/tools/ProgrammaticToolCalling.mjs +21 -17
  40. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  41. package/dist/esm/tools/ToolNode.mjs +1 -0
  42. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  43. package/dist/esm/tools/ToolSearch.mjs +37 -30
  44. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  45. package/dist/esm/tools/search/schema.mjs +25 -23
  46. package/dist/esm/tools/search/schema.mjs.map +1 -1
  47. package/dist/esm/tools/search/tool.mjs +10 -34
  48. package/dist/esm/tools/search/tool.mjs.map +1 -1
  49. package/dist/esm/utils/schema.mjs +24 -0
  50. package/dist/esm/utils/schema.mjs.map +1 -0
  51. package/dist/esm/utils/title.mjs +28 -14
  52. package/dist/esm/utils/title.mjs.map +1 -1
  53. package/dist/types/tools/CodeExecutor.d.ts +1 -15
  54. package/dist/types/tools/ProgrammaticToolCalling.d.ts +1 -13
  55. package/dist/types/tools/ToolSearch.d.ts +1 -15
  56. package/dist/types/tools/search/schema.d.ts +25 -7
  57. package/dist/types/tools/search/tool.d.ts +1 -52
  58. package/dist/types/tools/search/types.d.ts +5 -23
  59. package/dist/types/utils/index.d.ts +1 -0
  60. package/dist/types/utils/schema.d.ts +8 -0
  61. package/package.json +1 -1
  62. package/src/agents/AgentContext.ts +5 -11
  63. package/src/graphs/MultiAgentGraph.ts +26 -17
  64. package/src/specs/agent-handoffs.test.ts +1 -2
  65. package/src/specs/tool-error.test.ts +7 -2
  66. package/src/test/mockTools.ts +34 -14
  67. package/src/tools/CodeExecutor.ts +48 -31
  68. package/src/tools/ProgrammaticToolCalling.ts +24 -23
  69. package/src/tools/ToolSearch.ts +54 -43
  70. package/src/tools/search/schema.ts +30 -25
  71. package/src/tools/search/tool.ts +23 -16
  72. package/src/tools/search/types.ts +5 -29
  73. package/src/utils/index.ts +1 -0
  74. package/src/utils/schema.ts +35 -0
  75. package/src/utils/title.ts +31 -19
@@ -1,4 +1,3 @@
1
- import { z } from 'zod';
2
1
  import { config } from 'dotenv';
3
2
  import fetch, { RequestInit } from 'node-fetch';
4
3
  import { HttpsProxyAgent } from 'https-proxy-agent';
@@ -21,25 +20,33 @@ const accessMessage =
21
20
  const emptyOutputMessage =
22
21
  'stdout: Empty. Ensure you\'re writing output explicitly.\n';
23
22
 
24
- const CodeExecutionToolSchema = z.object({
25
- lang: z
26
- .enum([
27
- 'py',
28
- 'js',
29
- 'ts',
30
- 'c',
31
- 'cpp',
32
- 'java',
33
- 'php',
34
- 'rs',
35
- 'go',
36
- 'd',
37
- 'f90',
38
- 'r',
39
- ])
40
- .describe('The programming language or runtime to execute the code in.'),
41
- code: z.string()
42
- .describe(`The complete, self-contained code to execute, without any truncation or minimization.
23
+ const SUPPORTED_LANGUAGES = [
24
+ 'py',
25
+ 'js',
26
+ 'ts',
27
+ 'c',
28
+ 'cpp',
29
+ 'java',
30
+ 'php',
31
+ 'rs',
32
+ 'go',
33
+ 'd',
34
+ 'f90',
35
+ 'r',
36
+ ] as const;
37
+
38
+ const CodeExecutionToolSchema = {
39
+ type: 'object',
40
+ properties: {
41
+ lang: {
42
+ type: 'string',
43
+ enum: SUPPORTED_LANGUAGES,
44
+ description:
45
+ 'The programming language or runtime to execute the code in.',
46
+ },
47
+ code: {
48
+ type: 'string',
49
+ description: `The complete, self-contained code to execute, without any truncation or minimization.
43
50
  - The environment is stateless; variables and imports don't persist between executions.
44
51
  - Generated files from previous executions are automatically available in "/mnt/data/".
45
52
  - Files from previous executions are automatically available and can be modified in place.
@@ -50,21 +57,26 @@ const CodeExecutionToolSchema = z.object({
50
57
  - py: Matplotlib: Use \`plt.savefig()\` to save plots as files.
51
58
  - js: use the \`console\` or \`process\` methods for all outputs.
52
59
  - r: IMPORTANT: No X11 display available. ALL graphics MUST use Cairo library (library(Cairo)).
53
- - Other languages: use appropriate output functions.`),
54
- args: z
55
- .array(z.string())
56
- .optional()
57
- .describe(
58
- 'Additional arguments to execute the code with. This should only be used if the input code requires additional arguments to run.'
59
- ),
60
- });
60
+ - Other languages: use appropriate output functions.`,
61
+ },
62
+ args: {
63
+ type: 'array',
64
+ items: { type: 'string' },
65
+ description:
66
+ 'Additional arguments to execute the code with. This should only be used if the input code requires additional arguments to run.',
67
+ },
68
+ },
69
+ required: ['lang', 'code'],
70
+ } as const;
61
71
 
62
72
  const baseEndpoint = getCodeBaseURL();
63
73
  const EXEC_ENDPOINT = `${baseEndpoint}/exec`;
64
74
 
75
+ type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number];
76
+
65
77
  function createCodeExecutionTool(
66
78
  params: t.CodeExecutionToolParams = {}
67
- ): DynamicStructuredTool<typeof CodeExecutionToolSchema> {
79
+ ): DynamicStructuredTool {
68
80
  const apiKey =
69
81
  params[EnvVar.CODE_API_KEY] ??
70
82
  params.apiKey ??
@@ -83,8 +95,13 @@ Usage:
83
95
  - NEVER use this tool to execute malicious code.
84
96
  `.trim();
85
97
 
86
- return tool<typeof CodeExecutionToolSchema>(
87
- async ({ lang, code, ...rest }, config) => {
98
+ return tool(
99
+ async (rawInput, config) => {
100
+ const { lang, code, ...rest } = rawInput as {
101
+ lang: SupportedLanguage;
102
+ code: string;
103
+ args?: string[];
104
+ };
88
105
  /**
89
106
  * Extract session context from config.toolCall (injected by ToolNode).
90
107
  * - session_id: For API to associate with previous session
@@ -1,5 +1,4 @@
1
1
  // src/tools/ProgrammaticToolCalling.ts
2
- import { z } from 'zod';
3
2
  import { config } from 'dotenv';
4
3
  import fetch, { RequestInit } from 'node-fetch';
5
4
  import { HttpsProxyAgent } from 'https-proxy-agent';
@@ -33,12 +32,13 @@ const DEFAULT_TIMEOUT = 60000;
33
32
  // Schema
34
33
  // ============================================================================
35
34
 
36
- const ProgrammaticToolCallingSchema = z.object({
37
- code: z
38
- .string()
39
- .min(1)
40
- .describe(
41
- `Python code that calls tools programmatically. Tools are available as async functions.
35
+ const ProgrammaticToolCallingSchema = {
36
+ type: 'object',
37
+ properties: {
38
+ code: {
39
+ type: 'string',
40
+ minLength: 1,
41
+ description: `Python code that calls tools programmatically. Tools are available as async functions.
42
42
 
43
43
  CRITICAL - STATELESS EXECUTION:
44
44
  Each call is a fresh Python interpreter. Variables, imports, and data do NOT persist between calls.
@@ -66,19 +66,19 @@ Rules:
66
66
  - Just write code with await—auto-wrapped in async context
67
67
  - DO NOT define async def main() or call asyncio.run()
68
68
  - Tools are pre-defined—DO NOT write function definitions
69
- - Only print() output returns to the model`
70
- ),
71
- timeout: z
72
- .number()
73
- .int()
74
- .min(1000)
75
- .max(300000)
76
- .optional()
77
- .default(DEFAULT_TIMEOUT)
78
- .describe(
79
- 'Maximum execution time in milliseconds. Default: 60 seconds. Max: 5 minutes.'
80
- ),
81
- });
69
+ - Only print() output returns to the model`,
70
+ },
71
+ timeout: {
72
+ type: 'integer',
73
+ minimum: 1000,
74
+ maximum: 300000,
75
+ default: DEFAULT_TIMEOUT,
76
+ description:
77
+ 'Maximum execution time in milliseconds. Default: 60 seconds. Max: 5 minutes.',
78
+ },
79
+ },
80
+ required: ['code'],
81
+ } as const;
82
82
 
83
83
  // ============================================================================
84
84
  // Helper Functions
@@ -576,7 +576,7 @@ export function formatCompletedResponse(
576
576
  */
577
577
  export function createProgrammaticToolCallingTool(
578
578
  initParams: t.ProgrammaticToolCallingParams = {}
579
- ): DynamicStructuredTool<typeof ProgrammaticToolCallingSchema> {
579
+ ): DynamicStructuredTool {
580
580
  const apiKey =
581
581
  (initParams[EnvVar.CODE_API_KEY] as string | undefined) ??
582
582
  initParams.apiKey ??
@@ -616,8 +616,9 @@ Example (complete pipeline):
616
616
  data = await query_db(sql="..."); df = process(data); await save_to_sheet(data=df); print("Done")
617
617
  `.trim();
618
618
 
619
- return tool<typeof ProgrammaticToolCallingSchema>(
620
- async (params, config) => {
619
+ return tool(
620
+ async (rawParams, config) => {
621
+ const params = rawParams as { code: string; timeout?: number };
621
622
  const { code, timeout = DEFAULT_TIMEOUT } = params;
622
623
 
623
624
  // Extra params injected by ToolNode (follows web_search pattern)
@@ -1,5 +1,4 @@
1
1
  // src/tools/ToolSearch.ts
2
- import { z } from 'zod';
3
2
  import * as okapibm25Module from 'okapibm25';
4
3
  import { config } from 'dotenv';
5
4
 
@@ -40,20 +39,25 @@ const MAX_REGEX_COMPLEXITY = 5;
40
39
  /** Default search timeout in milliseconds */
41
40
  const SEARCH_TIMEOUT = 5000;
42
41
 
43
- /** Zod schema type for tool search parameters */
44
- type ToolSearchSchema = z.ZodObject<{
45
- query: z.ZodDefault<z.ZodOptional<z.ZodString>>;
46
- fields: z.ZodDefault<
47
- z.ZodOptional<z.ZodArray<z.ZodEnum<['name', 'description', 'parameters']>>>
48
- >;
49
- max_results: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
50
- mcp_server: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;
51
- }>;
42
+ /** JSON schema type for tool search parameters */
43
+ interface ToolSearchSchema {
44
+ type: 'object';
45
+ properties: Record<string, unknown>;
46
+ required: string[];
47
+ }
48
+
49
+ /** Input params type for tool search */
50
+ interface ToolSearchParams {
51
+ query?: string;
52
+ fields?: ('name' | 'description' | 'parameters')[];
53
+ max_results?: number;
54
+ mcp_server?: string | string[];
55
+ }
52
56
 
53
57
  /**
54
- * Creates the Zod schema with dynamic query description based on mode.
58
+ * Creates the JSON schema with dynamic query description based on mode.
55
59
  * @param mode - The search mode determining query interpretation
56
- * @returns Zod schema for tool search parameters
60
+ * @returns JSON schema for tool search parameters
57
61
  */
58
62
  function createToolSearchSchema(mode: t.ToolSearchMode): ToolSearchSchema {
59
63
  const queryDescription =
@@ -61,33 +65,39 @@ function createToolSearchSchema(mode: t.ToolSearchMode): ToolSearchSchema {
61
65
  ? 'Search term to find in tool names and descriptions. Case-insensitive substring matching. Optional if mcp_server is provided.'
62
66
  : 'Regex pattern to search tool names and descriptions. Optional if mcp_server is provided.';
63
67
 
64
- return z.object({
65
- query: z
66
- .string()
67
- .max(MAX_PATTERN_LENGTH)
68
- .optional()
69
- .default('')
70
- .describe(queryDescription),
71
- fields: z
72
- .array(z.enum(['name', 'description', 'parameters']))
73
- .optional()
74
- .default(['name', 'description'])
75
- .describe('Which fields to search. Default: name and description'),
76
- max_results: z
77
- .number()
78
- .int()
79
- .min(1)
80
- .max(50)
81
- .optional()
82
- .default(10)
83
- .describe('Maximum number of matching tools to return'),
84
- mcp_server: z
85
- .union([z.string(), z.array(z.string())])
86
- .optional()
87
- .describe(
88
- 'Filter to tools from specific MCP server(s). Can be a single server name or array of names. If provided without a query, lists all tools from those servers.'
89
- ),
90
- });
68
+ return {
69
+ type: 'object',
70
+ properties: {
71
+ query: {
72
+ type: 'string',
73
+ maxLength: MAX_PATTERN_LENGTH,
74
+ default: '',
75
+ description: queryDescription,
76
+ },
77
+ fields: {
78
+ type: 'array',
79
+ items: { type: 'string', enum: ['name', 'description', 'parameters'] },
80
+ default: ['name', 'description'],
81
+ description: 'Which fields to search. Default: name and description',
82
+ },
83
+ max_results: {
84
+ type: 'integer',
85
+ minimum: 1,
86
+ maximum: 50,
87
+ default: 10,
88
+ description: 'Maximum number of matching tools to return',
89
+ },
90
+ mcp_server: {
91
+ oneOf: [
92
+ { type: 'string' },
93
+ { type: 'array', items: { type: 'string' } },
94
+ ],
95
+ description:
96
+ 'Filter to tools from specific MCP server(s). Can be a single server name or array of names. If provided without a query, lists all tools from those servers.',
97
+ },
98
+ },
99
+ required: [],
100
+ };
91
101
  }
92
102
 
93
103
  /**
@@ -748,7 +758,7 @@ function formatServerListing(
748
758
  */
749
759
  function createToolSearch(
750
760
  initParams: t.ToolSearchParams = {}
751
- ): DynamicStructuredTool<ReturnType<typeof createToolSearchSchema>> {
761
+ ): DynamicStructuredTool {
752
762
  const mode: t.ToolSearchMode = initParams.mode ?? 'code_interpreter';
753
763
  const defaultOnlyDeferred = initParams.onlyDeferred ?? true;
754
764
  const schema = createToolSearchSchema(mode);
@@ -802,10 +812,11 @@ Searches deferred tools by regex pattern.
802
812
  ${mcpNote}${toolsListSection}
803
813
  `.trim();
804
814
 
805
- return tool<typeof schema>(
806
- async (params, config) => {
815
+ return tool(
816
+ async (rawParams, config) => {
817
+ const params = rawParams as ToolSearchParams;
807
818
  const {
808
- query,
819
+ query = '',
809
820
  fields = ['name', 'description'],
810
821
  max_results = 10,
811
822
  mcp_server,
@@ -1,5 +1,3 @@
1
- import { z } from 'zod';
2
-
3
1
  export enum DATE_RANGE {
4
2
  PAST_HOUR = 'h',
5
3
  PAST_24_HOURS = 'd',
@@ -38,26 +36,33 @@ Examples:
38
36
  - "in" for India
39
37
  `.trim();
40
38
 
41
- export const querySchema = z.string().describe(DEFAULT_QUERY_DESCRIPTION);
42
- export const dateSchema = z
43
- .nativeEnum(DATE_RANGE)
44
- .optional()
45
- .describe('Date range for search results.');
46
- export const countrySchema = z
47
- .string()
48
- .optional()
49
- .describe(DEFAULT_COUNTRY_DESCRIPTION);
50
- export const imagesSchema = z
51
- .boolean()
52
- .optional()
53
- .describe('Whether to also run an image search.');
54
-
55
- export const videosSchema = z
56
- .boolean()
57
- .optional()
58
- .describe('Whether to also run a video search.');
59
-
60
- export const newsSchema = z
61
- .boolean()
62
- .optional()
63
- .describe('Whether to also run a news search.');
39
+ export const querySchema = {
40
+ type: 'string',
41
+ description: DEFAULT_QUERY_DESCRIPTION,
42
+ } as const;
43
+
44
+ export const dateSchema = {
45
+ type: 'string',
46
+ enum: Object.values(DATE_RANGE),
47
+ description: 'Date range for search results.',
48
+ } as const;
49
+
50
+ export const countrySchema = {
51
+ type: 'string',
52
+ description: DEFAULT_COUNTRY_DESCRIPTION,
53
+ } as const;
54
+
55
+ export const imagesSchema = {
56
+ type: 'boolean',
57
+ description: 'Whether to also run an image search.',
58
+ } as const;
59
+
60
+ export const videosSchema = {
61
+ type: 'boolean',
62
+ description: 'Whether to also run a video search.',
63
+ } as const;
64
+
65
+ export const newsSchema = {
66
+ type: 'boolean',
67
+ description: 'Whether to also run a news search.',
68
+ } as const;
@@ -1,4 +1,3 @@
1
- import { z } from 'zod';
2
1
  import { tool, DynamicStructuredTool } from '@langchain/core/tools';
3
2
  import type { RunnableConfig } from '@langchain/core/runnables';
4
3
  import type * as t from './types';
@@ -269,12 +268,13 @@ function createTool({
269
268
  search,
270
269
  onSearchResults: _onSearchResults,
271
270
  }: {
272
- schema: t.SearchToolSchema;
271
+ schema: Record<string, unknown>;
273
272
  search: ReturnType<typeof createSearchProcessor>;
274
273
  onSearchResults: t.SearchToolConfig['onSearchResults'];
275
- }): DynamicStructuredTool<typeof schema> {
276
- return tool<typeof schema>(
277
- async (params, runnableConfig) => {
274
+ }): DynamicStructuredTool {
275
+ return tool(
276
+ async (rawParams, runnableConfig) => {
277
+ const params = rawParams as SearchToolParams;
278
278
  const { query, date, country: _c, images, videos, news } = params;
279
279
  const country = typeof _c === 'string' && _c ? _c : undefined;
280
280
  const searchResult = await search({
@@ -353,9 +353,19 @@ Use anchor marker(s) immediately after the statement:
353
353
  * @param config - The search tool configuration
354
354
  * @returns A DynamicStructuredTool with a schema that depends on the searchProvider
355
355
  */
356
+ /** Input params type for search tool */
357
+ interface SearchToolParams {
358
+ query: string;
359
+ date?: DATE_RANGE;
360
+ country?: string;
361
+ images?: boolean;
362
+ videos?: boolean;
363
+ news?: boolean;
364
+ }
365
+
356
366
  export const createSearchTool = (
357
367
  config: t.SearchToolConfig = {}
358
- ): DynamicStructuredTool<typeof toolSchema> => {
368
+ ): DynamicStructuredTool => {
359
369
  const {
360
370
  searchProvider = 'serper',
361
371
  serperApiKey,
@@ -382,14 +392,7 @@ export const createSearchTool = (
382
392
 
383
393
  const logger = config.logger || createDefaultLogger();
384
394
 
385
- const schemaObject: {
386
- query: z.ZodString;
387
- date: z.ZodOptional<z.ZodNativeEnum<typeof DATE_RANGE>>;
388
- country?: z.ZodOptional<z.ZodString>;
389
- images: z.ZodOptional<z.ZodBoolean>;
390
- videos: z.ZodOptional<z.ZodBoolean>;
391
- news: z.ZodOptional<z.ZodBoolean>;
392
- } = {
395
+ const schemaProperties: Record<string, unknown> = {
393
396
  query: querySchema,
394
397
  date: dateSchema,
395
398
  images: imagesSchema,
@@ -398,10 +401,14 @@ export const createSearchTool = (
398
401
  };
399
402
 
400
403
  if (searchProvider === 'serper') {
401
- schemaObject.country = countrySchema;
404
+ schemaProperties.country = countrySchema;
402
405
  }
403
406
 
404
- const toolSchema = z.object(schemaObject);
407
+ const toolSchema = {
408
+ type: 'object',
409
+ properties: schemaProperties,
410
+ required: ['query'],
411
+ };
405
412
 
406
413
  const searchAPI = createSearchAPI({
407
414
  searchProvider,
@@ -1,4 +1,3 @@
1
- import { z } from 'zod';
2
1
  import type { Logger as WinstonLogger } from 'winston';
3
2
  import type { RunnableConfig } from '@langchain/core/runnables';
4
3
  import type { BaseReranker } from './rerankers';
@@ -657,31 +656,8 @@ export type ProcessSourcesFields = {
657
656
  onGetHighlights: SearchToolConfig['onGetHighlights'];
658
657
  };
659
658
 
660
- export type SearchToolSchema = z.ZodObject<
661
- {
662
- query: z.ZodString;
663
- date: z.ZodOptional<z.ZodNativeEnum<typeof DATE_RANGE>>;
664
- country?: z.ZodOptional<z.ZodString>;
665
- images: z.ZodOptional<z.ZodBoolean>;
666
- videos: z.ZodOptional<z.ZodBoolean>;
667
- news: z.ZodOptional<z.ZodBoolean>;
668
- },
669
- 'strip',
670
- z.ZodTypeAny,
671
- {
672
- query: string;
673
- date?: DATE_RANGE;
674
- country?: unknown;
675
- images?: boolean;
676
- videos?: boolean;
677
- news?: boolean;
678
- },
679
- {
680
- query: string;
681
- date?: DATE_RANGE;
682
- country?: unknown;
683
- images?: boolean;
684
- videos?: boolean;
685
- news?: boolean;
686
- }
687
- >;
659
+ export interface SearchToolSchema {
660
+ type: 'object';
661
+ properties: Record<string, unknown>;
662
+ required: string[];
663
+ }
@@ -4,3 +4,4 @@ export * from './misc';
4
4
  export * from './handlers';
5
5
  export * from './run';
6
6
  export * from './tokens';
7
+ export * from './schema';
@@ -0,0 +1,35 @@
1
+ // src/utils/schema.ts
2
+ import { zodToJsonSchema } from 'zod-to-json-schema';
3
+ import type { ZodTypeAny } from 'zod';
4
+
5
+ /** Checks if a schema is a Zod schema by looking for the _def property */
6
+ export function isZodSchema(schema: unknown): schema is ZodTypeAny {
7
+ return (
8
+ schema != null && typeof schema === 'object' && '_def' in (schema as object)
9
+ );
10
+ }
11
+
12
+ /**
13
+ * Converts a schema to JSON schema format.
14
+ * Handles both Zod schemas (converts) and JSON schemas (passthrough).
15
+ */
16
+ export function toJsonSchema(
17
+ schema: unknown,
18
+ name?: string,
19
+ description?: string
20
+ ): Record<string, unknown> {
21
+ if (isZodSchema(schema)) {
22
+ const zodSchema = schema as ZodTypeAny & {
23
+ describe: (desc: string) => ZodTypeAny;
24
+ };
25
+ const described =
26
+ description != null && description !== ''
27
+ ? zodSchema.describe(description)
28
+ : schema;
29
+ return zodToJsonSchema(
30
+ described as Parameters<typeof zodToJsonSchema>[0],
31
+ name ?? ''
32
+ );
33
+ }
34
+ return schema as Record<string, unknown>;
35
+ }
@@ -1,4 +1,3 @@
1
- import { z } from 'zod';
2
1
  import { ChatPromptTemplate } from '@langchain/core/prompts';
3
2
  import { RunnableLambda, RunnableSequence } from '@langchain/core/runnables';
4
3
  import type { Runnable, RunnableConfig } from '@langchain/core/runnables';
@@ -12,22 +11,33 @@ const defaultTitlePrompt = `Analyze this conversation and provide:
12
11
 
13
12
  {convo}`;
14
13
 
15
- const titleSchema = z.object({
16
- title: z
17
- .string()
18
- .describe(
19
- 'A concise title for the conversation in 5 words or less, without punctuation or quotation'
20
- ),
21
- });
22
-
23
- const combinedSchema = z.object({
24
- language: z.string().describe('The detected language of the conversation'),
25
- title: z
26
- .string()
27
- .describe(
28
- 'A concise title for the conversation in 5 words or less, without punctuation or quotation'
29
- ),
30
- });
14
+ const titleSchema = {
15
+ type: 'object',
16
+ properties: {
17
+ title: {
18
+ type: 'string',
19
+ description:
20
+ 'A concise title for the conversation in 5 words or less, without punctuation or quotation',
21
+ },
22
+ },
23
+ required: ['title'],
24
+ } as const;
25
+
26
+ const combinedSchema = {
27
+ type: 'object',
28
+ properties: {
29
+ language: {
30
+ type: 'string',
31
+ description: 'The detected language of the conversation',
32
+ },
33
+ title: {
34
+ type: 'string',
35
+ description:
36
+ 'A concise title for the conversation in 5 words or less, without punctuation or quotation',
37
+ },
38
+ },
39
+ required: ['language', 'title'],
40
+ } as const;
31
41
 
32
42
  export const createTitleRunnable = async (
33
43
  model: t.ChatModelInstance,
@@ -54,7 +64,8 @@ export const createTitleRunnable = async (
54
64
  input: { convo: string },
55
65
  config?: Partial<RunnableConfig>
56
66
  ): Promise<{ title: string }> => {
57
- return await titleOnlyInnerChain.invoke(input, config);
67
+ const result = await titleOnlyInnerChain.invoke(input, config);
68
+ return result as { title: string };
58
69
  },
59
70
  }).withConfig({ runName: 'TitleOnlyChain' });
60
71
 
@@ -64,7 +75,8 @@ export const createTitleRunnable = async (
64
75
  input: { convo: string },
65
76
  config?: Partial<RunnableConfig>
66
77
  ): Promise<{ language: string; title: string }> => {
67
- return await combinedInnerChain.invoke(input, config);
78
+ const result = await combinedInnerChain.invoke(input, config);
79
+ return result as { language: string; title: string };
68
80
  },
69
81
  }).withConfig({ runName: 'TitleLanguageChain' });
70
82