@librechat/agents 3.1.0 → 3.1.2
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/cjs/agents/AgentContext.cjs +2 -5
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +1 -0
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +26 -17
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +1 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +3 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +37 -27
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +21 -17
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +1 -0
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +37 -30
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/search/schema.cjs +25 -23
- package/dist/cjs/tools/search/schema.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +9 -33
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/utils/schema.cjs +27 -0
- package/dist/cjs/utils/schema.cjs.map +1 -0
- package/dist/cjs/utils/title.cjs +28 -14
- package/dist/cjs/utils/title.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +2 -5
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +1 -0
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +26 -17
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +1 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +1 -0
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +37 -27
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +21 -17
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +1 -0
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +37 -30
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/search/schema.mjs +25 -23
- package/dist/esm/tools/search/schema.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +10 -34
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/utils/schema.mjs +24 -0
- package/dist/esm/utils/schema.mjs.map +1 -0
- package/dist/esm/utils/title.mjs +28 -14
- package/dist/esm/utils/title.mjs.map +1 -1
- package/dist/types/tools/CodeExecutor.d.ts +1 -15
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +1 -13
- package/dist/types/tools/ToolSearch.d.ts +1 -15
- package/dist/types/tools/search/schema.d.ts +25 -7
- package/dist/types/tools/search/tool.d.ts +1 -52
- package/dist/types/tools/search/types.d.ts +5 -23
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/schema.d.ts +8 -0
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +5 -11
- package/src/graphs/MultiAgentGraph.ts +26 -17
- package/src/specs/agent-handoffs.test.ts +1 -2
- package/src/specs/azure.simple.test.ts +214 -175
- package/src/specs/tool-error.test.ts +7 -2
- package/src/test/mockTools.ts +34 -14
- package/src/tools/CodeExecutor.ts +48 -31
- package/src/tools/ProgrammaticToolCalling.ts +24 -23
- package/src/tools/ToolSearch.ts +54 -43
- package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.ts +10 -9
- package/src/tools/__tests__/ToolSearch.integration.test.ts +10 -9
- package/src/tools/search/schema.ts +30 -25
- package/src/tools/search/tool.ts +23 -16
- package/src/tools/search/types.ts +5 -29
- package/src/utils/index.ts +1 -0
- package/src/utils/schema.ts +35 -0
- package/src/utils/title.ts +31 -19
|
@@ -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 =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
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
|
|
620
|
-
async (
|
|
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)
|
package/src/tools/ToolSearch.ts
CHANGED
|
@@ -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
|
-
/**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
58
|
+
* Creates the JSON schema with dynamic query description based on mode.
|
|
55
59
|
* @param mode - The search mode determining query interpretation
|
|
56
|
-
* @returns
|
|
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
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
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
|
|
806
|
-
async (
|
|
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,
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* These tests hit the LIVE Code API and verify end-to-end functionality.
|
|
5
5
|
*
|
|
6
6
|
* Run with: npm test -- ProgrammaticToolCalling.integration.test.ts
|
|
7
|
+
*
|
|
8
|
+
* Requires LIBRECHAT_CODE_API_KEY environment variable.
|
|
9
|
+
* Tests are skipped when the API key is not available.
|
|
7
10
|
*/
|
|
8
11
|
import { config as dotenvConfig } from 'dotenv';
|
|
9
12
|
dotenvConfig();
|
|
@@ -19,19 +22,17 @@ import {
|
|
|
19
22
|
createProgrammaticToolRegistry,
|
|
20
23
|
} from '@/test/mockTools';
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
const apiKey = process.env.LIBRECHAT_CODE_API_KEY;
|
|
26
|
+
const shouldSkip = apiKey == null || apiKey === '';
|
|
27
|
+
|
|
28
|
+
const describeIfApiKey = shouldSkip ? describe.skip : describe;
|
|
29
|
+
|
|
30
|
+
describeIfApiKey('ProgrammaticToolCalling - Live API Integration', () => {
|
|
23
31
|
let ptcTool: ReturnType<typeof createProgrammaticToolCallingTool>;
|
|
24
32
|
let toolMap: t.ToolMap;
|
|
25
33
|
let toolDefinitions: t.LCTool[];
|
|
26
34
|
|
|
27
35
|
beforeAll(() => {
|
|
28
|
-
const apiKey = process.env.LIBRECHAT_CODE_API_KEY;
|
|
29
|
-
if (apiKey == null || apiKey === '') {
|
|
30
|
-
throw new Error(
|
|
31
|
-
'LIBRECHAT_CODE_API_KEY not set. Required for integration tests.'
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
36
|
const tools = [
|
|
36
37
|
createGetTeamMembersTool(),
|
|
37
38
|
createGetExpensesTool(),
|
|
@@ -42,7 +43,7 @@ describe('ProgrammaticToolCalling - Live API Integration', () => {
|
|
|
42
43
|
toolMap = new Map(tools.map((t) => [t.name, t]));
|
|
43
44
|
toolDefinitions = Array.from(createProgrammaticToolRegistry().values());
|
|
44
45
|
|
|
45
|
-
ptcTool = createProgrammaticToolCallingTool({ apiKey });
|
|
46
|
+
ptcTool = createProgrammaticToolCallingTool({ apiKey: apiKey! });
|
|
46
47
|
});
|
|
47
48
|
|
|
48
49
|
it('executes simple single tool call', async () => {
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* These tests hit the LIVE Code API and verify end-to-end search functionality.
|
|
5
5
|
*
|
|
6
6
|
* Run with: npm test -- ToolSearch.integration.test.ts
|
|
7
|
+
*
|
|
8
|
+
* Requires LIBRECHAT_CODE_API_KEY environment variable.
|
|
9
|
+
* Tests are skipped when the API key is not available.
|
|
7
10
|
*/
|
|
8
11
|
import { config as dotenvConfig } from 'dotenv';
|
|
9
12
|
dotenvConfig();
|
|
@@ -12,19 +15,17 @@ import { describe, it, expect, beforeAll } from '@jest/globals';
|
|
|
12
15
|
import { createToolSearch } from '../ToolSearch';
|
|
13
16
|
import { createToolSearchToolRegistry } from '@/test/mockTools';
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
const apiKey = process.env.LIBRECHAT_CODE_API_KEY;
|
|
19
|
+
const shouldSkip = apiKey == null || apiKey === '';
|
|
20
|
+
|
|
21
|
+
const describeIfApiKey = shouldSkip ? describe.skip : describe;
|
|
22
|
+
|
|
23
|
+
describeIfApiKey('ToolSearch - Live API Integration', () => {
|
|
16
24
|
let searchTool: ReturnType<typeof createToolSearch>;
|
|
17
25
|
const toolRegistry = createToolSearchToolRegistry();
|
|
18
26
|
|
|
19
27
|
beforeAll(() => {
|
|
20
|
-
|
|
21
|
-
if (apiKey == null || apiKey === '') {
|
|
22
|
-
throw new Error(
|
|
23
|
-
'LIBRECHAT_CODE_API_KEY not set. Required for integration tests.'
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
searchTool = createToolSearch({ apiKey, toolRegistry });
|
|
28
|
+
searchTool = createToolSearch({ apiKey: apiKey!, toolRegistry });
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
it('searches for expense-related tools', async () => {
|
|
@@ -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 =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
export const
|
|
47
|
-
|
|
48
|
-
.
|
|
49
|
-
.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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;
|
package/src/tools/search/tool.ts
CHANGED
|
@@ -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:
|
|
271
|
+
schema: Record<string, unknown>;
|
|
273
272
|
search: ReturnType<typeof createSearchProcessor>;
|
|
274
273
|
onSearchResults: t.SearchToolConfig['onSearchResults'];
|
|
275
|
-
}): DynamicStructuredTool
|
|
276
|
-
return tool
|
|
277
|
-
async (
|
|
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
|
|
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
|
|
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
|
-
|
|
404
|
+
schemaProperties.country = countrySchema;
|
|
402
405
|
}
|
|
403
406
|
|
|
404
|
-
const toolSchema =
|
|
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
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
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
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/utils/title.ts
CHANGED
|
@@ -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 =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
'
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|