@librechat/agents 3.0.41 → 3.0.43
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 +177 -69
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/enum.cjs +1 -1
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +19 -36
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/main.cjs +5 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/tools.cjs +85 -0
- package/dist/cjs/messages/tools.cjs.map +1 -0
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +55 -32
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +30 -13
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +177 -69
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/enum.mjs +1 -1
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +19 -36
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/main.mjs +2 -1
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages/tools.mjs +82 -0
- package/dist/esm/messages/tools.mjs.map +1 -0
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +54 -33
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +30 -13
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +52 -16
- package/dist/types/common/enum.d.ts +1 -1
- package/dist/types/graphs/Graph.d.ts +1 -1
- package/dist/types/messages/index.d.ts +1 -0
- package/dist/types/messages/tools.d.ts +17 -0
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +15 -23
- package/dist/types/tools/ToolNode.d.ts +9 -7
- package/dist/types/types/tools.d.ts +5 -5
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +205 -80
- package/src/agents/__tests__/AgentContext.test.ts +805 -0
- package/src/common/enum.ts +1 -1
- package/src/graphs/Graph.ts +24 -40
- package/src/messages/__tests__/tools.test.ts +473 -0
- package/src/messages/index.ts +1 -0
- package/src/messages/tools.ts +99 -0
- package/src/scripts/code_exec_ptc.ts +78 -21
- package/src/scripts/programmatic_exec.ts +3 -3
- package/src/scripts/programmatic_exec_agent.ts +4 -4
- package/src/tools/ProgrammaticToolCalling.ts +71 -39
- package/src/tools/ToolNode.ts +33 -14
- package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.ts +9 -9
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +180 -5
- package/src/types/tools.ts +3 -5
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BaseMessage } from '@langchain/core/messages';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts discovered tool names from tool search results in the current turn.
|
|
4
|
+
* Only processes tool search messages after the latest AI message with tool calls.
|
|
5
|
+
*
|
|
6
|
+
* Similar pattern to formatArtifactPayload - finds relevant messages efficiently
|
|
7
|
+
* by identifying the latest AI parent and only processing subsequent tool messages.
|
|
8
|
+
*
|
|
9
|
+
* @param messages - All messages in the conversation
|
|
10
|
+
* @returns Array of discovered tool names (empty if no new discoveries)
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractToolDiscoveries(messages: BaseMessage[]): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Checks if the current turn has any tool search results.
|
|
15
|
+
* Quick check to avoid full extraction when not needed.
|
|
16
|
+
*/
|
|
17
|
+
export declare function hasToolSearchInCurrentTurn(messages: BaseMessage[]): boolean;
|
|
@@ -3,40 +3,32 @@ import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
|
3
3
|
import type * as t from '@/types';
|
|
4
4
|
declare const ProgrammaticToolCallingSchema: z.ZodObject<{
|
|
5
5
|
code: z.ZodString;
|
|
6
|
-
tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
7
|
-
name: z.ZodString;
|
|
8
|
-
description: z.ZodOptional<z.ZodString>;
|
|
9
|
-
parameters: z.ZodAny;
|
|
10
|
-
}, "strip", z.ZodTypeAny, {
|
|
11
|
-
name: string;
|
|
12
|
-
description?: string | undefined;
|
|
13
|
-
parameters?: any;
|
|
14
|
-
}, {
|
|
15
|
-
name: string;
|
|
16
|
-
description?: string | undefined;
|
|
17
|
-
parameters?: any;
|
|
18
|
-
}>, "many">>;
|
|
19
6
|
session_id: z.ZodOptional<z.ZodString>;
|
|
20
7
|
timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
21
8
|
}, "strip", z.ZodTypeAny, {
|
|
22
9
|
code: string;
|
|
23
10
|
timeout: number;
|
|
24
|
-
tools?: {
|
|
25
|
-
name: string;
|
|
26
|
-
description?: string | undefined;
|
|
27
|
-
parameters?: any;
|
|
28
|
-
}[] | undefined;
|
|
29
11
|
session_id?: string | undefined;
|
|
30
12
|
}, {
|
|
31
13
|
code: string;
|
|
32
|
-
tools?: {
|
|
33
|
-
name: string;
|
|
34
|
-
description?: string | undefined;
|
|
35
|
-
parameters?: any;
|
|
36
|
-
}[] | undefined;
|
|
37
14
|
timeout?: number | undefined;
|
|
38
15
|
session_id?: string | undefined;
|
|
39
16
|
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Extracts tool names that are actually called in the Python code.
|
|
19
|
+
* Matches patterns like `await tool_name(`, `tool_name(`, and asyncio.gather calls.
|
|
20
|
+
* @param code - The Python code to analyze
|
|
21
|
+
* @param availableToolNames - Set of available tool names to match against
|
|
22
|
+
* @returns Set of tool names found in the code
|
|
23
|
+
*/
|
|
24
|
+
export declare function extractUsedToolNames(code: string, availableToolNames: Set<string>): Set<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Filters tool definitions to only include tools actually used in the code.
|
|
27
|
+
* @param toolDefs - All available tool definitions
|
|
28
|
+
* @param code - The Python code to analyze
|
|
29
|
+
* @returns Filtered array of tool definitions
|
|
30
|
+
*/
|
|
31
|
+
export declare function filterToolsByUsage(toolDefs: t.LCTool[], code: string): t.LCTool[];
|
|
40
32
|
/**
|
|
41
33
|
* Makes an HTTP request to the Code API.
|
|
42
34
|
* @param endpoint - The API endpoint URL
|
|
@@ -5,7 +5,6 @@ import type { BaseMessage } from '@langchain/core/messages';
|
|
|
5
5
|
import type * as t from '@/types';
|
|
6
6
|
import { RunnableCallable } from '@/utils';
|
|
7
7
|
export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
8
|
-
tools: t.GenericTool[];
|
|
9
8
|
private toolMap;
|
|
10
9
|
private loadRuntimeTools?;
|
|
11
10
|
handleToolErrors: boolean;
|
|
@@ -13,13 +12,16 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
13
12
|
toolCallStepIds?: Map<string, string>;
|
|
14
13
|
errorHandler?: t.ToolNodeConstructorParams['errorHandler'];
|
|
15
14
|
private toolUsageCount;
|
|
16
|
-
/**
|
|
17
|
-
private programmaticToolMap?;
|
|
18
|
-
/** Tool definitions for programmatic code execution (sent to Code API) */
|
|
19
|
-
private programmaticToolDefs?;
|
|
20
|
-
/** Tool registry for tool search (deferred tools) */
|
|
15
|
+
/** Tool registry for filtering (lazy computation of programmatic maps) */
|
|
21
16
|
private toolRegistry?;
|
|
22
|
-
|
|
17
|
+
/** Cached programmatic tools (computed once on first PTC call) */
|
|
18
|
+
private programmaticCache?;
|
|
19
|
+
constructor({ tools, toolMap, name, tags, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, toolRegistry, }: t.ToolNodeConstructorParams);
|
|
20
|
+
/**
|
|
21
|
+
* Returns cached programmatic tools, computing once on first access.
|
|
22
|
+
* Single iteration builds both toolMap and toolDefs simultaneously.
|
|
23
|
+
*/
|
|
24
|
+
private getProgrammaticTools;
|
|
23
25
|
/**
|
|
24
26
|
* Returns a snapshot of the current tool usage counts.
|
|
25
27
|
* @returns A ReadonlyMap where keys are tool names and values are their usage counts.
|
|
@@ -25,11 +25,7 @@ export type ToolNodeOptions = {
|
|
|
25
25
|
loadRuntimeTools?: ToolRefGenerator;
|
|
26
26
|
toolCallStepIds?: Map<string, string>;
|
|
27
27
|
errorHandler?: (data: ToolErrorData, metadata?: Record<string, unknown>) => Promise<void>;
|
|
28
|
-
/**
|
|
29
|
-
programmaticToolMap?: ToolMap;
|
|
30
|
-
/** Tool definitions for programmatic code execution (sent to Code API for stub generation) */
|
|
31
|
-
programmaticToolDefs?: LCTool[];
|
|
32
|
-
/** Tool registry for tool search (deferred tool definitions) */
|
|
28
|
+
/** Tool registry for lazy computation of programmatic tools and tool search */
|
|
33
29
|
toolRegistry?: LCToolRegistry;
|
|
34
30
|
};
|
|
35
31
|
export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
|
|
@@ -97,6 +93,10 @@ export type LCTool = {
|
|
|
97
93
|
};
|
|
98
94
|
/** Map of tool names to tool definitions */
|
|
99
95
|
export type LCToolRegistry = Map<string, LCTool>;
|
|
96
|
+
export type ProgrammaticCache = {
|
|
97
|
+
toolMap: ToolMap;
|
|
98
|
+
toolDefs: LCTool[];
|
|
99
|
+
};
|
|
100
100
|
/** Parameters for creating a Tool Search Regex tool */
|
|
101
101
|
export type ToolSearchRegexParams = {
|
|
102
102
|
apiKey?: string;
|
package/package.json
CHANGED
|
@@ -13,19 +13,6 @@ import type * as t from '@/types';
|
|
|
13
13
|
import type { createPruneMessages } from '@/messages';
|
|
14
14
|
import { ContentTypes, Providers } from '@/common';
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
* Checks if a tool allows the specified caller type.
|
|
18
|
-
* Default is 'direct' only if allowed_callers is not specified.
|
|
19
|
-
*/
|
|
20
|
-
function toolAllowsCaller(
|
|
21
|
-
toolDef: t.LCTool | undefined,
|
|
22
|
-
caller: t.AllowedCaller
|
|
23
|
-
): boolean {
|
|
24
|
-
if (!toolDef) return false;
|
|
25
|
-
const allowedCallers = toolDef.allowed_callers ?? ['direct'];
|
|
26
|
-
return allowedCallers.includes(caller);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
16
|
/**
|
|
30
17
|
* Encapsulates agent-specific state that can vary between agents in a multi-agent system
|
|
31
18
|
*/
|
|
@@ -73,12 +60,17 @@ export class AgentContext {
|
|
|
73
60
|
});
|
|
74
61
|
|
|
75
62
|
if (tokenCounter) {
|
|
63
|
+
// Initialize system runnable BEFORE async tool token calculation
|
|
64
|
+
// This ensures system message tokens are in instructionTokens before
|
|
65
|
+
// updateTokenMapWithInstructions is called
|
|
66
|
+
agentContext.initializeSystemRunnable();
|
|
67
|
+
|
|
76
68
|
const tokenMap = indexTokenCountMap || {};
|
|
77
69
|
agentContext.indexTokenCountMap = tokenMap;
|
|
78
70
|
agentContext.tokenCalculationPromise = agentContext
|
|
79
71
|
.calculateInstructionTokens(tokenCounter)
|
|
80
72
|
.then(() => {
|
|
81
|
-
// Update token map with instruction tokens
|
|
73
|
+
// Update token map with instruction tokens (includes system + tool tokens)
|
|
82
74
|
agentContext.updateTokenMapWithInstructions(tokenMap);
|
|
83
75
|
})
|
|
84
76
|
.catch((err) => {
|
|
@@ -122,6 +114,8 @@ export class AgentContext {
|
|
|
122
114
|
* Used for tool search and programmatic tool calling.
|
|
123
115
|
*/
|
|
124
116
|
toolRegistry?: t.LCToolRegistry;
|
|
117
|
+
/** Set of tool names discovered via tool search (to be loaded) */
|
|
118
|
+
discoveredToolNames: Set<string> = new Set();
|
|
125
119
|
/** Instructions for this agent */
|
|
126
120
|
instructions?: string;
|
|
127
121
|
/** Additional instructions for this agent */
|
|
@@ -137,12 +131,16 @@ export class AgentContext {
|
|
|
137
131
|
ContentTypes.TEXT;
|
|
138
132
|
/** Whether tools should end the workflow */
|
|
139
133
|
toolEnd: boolean = false;
|
|
140
|
-
/**
|
|
141
|
-
|
|
134
|
+
/** Cached system runnable (created lazily) */
|
|
135
|
+
private cachedSystemRunnable?: Runnable<
|
|
142
136
|
BaseMessage[],
|
|
143
137
|
(BaseMessage | SystemMessage)[],
|
|
144
138
|
RunnableConfig<Record<string, unknown>>
|
|
145
139
|
>;
|
|
140
|
+
/** Whether system runnable needs rebuild (set when discovered tools change) */
|
|
141
|
+
private systemRunnableStale: boolean = true;
|
|
142
|
+
/** Cached system message token count (separate from tool tokens) */
|
|
143
|
+
private systemMessageTokens: number = 0;
|
|
146
144
|
/** Promise for token calculation initialization */
|
|
147
145
|
tokenCalculationPromise?: Promise<void>;
|
|
148
146
|
/** Format content blocks as strings (for legacy compatibility) */
|
|
@@ -203,39 +201,145 @@ export class AgentContext {
|
|
|
203
201
|
}
|
|
204
202
|
|
|
205
203
|
this.useLegacyContent = useLegacyContent ?? false;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Builds instructions text for tools that are ONLY callable via programmatic code execution.
|
|
208
|
+
* These tools cannot be called directly by the LLM but are available through the
|
|
209
|
+
* run_tools_with_code tool.
|
|
210
|
+
*
|
|
211
|
+
* Includes:
|
|
212
|
+
* - Code_execution-only tools that are NOT deferred
|
|
213
|
+
* - Code_execution-only tools that ARE deferred but have been discovered via tool search
|
|
214
|
+
*/
|
|
215
|
+
private buildProgrammaticOnlyToolsInstructions(): string {
|
|
216
|
+
if (!this.toolRegistry) return '';
|
|
217
|
+
|
|
218
|
+
const programmaticOnlyTools: t.LCTool[] = [];
|
|
219
|
+
for (const [name, toolDef] of this.toolRegistry) {
|
|
220
|
+
const allowedCallers = toolDef.allowed_callers ?? ['direct'];
|
|
221
|
+
const isCodeExecutionOnly =
|
|
222
|
+
allowedCallers.includes('code_execution') &&
|
|
223
|
+
!allowedCallers.includes('direct');
|
|
206
224
|
|
|
207
|
-
|
|
225
|
+
if (!isCodeExecutionOnly) continue;
|
|
226
|
+
|
|
227
|
+
// Include if: not deferred OR deferred but discovered
|
|
228
|
+
const isDeferred = toolDef.defer_loading === true;
|
|
229
|
+
const isDiscovered = this.discoveredToolNames.has(name);
|
|
230
|
+
if (!isDeferred || isDiscovered) {
|
|
231
|
+
programmaticOnlyTools.push(toolDef);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (programmaticOnlyTools.length === 0) return '';
|
|
236
|
+
|
|
237
|
+
const toolDescriptions = programmaticOnlyTools
|
|
238
|
+
.map((tool) => {
|
|
239
|
+
let desc = `- **${tool.name}**`;
|
|
240
|
+
if (tool.description != null && tool.description !== '') {
|
|
241
|
+
desc += `: ${tool.description}`;
|
|
242
|
+
}
|
|
243
|
+
if (tool.parameters) {
|
|
244
|
+
desc += `\n Parameters: ${JSON.stringify(tool.parameters, null, 2).replace(/\n/g, '\n ')}`;
|
|
245
|
+
}
|
|
246
|
+
return desc;
|
|
247
|
+
})
|
|
248
|
+
.join('\n\n');
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
'\n\n## Programmatic-Only Tools\n\n' +
|
|
252
|
+
'The following tools are available exclusively through the `run_tools_with_code` tool. ' +
|
|
253
|
+
'You cannot call these tools directly; instead, use `run_tools_with_code` with Python code that invokes them.\n\n' +
|
|
254
|
+
toolDescriptions
|
|
255
|
+
);
|
|
208
256
|
}
|
|
209
257
|
|
|
210
258
|
/**
|
|
211
|
-
*
|
|
259
|
+
* Gets the system runnable, creating it lazily if needed.
|
|
260
|
+
* Includes instructions, additional instructions, and programmatic-only tools documentation.
|
|
261
|
+
* Only rebuilds when marked stale (via markToolsAsDiscovered).
|
|
212
262
|
*/
|
|
213
|
-
|
|
263
|
+
get systemRunnable():
|
|
214
264
|
| Runnable<
|
|
215
265
|
BaseMessage[],
|
|
216
266
|
(BaseMessage | SystemMessage)[],
|
|
217
267
|
RunnableConfig<Record<string, unknown>>
|
|
218
268
|
>
|
|
219
269
|
| undefined {
|
|
220
|
-
|
|
221
|
-
|
|
270
|
+
// Return cached if not stale
|
|
271
|
+
if (!this.systemRunnableStale && this.cachedSystemRunnable !== undefined) {
|
|
272
|
+
return this.cachedSystemRunnable;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Stale or first access - rebuild
|
|
276
|
+
const instructionsString = this.buildInstructionsString();
|
|
277
|
+
this.cachedSystemRunnable = this.buildSystemRunnable(instructionsString);
|
|
278
|
+
this.systemRunnableStale = false;
|
|
279
|
+
return this.cachedSystemRunnable;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Explicitly initializes the system runnable.
|
|
284
|
+
* Call this before async token calculation to ensure system message tokens are counted first.
|
|
285
|
+
*/
|
|
286
|
+
initializeSystemRunnable(): void {
|
|
287
|
+
if (this.systemRunnableStale || this.cachedSystemRunnable === undefined) {
|
|
288
|
+
const instructionsString = this.buildInstructionsString();
|
|
289
|
+
this.cachedSystemRunnable = this.buildSystemRunnable(instructionsString);
|
|
290
|
+
this.systemRunnableStale = false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Builds the raw instructions string (without creating SystemMessage).
|
|
296
|
+
*/
|
|
297
|
+
private buildInstructionsString(): string {
|
|
298
|
+
let result = this.instructions ?? '';
|
|
222
299
|
|
|
223
300
|
if (
|
|
224
301
|
this.additionalInstructions != null &&
|
|
225
302
|
this.additionalInstructions !== ''
|
|
226
303
|
) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
304
|
+
result = result
|
|
305
|
+
? `${result}\n\n${this.additionalInstructions}`
|
|
306
|
+
: this.additionalInstructions;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const programmaticToolsDoc = this.buildProgrammaticOnlyToolsInstructions();
|
|
310
|
+
if (programmaticToolsDoc) {
|
|
311
|
+
result = result
|
|
312
|
+
? `${result}${programmaticToolsDoc}`
|
|
313
|
+
: programmaticToolsDoc;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Build system runnable from pre-built instructions string.
|
|
321
|
+
* Only called when content has actually changed.
|
|
322
|
+
*/
|
|
323
|
+
private buildSystemRunnable(
|
|
324
|
+
instructionsString: string
|
|
325
|
+
):
|
|
326
|
+
| Runnable<
|
|
327
|
+
BaseMessage[],
|
|
328
|
+
(BaseMessage | SystemMessage)[],
|
|
329
|
+
RunnableConfig<Record<string, unknown>>
|
|
330
|
+
>
|
|
331
|
+
| undefined {
|
|
332
|
+
if (!instructionsString) {
|
|
333
|
+
// Remove previous tokens if we had a system message before
|
|
334
|
+
this.instructionTokens -= this.systemMessageTokens;
|
|
335
|
+
this.systemMessageTokens = 0;
|
|
336
|
+
return undefined;
|
|
231
337
|
}
|
|
232
338
|
|
|
339
|
+
let finalInstructions: string | BaseMessageFields = instructionsString;
|
|
340
|
+
|
|
233
341
|
// Handle Anthropic prompt caching
|
|
234
|
-
if (
|
|
235
|
-
finalInstructions != null &&
|
|
236
|
-
finalInstructions !== '' &&
|
|
237
|
-
this.provider === Providers.ANTHROPIC
|
|
238
|
-
) {
|
|
342
|
+
if (this.provider === Providers.ANTHROPIC) {
|
|
239
343
|
const anthropicOptions = this.clientOptions as
|
|
240
344
|
| t.AnthropicClientOptions
|
|
241
345
|
| undefined;
|
|
@@ -251,7 +355,7 @@ export class AgentContext {
|
|
|
251
355
|
content: [
|
|
252
356
|
{
|
|
253
357
|
type: 'text',
|
|
254
|
-
text:
|
|
358
|
+
text: instructionsString,
|
|
255
359
|
cache_control: { type: 'ephemeral' },
|
|
256
360
|
},
|
|
257
361
|
],
|
|
@@ -259,19 +363,18 @@ export class AgentContext {
|
|
|
259
363
|
}
|
|
260
364
|
}
|
|
261
365
|
|
|
262
|
-
|
|
263
|
-
const systemMessage = new SystemMessage(finalInstructions);
|
|
366
|
+
const systemMessage = new SystemMessage(finalInstructions);
|
|
264
367
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return [systemMessage, ...messages];
|
|
271
|
-
}).withConfig({ runName: 'prompt' });
|
|
368
|
+
// Update token counts (subtract old, add new)
|
|
369
|
+
if (this.tokenCounter) {
|
|
370
|
+
this.instructionTokens -= this.systemMessageTokens;
|
|
371
|
+
this.systemMessageTokens = this.tokenCounter(systemMessage);
|
|
372
|
+
this.instructionTokens += this.systemMessageTokens;
|
|
272
373
|
}
|
|
273
374
|
|
|
274
|
-
return
|
|
375
|
+
return RunnableLambda.from((messages: BaseMessage[]) => {
|
|
376
|
+
return [systemMessage, ...messages];
|
|
377
|
+
}).withConfig({ runName: 'prompt' });
|
|
275
378
|
}
|
|
276
379
|
|
|
277
380
|
/**
|
|
@@ -279,6 +382,9 @@ export class AgentContext {
|
|
|
279
382
|
*/
|
|
280
383
|
reset(): void {
|
|
281
384
|
this.instructionTokens = 0;
|
|
385
|
+
this.systemMessageTokens = 0;
|
|
386
|
+
this.cachedSystemRunnable = undefined;
|
|
387
|
+
this.systemRunnableStale = true;
|
|
282
388
|
this.lastToken = undefined;
|
|
283
389
|
this.indexTokenCountMap = {};
|
|
284
390
|
this.currentUsage = undefined;
|
|
@@ -286,6 +392,7 @@ export class AgentContext {
|
|
|
286
392
|
this.lastStreamCall = undefined;
|
|
287
393
|
this.tokenTypeSwitch = undefined;
|
|
288
394
|
this.currentTokenType = ContentTypes.TEXT;
|
|
395
|
+
this.discoveredToolNames.clear();
|
|
289
396
|
}
|
|
290
397
|
|
|
291
398
|
/**
|
|
@@ -345,65 +452,83 @@ export class AgentContext {
|
|
|
345
452
|
}
|
|
346
453
|
|
|
347
454
|
/**
|
|
348
|
-
* Gets
|
|
349
|
-
*
|
|
350
|
-
* @returns
|
|
455
|
+
* Gets the tool registry for deferred tools (for tool search).
|
|
456
|
+
* @param onlyDeferred If true, only returns tools with defer_loading=true
|
|
457
|
+
* @returns LCToolRegistry with tool definitions
|
|
351
458
|
*/
|
|
352
|
-
|
|
353
|
-
const
|
|
459
|
+
getDeferredToolRegistry(onlyDeferred: boolean = true): t.LCToolRegistry {
|
|
460
|
+
const registry: t.LCToolRegistry = new Map();
|
|
354
461
|
|
|
355
|
-
if (!this.
|
|
356
|
-
return
|
|
462
|
+
if (!this.toolRegistry) {
|
|
463
|
+
return registry;
|
|
357
464
|
}
|
|
358
465
|
|
|
359
|
-
for (const [name,
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
programmaticMap.set(name, tool);
|
|
466
|
+
for (const [name, toolDef] of this.toolRegistry) {
|
|
467
|
+
if (!onlyDeferred || toolDef.defer_loading === true) {
|
|
468
|
+
registry.set(name, toolDef);
|
|
363
469
|
}
|
|
364
470
|
}
|
|
365
471
|
|
|
366
|
-
return
|
|
472
|
+
return registry;
|
|
367
473
|
}
|
|
368
474
|
|
|
369
475
|
/**
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
476
|
+
* Marks tools as discovered via tool search.
|
|
477
|
+
* Discovered tools will be included in the next model binding.
|
|
478
|
+
* Only marks system runnable stale if NEW tools were actually added.
|
|
479
|
+
* @param toolNames - Array of discovered tool names
|
|
480
|
+
* @returns true if any new tools were discovered
|
|
373
481
|
*/
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
for (const [_name, toolDef] of this.toolRegistry) {
|
|
381
|
-
if (toolAllowsCaller(toolDef, 'code_execution')) {
|
|
382
|
-
defs.push(toolDef);
|
|
482
|
+
markToolsAsDiscovered(toolNames: string[]): boolean {
|
|
483
|
+
let hasNewDiscoveries = false;
|
|
484
|
+
for (const name of toolNames) {
|
|
485
|
+
if (!this.discoveredToolNames.has(name)) {
|
|
486
|
+
this.discoveredToolNames.add(name);
|
|
487
|
+
hasNewDiscoveries = true;
|
|
383
488
|
}
|
|
384
489
|
}
|
|
385
|
-
|
|
386
|
-
|
|
490
|
+
if (hasNewDiscoveries) {
|
|
491
|
+
this.systemRunnableStale = true;
|
|
492
|
+
}
|
|
493
|
+
return hasNewDiscoveries;
|
|
387
494
|
}
|
|
388
495
|
|
|
389
496
|
/**
|
|
390
|
-
* Gets
|
|
391
|
-
*
|
|
392
|
-
*
|
|
497
|
+
* Gets tools that should be bound to the LLM.
|
|
498
|
+
* Includes:
|
|
499
|
+
* 1. Non-deferred tools with allowed_callers: ['direct']
|
|
500
|
+
* 2. Discovered tools (from tool search)
|
|
501
|
+
* @returns Array of tools to bind to model
|
|
393
502
|
*/
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (!this.toolRegistry) {
|
|
398
|
-
return registry;
|
|
503
|
+
getToolsForBinding(): t.GraphTools | undefined {
|
|
504
|
+
if (!this.tools || !this.toolRegistry) {
|
|
505
|
+
return this.tools;
|
|
399
506
|
}
|
|
400
507
|
|
|
401
|
-
|
|
402
|
-
if (!
|
|
403
|
-
|
|
508
|
+
const toolsToInclude = this.tools.filter((tool) => {
|
|
509
|
+
if (!('name' in tool)) {
|
|
510
|
+
return true; // No name, include by default
|
|
404
511
|
}
|
|
405
|
-
}
|
|
406
512
|
|
|
407
|
-
|
|
513
|
+
const toolDef = this.toolRegistry?.get(tool.name);
|
|
514
|
+
if (!toolDef) {
|
|
515
|
+
return true; // Not in registry, include by default
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Check if discovered (overrides defer_loading)
|
|
519
|
+
if (this.discoveredToolNames.has(tool.name)) {
|
|
520
|
+
// Discovered tools must still have allowed_callers: ['direct']
|
|
521
|
+
const allowedCallers = toolDef.allowed_callers ?? ['direct'];
|
|
522
|
+
return allowedCallers.includes('direct');
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Not discovered: must be direct-callable AND not deferred
|
|
526
|
+
const allowedCallers = toolDef.allowed_callers ?? ['direct'];
|
|
527
|
+
return (
|
|
528
|
+
allowedCallers.includes('direct') && toolDef.defer_loading !== true
|
|
529
|
+
);
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
return toolsToInclude;
|
|
408
533
|
}
|
|
409
534
|
}
|