illuma-agents 1.0.10 → 1.0.11
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/LICENSE +1 -1
- package/dist/cjs/agents/AgentContext.cjs +228 -27
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/enum.cjs +2 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +3 -11
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +27 -18
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/instrumentation.cjs +1 -3
- package/dist/cjs/instrumentation.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/index.cjs +1 -1
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +122 -7
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/google/index.cjs +1 -1
- package/dist/cjs/llm/google/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +6 -6
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs +1 -1
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +18 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +149 -54
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/tools.cjs +85 -0
- package/dist/cjs/messages/tools.cjs.map +1 -0
- package/dist/cjs/run.cjs +0 -8
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +4 -0
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +438 -0
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -0
- package/dist/cjs/tools/ToolNode.cjs +53 -15
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearchRegex.cjs +455 -0
- package/dist/cjs/tools/ToolSearchRegex.cjs.map +1 -0
- package/dist/cjs/tools/search/schema.cjs +7 -9
- package/dist/cjs/tools/search/schema.cjs.map +1 -1
- package/dist/cjs/utils/run.cjs +5 -1
- package/dist/cjs/utils/run.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +228 -27
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/enum.mjs +2 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +4 -12
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +27 -18
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/instrumentation.mjs +1 -3
- package/dist/esm/instrumentation.mjs.map +1 -1
- package/dist/esm/llm/anthropic/index.mjs +1 -1
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +122 -7
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/google/index.mjs +1 -1
- package/dist/esm/llm/google/index.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +6 -6
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs +1 -1
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/main.mjs +3 -0
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages/cache.mjs +149 -54
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/tools.mjs +82 -0
- package/dist/esm/messages/tools.mjs.map +1 -0
- package/dist/esm/run.mjs +0 -8
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +4 -0
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +430 -0
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -0
- package/dist/esm/tools/ToolNode.mjs +53 -15
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearchRegex.mjs +448 -0
- package/dist/esm/tools/ToolSearchRegex.mjs.map +1 -0
- package/dist/esm/tools/search/schema.mjs +7 -9
- package/dist/esm/tools/search/schema.mjs.map +1 -1
- package/dist/esm/utils/run.mjs +5 -1
- package/dist/esm/utils/run.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +65 -5
- package/dist/types/common/enum.d.ts +2 -0
- package/dist/types/graphs/Graph.d.ts +3 -2
- package/dist/types/index.d.ts +2 -0
- package/dist/types/llm/anthropic/index.d.ts +1 -1
- package/dist/types/llm/bedrock/index.d.ts +31 -4
- package/dist/types/llm/google/index.d.ts +1 -1
- package/dist/types/llm/openai/index.d.ts +3 -3
- package/dist/types/llm/openrouter/index.d.ts +1 -1
- package/dist/types/messages/cache.d.ts +23 -8
- package/dist/types/messages/index.d.ts +1 -0
- package/dist/types/messages/tools.d.ts +17 -0
- package/dist/types/test/mockTools.d.ts +28 -0
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +91 -0
- package/dist/types/tools/ToolNode.d.ts +10 -2
- package/dist/types/tools/ToolSearchRegex.d.ts +80 -0
- package/dist/types/types/graph.d.ts +7 -1
- package/dist/types/types/tools.d.ts +138 -0
- package/package.json +7 -2
- package/src/agents/AgentContext.ts +267 -27
- package/src/agents/__tests__/AgentContext.test.ts +805 -0
- package/src/common/enum.ts +2 -0
- package/src/events.ts +5 -12
- package/src/graphs/Graph.ts +33 -19
- package/src/index.ts +2 -0
- package/src/instrumentation.ts +1 -4
- package/src/llm/anthropic/index.ts +2 -2
- package/src/llm/bedrock/__tests__/bedrock-caching.test.ts +473 -0
- package/src/llm/bedrock/index.ts +150 -13
- package/src/llm/google/index.ts +2 -2
- package/src/llm/openai/index.ts +9 -9
- package/src/llm/openrouter/index.ts +2 -2
- package/src/messages/__tests__/tools.test.ts +473 -0
- package/src/messages/cache.ts +163 -61
- package/src/messages/index.ts +1 -0
- package/src/messages/tools.ts +99 -0
- package/src/run.ts +0 -9
- package/src/scripts/code_exec_ptc.ts +334 -0
- package/src/scripts/image.ts +178 -0
- package/src/scripts/programmatic_exec.ts +396 -0
- package/src/scripts/programmatic_exec_agent.ts +231 -0
- package/src/scripts/test-tools-before-handoff.ts +5 -1
- package/src/scripts/tool_search_regex.ts +162 -0
- package/src/scripts/tools.ts +4 -1
- package/src/specs/thinking-prune.test.ts +52 -118
- package/src/test/mockTools.ts +366 -0
- package/src/tools/CodeExecutor.ts +4 -0
- package/src/tools/ProgrammaticToolCalling.ts +558 -0
- package/src/tools/ToolNode.ts +59 -18
- package/src/tools/ToolSearchRegex.ts +535 -0
- package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.ts +318 -0
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +853 -0
- package/src/tools/__tests__/ToolSearchRegex.integration.test.ts +161 -0
- package/src/tools/__tests__/ToolSearchRegex.test.ts +232 -0
- package/src/tools/search/jina-reranker.test.ts +16 -16
- package/src/tools/search/schema.ts +7 -9
- package/src/types/graph.ts +7 -1
- package/src/types/tools.ts +166 -0
- package/src/utils/run.ts +5 -1
- package/src/tools/search/direct-url.test.ts +0 -530
|
@@ -25,6 +25,8 @@ 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
|
+
/** Tool registry for lazy computation of programmatic tools and tool search */
|
|
29
|
+
toolRegistry?: LCToolRegistry;
|
|
28
30
|
};
|
|
29
31
|
export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
|
|
30
32
|
export type ToolEndEvent = {
|
|
@@ -59,3 +61,139 @@ export type ExecuteResult = {
|
|
|
59
61
|
stderr: string;
|
|
60
62
|
files?: FileRefs;
|
|
61
63
|
};
|
|
64
|
+
/** JSON Schema type definition for tool parameters */
|
|
65
|
+
export type JsonSchemaType = {
|
|
66
|
+
type: 'string' | 'number' | 'integer' | 'float' | 'boolean' | 'array' | 'object';
|
|
67
|
+
enum?: string[];
|
|
68
|
+
items?: JsonSchemaType;
|
|
69
|
+
properties?: Record<string, JsonSchemaType>;
|
|
70
|
+
required?: string[];
|
|
71
|
+
description?: string;
|
|
72
|
+
additionalProperties?: boolean | JsonSchemaType;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Specifies which contexts can invoke a tool (inspired by Anthropic's allowed_callers)
|
|
76
|
+
* - 'direct': Only callable directly by the LLM (default if omitted)
|
|
77
|
+
* - 'code_execution': Only callable from within programmatic code execution
|
|
78
|
+
*/
|
|
79
|
+
export type AllowedCaller = 'direct' | 'code_execution';
|
|
80
|
+
/** Tool definition with optional deferred loading and caller restrictions */
|
|
81
|
+
export type LCTool = {
|
|
82
|
+
name: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
parameters?: JsonSchemaType;
|
|
85
|
+
/** When true, tool is not loaded into context initially (for tool search) */
|
|
86
|
+
defer_loading?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Which contexts can invoke this tool.
|
|
89
|
+
* Default: ['direct'] (only callable directly by LLM)
|
|
90
|
+
* Options: 'direct', 'code_execution'
|
|
91
|
+
*/
|
|
92
|
+
allowed_callers?: AllowedCaller[];
|
|
93
|
+
};
|
|
94
|
+
/** Map of tool names to tool definitions */
|
|
95
|
+
export type LCToolRegistry = Map<string, LCTool>;
|
|
96
|
+
export type ProgrammaticCache = {
|
|
97
|
+
toolMap: ToolMap;
|
|
98
|
+
toolDefs: LCTool[];
|
|
99
|
+
};
|
|
100
|
+
/** Parameters for creating a Tool Search Regex tool */
|
|
101
|
+
export type ToolSearchRegexParams = {
|
|
102
|
+
apiKey?: string;
|
|
103
|
+
toolRegistry?: LCToolRegistry;
|
|
104
|
+
onlyDeferred?: boolean;
|
|
105
|
+
baseUrl?: string;
|
|
106
|
+
[key: string]: unknown;
|
|
107
|
+
};
|
|
108
|
+
/** Simplified tool metadata for search purposes */
|
|
109
|
+
export type ToolMetadata = {
|
|
110
|
+
name: string;
|
|
111
|
+
description: string;
|
|
112
|
+
parameters?: JsonSchemaType;
|
|
113
|
+
};
|
|
114
|
+
/** Individual search result for a matching tool */
|
|
115
|
+
export type ToolSearchResult = {
|
|
116
|
+
tool_name: string;
|
|
117
|
+
match_score: number;
|
|
118
|
+
matched_field: string;
|
|
119
|
+
snippet: string;
|
|
120
|
+
};
|
|
121
|
+
/** Response from the tool search operation */
|
|
122
|
+
export type ToolSearchResponse = {
|
|
123
|
+
tool_references: ToolSearchResult[];
|
|
124
|
+
total_tools_searched: number;
|
|
125
|
+
pattern_used: string;
|
|
126
|
+
};
|
|
127
|
+
/** Artifact returned alongside the formatted search results */
|
|
128
|
+
export type ToolSearchArtifact = {
|
|
129
|
+
tool_references: ToolSearchResult[];
|
|
130
|
+
metadata: {
|
|
131
|
+
total_searched: number;
|
|
132
|
+
pattern: string;
|
|
133
|
+
error?: string;
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Tool call requested by the Code API during programmatic execution
|
|
138
|
+
*/
|
|
139
|
+
export type PTCToolCall = {
|
|
140
|
+
/** Unique ID like "call_001" */
|
|
141
|
+
id: string;
|
|
142
|
+
/** Tool name */
|
|
143
|
+
name: string;
|
|
144
|
+
/** Input parameters */
|
|
145
|
+
input: Record<string, any>;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Tool result sent back to the Code API
|
|
149
|
+
*/
|
|
150
|
+
export type PTCToolResult = {
|
|
151
|
+
/** Matches PTCToolCall.id */
|
|
152
|
+
call_id: string;
|
|
153
|
+
/** Tool execution result (any JSON-serializable value) */
|
|
154
|
+
result: any;
|
|
155
|
+
/** Whether tool execution failed */
|
|
156
|
+
is_error: boolean;
|
|
157
|
+
/** Error details if is_error=true */
|
|
158
|
+
error_message?: string;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Response from the Code API for programmatic execution
|
|
162
|
+
*/
|
|
163
|
+
export type ProgrammaticExecutionResponse = {
|
|
164
|
+
status: 'tool_call_required' | 'completed' | 'error' | unknown;
|
|
165
|
+
session_id?: string;
|
|
166
|
+
/** Present when status='tool_call_required' */
|
|
167
|
+
continuation_token?: string;
|
|
168
|
+
tool_calls?: PTCToolCall[];
|
|
169
|
+
/** Present when status='completed' */
|
|
170
|
+
stdout?: string;
|
|
171
|
+
stderr?: string;
|
|
172
|
+
files?: FileRefs;
|
|
173
|
+
/** Present when status='error' */
|
|
174
|
+
error?: string;
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Artifact returned by the PTC tool
|
|
178
|
+
*/
|
|
179
|
+
export type ProgrammaticExecutionArtifact = {
|
|
180
|
+
session_id?: string;
|
|
181
|
+
files?: FileRefs;
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Initialization parameters for the PTC tool
|
|
185
|
+
*/
|
|
186
|
+
export type ProgrammaticToolCallingParams = {
|
|
187
|
+
/** Code API key (or use CODE_API_KEY env var) */
|
|
188
|
+
apiKey?: string;
|
|
189
|
+
/** Code API base URL (or use CODE_BASEURL env var) */
|
|
190
|
+
baseUrl?: string;
|
|
191
|
+
/** Safety limit for round-trips (default: 20) */
|
|
192
|
+
maxRoundTrips?: number;
|
|
193
|
+
/** HTTP proxy URL */
|
|
194
|
+
proxy?: string;
|
|
195
|
+
/** Enable debug logging (or set PTC_DEBUG=true env var) */
|
|
196
|
+
debug?: boolean;
|
|
197
|
+
/** Environment variable key for API key */
|
|
198
|
+
[key: string]: unknown;
|
|
199
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "illuma-agents",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"main": "./dist/cjs/main.cjs",
|
|
5
5
|
"module": "./dist/esm/main.mjs",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"scripts": {
|
|
35
35
|
"prepare": "node husky-setup.js",
|
|
36
36
|
"prepublishOnly": "npm run build",
|
|
37
|
-
"build": "
|
|
37
|
+
"build": "cross-env NODE_ENV=production rollup -c && tsc -p tsconfig.build.json",
|
|
38
38
|
"build:dev": "rollup -c",
|
|
39
39
|
"start": "node dist/esm/main.js",
|
|
40
40
|
"clean": "node ./config/clean.js",
|
|
@@ -53,6 +53,10 @@
|
|
|
53
53
|
"memory": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/memory.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
|
|
54
54
|
"tool": "node --trace-warnings -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tools.ts --provider 'openrouter' --name 'Jo' --location 'New York, NY'",
|
|
55
55
|
"search": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/search.ts --provider 'bedrock' --name 'Jo' --location 'New York, NY'",
|
|
56
|
+
"tool_search_regex": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tool_search_regex.ts",
|
|
57
|
+
"programmatic_exec": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/programmatic_exec.ts",
|
|
58
|
+
"code_exec_ptc": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_ptc.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
|
|
59
|
+
"programmatic_exec_agent": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/programmatic_exec_agent.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
|
|
56
60
|
"ant_web_search": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/ant_web_search.ts --name 'Jo' --location 'New York, NY'",
|
|
57
61
|
"ant_web_search_edge_case": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/ant_web_search_edge_case.ts --name 'Jo' --location 'New York, NY'",
|
|
58
62
|
"ant_web_search_error_edge_case": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/ant_web_search_error_edge_case.ts --name 'Jo' --location 'New York, NY'",
|
|
@@ -140,6 +144,7 @@
|
|
|
140
144
|
"@types/yargs-parser": "^21.0.3",
|
|
141
145
|
"@typescript-eslint/eslint-plugin": "^8.24.0",
|
|
142
146
|
"@typescript-eslint/parser": "^8.24.0",
|
|
147
|
+
"cross-env": "^10.1.0",
|
|
143
148
|
"eslint": "^9.39.1",
|
|
144
149
|
"eslint-import-resolver-typescript": "^3.7.0",
|
|
145
150
|
"eslint-plugin-import": "^2.31.0",
|
|
@@ -32,6 +32,7 @@ export class AgentContext {
|
|
|
32
32
|
tools,
|
|
33
33
|
toolMap,
|
|
34
34
|
toolEnd,
|
|
35
|
+
toolRegistry,
|
|
35
36
|
instructions,
|
|
36
37
|
additional_instructions,
|
|
37
38
|
streamBuffer,
|
|
@@ -48,6 +49,7 @@ export class AgentContext {
|
|
|
48
49
|
streamBuffer,
|
|
49
50
|
tools,
|
|
50
51
|
toolMap,
|
|
52
|
+
toolRegistry,
|
|
51
53
|
instructions,
|
|
52
54
|
additionalInstructions: additional_instructions,
|
|
53
55
|
reasoningKey,
|
|
@@ -58,12 +60,17 @@ export class AgentContext {
|
|
|
58
60
|
});
|
|
59
61
|
|
|
60
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
|
+
|
|
61
68
|
const tokenMap = indexTokenCountMap || {};
|
|
62
69
|
agentContext.indexTokenCountMap = tokenMap;
|
|
63
70
|
agentContext.tokenCalculationPromise = agentContext
|
|
64
71
|
.calculateInstructionTokens(tokenCounter)
|
|
65
72
|
.then(() => {
|
|
66
|
-
// Update token map with instruction tokens
|
|
73
|
+
// Update token map with instruction tokens (includes system + tool tokens)
|
|
67
74
|
agentContext.updateTokenMapWithInstructions(tokenMap);
|
|
68
75
|
})
|
|
69
76
|
.catch((err) => {
|
|
@@ -102,6 +109,13 @@ export class AgentContext {
|
|
|
102
109
|
tools?: t.GraphTools;
|
|
103
110
|
/** Tool map for this agent */
|
|
104
111
|
toolMap?: t.ToolMap;
|
|
112
|
+
/**
|
|
113
|
+
* Tool definitions registry (includes deferred and programmatic tool metadata).
|
|
114
|
+
* Used for tool search and programmatic tool calling.
|
|
115
|
+
*/
|
|
116
|
+
toolRegistry?: t.LCToolRegistry;
|
|
117
|
+
/** Set of tool names discovered via tool search (to be loaded) */
|
|
118
|
+
discoveredToolNames: Set<string> = new Set();
|
|
105
119
|
/** Instructions for this agent */
|
|
106
120
|
instructions?: string;
|
|
107
121
|
/** Additional instructions for this agent */
|
|
@@ -117,12 +131,16 @@ export class AgentContext {
|
|
|
117
131
|
ContentTypes.TEXT;
|
|
118
132
|
/** Whether tools should end the workflow */
|
|
119
133
|
toolEnd: boolean = false;
|
|
120
|
-
/**
|
|
121
|
-
|
|
134
|
+
/** Cached system runnable (created lazily) */
|
|
135
|
+
private cachedSystemRunnable?: Runnable<
|
|
122
136
|
BaseMessage[],
|
|
123
137
|
(BaseMessage | SystemMessage)[],
|
|
124
138
|
RunnableConfig<Record<string, unknown>>
|
|
125
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;
|
|
126
144
|
/** Promise for token calculation initialization */
|
|
127
145
|
tokenCalculationPromise?: Promise<void>;
|
|
128
146
|
/** Format content blocks as strings (for legacy compatibility) */
|
|
@@ -137,6 +155,7 @@ export class AgentContext {
|
|
|
137
155
|
tokenCounter,
|
|
138
156
|
tools,
|
|
139
157
|
toolMap,
|
|
158
|
+
toolRegistry,
|
|
140
159
|
instructions,
|
|
141
160
|
additionalInstructions,
|
|
142
161
|
reasoningKey,
|
|
@@ -152,6 +171,7 @@ export class AgentContext {
|
|
|
152
171
|
tokenCounter?: t.TokenCounter;
|
|
153
172
|
tools?: t.GraphTools;
|
|
154
173
|
toolMap?: t.ToolMap;
|
|
174
|
+
toolRegistry?: t.LCToolRegistry;
|
|
155
175
|
instructions?: string;
|
|
156
176
|
additionalInstructions?: string;
|
|
157
177
|
reasoningKey?: 'reasoning_content' | 'reasoning';
|
|
@@ -167,6 +187,7 @@ export class AgentContext {
|
|
|
167
187
|
this.tokenCounter = tokenCounter;
|
|
168
188
|
this.tools = tools;
|
|
169
189
|
this.toolMap = toolMap;
|
|
190
|
+
this.toolRegistry = toolRegistry;
|
|
170
191
|
this.instructions = instructions;
|
|
171
192
|
this.additionalInstructions = additionalInstructions;
|
|
172
193
|
if (reasoningKey) {
|
|
@@ -180,39 +201,145 @@ export class AgentContext {
|
|
|
180
201
|
}
|
|
181
202
|
|
|
182
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');
|
|
224
|
+
|
|
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');
|
|
183
249
|
|
|
184
|
-
|
|
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
|
+
);
|
|
185
256
|
}
|
|
186
257
|
|
|
187
258
|
/**
|
|
188
|
-
*
|
|
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).
|
|
189
262
|
*/
|
|
190
|
-
|
|
263
|
+
get systemRunnable():
|
|
191
264
|
| Runnable<
|
|
192
265
|
BaseMessage[],
|
|
193
266
|
(BaseMessage | SystemMessage)[],
|
|
194
267
|
RunnableConfig<Record<string, unknown>>
|
|
195
268
|
>
|
|
196
269
|
| undefined {
|
|
197
|
-
|
|
198
|
-
|
|
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 ?? '';
|
|
199
299
|
|
|
200
300
|
if (
|
|
201
301
|
this.additionalInstructions != null &&
|
|
202
302
|
this.additionalInstructions !== ''
|
|
203
303
|
) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
: this.additionalInstructions;
|
|
304
|
+
result = result
|
|
305
|
+
? `${result}\n\n${this.additionalInstructions}`
|
|
306
|
+
: this.additionalInstructions;
|
|
208
307
|
}
|
|
209
308
|
|
|
210
|
-
|
|
211
|
-
if (
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
let finalInstructions: string | BaseMessageFields = instructionsString;
|
|
340
|
+
|
|
341
|
+
// Handle Anthropic prompt caching (Direct API)
|
|
342
|
+
if (this.provider === Providers.ANTHROPIC) {
|
|
216
343
|
const anthropicOptions = this.clientOptions as
|
|
217
344
|
| t.AnthropicClientOptions
|
|
218
345
|
| undefined;
|
|
@@ -228,7 +355,7 @@ export class AgentContext {
|
|
|
228
355
|
content: [
|
|
229
356
|
{
|
|
230
357
|
type: 'text',
|
|
231
|
-
text:
|
|
358
|
+
text: instructionsString,
|
|
232
359
|
cache_control: { type: 'ephemeral' },
|
|
233
360
|
},
|
|
234
361
|
],
|
|
@@ -236,19 +363,47 @@ export class AgentContext {
|
|
|
236
363
|
}
|
|
237
364
|
}
|
|
238
365
|
|
|
239
|
-
|
|
240
|
-
|
|
366
|
+
// Handle Bedrock prompt caching (Converse API)
|
|
367
|
+
// Adds cachePoint block after text content for system message caching
|
|
368
|
+
// NOTE: Both Claude and Nova models support cachePoint in system and messages
|
|
369
|
+
// (Nova does NOT support cachePoint in tools - that check is in bedrock/index.ts)
|
|
370
|
+
if (this.provider === Providers.BEDROCK) {
|
|
371
|
+
const bedrockOptions = this.clientOptions as
|
|
372
|
+
| t.BedrockAnthropicInput
|
|
373
|
+
| undefined;
|
|
374
|
+
const modelId = bedrockOptions?.model?.toLowerCase() ?? '';
|
|
375
|
+
const supportsCaching = modelId.includes('claude') || modelId.includes('anthropic') || modelId.includes('nova');
|
|
241
376
|
|
|
242
|
-
if (
|
|
243
|
-
|
|
377
|
+
if (bedrockOptions?.promptCache === true && supportsCaching) {
|
|
378
|
+
// Always log system cache structure
|
|
379
|
+
console.log(`[Cache] 📝 System | chars=${instructionsString.length} | tokens=${this.systemMessageTokens} | model=${modelId}`);
|
|
380
|
+
|
|
381
|
+
finalInstructions = {
|
|
382
|
+
content: [
|
|
383
|
+
{
|
|
384
|
+
type: 'text',
|
|
385
|
+
text: instructionsString,
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
cachePoint: { type: 'default' },
|
|
389
|
+
},
|
|
390
|
+
],
|
|
391
|
+
};
|
|
244
392
|
}
|
|
393
|
+
}
|
|
245
394
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
395
|
+
const systemMessage = new SystemMessage(finalInstructions);
|
|
396
|
+
|
|
397
|
+
// Update token counts (subtract old, add new)
|
|
398
|
+
if (this.tokenCounter) {
|
|
399
|
+
this.instructionTokens -= this.systemMessageTokens;
|
|
400
|
+
this.systemMessageTokens = this.tokenCounter(systemMessage);
|
|
401
|
+
this.instructionTokens += this.systemMessageTokens;
|
|
249
402
|
}
|
|
250
403
|
|
|
251
|
-
return
|
|
404
|
+
return RunnableLambda.from((messages: BaseMessage[]) => {
|
|
405
|
+
return [systemMessage, ...messages];
|
|
406
|
+
}).withConfig({ runName: 'prompt' });
|
|
252
407
|
}
|
|
253
408
|
|
|
254
409
|
/**
|
|
@@ -256,6 +411,9 @@ export class AgentContext {
|
|
|
256
411
|
*/
|
|
257
412
|
reset(): void {
|
|
258
413
|
this.instructionTokens = 0;
|
|
414
|
+
this.systemMessageTokens = 0;
|
|
415
|
+
this.cachedSystemRunnable = undefined;
|
|
416
|
+
this.systemRunnableStale = true;
|
|
259
417
|
this.lastToken = undefined;
|
|
260
418
|
this.indexTokenCountMap = {};
|
|
261
419
|
this.currentUsage = undefined;
|
|
@@ -263,6 +421,7 @@ export class AgentContext {
|
|
|
263
421
|
this.lastStreamCall = undefined;
|
|
264
422
|
this.tokenTypeSwitch = undefined;
|
|
265
423
|
this.currentTokenType = ContentTypes.TEXT;
|
|
424
|
+
this.discoveredToolNames.clear();
|
|
266
425
|
}
|
|
267
426
|
|
|
268
427
|
/**
|
|
@@ -320,4 +479,85 @@ export class AgentContext {
|
|
|
320
479
|
// Add tool tokens to existing instruction tokens (which may already include system message tokens)
|
|
321
480
|
this.instructionTokens += toolTokens;
|
|
322
481
|
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Gets the tool registry for deferred tools (for tool search).
|
|
485
|
+
* @param onlyDeferred If true, only returns tools with defer_loading=true
|
|
486
|
+
* @returns LCToolRegistry with tool definitions
|
|
487
|
+
*/
|
|
488
|
+
getDeferredToolRegistry(onlyDeferred: boolean = true): t.LCToolRegistry {
|
|
489
|
+
const registry: t.LCToolRegistry = new Map();
|
|
490
|
+
|
|
491
|
+
if (!this.toolRegistry) {
|
|
492
|
+
return registry;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
for (const [name, toolDef] of this.toolRegistry) {
|
|
496
|
+
if (!onlyDeferred || toolDef.defer_loading === true) {
|
|
497
|
+
registry.set(name, toolDef);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return registry;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Marks tools as discovered via tool search.
|
|
506
|
+
* Discovered tools will be included in the next model binding.
|
|
507
|
+
* Only marks system runnable stale if NEW tools were actually added.
|
|
508
|
+
* @param toolNames - Array of discovered tool names
|
|
509
|
+
* @returns true if any new tools were discovered
|
|
510
|
+
*/
|
|
511
|
+
markToolsAsDiscovered(toolNames: string[]): boolean {
|
|
512
|
+
let hasNewDiscoveries = false;
|
|
513
|
+
for (const name of toolNames) {
|
|
514
|
+
if (!this.discoveredToolNames.has(name)) {
|
|
515
|
+
this.discoveredToolNames.add(name);
|
|
516
|
+
hasNewDiscoveries = true;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
if (hasNewDiscoveries) {
|
|
520
|
+
this.systemRunnableStale = true;
|
|
521
|
+
}
|
|
522
|
+
return hasNewDiscoveries;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Gets tools that should be bound to the LLM.
|
|
527
|
+
* Includes:
|
|
528
|
+
* 1. Non-deferred tools with allowed_callers: ['direct']
|
|
529
|
+
* 2. Discovered tools (from tool search)
|
|
530
|
+
* @returns Array of tools to bind to model
|
|
531
|
+
*/
|
|
532
|
+
getToolsForBinding(): t.GraphTools | undefined {
|
|
533
|
+
if (!this.tools || !this.toolRegistry) {
|
|
534
|
+
return this.tools;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const toolsToInclude = this.tools.filter((tool) => {
|
|
538
|
+
if (!('name' in tool)) {
|
|
539
|
+
return true; // No name, include by default
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const toolDef = this.toolRegistry?.get(tool.name);
|
|
543
|
+
if (!toolDef) {
|
|
544
|
+
return true; // Not in registry, include by default
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Check if discovered (overrides defer_loading)
|
|
548
|
+
if (this.discoveredToolNames.has(tool.name)) {
|
|
549
|
+
// Discovered tools must still have allowed_callers: ['direct']
|
|
550
|
+
const allowedCallers = toolDef.allowed_callers ?? ['direct'];
|
|
551
|
+
return allowedCallers.includes('direct');
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Not discovered: must be direct-callable AND not deferred
|
|
555
|
+
const allowedCallers = toolDef.allowed_callers ?? ['direct'];
|
|
556
|
+
return (
|
|
557
|
+
allowedCallers.includes('direct') && toolDef.defer_loading !== true
|
|
558
|
+
);
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
return toolsToInclude;
|
|
562
|
+
}
|
|
323
563
|
}
|