@amitdeshmukh/ax-crew 8.7.3 → 9.0.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.
@@ -192,7 +192,7 @@ async function main() {
192
192
  const crew = new AxCrew(config, customFunctions);
193
193
 
194
194
  // Set state for class-based functions
195
- crew.state.set("env", { API_BASE_URL: "https://api.example.com" });
195
+ crew.crewState.set("env", { API_BASE_URL: "https://api.example.com" });
196
196
 
197
197
  await crew.addAllAgents();
198
198
  const assistant = crew.agents?.get("assistant");
@@ -210,7 +210,7 @@ main().catch(console.error);
210
210
  ## Do Not Generate
211
211
 
212
212
  - Do NOT define functions inline in AgentConfig; always use a `FunctionRegistryType` registry passed to the `AxCrew` constructor.
213
- - Do NOT forget that class-based function constructors receive `state: Record<string, any>`, not `StateInstance`. Access values directly (e.g. `this.state.env`), since the state object is a plain record populated via `crew.state.set()`.
213
+ - Do NOT forget that class-based function constructors receive `state: Record<string, any>`, not `StateInstance`. Access values directly (e.g. `this.state.env`), since the state object is a plain record populated via `crew.crewState.set()`.
214
214
  - Do NOT use a registry key that differs from the function name used in `AgentConfig.functions[]` -- they must match.
215
215
  - Do NOT import `AxCrewFunctions` from `@ax-llm/ax`; import from `@amitdeshmukh/ax-crew`.
216
216
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: axcrew-mcp
3
- version: "8.7.3"
3
+ version: "9.0.0"
4
4
  description: "ax-crew MCP integration: MCP, Model Context Protocol, STDIO, HTTP SSE, Streamable HTTP, mcpServers, tools, tool filtering, multiple servers"
5
5
  argument-hint: [topic]
6
6
  allowed-tools: Read, Grep, Glob
@@ -205,6 +205,46 @@ async function main() {
205
205
  main().catch(console.error);
206
206
  ```
207
207
 
208
+ ## Deferred Tool Loading
209
+
210
+ When an agent has many MCP tools (20+), use the `deferredTools` config to reduce token usage. Only core tools + a `search_tools` meta-function are sent to the LLM. The LLM discovers additional tools on demand. Discovered tools persist across `forward()` calls. Tool results that mention deferred tool names (e.g., error responses suggesting `fix_query_error`) auto-activate those tools.
211
+
212
+ ```typescript
213
+ {
214
+ name: "BigMCPAgent",
215
+ description: "Agent with many MCP tools",
216
+ signature: 'query:string -> answer:string',
217
+ provider: "anthropic",
218
+ providerKeyName: "ANTHROPIC_API_KEY",
219
+ ai: { model: "claude-sonnet-4-6", temperature: 0 },
220
+ mcpServers: {
221
+ "large-server": {
222
+ command: "npx",
223
+ args: ["-y", "some-large-mcp-server"],
224
+ },
225
+ },
226
+ deferredTools: {
227
+ enabled: true, // default: auto (true when tool count > threshold)
228
+ threshold: 20, // tool count to activate deferred mode
229
+ maxSearchResults: 10, // max tools returned per search
230
+ coreTools: ["execute_graphql", "list_tables"], // always keep active
231
+ },
232
+ }
233
+ ```
234
+
235
+ ### What is "core" vs "deferred"
236
+
237
+ - **Core** (always visible): custom functions, sub-agent functions, `resource_*` functions, explicitly listed `coreTools`
238
+ - **Deferred** (discoverable via search): MCP tool functions (except `resource_*`)
239
+
240
+ ### Resource Caching
241
+
242
+ MCP `resource_*` functions (reference docs like query syntax guides) are automatically cached in-memory. Repeated calls return the cached result without re-fetching from the MCP server.
243
+
244
+ ## Prompt Caching
245
+
246
+ Prompt caching is enabled by default for all agents. System prompts and tool definitions are cached across multi-step interactions via Anthropic's implicit caching or Gemini's context caching. This reduces token costs by up to 6x for agents with many tools — the system prompt (~13K tokens of tool schemas) is processed once and reused on subsequent steps.
247
+
208
248
  ## Supporting files
209
249
  - See [examples/mcp-agent.ts](examples/mcp-agent.ts) for a complete runnable example.
210
250
  - See [examples/graphjin-database-agent.ts](examples/graphjin-database-agent.ts) for Streamable HTTP transport.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: axcrew-patterns
3
- version: 8.7.3
3
+ version: 9.0.0
4
4
  description: "AxCrew multi-agent patterns: pipeline, delegation, fan-out, orchestrator, sequential workflows, and agent coordination."
5
5
  tags: [patterns, workflow, pipeline, multi-agent, orchestrator, delegation, sequential, fan-out]
6
6
  ---
@@ -251,8 +251,8 @@ Target audience: intermediate developers familiar with TypeScript.`,
251
251
  All agents in a crew share a mutable `state` object for out-of-band data passing:
252
252
 
253
253
  ```ts
254
- crew.state.set("env", { WORDPRESS_URL: "http://...", WORDPRESS_USERNAME: "..." });
255
- crew.state.set("context", { userId: "abc-123" });
254
+ crew.crewState.set("env", { WORDPRESS_URL: "http://...", WORDPRESS_USERNAME: "..." });
255
+ crew.crewState.set("context", { userId: "abc-123" });
256
256
 
257
257
  // Inside a custom function, state is accessible via the constructor:
258
258
  class MyTool {
@@ -271,17 +271,61 @@ class MyTool {
271
271
  }
272
272
  ```
273
273
 
274
+ ## Cost Optimization Pattern (Single-Delegation Manager)
275
+
276
+ When a manager orchestrates sub-agents, use a **single-delegation** pattern: send the full question to the sub-agent in one call. Do NOT break questions into sub-queries — the sub-agent handles multi-step work internally.
277
+
278
+ This pattern reduced costs from $128 to $1 on the same query in testing.
279
+
280
+ ```ts
281
+ {
282
+ name: "ManagerAgent",
283
+ description: "Orchestrates database queries and analysis tasks",
284
+ definition: `You are an orchestrator that routes questions to specialized agents.
285
+ Delegate each question to the most relevant agent in a SINGLE call — do not break questions into sub-queries.
286
+ The sub-agent will handle all the steps internally. Your job is to route and synthesize, not to decompose.
287
+ If multiple agents are needed, call them and combine their answers.`,
288
+ signature: 'question:string -> answer:string',
289
+ provider: "anthropic" as Provider,
290
+ providerKeyName: "ANTHROPIC_API_KEY",
291
+ ai: { model: "claude-sonnet-4-6", maxTokens: 2000, temperature: 0 },
292
+ agents: ["DatabaseAgent", "AnalyticsAgent"],
293
+ }
294
+ ```
295
+
296
+ ## Workflow Reuse Pattern (MCP Agents)
297
+
298
+ For agents connected to MCP servers, use a strategy-driven definition that checks for saved workflows before building new ones. This ensures repeat questions reuse cached workflows ($0.17) instead of rebuilding from scratch ($0.55).
299
+
300
+ ```ts
301
+ {
302
+ name: "DatabaseAgent",
303
+ definition: `You answer questions by querying databases via an MCP server.
304
+
305
+ STRATEGY:
306
+ 1. Check first — call list_workflows and list_saved_queries. If a match exists, execute it directly.
307
+ 2. Learn — read resource docs, list tables, describe schema.
308
+ 3. Build — author a JS workflow with server-side computation, validate with a test query.
309
+ 4. Save and run — save the workflow for reuse, then execute it.
310
+ 5. If a query fails, call fix_query_error to diagnose. Do not retry the same query.
311
+ 6. Synthesize the answer from results.`,
312
+ // ...
313
+ }
314
+ ```
315
+
274
316
  ## Supporting files
275
317
  - See [examples/write-post-and-publish-to-wordpress.ts](examples/write-post-and-publish-to-wordpress.ts) for a complete pipeline example.
276
318
  - See [examples/solve-math-problem.ts](examples/solve-math-problem.ts) for a delegation example.
319
+ - See [examples/graphjin-database-agent.ts](examples/graphjin-database-agent.ts) for single-delegation + workflow reuse pattern.
277
320
 
278
321
  ## Do Not Generate
279
322
 
280
323
  - Do NOT add a parent agent before its sub-agents -- `addAgentsToCrew` resolves dependencies but `addAgent` does not.
281
324
  - Do NOT use `agents: ["SelfName"]` -- an agent cannot be its own sub-agent (circular dependency error).
282
- - Do NOT assume agents share conversation context -- they share `state` but each `forward()` call is independent. Pass data explicitly via signatures.
325
+ - Do NOT assume agents share conversation context -- they share `crewState` but each `forward()` call is independent. Pass data explicitly via signatures.
283
326
  - Do NOT use `definition` shorter than 100 characters -- Ax requires minimum length for program definitions.
284
327
  - Do NOT confuse `description` (used as the tool description when this agent is a sub-agent) with `definition` (the system prompt).
328
+ - Do NOT have the manager decompose questions into sub-queries -- send the full question to the sub-agent in one call.
285
329
 
286
330
  ## References
287
331
 
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  name: axcrew-state
3
- version: 8.7.3
3
+ version: 9.0.0
4
4
  description: "State management: shared state, StateInstance, set, get, getAll, reset, accessing state from class-based functions"
5
5
  ---
6
6
 
7
7
  # State
8
8
 
9
- Every `AxCrew` instance has a shared `StateInstance` at `crew.state`. All agents and class-based functions in the crew can access the same state.
9
+ Every `AxCrew` instance has a shared `StateInstance` at `crew.crewState`. All agents and class-based functions in the crew can access the same state.
10
10
 
11
11
  ## StateInstance API
12
12
 
@@ -21,9 +21,9 @@ interface StateInstance {
21
21
 
22
22
  ## Core Behavior
23
23
 
24
- - `crew.state` is created automatically when `new AxCrew(config)` is called.
24
+ - `crew.crewState` is created automatically when `new AxCrew(config)` is called.
25
25
  - State is keyed by `crewId` (auto-generated UUID). Each crew instance has its own isolated state.
26
- - State persists for the lifetime of the crew. Calling `crew.destroy()` calls `state.reset()`.
26
+ - State persists for the lifetime of the crew. Calling `crew.destroy()` calls `crewState.reset()`.
27
27
  - Values can be any type: strings, objects, arrays, etc.
28
28
 
29
29
  ## Canonical Pattern
@@ -53,7 +53,7 @@ class SendEmail {
53
53
  required: ['to', 'subject', 'body']
54
54
  },
55
55
  func: async ({ to, subject, body }: { to: string; subject: string; body: string }) => {
56
- // Access env credentials set via crew.state.set("env", {...})
56
+ // Access env credentials set via crew.crewState.set("env", {...})
57
57
  const env = this.state.env || {};
58
58
  const smtpHost = env.SMTP_HOST;
59
59
  const smtpUser = env.SMTP_USER;
@@ -84,15 +84,15 @@ async function main() {
84
84
  const crew = new AxCrew(config, functions);
85
85
 
86
86
  // Set environment variables in shared state BEFORE adding agents
87
- crew.state.set("env", {
87
+ crew.crewState.set("env", {
88
88
  SMTP_HOST: "smtp.example.com",
89
89
  SMTP_USER: "user@example.com",
90
90
  SMTP_PASS: "secret",
91
91
  });
92
92
 
93
93
  // You can also set arbitrary data
94
- crew.state.set("company", "Acme Corp");
95
- crew.state.set("maxRetries", 3);
94
+ crew.crewState.set("company", "Acme Corp");
95
+ crew.crewState.set("maxRetries", 3);
96
96
 
97
97
  await crew.addAllAgents();
98
98
  const notifier = crew.agents?.get("notifier");
@@ -101,11 +101,11 @@ async function main() {
101
101
  console.log(result?.result);
102
102
 
103
103
  // Read state back
104
- console.log("All state:", crew.state.getAll());
105
- console.log("Company:", crew.state.get("company"));
104
+ console.log("All state:", crew.crewState.getAll());
105
+ console.log("Company:", crew.crewState.get("company"));
106
106
 
107
107
  // Reset state (clear all)
108
- crew.state.reset();
108
+ crew.crewState.reset();
109
109
 
110
110
  crew.destroy();
111
111
  }
@@ -118,7 +118,7 @@ main().catch(console.error);
118
118
  The common pattern for passing credentials to class-based functions:
119
119
 
120
120
  ```ts
121
- crew.state.set("env", {
121
+ crew.crewState.set("env", {
122
122
  WORDPRESS_URL: "http://my-wordpress-site.com",
123
123
  WORDPRESS_USERNAME: "my-username",
124
124
  WORDPRESS_PASSWORD: "my-password",
@@ -147,11 +147,11 @@ class MyFunction {
147
147
 
148
148
  ## Accessing State from Agents
149
149
 
150
- Each `StatefulAxAgent` has a `state` property that references the crew's shared state:
150
+ Each `StatefulAxAgent` has a `crewState` property that references the crew's shared state:
151
151
 
152
152
  ```ts
153
153
  const agent = crew.agents?.get("myAgent");
154
- // agent.state is the same StateInstance as crew.state
154
+ // agent.crewState is the same StateInstance as crew.crewState
155
155
  ```
156
156
 
157
157
  ## Supporting files
@@ -160,8 +160,8 @@ const agent = crew.agents?.get("myAgent");
160
160
  ## Do Not Generate
161
161
 
162
162
  - Do NOT assume state values exist without checking; always use optional chaining (e.g. `this.state.env?.KEY`).
163
- - Do NOT call `crew.state.set("env", ...)` after `addAllAgents()` if class-based functions read state during construction -- set state first.
164
- - Do NOT confuse `crew.state` (StateInstance with `set`/`get`/`getAll`/`reset`) with plain objects. The state object passed to class-based function constructors is a plain record, not the `StateInstance` interface.
163
+ - Do NOT call `crew.crewState.set("env", ...)` after `addAllAgents()` if class-based functions read state during construction -- set state first.
164
+ - Do NOT confuse `crew.crewState` (StateInstance with `set`/`get`/`getAll`/`reset`) with plain objects. The state object passed to class-based function constructors is a plain record, not the `StateInstance` interface.
165
165
  - Do NOT store sensitive credentials in state if the state object might be logged or serialized. The `getAll()` method returns all stored values.
166
166
 
167
167
  ## References
@@ -98,11 +98,24 @@ new AxCrew(crewConfig: AxCrewConfig, functionsRegistry?: FunctionRegistryType, o
98
98
  | `crew.agents?.get("A")` | Retrieve a `StatefulAxAgent` |
99
99
  | `await agent.forward({ key: "value" })` | Run the agent |
100
100
  | `agent.streamingForward({ key: "value" })` | Stream output chunks |
101
- | `crew.state` | Shared `StateInstance` across all agents |
101
+ | `crew.crewState` | Shared `StateInstance` across all agents |
102
102
  | `crew.resetCosts()` | Reset usage/metrics for all agents |
103
103
  | `crew.getCrewMetrics()` | Aggregate metrics snapshot |
104
104
  | `crew.destroy()` | Clean up agents, state, execution history |
105
105
 
106
+ ## Deferred Tool Loading
107
+
108
+ Agents with many MCP tools can use `deferredTools` in their agent config to avoid overwhelming the LLM context. When the total tool count exceeds a threshold (default 20), only core tools plus a `search_tools` meta-tool are visible to the agent. The LLM discovers additional tools by calling `search_tools`, which uses local multi-signal search (no API calls). Discovered tools persist across `forward()` calls, and related tools are proactively activated alongside the requested tool.
109
+
110
+ ```ts
111
+ {
112
+ name: "BigToolAgent",
113
+ // ...
114
+ mcpServers: { /* ... */ },
115
+ deferredTools: { maxTools: 20 }, // optional, 20 is the default threshold
116
+ }
117
+ ```
118
+
106
119
  ## Related Skills
107
120
 
108
121
  - `ax-crew-agent-config` -- AgentConfig fields, provider setup, executionMode
package/src/types.ts CHANGED
@@ -202,6 +202,22 @@ interface ACEConfig {
202
202
  compileOnStart?: boolean;
203
203
  }
204
204
 
205
+ /**
206
+ * Configuration for deferred tool loading.
207
+ * When an agent has many tools, only core tools are visible by default.
208
+ * A search_tools meta-function lets the LLM discover and activate deferred tools on demand.
209
+ */
210
+ interface DeferredToolsConfig {
211
+ /** Enable deferred tool loading. Default: auto (true when tool count > threshold) */
212
+ enabled?: boolean;
213
+ /** Tool count threshold to activate deferred mode. Default: 20 */
214
+ threshold?: number;
215
+ /** Max tools returned per search. Default: 10 */
216
+ maxSearchResults?: number;
217
+ /** Tool names to always keep active (bypasses deferral) */
218
+ coreTools?: string[];
219
+ }
220
+
205
221
  /**
206
222
  * The configuration for an agent.
207
223
  *
@@ -261,6 +277,8 @@ interface AgentConfig {
261
277
  mcpServers?: Record<string, MCPTransportConfig>;
262
278
  /** Optional AxACE configuration to enable optimization for this agent */
263
279
  ace?: ACEConfig;
280
+ /** Deferred tool loading — reduces token usage when an agent has many tools */
281
+ deferredTools?: DeferredToolsConfig;
264
282
  }
265
283
 
266
284
  /**
@@ -335,6 +353,7 @@ export {
335
353
  type ModelInfo,
336
354
  type UsageCost,
337
355
  type AggregatedCosts,
356
+ type DeferredToolsConfig,
338
357
  // ACE exports
339
358
  type ACEConfig,
340
359
  type ACEMetricConfig,
@@ -1,13 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(npm test:*)",
5
- "Bash(git push:*)",
6
- "Bash(git status:*)",
7
- "Bash(node:*)",
8
- "Bash(npm version:*)",
9
- "WebFetch(domain:github.com)",
10
- "WebFetch(domain:tanstack.com)"
11
- ]
12
- }
13
- }