bigtool-ts 0.1.0
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/CHANGELOG.md +27 -0
- package/LICENSE +21 -0
- package/README.md +641 -0
- package/dist/adapters/agent-protocol.d.ts +149 -0
- package/dist/adapters/agent-protocol.d.ts.map +1 -0
- package/dist/adapters/agent-protocol.js +133 -0
- package/dist/adapters/agent-protocol.js.map +1 -0
- package/dist/adapters/index.d.ts +39 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +42 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/inngest.d.ts +234 -0
- package/dist/adapters/inngest.d.ts.map +1 -0
- package/dist/adapters/inngest.js +276 -0
- package/dist/adapters/inngest.js.map +1 -0
- package/dist/adapters/mastra.d.ts +201 -0
- package/dist/adapters/mastra.d.ts.map +1 -0
- package/dist/adapters/mastra.js +250 -0
- package/dist/adapters/mastra.js.map +1 -0
- package/dist/adapters/types.d.ts +42 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +6 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/adapters/vercel-ai.d.ts +176 -0
- package/dist/adapters/vercel-ai.d.ts.map +1 -0
- package/dist/adapters/vercel-ai.js +244 -0
- package/dist/adapters/vercel-ai.js.map +1 -0
- package/dist/catalog/index.d.ts +177 -0
- package/dist/catalog/index.d.ts.map +1 -0
- package/dist/catalog/index.js +244 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/graph/agent.d.ts +214 -0
- package/dist/graph/agent.d.ts.map +1 -0
- package/dist/graph/agent.js +196 -0
- package/dist/graph/agent.js.map +1 -0
- package/dist/graph/index.d.ts +5 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +4 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/nodes.d.ts +100 -0
- package/dist/graph/nodes.d.ts.map +1 -0
- package/dist/graph/nodes.js +190 -0
- package/dist/graph/nodes.js.map +1 -0
- package/dist/graph/search-tool.d.ts +34 -0
- package/dist/graph/search-tool.d.ts.map +1 -0
- package/dist/graph/search-tool.js +54 -0
- package/dist/graph/search-tool.js.map +1 -0
- package/dist/graph/state.d.ts +26 -0
- package/dist/graph/state.d.ts.map +1 -0
- package/dist/graph/state.js +29 -0
- package/dist/graph/state.js.map +1 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +85 -0
- package/dist/index.js.map +1 -0
- package/dist/loader/index.d.ts +172 -0
- package/dist/loader/index.d.ts.map +1 -0
- package/dist/loader/index.js +179 -0
- package/dist/loader/index.js.map +1 -0
- package/dist/loader/loader.d.ts +114 -0
- package/dist/loader/loader.d.ts.map +1 -0
- package/dist/loader/loader.js +185 -0
- package/dist/loader/loader.js.map +1 -0
- package/dist/search/cache.d.ts +76 -0
- package/dist/search/cache.d.ts.map +1 -0
- package/dist/search/cache.js +135 -0
- package/dist/search/cache.js.map +1 -0
- package/dist/search/index.d.ts +63 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +122 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/normalize.d.ts +104 -0
- package/dist/search/normalize.d.ts.map +1 -0
- package/dist/search/normalize.js +211 -0
- package/dist/search/normalize.js.map +1 -0
- package/dist/search/orama.d.ts +256 -0
- package/dist/search/orama.d.ts.map +1 -0
- package/dist/search/orama.js +511 -0
- package/dist/search/orama.js.map +1 -0
- package/dist/search/types.d.ts +96 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +8 -0
- package/dist/search/types.js.map +1 -0
- package/dist/sources/dynamic.d.ts +200 -0
- package/dist/sources/dynamic.d.ts.map +1 -0
- package/dist/sources/dynamic.js +194 -0
- package/dist/sources/dynamic.js.map +1 -0
- package/dist/sources/index.d.ts +11 -0
- package/dist/sources/index.d.ts.map +1 -0
- package/dist/sources/index.js +14 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/sources/local.d.ts +128 -0
- package/dist/sources/local.d.ts.map +1 -0
- package/dist/sources/local.js +155 -0
- package/dist/sources/local.js.map +1 -0
- package/dist/sources/mcp.d.ts +438 -0
- package/dist/sources/mcp.d.ts.map +1 -0
- package/dist/sources/mcp.js +438 -0
- package/dist/sources/mcp.js.map +1 -0
- package/dist/sources/types.d.ts +16 -0
- package/dist/sources/types.d.ts.map +1 -0
- package/dist/sources/types.js +7 -0
- package/dist/sources/types.js.map +1 -0
- package/dist/sources/with-metadata.d.ts +7 -0
- package/dist/sources/with-metadata.d.ts.map +1 -0
- package/dist/sources/with-metadata.js +7 -0
- package/dist/sources/with-metadata.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types.d.ts +700 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +97 -0
- package/dist/types.js.map +1 -0
- package/package.json +118 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent factory module.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the main entry point for creating LangGraph agents
|
|
5
|
+
* with dynamic tool discovery capabilities.
|
|
6
|
+
*
|
|
7
|
+
* @module graph/agent
|
|
8
|
+
*/
|
|
9
|
+
import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
|
|
10
|
+
import type { StructuredTool } from "@langchain/core/tools";
|
|
11
|
+
import type { CompiledStateGraph } from "@langchain/langgraph";
|
|
12
|
+
import type { ToolSource, SearchIndex } from "../types.js";
|
|
13
|
+
import { type ToolDiscoveryState } from "./state.js";
|
|
14
|
+
/**
|
|
15
|
+
* Configuration options for createAgent.
|
|
16
|
+
*
|
|
17
|
+
* Controls the LLM, tool sources, search behavior, and caching.
|
|
18
|
+
*
|
|
19
|
+
* @example Minimal configuration
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const options: CreateAgentOptions = {
|
|
22
|
+
* llm: new ChatOpenAI({ model: 'gpt-4o' }),
|
|
23
|
+
* tools: [myTool1, myTool2],
|
|
24
|
+
* search: new OramaSearch(),
|
|
25
|
+
* };
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example Full configuration
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const options: CreateAgentOptions = {
|
|
31
|
+
* llm: new ChatOpenAI({ model: 'gpt-4o' }),
|
|
32
|
+
* sources: [
|
|
33
|
+
* new LocalSource(utilityTools),
|
|
34
|
+
* new MCPSource(githubClient),
|
|
35
|
+
* ],
|
|
36
|
+
* search: new OramaSearch({ mode: 'hybrid', embeddings }),
|
|
37
|
+
* pinnedTools: [helpTool],
|
|
38
|
+
* systemPrompt: 'You are a helpful coding assistant.',
|
|
39
|
+
* searchLimit: 10,
|
|
40
|
+
* searchThreshold: 0.3,
|
|
41
|
+
* cacheSize: 200,
|
|
42
|
+
* };
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export interface CreateAgentOptions {
|
|
46
|
+
/**
|
|
47
|
+
* The LLM to use for the agent.
|
|
48
|
+
*
|
|
49
|
+
* Must support tool binding (bindTools method).
|
|
50
|
+
*/
|
|
51
|
+
llm: BaseChatModel;
|
|
52
|
+
/**
|
|
53
|
+
* Tools to register.
|
|
54
|
+
*
|
|
55
|
+
* Can be either an array of StructuredTool instances or
|
|
56
|
+
* an array of ToolSource instances. If StructuredTools are
|
|
57
|
+
* provided, they are wrapped in a LocalSource automatically.
|
|
58
|
+
*/
|
|
59
|
+
tools?: StructuredTool[] | ToolSource[];
|
|
60
|
+
/**
|
|
61
|
+
* Tool sources to register.
|
|
62
|
+
*
|
|
63
|
+
* Alternative to `tools` for when you have pre-configured
|
|
64
|
+
* sources. Can be used together with `tools`.
|
|
65
|
+
*/
|
|
66
|
+
sources?: ToolSource[];
|
|
67
|
+
/**
|
|
68
|
+
* Search index implementation.
|
|
69
|
+
*
|
|
70
|
+
* Required. Use OramaSearch for most cases.
|
|
71
|
+
*/
|
|
72
|
+
search: SearchIndex;
|
|
73
|
+
/**
|
|
74
|
+
* Tools that are always available.
|
|
75
|
+
*
|
|
76
|
+
* These tools bypass search and are always in the LLM's context.
|
|
77
|
+
* Use for frequently-needed tools to avoid search overhead.
|
|
78
|
+
*/
|
|
79
|
+
pinnedTools?: StructuredTool[];
|
|
80
|
+
/**
|
|
81
|
+
* System prompt to prepend to conversations.
|
|
82
|
+
*
|
|
83
|
+
* Added as a SystemMessage at the start of the message list
|
|
84
|
+
* if not already present.
|
|
85
|
+
*/
|
|
86
|
+
systemPrompt?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Maximum tools returned per search.
|
|
89
|
+
*
|
|
90
|
+
* @default 5
|
|
91
|
+
*/
|
|
92
|
+
searchLimit?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Minimum search score threshold (0-1).
|
|
95
|
+
*
|
|
96
|
+
* Results with scores below this are filtered out.
|
|
97
|
+
*
|
|
98
|
+
* @default 0
|
|
99
|
+
*/
|
|
100
|
+
searchThreshold?: number;
|
|
101
|
+
/**
|
|
102
|
+
* Maximum tools to cache in the loader.
|
|
103
|
+
*
|
|
104
|
+
* Uses LRU eviction when limit is reached.
|
|
105
|
+
*
|
|
106
|
+
* @default 100
|
|
107
|
+
*/
|
|
108
|
+
cacheSize?: number;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The compiled agent graph type.
|
|
112
|
+
*
|
|
113
|
+
* This is the return type of createAgent and createToolDiscoveryGraph.
|
|
114
|
+
* Can be invoked with messages to run the agent.
|
|
115
|
+
*/
|
|
116
|
+
export type CompiledToolDiscoveryGraph = CompiledStateGraph<ToolDiscoveryState, Partial<ToolDiscoveryState>, "__start__" | "agent" | "search" | "execute">;
|
|
117
|
+
/**
|
|
118
|
+
* Creates a LangGraph agent with dynamic tool discovery.
|
|
119
|
+
*
|
|
120
|
+
* This is the main entry point for bigtool-ts. It creates a complete
|
|
121
|
+
* agent graph that can discover and use tools based on user requests.
|
|
122
|
+
*
|
|
123
|
+
* ## How It Works
|
|
124
|
+
*
|
|
125
|
+
* The agent follows this workflow:
|
|
126
|
+
*
|
|
127
|
+
* 1. **Agent Node**: LLM receives the conversation plus available tools
|
|
128
|
+
* (search_tools + pinned + previously discovered tools)
|
|
129
|
+
*
|
|
130
|
+
* 2. **Routing**: Based on the LLM's response:
|
|
131
|
+
* - If it calls `search_tools` → go to Search Node
|
|
132
|
+
* - If it calls other tools → go to Execute Node
|
|
133
|
+
* - If no tool calls → END
|
|
134
|
+
*
|
|
135
|
+
* 3. **Search Node**: Executes the search query, updates state with
|
|
136
|
+
* discovered tool IDs, returns to Agent Node
|
|
137
|
+
*
|
|
138
|
+
* 4. **Execute Node**: Runs the called tools, returns results to
|
|
139
|
+
* Agent Node
|
|
140
|
+
*
|
|
141
|
+
* @param options - Configuration options for the agent
|
|
142
|
+
* @returns Promise resolving to the compiled agent graph
|
|
143
|
+
*
|
|
144
|
+
* @example Basic usage
|
|
145
|
+
* ```typescript
|
|
146
|
+
* import { createAgent, OramaSearch } from '@repo/bigtool-ts';
|
|
147
|
+
* import { ChatOpenAI } from '@langchain/openai';
|
|
148
|
+
*
|
|
149
|
+
* const agent = await createAgent({
|
|
150
|
+
* llm: new ChatOpenAI({ model: 'gpt-4o' }),
|
|
151
|
+
* tools: [calculatorTool, weatherTool, searchTool],
|
|
152
|
+
* search: new OramaSearch(),
|
|
153
|
+
* });
|
|
154
|
+
*
|
|
155
|
+
* const result = await agent.invoke({
|
|
156
|
+
* messages: [{ role: 'user', content: 'What is the weather in NYC?' }]
|
|
157
|
+
* });
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @example With MCP and pinned tools
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const agent = await createAgent({
|
|
163
|
+
* llm: new ChatOpenAI({ model: 'gpt-4o' }),
|
|
164
|
+
* sources: [
|
|
165
|
+
* new MCPSource(githubClient, { namespace: 'github' }),
|
|
166
|
+
* new MCPSource(slackClient, { namespace: 'slack' }),
|
|
167
|
+
* ],
|
|
168
|
+
* search: new OramaSearch({ mode: 'hybrid', embeddings }),
|
|
169
|
+
* pinnedTools: [helpTool],
|
|
170
|
+
* systemPrompt: 'You are a DevOps assistant.',
|
|
171
|
+
* searchLimit: 10,
|
|
172
|
+
* });
|
|
173
|
+
* ```
|
|
174
|
+
*
|
|
175
|
+
* @throws Error if LLM does not support tool binding
|
|
176
|
+
*/
|
|
177
|
+
export declare function createAgent(options: CreateAgentOptions): Promise<CompiledToolDiscoveryGraph>;
|
|
178
|
+
/**
|
|
179
|
+
* Creates the tool discovery graph for advanced composition.
|
|
180
|
+
*
|
|
181
|
+
* This is functionally identical to createAgent but named to clarify
|
|
182
|
+
* its use as a subgraph in larger LangGraph workflows.
|
|
183
|
+
*
|
|
184
|
+
* Use this when you want to integrate tool discovery into an existing
|
|
185
|
+
* LangGraph workflow rather than using the full agent standalone.
|
|
186
|
+
*
|
|
187
|
+
* @param options - Configuration options (same as createAgent)
|
|
188
|
+
* @returns Promise resolving to the compiled discovery graph
|
|
189
|
+
*
|
|
190
|
+
* @example Embedding in a larger workflow
|
|
191
|
+
* ```typescript
|
|
192
|
+
* import { createToolDiscoveryGraph, OramaSearch } from '@repo/bigtool-ts';
|
|
193
|
+
* import { StateGraph } from '@langchain/langgraph';
|
|
194
|
+
*
|
|
195
|
+
* // Create the discovery subgraph
|
|
196
|
+
* const discoveryGraph = await createToolDiscoveryGraph({
|
|
197
|
+
* llm: new ChatOpenAI({ model: 'gpt-4o' }),
|
|
198
|
+
* tools: myTools,
|
|
199
|
+
* search: new OramaSearch(),
|
|
200
|
+
* });
|
|
201
|
+
*
|
|
202
|
+
* // Integrate into your main workflow
|
|
203
|
+
* const mainGraph = new StateGraph(MyAnnotation)
|
|
204
|
+
* .addNode('preprocess', preprocessNode)
|
|
205
|
+
* .addNode('discover', discoveryGraph)
|
|
206
|
+
* .addNode('postprocess', postprocessNode)
|
|
207
|
+
* .addEdge('preprocess', 'discover')
|
|
208
|
+
* .addEdge('discover', 'postprocess');
|
|
209
|
+
* ```
|
|
210
|
+
*
|
|
211
|
+
* @see {@link createAgent} for standalone agent usage
|
|
212
|
+
*/
|
|
213
|
+
export declare function createToolDiscoveryGraph(options: CreateAgentOptions): Promise<CompiledToolDiscoveryGraph>;
|
|
214
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/graph/agent.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAA2B,MAAM,aAAa,CAAC;AACpF,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAgB9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,GAAG,EAAE,aAAa,CAAC;IAEnB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,cAAc,EAAE,GAAG,UAAU,EAAE,CAAC;IAExC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IAEvB;;;;OAIG;IACH,MAAM,EAAE,WAAW,CAAC;IAEpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;IAE/B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG,kBAAkB,CACzD,kBAAkB,EAClB,OAAO,CAAC,kBAAkB,CAAC,EAC3B,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAC7C,CAAC;AAuBF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,0BAA0B,CAAC,CAsFrC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,0BAA0B,CAAC,CAGrC"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent factory module.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the main entry point for creating LangGraph agents
|
|
5
|
+
* with dynamic tool discovery capabilities.
|
|
6
|
+
*
|
|
7
|
+
* @module graph/agent
|
|
8
|
+
*/
|
|
9
|
+
import { StateGraph, START, END } from "@langchain/langgraph";
|
|
10
|
+
import { ToolDiscoveryAnnotation } from "./state.js";
|
|
11
|
+
import { createAgentNode, createSearchNode, createExecuteNode, routeNode, } from "./nodes.js";
|
|
12
|
+
import { createSearchToolsTool } from "./search-tool.js";
|
|
13
|
+
import { DefaultToolCatalog } from "../catalog/index.js";
|
|
14
|
+
import { DefaultToolLoader } from "../loader/index.js";
|
|
15
|
+
import { LocalSource } from "../sources/local.js";
|
|
16
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
17
|
+
// IMPLEMENTATION
|
|
18
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
19
|
+
/**
|
|
20
|
+
* Type guard to check if the input is a ToolSource array.
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
* @param input - Array to check
|
|
24
|
+
* @returns True if input contains ToolSource instances
|
|
25
|
+
*/
|
|
26
|
+
function isToolSourceArray(input) {
|
|
27
|
+
if (input.length === 0)
|
|
28
|
+
return false;
|
|
29
|
+
// ToolSource has getMetadata method
|
|
30
|
+
const first = input[0];
|
|
31
|
+
return typeof first.getMetadata === "function";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates a LangGraph agent with dynamic tool discovery.
|
|
35
|
+
*
|
|
36
|
+
* This is the main entry point for bigtool-ts. It creates a complete
|
|
37
|
+
* agent graph that can discover and use tools based on user requests.
|
|
38
|
+
*
|
|
39
|
+
* ## How It Works
|
|
40
|
+
*
|
|
41
|
+
* The agent follows this workflow:
|
|
42
|
+
*
|
|
43
|
+
* 1. **Agent Node**: LLM receives the conversation plus available tools
|
|
44
|
+
* (search_tools + pinned + previously discovered tools)
|
|
45
|
+
*
|
|
46
|
+
* 2. **Routing**: Based on the LLM's response:
|
|
47
|
+
* - If it calls `search_tools` → go to Search Node
|
|
48
|
+
* - If it calls other tools → go to Execute Node
|
|
49
|
+
* - If no tool calls → END
|
|
50
|
+
*
|
|
51
|
+
* 3. **Search Node**: Executes the search query, updates state with
|
|
52
|
+
* discovered tool IDs, returns to Agent Node
|
|
53
|
+
*
|
|
54
|
+
* 4. **Execute Node**: Runs the called tools, returns results to
|
|
55
|
+
* Agent Node
|
|
56
|
+
*
|
|
57
|
+
* @param options - Configuration options for the agent
|
|
58
|
+
* @returns Promise resolving to the compiled agent graph
|
|
59
|
+
*
|
|
60
|
+
* @example Basic usage
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import { createAgent, OramaSearch } from '@repo/bigtool-ts';
|
|
63
|
+
* import { ChatOpenAI } from '@langchain/openai';
|
|
64
|
+
*
|
|
65
|
+
* const agent = await createAgent({
|
|
66
|
+
* llm: new ChatOpenAI({ model: 'gpt-4o' }),
|
|
67
|
+
* tools: [calculatorTool, weatherTool, searchTool],
|
|
68
|
+
* search: new OramaSearch(),
|
|
69
|
+
* });
|
|
70
|
+
*
|
|
71
|
+
* const result = await agent.invoke({
|
|
72
|
+
* messages: [{ role: 'user', content: 'What is the weather in NYC?' }]
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @example With MCP and pinned tools
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const agent = await createAgent({
|
|
79
|
+
* llm: new ChatOpenAI({ model: 'gpt-4o' }),
|
|
80
|
+
* sources: [
|
|
81
|
+
* new MCPSource(githubClient, { namespace: 'github' }),
|
|
82
|
+
* new MCPSource(slackClient, { namespace: 'slack' }),
|
|
83
|
+
* ],
|
|
84
|
+
* search: new OramaSearch({ mode: 'hybrid', embeddings }),
|
|
85
|
+
* pinnedTools: [helpTool],
|
|
86
|
+
* systemPrompt: 'You are a DevOps assistant.',
|
|
87
|
+
* searchLimit: 10,
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* @throws Error if LLM does not support tool binding
|
|
92
|
+
*/
|
|
93
|
+
export async function createAgent(options) {
|
|
94
|
+
const { llm, tools = [], sources = [], search: searchIndex, pinnedTools = [], systemPrompt, searchLimit = 5, cacheSize = 100, } = options;
|
|
95
|
+
// 1. Create catalog
|
|
96
|
+
const catalog = new DefaultToolCatalog();
|
|
97
|
+
// 2. Collect all sources
|
|
98
|
+
const allSources = [...sources];
|
|
99
|
+
if (tools.length > 0) {
|
|
100
|
+
if (isToolSourceArray(tools)) {
|
|
101
|
+
allSources.push(...tools);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
allSources.push(new LocalSource(tools));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// 3. Register all sources with catalog
|
|
108
|
+
for (const source of allSources) {
|
|
109
|
+
await catalog.register(source);
|
|
110
|
+
}
|
|
111
|
+
// 4. Index tools for search
|
|
112
|
+
const allMetadata = catalog.getAllMetadata();
|
|
113
|
+
await searchIndex.index(allMetadata);
|
|
114
|
+
// 5. Create loader
|
|
115
|
+
const loader = new DefaultToolLoader(catalog, {
|
|
116
|
+
maxSize: cacheSize,
|
|
117
|
+
});
|
|
118
|
+
// 6. Create search_tools tool
|
|
119
|
+
const searchTool = createSearchToolsTool({
|
|
120
|
+
index: searchIndex,
|
|
121
|
+
catalog,
|
|
122
|
+
limit: searchLimit,
|
|
123
|
+
});
|
|
124
|
+
// 7. Build the graph
|
|
125
|
+
const workflow = new StateGraph(ToolDiscoveryAnnotation)
|
|
126
|
+
.addNode("agent", createAgentNode({
|
|
127
|
+
llm,
|
|
128
|
+
catalog,
|
|
129
|
+
loader,
|
|
130
|
+
pinnedTools,
|
|
131
|
+
searchTool,
|
|
132
|
+
systemPrompt,
|
|
133
|
+
}))
|
|
134
|
+
.addNode("search", createSearchNode({
|
|
135
|
+
index: searchIndex,
|
|
136
|
+
catalog,
|
|
137
|
+
searchLimit,
|
|
138
|
+
}))
|
|
139
|
+
.addNode("execute", createExecuteNode({
|
|
140
|
+
loader,
|
|
141
|
+
pinnedTools,
|
|
142
|
+
}))
|
|
143
|
+
.addEdge(START, "agent")
|
|
144
|
+
.addConditionalEdges("agent", routeNode, {
|
|
145
|
+
search: "search",
|
|
146
|
+
execute: "execute",
|
|
147
|
+
end: END,
|
|
148
|
+
})
|
|
149
|
+
.addEdge("search", "agent")
|
|
150
|
+
.addEdge("execute", "agent");
|
|
151
|
+
// 8. Compile and return
|
|
152
|
+
return workflow.compile();
|
|
153
|
+
}
|
|
154
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
155
|
+
// SUBGRAPH FACTORY
|
|
156
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
157
|
+
/**
|
|
158
|
+
* Creates the tool discovery graph for advanced composition.
|
|
159
|
+
*
|
|
160
|
+
* This is functionally identical to createAgent but named to clarify
|
|
161
|
+
* its use as a subgraph in larger LangGraph workflows.
|
|
162
|
+
*
|
|
163
|
+
* Use this when you want to integrate tool discovery into an existing
|
|
164
|
+
* LangGraph workflow rather than using the full agent standalone.
|
|
165
|
+
*
|
|
166
|
+
* @param options - Configuration options (same as createAgent)
|
|
167
|
+
* @returns Promise resolving to the compiled discovery graph
|
|
168
|
+
*
|
|
169
|
+
* @example Embedding in a larger workflow
|
|
170
|
+
* ```typescript
|
|
171
|
+
* import { createToolDiscoveryGraph, OramaSearch } from '@repo/bigtool-ts';
|
|
172
|
+
* import { StateGraph } from '@langchain/langgraph';
|
|
173
|
+
*
|
|
174
|
+
* // Create the discovery subgraph
|
|
175
|
+
* const discoveryGraph = await createToolDiscoveryGraph({
|
|
176
|
+
* llm: new ChatOpenAI({ model: 'gpt-4o' }),
|
|
177
|
+
* tools: myTools,
|
|
178
|
+
* search: new OramaSearch(),
|
|
179
|
+
* });
|
|
180
|
+
*
|
|
181
|
+
* // Integrate into your main workflow
|
|
182
|
+
* const mainGraph = new StateGraph(MyAnnotation)
|
|
183
|
+
* .addNode('preprocess', preprocessNode)
|
|
184
|
+
* .addNode('discover', discoveryGraph)
|
|
185
|
+
* .addNode('postprocess', postprocessNode)
|
|
186
|
+
* .addEdge('preprocess', 'discover')
|
|
187
|
+
* .addEdge('discover', 'postprocess');
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @see {@link createAgent} for standalone agent usage
|
|
191
|
+
*/
|
|
192
|
+
export async function createToolDiscoveryGraph(options) {
|
|
193
|
+
// Same implementation as createAgent - the full graph IS the discovery graph
|
|
194
|
+
return createAgent(options);
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/graph/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { createAgent, createToolDiscoveryGraph } from './agent.js';
|
|
2
|
+
export type { CreateAgentOptions } from './agent.js';
|
|
3
|
+
export { ToolDiscoveryAnnotation, type ToolDiscoveryState, type ToolDiscoveryUpdate, type SearchQuery } from './state.js';
|
|
4
|
+
export { searchNode, routeNode, executeNode } from './nodes.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACnE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,KAAK,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1H,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAEnE,OAAO,EAAE,uBAAuB,EAAuE,MAAM,YAAY,CAAC;AAC1H,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph Nodes
|
|
3
|
+
*
|
|
4
|
+
* Node factories for the BigTool LangGraph agent.
|
|
5
|
+
*/
|
|
6
|
+
import type { RunnableConfig } from "@langchain/core/runnables";
|
|
7
|
+
import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
|
|
8
|
+
import type { StructuredTool } from "@langchain/core/tools";
|
|
9
|
+
import type { ToolCatalog, ToolLoader, SearchIndex } from "../types.js";
|
|
10
|
+
import type { ToolDiscoveryState, ToolDiscoveryUpdate } from "./state.js";
|
|
11
|
+
/**
|
|
12
|
+
* Configuration for the agent node
|
|
13
|
+
*/
|
|
14
|
+
export interface AgentNodeConfig {
|
|
15
|
+
/** The LLM to use */
|
|
16
|
+
llm: BaseChatModel;
|
|
17
|
+
/** Tool catalog for metadata lookups */
|
|
18
|
+
catalog: ToolCatalog;
|
|
19
|
+
/** Tool loader for loading selected tools */
|
|
20
|
+
loader: ToolLoader;
|
|
21
|
+
/** Tools that are always available (bypass search) */
|
|
22
|
+
pinnedTools: StructuredTool[];
|
|
23
|
+
/** The search_tools tool */
|
|
24
|
+
searchTool: StructuredTool;
|
|
25
|
+
/** Optional system prompt to prepend */
|
|
26
|
+
systemPrompt?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Creates the agent node that invokes the LLM with bound tools.
|
|
30
|
+
*
|
|
31
|
+
* The agent always has access to:
|
|
32
|
+
* 1. search_tools - for discovering new tools
|
|
33
|
+
* 2. pinnedTools - always available tools
|
|
34
|
+
* 3. selectedTools - tools discovered via search
|
|
35
|
+
*
|
|
36
|
+
* @param config - Agent node configuration
|
|
37
|
+
* @returns A node function for the StateGraph
|
|
38
|
+
*/
|
|
39
|
+
export declare function createAgentNode(config: AgentNodeConfig): (state: ToolDiscoveryState, runnableConfig: RunnableConfig) => Promise<Partial<ToolDiscoveryUpdate>>;
|
|
40
|
+
/**
|
|
41
|
+
* Configuration for the search node
|
|
42
|
+
*/
|
|
43
|
+
export interface SearchNodeConfig {
|
|
44
|
+
/** Search index for finding tools */
|
|
45
|
+
index: SearchIndex;
|
|
46
|
+
/** Tool catalog for metadata lookups */
|
|
47
|
+
catalog: ToolCatalog;
|
|
48
|
+
/** Maximum results per search (default: 5) */
|
|
49
|
+
searchLimit?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Creates the search node that executes search_tools calls.
|
|
53
|
+
*
|
|
54
|
+
* This node:
|
|
55
|
+
* 1. Extracts search_tools calls from the last message
|
|
56
|
+
* 2. Executes searches against the index
|
|
57
|
+
* 3. Updates selectedToolIds with found tools
|
|
58
|
+
* 4. Returns ToolMessages with search results
|
|
59
|
+
*
|
|
60
|
+
* @param config - Search node configuration
|
|
61
|
+
* @returns A node function for the StateGraph
|
|
62
|
+
*/
|
|
63
|
+
export declare function createSearchNode(config: SearchNodeConfig): (state: ToolDiscoveryState, _runnableConfig: RunnableConfig) => Promise<Partial<ToolDiscoveryUpdate>>;
|
|
64
|
+
/**
|
|
65
|
+
* Configuration for the execute node
|
|
66
|
+
*/
|
|
67
|
+
export interface ExecuteNodeConfig {
|
|
68
|
+
/** Tool loader for loading tools */
|
|
69
|
+
loader: ToolLoader;
|
|
70
|
+
/** Tools that are always available */
|
|
71
|
+
pinnedTools: StructuredTool[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates the execute node that runs selected tools.
|
|
75
|
+
*
|
|
76
|
+
* Uses LangGraph's ToolNode to execute tool calls from the last message.
|
|
77
|
+
* Tools are loaded from the loader + pinnedTools.
|
|
78
|
+
*
|
|
79
|
+
* @param config - Execute node configuration
|
|
80
|
+
* @returns A node function for the StateGraph
|
|
81
|
+
*/
|
|
82
|
+
export declare function createExecuteNode(config: ExecuteNodeConfig): (state: ToolDiscoveryState, runnableConfig: RunnableConfig) => Promise<Partial<ToolDiscoveryUpdate>>;
|
|
83
|
+
/**
|
|
84
|
+
* @deprecated Use createSearchNode instead
|
|
85
|
+
*/
|
|
86
|
+
export declare function searchNode(_state: ToolDiscoveryState, _config: RunnableConfig): Promise<Partial<ToolDiscoveryUpdate>>;
|
|
87
|
+
/**
|
|
88
|
+
* Routing function - determines next node based on last message.
|
|
89
|
+
*
|
|
90
|
+
* Returns:
|
|
91
|
+
* - "search" if agent called search_tools
|
|
92
|
+
* - "execute" if agent called other tools
|
|
93
|
+
* - "end" if agent responded without tool calls
|
|
94
|
+
*/
|
|
95
|
+
export declare function routeNode(state: ToolDiscoveryState): "search" | "execute" | "end";
|
|
96
|
+
/**
|
|
97
|
+
* @deprecated Use createExecuteNode instead
|
|
98
|
+
*/
|
|
99
|
+
export declare function executeNode(_state: ToolDiscoveryState, _config: RunnableConfig): Promise<Partial<ToolDiscoveryUpdate>>;
|
|
100
|
+
//# sourceMappingURL=nodes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../../src/graph/nodes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAMpB;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,qBAAqB;IACrB,GAAG,EAAE,aAAa,CAAC;IACnB,wCAAwC;IACxC,OAAO,EAAE,WAAW,CAAC;IACrB,6CAA6C;IAC7C,MAAM,EAAE,UAAU,CAAC;IACnB,sDAAsD;IACtD,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,4BAA4B;IAC5B,UAAU,EAAE,cAAc,CAAC;IAC3B,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,IAInD,OAAO,kBAAkB,EACzB,gBAAgB,cAAc,KAC7B,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAyCzC;AAMD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,KAAK,EAAE,WAAW,CAAC;IACnB,wCAAwC;IACxC,OAAO,EAAE,WAAW,CAAC;IACrB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,IAIrD,OAAO,kBAAkB,EACzB,iBAAiB,cAAc,KAC9B,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAgEzC;AAMD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,sCAAsC;IACtC,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,IAIvD,OAAO,kBAAkB,EACzB,gBAAgB,cAAc,KAC7B,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAyBzC;AAMD;;GAEG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAIvC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,kBAAkB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,CAuBjF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAIvC"}
|