@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.
Files changed (81) hide show
  1. package/dist_ts/00_commitinfo_data.js +3 -3
  2. package/dist_ts/index.d.ts +9 -12
  3. package/dist_ts/index.js +9 -20
  4. package/dist_ts/plugins.d.ts +8 -9
  5. package/dist_ts/plugins.js +10 -12
  6. package/dist_ts/smartagent.classes.agent.d.ts +2 -0
  7. package/dist_ts/smartagent.classes.agent.js +173 -0
  8. package/dist_ts/smartagent.classes.toolregistry.d.ts +12 -0
  9. package/dist_ts/smartagent.classes.toolregistry.js +17 -0
  10. package/dist_ts/smartagent.interfaces.d.ts +47 -231
  11. package/dist_ts/smartagent.interfaces.js +6 -7
  12. package/dist_ts/smartagent.utils.truncation.d.ts +10 -0
  13. package/dist_ts/smartagent.utils.truncation.js +26 -0
  14. package/dist_ts_compaction/index.d.ts +1 -0
  15. package/dist_ts_compaction/index.js +2 -0
  16. package/dist_ts_compaction/plugins.d.ts +4 -0
  17. package/dist_ts_compaction/plugins.js +3 -0
  18. package/dist_ts_compaction/smartagent.compaction.d.ts +10 -0
  19. package/dist_ts_compaction/smartagent.compaction.js +46 -0
  20. package/dist_ts_tools/index.d.ts +8 -0
  21. package/dist_ts_tools/index.js +6 -0
  22. package/dist_ts_tools/plugins.d.ts +15 -0
  23. package/dist_ts_tools/plugins.js +19 -0
  24. package/dist_ts_tools/tool.filesystem.d.ts +6 -0
  25. package/dist_ts_tools/tool.filesystem.js +102 -0
  26. package/dist_ts_tools/tool.http.d.ts +2 -0
  27. package/dist_ts_tools/tool.http.js +65 -0
  28. package/dist_ts_tools/tool.json.d.ts +2 -0
  29. package/dist_ts_tools/tool.json.js +47 -0
  30. package/dist_ts_tools/tool.shell.d.ts +8 -0
  31. package/dist_ts_tools/tool.shell.js +40 -0
  32. package/npmextra.json +1 -1
  33. package/package.json +30 -18
  34. package/readme.hints.md +43 -42
  35. package/readme.md +257 -526
  36. package/ts/00_commitinfo_data.ts +2 -2
  37. package/ts/index.ts +11 -31
  38. package/ts/plugins.ts +22 -21
  39. package/ts/smartagent.classes.agent.ts +198 -0
  40. package/ts/smartagent.classes.toolregistry.ts +20 -0
  41. package/ts/smartagent.interfaces.ts +51 -303
  42. package/ts/smartagent.utils.truncation.ts +39 -0
  43. package/ts_compaction/index.ts +1 -0
  44. package/ts_compaction/plugins.ts +6 -0
  45. package/ts_compaction/smartagent.compaction.ts +51 -0
  46. package/ts_tools/index.ts +8 -0
  47. package/ts_tools/plugins.ts +30 -0
  48. package/ts_tools/tool.filesystem.ts +131 -0
  49. package/ts_tools/tool.http.ts +78 -0
  50. package/ts_tools/tool.json.ts +53 -0
  51. package/ts_tools/tool.shell.ts +62 -0
  52. package/dist_ts/smartagent.classes.driveragent.d.ts +0 -134
  53. package/dist_ts/smartagent.classes.driveragent.js +0 -671
  54. package/dist_ts/smartagent.classes.dualagent.d.ts +0 -79
  55. package/dist_ts/smartagent.classes.dualagent.js +0 -583
  56. package/dist_ts/smartagent.classes.guardianagent.d.ts +0 -46
  57. package/dist_ts/smartagent.classes.guardianagent.js +0 -201
  58. package/dist_ts/smartagent.tools.base.d.ts +0 -52
  59. package/dist_ts/smartagent.tools.base.js +0 -42
  60. package/dist_ts/smartagent.tools.browser.d.ts +0 -17
  61. package/dist_ts/smartagent.tools.browser.js +0 -229
  62. package/dist_ts/smartagent.tools.deno.d.ts +0 -21
  63. package/dist_ts/smartagent.tools.deno.js +0 -191
  64. package/dist_ts/smartagent.tools.filesystem.d.ts +0 -40
  65. package/dist_ts/smartagent.tools.filesystem.js +0 -801
  66. package/dist_ts/smartagent.tools.http.d.ts +0 -16
  67. package/dist_ts/smartagent.tools.http.js +0 -264
  68. package/dist_ts/smartagent.tools.json.d.ts +0 -24
  69. package/dist_ts/smartagent.tools.json.js +0 -202
  70. package/dist_ts/smartagent.tools.shell.d.ts +0 -17
  71. package/dist_ts/smartagent.tools.shell.js +0 -202
  72. package/ts/smartagent.classes.driveragent.ts +0 -775
  73. package/ts/smartagent.classes.dualagent.ts +0 -657
  74. package/ts/smartagent.classes.guardianagent.ts +0 -241
  75. package/ts/smartagent.tools.base.ts +0 -83
  76. package/ts/smartagent.tools.browser.ts +0 -253
  77. package/ts/smartagent.tools.deno.ts +0 -230
  78. package/ts/smartagent.tools.filesystem.ts +0 -885
  79. package/ts/smartagent.tools.http.ts +0 -283
  80. package/ts/smartagent.tools.json.ts +0 -224
  81. package/ts/smartagent.tools.shell.ts +0 -230
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartagent',
6
- version: '1.7.0',
7
- description: 'an agentic framework built on top of @push.rocks/smartai'
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
- import * as plugins from './plugins.js';
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 base tool class for custom tool creation
11
- export { BaseToolWrapper } from './smartagent.tools.base.js';
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
- // third party
7
- import { minimatch } from 'minimatch';
8
-
9
- export { minimatch };
10
-
11
- // @push.rocks scope
12
- import * as smartai from '@push.rocks/smartai';
13
- import * as smartdeno from '@push.rocks/smartdeno';
14
- import * as smartfs from '@push.rocks/smartfs';
15
- import * as smartrequest from '@push.rocks/smartrequest';
16
- import * as smartbrowser from '@push.rocks/smartbrowser';
17
- import * as smartshell from '@push.rocks/smartshell';
18
-
19
- export {
20
- smartai,
21
- smartdeno,
22
- smartfs,
23
- smartrequest,
24
- smartbrowser,
25
- smartshell,
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 * as plugins from './plugins.js';
2
-
3
- // ================================
4
- // Task Run Options
5
- // ================================
6
-
7
- /**
8
- * Options for running a task with the DualAgentOrchestrator
9
- */
10
- export interface ITaskRunOptions {
11
- /** Base64-encoded images to include with the task (for vision-capable models) */
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
- * Enable native tool calling mode (default: false)
53
- * When enabled, uses Ollama's native tool calling API instead of XML parsing
54
- * This is more efficient for models that support it (e.g., GPT-OSS with Harmony format)
13
+ * Maximum number of LLM↔tool round trips.
14
+ * Each step may execute multiple tools in parallel.
15
+ * Default: 20
55
16
  */
56
- useNativeToolCalling?: boolean;
57
- }
58
-
59
- // ================================
60
- // Message Interfaces
61
- // ================================
62
-
63
- /**
64
- * Represents a message in the agent's conversation history
65
- */
66
- export interface IAgentMessage {
67
- role: 'system' | 'user' | 'assistant' | 'tool' | 'guardian';
68
- content: string;
69
- toolName?: string;
70
- toolResult?: unknown;
71
- toolCall?: IToolCallProposal;
72
- guardianDecision?: IGuardianDecision;
73
- timestamp?: Date;
74
- }
75
-
76
- // ================================
77
- // Tool Interfaces
78
- // ================================
79
-
80
- /**
81
- * Represents an action that a tool can perform
82
- */
83
- export interface IToolAction {
84
- /** Action name (e.g., 'read', 'write', 'delete') */
85
- name: string;
86
- /** Description of what this action does */
87
- description: string;
88
- /** JSON schema for action parameters */
89
- parameters: Record<string, unknown>;
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
  }