@push.rocks/smartagent 1.7.0 → 3.0.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/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/index.d.ts +9 -12
- package/dist_ts/index.js +9 -20
- 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 +12 -0
- package/dist_ts/smartagent.classes.toolregistry.js +17 -0
- package/dist_ts/smartagent.interfaces.d.ts +47 -231
- 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 +43 -42
- package/readme.md +257 -526
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/index.ts +11 -31
- package/ts/plugins.ts +22 -21
- package/ts/smartagent.classes.agent.ts +198 -0
- package/ts/smartagent.classes.toolregistry.ts +20 -0
- package/ts/smartagent.interfaces.ts +51 -303
- 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 -79
- package/dist_ts/smartagent.classes.dualagent.js +0 -583
- 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.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.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 -657
- 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.filesystem.ts +0 -885
- package/ts/smartagent.tools.http.ts +0 -283
- package/ts/smartagent.tools.json.ts +0 -224
- 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.0',
|
|
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,31 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export {
|
|
12
|
-
|
|
13
|
-
// Export standard tools
|
|
14
|
-
export { FilesystemTool, type IFilesystemToolOptions } from './smartagent.tools.filesystem.js';
|
|
15
|
-
export { HttpTool } from './smartagent.tools.http.js';
|
|
16
|
-
export { ShellTool } from './smartagent.tools.shell.js';
|
|
17
|
-
export { BrowserTool } from './smartagent.tools.browser.js';
|
|
18
|
-
export { DenoTool, type TDenoPermission } from './smartagent.tools.deno.js';
|
|
19
|
-
export { JsonValidatorTool } from './smartagent.tools.json.js';
|
|
20
|
-
|
|
21
|
-
// Export all interfaces
|
|
22
|
-
export * from './smartagent.interfaces.js';
|
|
23
|
-
|
|
24
|
-
// Re-export useful types from smartai
|
|
25
|
-
export {
|
|
26
|
-
type ISmartAiOptions,
|
|
27
|
-
type TProvider,
|
|
28
|
-
type ChatMessage,
|
|
29
|
-
type ChatOptions,
|
|
30
|
-
type ChatResponse,
|
|
31
|
-
} from '@push.rocks/smartai';
|
|
1
|
+
export { runAgent } from './smartagent.classes.agent.js';
|
|
2
|
+
export { ToolRegistry } from './smartagent.classes.toolregistry.js';
|
|
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
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ToolSet } from './plugins.js';
|
|
2
|
+
|
|
3
|
+
export class ToolRegistry {
|
|
4
|
+
private tools: ToolSet = {};
|
|
5
|
+
|
|
6
|
+
/**
|
|
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
|
|
10
|
+
*/
|
|
11
|
+
public register(name: string, def: ToolSet[string]): this {
|
|
12
|
+
this.tools[name] = def;
|
|
13
|
+
return this;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Get the full ToolSet for passing to runAgent */
|
|
17
|
+
public getTools(): ToolSet {
|
|
18
|
+
return { ...this.tools };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,306 +1,54 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
images?: string[];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// ================================
|
|
16
|
-
// Agent Configuration Interfaces
|
|
17
|
-
// ================================
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Configuration options for the DualAgentOrchestrator
|
|
21
|
-
*/
|
|
22
|
-
export interface IDualAgentOptions extends plugins.smartai.ISmartAiOptions {
|
|
23
|
-
/** Existing SmartAi instance to reuse (avoids creating duplicate providers) */
|
|
24
|
-
smartAiInstance?: plugins.smartai.SmartAi;
|
|
25
|
-
/** Name of the agent system */
|
|
26
|
-
name?: string;
|
|
27
|
-
/** Default AI provider for both Driver and Guardian */
|
|
28
|
-
defaultProvider?: plugins.smartai.TProvider;
|
|
29
|
-
/** Optional separate provider for Guardian (for cost optimization) */
|
|
30
|
-
guardianProvider?: plugins.smartai.TProvider;
|
|
31
|
-
/** System message for the Driver agent */
|
|
32
|
-
driverSystemMessage?: string;
|
|
33
|
-
/** Policy prompt for the Guardian agent - REQUIRED */
|
|
34
|
-
guardianPolicyPrompt: string;
|
|
35
|
-
/** Maximum iterations for task completion (default: 20) */
|
|
36
|
-
maxIterations?: number;
|
|
37
|
-
/** Maximum consecutive rejections before aborting (default: 3) */
|
|
38
|
-
maxConsecutiveRejections?: number;
|
|
39
|
-
/** Enable verbose logging */
|
|
40
|
-
verbose?: boolean;
|
|
41
|
-
/** Maximum characters for tool result output before truncation (default: 15000). Set to 0 to disable. */
|
|
42
|
-
maxResultChars?: number;
|
|
43
|
-
/** Maximum history messages to pass to API (default: 20). Set to 0 for unlimited. */
|
|
44
|
-
maxHistoryMessages?: number;
|
|
45
|
-
/** Optional callback for live progress updates during execution */
|
|
46
|
-
onProgress?: (event: IProgressEvent) => void;
|
|
47
|
-
/** Prefix for log messages (e.g., "[README]", "[Commit]"). Default: empty */
|
|
48
|
-
logPrefix?: string;
|
|
49
|
-
/** Callback fired for each token during LLM generation (streaming mode) */
|
|
50
|
-
onToken?: (token: string, source: 'driver' | 'guardian') => void;
|
|
1
|
+
import type { ToolSet, ModelMessage, LanguageModelV3 } from './plugins.js';
|
|
2
|
+
|
|
3
|
+
export interface IAgentRunOptions {
|
|
4
|
+
/** The LanguageModelV3 to use — from smartai.getModel() */
|
|
5
|
+
model: LanguageModelV3;
|
|
6
|
+
/** Initial user message or task description */
|
|
7
|
+
prompt: string;
|
|
8
|
+
/** System prompt override */
|
|
9
|
+
system?: string;
|
|
10
|
+
/** Tools available to the agent */
|
|
11
|
+
tools?: ToolSet;
|
|
51
12
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
13
|
+
* Maximum number of LLM↔tool round trips.
|
|
14
|
+
* Each step may execute multiple tools in parallel.
|
|
15
|
+
* Default: 20
|
|
55
16
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
*/
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
* Native tool call from provider (matches Ollama's tool calling format)
|
|
94
|
-
* Format: function name is "toolName_actionName" (e.g., "json_validate")
|
|
95
|
-
*/
|
|
96
|
-
export interface INativeToolCall {
|
|
97
|
-
function: {
|
|
98
|
-
name: string; // Format: "toolName_actionName"
|
|
99
|
-
arguments: Record<string, unknown>;
|
|
100
|
-
index?: number;
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Proposed tool call from the Driver
|
|
106
|
-
*/
|
|
107
|
-
export interface IToolCallProposal {
|
|
108
|
-
/** Unique ID for this proposal */
|
|
109
|
-
proposalId: string;
|
|
110
|
-
/** Name of the tool */
|
|
111
|
-
toolName: string;
|
|
112
|
-
/** Specific action to perform */
|
|
113
|
-
action: string;
|
|
114
|
-
/** Parameters for the action */
|
|
115
|
-
params: Record<string, unknown>;
|
|
116
|
-
/** Driver's reasoning for this call */
|
|
117
|
-
reasoning?: string;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Result of tool execution
|
|
122
|
-
*/
|
|
123
|
-
export interface IToolExecutionResult {
|
|
124
|
-
success: boolean;
|
|
125
|
-
result?: unknown;
|
|
126
|
-
error?: string;
|
|
127
|
-
/** Optional human-readable summary for history (if provided, used instead of full result) */
|
|
128
|
-
summary?: string;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Base interface for wrapped tools
|
|
133
|
-
*/
|
|
134
|
-
export interface IAgentToolWrapper {
|
|
135
|
-
/** Tool name */
|
|
136
|
-
name: string;
|
|
137
|
-
/** Tool description */
|
|
138
|
-
description: string;
|
|
139
|
-
/** Available actions */
|
|
140
|
-
actions: IToolAction[];
|
|
141
|
-
/** Initialize the tool */
|
|
142
|
-
initialize(): Promise<void>;
|
|
143
|
-
/** Cleanup resources */
|
|
144
|
-
cleanup(): Promise<void>;
|
|
145
|
-
/** Execute an action */
|
|
146
|
-
execute(action: string, params: Record<string, unknown>): Promise<IToolExecutionResult>;
|
|
147
|
-
/** Get a summary for Guardian review */
|
|
148
|
-
getCallSummary(action: string, params: Record<string, unknown>): string;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// ================================
|
|
152
|
-
// Guardian Interfaces
|
|
153
|
-
// ================================
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Request for Guardian evaluation
|
|
157
|
-
*/
|
|
158
|
-
export interface IGuardianEvaluationRequest {
|
|
159
|
-
/** The proposed tool call */
|
|
160
|
-
proposal: IToolCallProposal;
|
|
161
|
-
/** Current task context */
|
|
162
|
-
taskContext: string;
|
|
163
|
-
/** Recent conversation history (last N messages) */
|
|
164
|
-
recentHistory: IAgentMessage[];
|
|
165
|
-
/** Summary of what the tool call will do */
|
|
166
|
-
callSummary: string;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Guardian's decision
|
|
171
|
-
*/
|
|
172
|
-
export interface IGuardianDecision {
|
|
173
|
-
/** Approve or reject */
|
|
174
|
-
decision: 'approve' | 'reject';
|
|
175
|
-
/** Explanation of the decision */
|
|
176
|
-
reason: string;
|
|
177
|
-
/** Specific concerns if rejected */
|
|
178
|
-
concerns?: string[];
|
|
179
|
-
/** Suggestions for the Driver if rejected */
|
|
180
|
-
suggestions?: string;
|
|
181
|
-
/** Confidence level (0-1) */
|
|
182
|
-
confidence?: number;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// ================================
|
|
186
|
-
// Result Interfaces
|
|
187
|
-
// ================================
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Log entry for tool executions
|
|
191
|
-
*/
|
|
192
|
-
export interface IToolExecutionLog {
|
|
193
|
-
timestamp: Date;
|
|
194
|
-
toolName: string;
|
|
195
|
-
action: string;
|
|
196
|
-
params: Record<string, unknown>;
|
|
197
|
-
guardianDecision: 'approved' | 'rejected';
|
|
198
|
-
guardianReason: string;
|
|
199
|
-
executionResult?: unknown;
|
|
200
|
-
executionError?: string;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Status of a dual-agent run
|
|
205
|
-
*/
|
|
206
|
-
export type TDualAgentRunStatus =
|
|
207
|
-
| 'completed'
|
|
208
|
-
| 'in_progress'
|
|
209
|
-
| 'max_iterations_reached'
|
|
210
|
-
| 'max_rejections_reached'
|
|
211
|
-
| 'clarification_needed'
|
|
212
|
-
| 'error';
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Result of a dual-agent run
|
|
216
|
-
*/
|
|
217
|
-
export interface IDualAgentRunResult {
|
|
218
|
-
/** Whether the task was successful */
|
|
219
|
-
success: boolean;
|
|
220
|
-
/** Whether the task is completed */
|
|
221
|
-
completed: boolean;
|
|
222
|
-
/** Final result or response */
|
|
223
|
-
result: string;
|
|
224
|
-
/** Total iterations taken */
|
|
225
|
-
iterations: number;
|
|
226
|
-
/** Full conversation history */
|
|
227
|
-
history: IAgentMessage[];
|
|
228
|
-
/** Current status */
|
|
229
|
-
status: TDualAgentRunStatus;
|
|
230
|
-
/** Number of tool calls made */
|
|
231
|
-
toolCallCount?: number;
|
|
232
|
-
/** Number of Guardian rejections */
|
|
233
|
-
rejectionCount?: number;
|
|
234
|
-
/** Tool execution log */
|
|
235
|
-
toolLog?: IToolExecutionLog[];
|
|
236
|
-
/** Error message if status is 'error' */
|
|
237
|
-
error?: string;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// ================================
|
|
241
|
-
// Progress Event Interfaces
|
|
242
|
-
// ================================
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Progress event types for live feedback during agent execution
|
|
246
|
-
*/
|
|
247
|
-
export type TProgressEventType =
|
|
248
|
-
| 'task_started'
|
|
249
|
-
| 'iteration_started'
|
|
250
|
-
| 'tool_proposed'
|
|
251
|
-
| 'guardian_evaluating'
|
|
252
|
-
| 'tool_approved'
|
|
253
|
-
| 'tool_rejected'
|
|
254
|
-
| 'tool_executing'
|
|
255
|
-
| 'tool_completed'
|
|
256
|
-
| 'task_completed'
|
|
257
|
-
| 'clarification_needed'
|
|
258
|
-
| 'max_iterations'
|
|
259
|
-
| 'max_rejections';
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Log level for progress events
|
|
263
|
-
*/
|
|
264
|
-
export type TLogLevel = 'info' | 'warn' | 'error' | 'success';
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Progress event for live feedback during agent execution
|
|
268
|
-
*/
|
|
269
|
-
export interface IProgressEvent {
|
|
270
|
-
/** Type of progress event */
|
|
271
|
-
type: TProgressEventType;
|
|
272
|
-
/** Current iteration number */
|
|
273
|
-
iteration?: number;
|
|
274
|
-
/** Maximum iterations configured */
|
|
275
|
-
maxIterations?: number;
|
|
276
|
-
/** Name of the tool being used */
|
|
277
|
-
toolName?: string;
|
|
278
|
-
/** Action being performed */
|
|
279
|
-
action?: string;
|
|
280
|
-
/** Reason for rejection or other explanation */
|
|
281
|
-
reason?: string;
|
|
282
|
-
/** Human-readable message about the event */
|
|
283
|
-
message?: string;
|
|
284
|
-
/** Timestamp of the event */
|
|
285
|
-
timestamp: Date;
|
|
286
|
-
/** Log level for this event (info, warn, error, success) */
|
|
287
|
-
logLevel: TLogLevel;
|
|
288
|
-
/** Pre-formatted log message ready for output */
|
|
289
|
-
logMessage: string;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// ================================
|
|
293
|
-
// Utility Types
|
|
294
|
-
// ================================
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Available tool names
|
|
298
|
-
*/
|
|
299
|
-
export type TToolName = 'filesystem' | 'http' | 'browser' | 'shell';
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Generate a unique proposal ID
|
|
303
|
-
*/
|
|
304
|
-
export function generateProposalId(): string {
|
|
305
|
-
return `proposal_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
17
|
+
maxSteps?: number;
|
|
18
|
+
/** Prior conversation messages to include */
|
|
19
|
+
messages?: ModelMessage[];
|
|
20
|
+
/** Called for each streamed text delta */
|
|
21
|
+
onToken?: (delta: string) => void;
|
|
22
|
+
/** Called when a tool call starts */
|
|
23
|
+
onToolCall?: (toolName: string, input: unknown) => void;
|
|
24
|
+
/** Called when a tool call completes */
|
|
25
|
+
onToolResult?: (toolName: string, result: unknown) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Called when total token usage approaches the model's context limit.
|
|
28
|
+
* Receives the full message history and must return a compacted replacement.
|
|
29
|
+
* If not provided, runAgent throws a ContextOverflowError instead.
|
|
30
|
+
*/
|
|
31
|
+
onContextOverflow?: (messages: ModelMessage[]) => Promise<ModelMessage[]>;
|
|
32
|
+
/** AbortSignal to cancel the run mid-flight */
|
|
33
|
+
abort?: AbortSignal;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface IAgentRunResult {
|
|
37
|
+
/** Final text output from the model */
|
|
38
|
+
text: string;
|
|
39
|
+
/** All messages in the completed conversation */
|
|
40
|
+
messages: ModelMessage[];
|
|
41
|
+
/** Total steps taken */
|
|
42
|
+
steps: number;
|
|
43
|
+
/** Finish reason from the final step */
|
|
44
|
+
finishReason: string;
|
|
45
|
+
/** Accumulated token usage across all steps */
|
|
46
|
+
usage: { inputTokens: number; outputTokens: number; totalTokens: number };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class ContextOverflowError extends Error {
|
|
50
|
+
constructor(message = 'Agent context limit reached and no onContextOverflow handler provided') {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = 'ContextOverflowError';
|
|
53
|
+
}
|
|
306
54
|
}
|