@push.rocks/smartagent 1.8.0 → 3.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.
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/index.d.ts +8 -14
- package/dist_ts/index.js +8 -24
- package/dist_ts/plugins.d.ts +8 -9
- package/dist_ts/plugins.js +10 -12
- package/dist_ts/smartagent.classes.agent.d.ts +2 -0
- package/dist_ts/smartagent.classes.agent.js +173 -0
- package/dist_ts/smartagent.classes.toolregistry.d.ts +7 -70
- package/dist_ts/smartagent.classes.toolregistry.js +11 -155
- package/dist_ts/smartagent.interfaces.d.ts +47 -283
- package/dist_ts/smartagent.interfaces.js +6 -7
- package/dist_ts/smartagent.utils.truncation.d.ts +10 -0
- package/dist_ts/smartagent.utils.truncation.js +26 -0
- package/dist_ts_compaction/index.d.ts +1 -0
- package/dist_ts_compaction/index.js +2 -0
- package/dist_ts_compaction/plugins.d.ts +4 -0
- package/dist_ts_compaction/plugins.js +3 -0
- package/dist_ts_compaction/smartagent.compaction.d.ts +10 -0
- package/dist_ts_compaction/smartagent.compaction.js +46 -0
- package/dist_ts_tools/index.d.ts +8 -0
- package/dist_ts_tools/index.js +6 -0
- package/dist_ts_tools/plugins.d.ts +15 -0
- package/dist_ts_tools/plugins.js +19 -0
- package/dist_ts_tools/tool.filesystem.d.ts +6 -0
- package/dist_ts_tools/tool.filesystem.js +102 -0
- package/dist_ts_tools/tool.http.d.ts +2 -0
- package/dist_ts_tools/tool.http.js +65 -0
- package/dist_ts_tools/tool.json.d.ts +2 -0
- package/dist_ts_tools/tool.json.js +47 -0
- package/dist_ts_tools/tool.shell.d.ts +8 -0
- package/dist_ts_tools/tool.shell.js +40 -0
- package/npmextra.json +1 -1
- package/package.json +30 -18
- package/readme.hints.md +38 -84
- package/readme.md +254 -682
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/index.ts +10 -37
- package/ts/plugins.ts +22 -21
- package/ts/smartagent.classes.agent.ts +198 -0
- package/ts/smartagent.classes.toolregistry.ts +11 -179
- package/ts/smartagent.interfaces.ts +51 -363
- package/ts/smartagent.utils.truncation.ts +39 -0
- package/ts_compaction/index.ts +1 -0
- package/ts_compaction/plugins.ts +6 -0
- package/ts_compaction/smartagent.compaction.ts +51 -0
- package/ts_tools/index.ts +8 -0
- package/ts_tools/plugins.ts +30 -0
- package/ts_tools/tool.filesystem.ts +131 -0
- package/ts_tools/tool.http.ts +78 -0
- package/ts_tools/tool.json.ts +53 -0
- package/ts_tools/tool.shell.ts +62 -0
- package/dist_ts/smartagent.classes.driveragent.d.ts +0 -134
- package/dist_ts/smartagent.classes.driveragent.js +0 -671
- package/dist_ts/smartagent.classes.dualagent.d.ts +0 -93
- package/dist_ts/smartagent.classes.dualagent.js +0 -614
- package/dist_ts/smartagent.classes.guardianagent.d.ts +0 -46
- package/dist_ts/smartagent.classes.guardianagent.js +0 -201
- package/dist_ts/smartagent.tools.base.d.ts +0 -52
- package/dist_ts/smartagent.tools.base.js +0 -42
- package/dist_ts/smartagent.tools.browser.d.ts +0 -17
- package/dist_ts/smartagent.tools.browser.js +0 -229
- package/dist_ts/smartagent.tools.deno.d.ts +0 -21
- package/dist_ts/smartagent.tools.deno.js +0 -191
- package/dist_ts/smartagent.tools.expert.d.ts +0 -27
- package/dist_ts/smartagent.tools.expert.js +0 -126
- package/dist_ts/smartagent.tools.filesystem.d.ts +0 -40
- package/dist_ts/smartagent.tools.filesystem.js +0 -801
- package/dist_ts/smartagent.tools.http.d.ts +0 -16
- package/dist_ts/smartagent.tools.http.js +0 -264
- package/dist_ts/smartagent.tools.json.d.ts +0 -24
- package/dist_ts/smartagent.tools.json.js +0 -202
- package/dist_ts/smartagent.tools.search.d.ts +0 -29
- package/dist_ts/smartagent.tools.search.js +0 -215
- package/dist_ts/smartagent.tools.shell.d.ts +0 -17
- package/dist_ts/smartagent.tools.shell.js +0 -202
- package/ts/smartagent.classes.driveragent.ts +0 -775
- package/ts/smartagent.classes.dualagent.ts +0 -692
- package/ts/smartagent.classes.guardianagent.ts +0 -241
- package/ts/smartagent.tools.base.ts +0 -83
- package/ts/smartagent.tools.browser.ts +0 -253
- package/ts/smartagent.tools.deno.ts +0 -230
- package/ts/smartagent.tools.expert.ts +0 -144
- package/ts/smartagent.tools.filesystem.ts +0 -885
- package/ts/smartagent.tools.http.ts +0 -283
- package/ts/smartagent.tools.json.ts +0 -224
- package/ts/smartagent.tools.search.ts +0 -237
- package/ts/smartagent.tools.shell.ts +0 -230
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartagent',
|
|
6
|
-
version: '
|
|
7
|
-
description: '
|
|
6
|
+
version: '3.0.1',
|
|
7
|
+
description: 'Agentic loop for ai-sdk (Vercel AI SDK). Wraps streamText with stopWhen for parallel multi-step tool execution. Built on @push.rocks/smartai.'
|
|
8
8
|
}
|
package/ts/index.ts
CHANGED
|
@@ -1,38 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// Export the dual-agent orchestrator (main entry point)
|
|
4
|
-
export { DualAgentOrchestrator } from './smartagent.classes.dualagent.js';
|
|
5
|
-
|
|
6
|
-
// Export individual agents
|
|
7
|
-
export { DriverAgent } from './smartagent.classes.driveragent.js';
|
|
8
|
-
export { GuardianAgent } from './smartagent.classes.guardianagent.js';
|
|
9
|
-
|
|
10
|
-
// Export tool registry and related classes
|
|
1
|
+
export { runAgent } from './smartagent.classes.agent.js';
|
|
11
2
|
export { ToolRegistry } from './smartagent.classes.toolregistry.js';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export
|
|
18
|
-
export {
|
|
19
|
-
export {
|
|
20
|
-
export {
|
|
21
|
-
export { DenoTool, type TDenoPermission } from './smartagent.tools.deno.js';
|
|
22
|
-
export { JsonValidatorTool } from './smartagent.tools.json.js';
|
|
23
|
-
|
|
24
|
-
// Export tool search and expert tools
|
|
25
|
-
export { ToolSearchTool } from './smartagent.tools.search.js';
|
|
26
|
-
export { ExpertTool } from './smartagent.tools.expert.js';
|
|
27
|
-
|
|
28
|
-
// Export all interfaces
|
|
29
|
-
export * from './smartagent.interfaces.js';
|
|
30
|
-
|
|
31
|
-
// Re-export useful types from smartai
|
|
32
|
-
export {
|
|
33
|
-
type ISmartAiOptions,
|
|
34
|
-
type TProvider,
|
|
35
|
-
type ChatMessage,
|
|
36
|
-
type ChatOptions,
|
|
37
|
-
type ChatResponse,
|
|
38
|
-
} from '@push.rocks/smartai';
|
|
3
|
+
export { truncateOutput } from './smartagent.utils.truncation.js';
|
|
4
|
+
export type { ITruncateResult } from './smartagent.utils.truncation.js';
|
|
5
|
+
export { ContextOverflowError } from './smartagent.interfaces.js';
|
|
6
|
+
export type { IAgentRunOptions, IAgentRunResult } from './smartagent.interfaces.js';
|
|
7
|
+
|
|
8
|
+
// Re-export tool() and z so consumers can define tools without extra imports
|
|
9
|
+
export { tool, jsonSchema } from '@push.rocks/smartai';
|
|
10
|
+
export { z } from 'zod';
|
|
11
|
+
export { stepCountIs } from 'ai';
|
package/ts/plugins.ts
CHANGED
|
@@ -3,24 +3,25 @@ import * as path from 'path';
|
|
|
3
3
|
|
|
4
4
|
export { path };
|
|
5
5
|
|
|
6
|
-
//
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
export {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
6
|
+
// ai-sdk core
|
|
7
|
+
import { streamText, generateText, stepCountIs } from 'ai';
|
|
8
|
+
|
|
9
|
+
export { streamText, generateText, stepCountIs };
|
|
10
|
+
|
|
11
|
+
export type {
|
|
12
|
+
ModelMessage,
|
|
13
|
+
ToolSet,
|
|
14
|
+
StreamTextResult,
|
|
15
|
+
} from 'ai';
|
|
16
|
+
|
|
17
|
+
// @push.rocks/smartai
|
|
18
|
+
import { tool, jsonSchema } from '@push.rocks/smartai';
|
|
19
|
+
|
|
20
|
+
export { tool, jsonSchema };
|
|
21
|
+
|
|
22
|
+
export type { LanguageModelV3 } from '@push.rocks/smartai';
|
|
23
|
+
|
|
24
|
+
// zod
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
|
|
27
|
+
export { z };
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// Retry backoff and context overflow logic derived from opencode (MIT) — https://github.com/sst/opencode
|
|
2
|
+
|
|
3
|
+
import * as plugins from './plugins.js';
|
|
4
|
+
import type { IAgentRunOptions, IAgentRunResult } from './smartagent.interfaces.js';
|
|
5
|
+
import { ContextOverflowError } from './smartagent.interfaces.js';
|
|
6
|
+
|
|
7
|
+
// Retry constants
|
|
8
|
+
const RETRY_INITIAL_DELAY = 2000;
|
|
9
|
+
const RETRY_BACKOFF_FACTOR = 2;
|
|
10
|
+
const RETRY_MAX_DELAY = 30_000;
|
|
11
|
+
const MAX_RETRY_ATTEMPTS = 8;
|
|
12
|
+
|
|
13
|
+
function retryDelay(attempt: number, headers?: Record<string, string>): number {
|
|
14
|
+
if (headers) {
|
|
15
|
+
const ms = headers['retry-after-ms'];
|
|
16
|
+
if (ms) {
|
|
17
|
+
const n = parseFloat(ms);
|
|
18
|
+
if (!isNaN(n)) return n;
|
|
19
|
+
}
|
|
20
|
+
const after = headers['retry-after'];
|
|
21
|
+
if (after) {
|
|
22
|
+
const secs = parseFloat(after);
|
|
23
|
+
if (!isNaN(secs)) return Math.ceil(secs * 1000);
|
|
24
|
+
const date = Date.parse(after) - Date.now();
|
|
25
|
+
if (!isNaN(date) && date > 0) return Math.ceil(date);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return Math.min(
|
|
29
|
+
RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1),
|
|
30
|
+
RETRY_MAX_DELAY,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function sleep(ms: number, signal?: AbortSignal): Promise<void> {
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
if (signal?.aborted) {
|
|
37
|
+
reject(new DOMException('Aborted', 'AbortError'));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const t = setTimeout(resolve, ms);
|
|
41
|
+
signal?.addEventListener(
|
|
42
|
+
'abort',
|
|
43
|
+
() => {
|
|
44
|
+
clearTimeout(t);
|
|
45
|
+
reject(new DOMException('Aborted', 'AbortError'));
|
|
46
|
+
},
|
|
47
|
+
{ once: true },
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isRetryableError(err: unknown): boolean {
|
|
53
|
+
const status = (err as any)?.status ?? (err as any)?.statusCode;
|
|
54
|
+
if (status === 429 || status === 529 || status === 503) return true;
|
|
55
|
+
if (err instanceof Error) {
|
|
56
|
+
const msg = err.message.toLowerCase();
|
|
57
|
+
if (msg.includes('rate limit') || msg.includes('overloaded') || msg.includes('too many requests')) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isContextOverflow(err: unknown): boolean {
|
|
65
|
+
if (err instanceof Error) {
|
|
66
|
+
const msg = err.message.toLowerCase();
|
|
67
|
+
return (
|
|
68
|
+
msg.includes('context_length_exceeded') ||
|
|
69
|
+
msg.includes('context window') ||
|
|
70
|
+
msg.includes('maximum context length') ||
|
|
71
|
+
msg.includes('too many tokens') ||
|
|
72
|
+
msg.includes('input is too long') ||
|
|
73
|
+
(err as any)?.name === 'AI_ContextWindowExceededError'
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function runAgent(options: IAgentRunOptions): Promise<IAgentRunResult> {
|
|
80
|
+
let stepCount = 0;
|
|
81
|
+
let attempt = 0;
|
|
82
|
+
let totalInput = 0;
|
|
83
|
+
let totalOutput = 0;
|
|
84
|
+
|
|
85
|
+
const tools = options.tools ?? {};
|
|
86
|
+
|
|
87
|
+
// Add a no-op sink for repaired-but-unrecognised tool calls
|
|
88
|
+
const allTools: plugins.ToolSet = {
|
|
89
|
+
...tools,
|
|
90
|
+
invalid: plugins.tool({
|
|
91
|
+
description: 'Sink for unrecognised tool calls — returns an error message to the model',
|
|
92
|
+
inputSchema: plugins.z.object({
|
|
93
|
+
tool: plugins.z.string(),
|
|
94
|
+
error: plugins.z.string(),
|
|
95
|
+
}),
|
|
96
|
+
execute: async ({ tool, error }: { tool: string; error: string }) =>
|
|
97
|
+
`Unknown tool "${tool}": ${error}`,
|
|
98
|
+
}),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Build messages — streamText requires either prompt OR messages, not both
|
|
102
|
+
let messages: plugins.ModelMessage[] = options.messages
|
|
103
|
+
? [...options.messages, { role: 'user' as const, content: options.prompt }]
|
|
104
|
+
: [{ role: 'user' as const, content: options.prompt }];
|
|
105
|
+
|
|
106
|
+
while (true) {
|
|
107
|
+
try {
|
|
108
|
+
const result = plugins.streamText({
|
|
109
|
+
model: options.model,
|
|
110
|
+
system: options.system,
|
|
111
|
+
messages,
|
|
112
|
+
tools: allTools,
|
|
113
|
+
stopWhen: plugins.stepCountIs(options.maxSteps ?? 20),
|
|
114
|
+
maxRetries: 0, // handled manually below
|
|
115
|
+
abortSignal: options.abort,
|
|
116
|
+
|
|
117
|
+
experimental_repairToolCall: async ({ toolCall, tools: availableTools, error }) => {
|
|
118
|
+
const lower = toolCall.toolName.toLowerCase();
|
|
119
|
+
if (lower !== toolCall.toolName && (availableTools as any)[lower]) {
|
|
120
|
+
return { ...toolCall, toolName: lower };
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
...toolCall,
|
|
124
|
+
toolName: 'invalid',
|
|
125
|
+
args: JSON.stringify({
|
|
126
|
+
tool: toolCall.toolName,
|
|
127
|
+
error: String(error),
|
|
128
|
+
}),
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
onChunk: ({ chunk }) => {
|
|
133
|
+
if (chunk.type === 'text-delta' && options.onToken) {
|
|
134
|
+
options.onToken((chunk as any).textDelta ?? (chunk as any).text ?? '');
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
experimental_onToolCallStart: options.onToolCall
|
|
139
|
+
? ({ toolCall }) => {
|
|
140
|
+
options.onToolCall!(toolCall.toolName, (toolCall as any).input ?? (toolCall as any).args);
|
|
141
|
+
}
|
|
142
|
+
: undefined,
|
|
143
|
+
|
|
144
|
+
experimental_onToolCallFinish: options.onToolResult
|
|
145
|
+
? ({ toolCall }) => {
|
|
146
|
+
options.onToolResult!(toolCall.toolName, (toolCall as any).result);
|
|
147
|
+
}
|
|
148
|
+
: undefined,
|
|
149
|
+
|
|
150
|
+
onStepFinish: ({ usage }) => {
|
|
151
|
+
stepCount++;
|
|
152
|
+
totalInput += usage?.inputTokens ?? 0;
|
|
153
|
+
totalOutput += usage?.outputTokens ?? 0;
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Consume the stream and collect results
|
|
158
|
+
const text = await result.text;
|
|
159
|
+
const finishReason = await result.finishReason;
|
|
160
|
+
const responseData = await result.response;
|
|
161
|
+
|
|
162
|
+
attempt = 0; // reset on success
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
text,
|
|
166
|
+
messages: responseData.messages as plugins.ModelMessage[],
|
|
167
|
+
steps: stepCount,
|
|
168
|
+
finishReason,
|
|
169
|
+
usage: {
|
|
170
|
+
inputTokens: totalInput,
|
|
171
|
+
outputTokens: totalOutput,
|
|
172
|
+
totalTokens: totalInput + totalOutput,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
} catch (err: unknown) {
|
|
176
|
+
// Abort — don't retry
|
|
177
|
+
if (err instanceof DOMException && err.name === 'AbortError') throw err;
|
|
178
|
+
|
|
179
|
+
// Rate limit / overload — retry with backoff
|
|
180
|
+
if (isRetryableError(err) && attempt < MAX_RETRY_ATTEMPTS) {
|
|
181
|
+
attempt++;
|
|
182
|
+
const headers = (err as any)?.responseHeaders ?? (err as any)?.headers;
|
|
183
|
+
const delay = retryDelay(attempt, headers);
|
|
184
|
+
await sleep(delay, options.abort);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Context overflow — compact and retry if handler provided
|
|
189
|
+
if (isContextOverflow(err)) {
|
|
190
|
+
if (!options.onContextOverflow) throw new ContextOverflowError();
|
|
191
|
+
messages = await options.onContextOverflow(messages);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
throw err;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -1,188 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { BaseToolWrapper } from './smartagent.tools.base.js';
|
|
1
|
+
import type { ToolSet } from './plugins.js';
|
|
3
2
|
|
|
4
|
-
/**
|
|
5
|
-
* ToolRegistry - Manages tool registration, visibility, and lifecycle
|
|
6
|
-
*
|
|
7
|
-
* Responsibilities:
|
|
8
|
-
* - Track all registered tools with their metadata
|
|
9
|
-
* - Manage visibility (initial vs on-demand)
|
|
10
|
-
* - Handle activation of on-demand tools
|
|
11
|
-
* - Provide search functionality
|
|
12
|
-
*/
|
|
13
3
|
export class ToolRegistry {
|
|
14
|
-
private tools:
|
|
15
|
-
private metadata: Map<string, interfaces.IToolMetadata> = new Map();
|
|
16
|
-
private activated: Set<string> = new Set();
|
|
4
|
+
private tools: ToolSet = {};
|
|
17
5
|
|
|
18
6
|
/**
|
|
19
|
-
* Register a tool
|
|
7
|
+
* Register a tool.
|
|
8
|
+
* @param name Tool name (must be unique, snake_case recommended)
|
|
9
|
+
* @param def Tool definition created with ai-sdk's tool() helper
|
|
20
10
|
*/
|
|
21
|
-
register(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
this.tools.set(tool.name, tool);
|
|
25
|
-
this.metadata.set(tool.name, {
|
|
26
|
-
name: tool.name,
|
|
27
|
-
description: tool.description,
|
|
28
|
-
actions: tool.actions,
|
|
29
|
-
visibility,
|
|
30
|
-
isActivated: visibility === 'initial',
|
|
31
|
-
isInitialized: false,
|
|
32
|
-
tags: options.tags,
|
|
33
|
-
category: options.category,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
if (visibility === 'initial') {
|
|
37
|
-
this.activated.add(tool.name);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Get tools visible to the Driver (initial + activated on-demand)
|
|
43
|
-
*/
|
|
44
|
-
getVisibleTools(): BaseToolWrapper[] {
|
|
45
|
-
return Array.from(this.tools.entries())
|
|
46
|
-
.filter(([name]) => this.activated.has(name))
|
|
47
|
-
.map(([, tool]) => tool);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Get all tools (for search results)
|
|
52
|
-
*/
|
|
53
|
-
getAllTools(): BaseToolWrapper[] {
|
|
54
|
-
return Array.from(this.tools.values());
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Get a specific tool by name
|
|
59
|
-
*/
|
|
60
|
-
getTool(name: string): BaseToolWrapper | undefined {
|
|
61
|
-
return this.tools.get(name);
|
|
11
|
+
public register(name: string, def: ToolSet[string]): this {
|
|
12
|
+
this.tools[name] = def;
|
|
13
|
+
return this;
|
|
62
14
|
}
|
|
63
15
|
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
getMetadata(name: string): interfaces.IToolMetadata | undefined {
|
|
68
|
-
return this.metadata.get(name);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Get all metadata
|
|
73
|
-
*/
|
|
74
|
-
getAllMetadata(): interfaces.IToolMetadata[] {
|
|
75
|
-
return Array.from(this.metadata.values());
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Search tools by query (matches name, description, tags, action names)
|
|
80
|
-
*/
|
|
81
|
-
search(query: string): interfaces.IToolMetadata[] {
|
|
82
|
-
const q = query.toLowerCase();
|
|
83
|
-
return this.getAllMetadata().filter((meta) => {
|
|
84
|
-
if (meta.name.toLowerCase().includes(q)) return true;
|
|
85
|
-
if (meta.description.toLowerCase().includes(q)) return true;
|
|
86
|
-
if (meta.tags?.some((t) => t.toLowerCase().includes(q))) return true;
|
|
87
|
-
if (meta.category?.toLowerCase().includes(q)) return true;
|
|
88
|
-
if (
|
|
89
|
-
meta.actions.some(
|
|
90
|
-
(a) => a.name.toLowerCase().includes(q) || a.description.toLowerCase().includes(q)
|
|
91
|
-
)
|
|
92
|
-
)
|
|
93
|
-
return true;
|
|
94
|
-
return false;
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Activate an on-demand tool
|
|
100
|
-
*/
|
|
101
|
-
async activate(name: string): Promise<{ success: boolean; error?: string }> {
|
|
102
|
-
const tool = this.tools.get(name);
|
|
103
|
-
const meta = this.metadata.get(name);
|
|
104
|
-
|
|
105
|
-
if (!tool || !meta) {
|
|
106
|
-
return { success: false, error: `Tool "${name}" not found` };
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (this.activated.has(name)) {
|
|
110
|
-
return { success: true }; // Already activated
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Initialize if not already initialized
|
|
114
|
-
if (!meta.isInitialized) {
|
|
115
|
-
await tool.initialize();
|
|
116
|
-
meta.isInitialized = true;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
this.activated.add(name);
|
|
120
|
-
meta.isActivated = true;
|
|
121
|
-
|
|
122
|
-
return { success: true };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Check if a tool is activated
|
|
127
|
-
*/
|
|
128
|
-
isActivated(name: string): boolean {
|
|
129
|
-
return this.activated.has(name);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Initialize all initial (visible) tools
|
|
134
|
-
*/
|
|
135
|
-
async initializeVisibleTools(): Promise<void> {
|
|
136
|
-
const promises: Promise<void>[] = [];
|
|
137
|
-
|
|
138
|
-
for (const [name, tool] of this.tools) {
|
|
139
|
-
const meta = this.metadata.get(name);
|
|
140
|
-
if (meta && this.activated.has(name) && !meta.isInitialized) {
|
|
141
|
-
promises.push(
|
|
142
|
-
tool.initialize().then(() => {
|
|
143
|
-
meta.isInitialized = true;
|
|
144
|
-
})
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
await Promise.all(promises);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Cleanup all initialized tools
|
|
154
|
-
*/
|
|
155
|
-
async cleanup(): Promise<void> {
|
|
156
|
-
const promises: Promise<void>[] = [];
|
|
157
|
-
|
|
158
|
-
for (const [name, tool] of this.tools) {
|
|
159
|
-
const meta = this.metadata.get(name);
|
|
160
|
-
if (meta?.isInitialized) {
|
|
161
|
-
promises.push(tool.cleanup());
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
await Promise.all(promises);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Check if a tool exists in the registry
|
|
170
|
-
*/
|
|
171
|
-
has(name: string): boolean {
|
|
172
|
-
return this.tools.has(name);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Get the number of registered tools
|
|
177
|
-
*/
|
|
178
|
-
get size(): number {
|
|
179
|
-
return this.tools.size;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Get the number of activated tools
|
|
184
|
-
*/
|
|
185
|
-
get activatedCount(): number {
|
|
186
|
-
return this.activated.size;
|
|
16
|
+
/** Get the full ToolSet for passing to runAgent */
|
|
17
|
+
public getTools(): ToolSet {
|
|
18
|
+
return { ...this.tools };
|
|
187
19
|
}
|
|
188
20
|
}
|