@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
@@ -1,657 +0,0 @@
1
- import * as plugins from './plugins.js';
2
- import * as interfaces from './smartagent.interfaces.js';
3
- import { BaseToolWrapper } from './smartagent.tools.base.js';
4
- import { DriverAgent } from './smartagent.classes.driveragent.js';
5
- import { GuardianAgent } from './smartagent.classes.guardianagent.js';
6
- import { FilesystemTool } from './smartagent.tools.filesystem.js';
7
- import { HttpTool } from './smartagent.tools.http.js';
8
- import { ShellTool } from './smartagent.tools.shell.js';
9
- import { BrowserTool } from './smartagent.tools.browser.js';
10
- import { DenoTool } from './smartagent.tools.deno.js';
11
-
12
- /**
13
- * DualAgentOrchestrator - Coordinates Driver and Guardian agents
14
- * Manages the complete lifecycle of task execution with tool approval
15
- */
16
- export class DualAgentOrchestrator {
17
- private options: interfaces.IDualAgentOptions;
18
- private smartai: plugins.smartai.SmartAi;
19
- private driverProvider: plugins.smartai.MultiModalModel;
20
- private guardianProvider: plugins.smartai.MultiModalModel;
21
- private driver: DriverAgent;
22
- private guardian: GuardianAgent;
23
- private tools: Map<string, BaseToolWrapper> = new Map();
24
- private isRunning = false;
25
- private conversationHistory: interfaces.IAgentMessage[] = [];
26
- private ownsSmartAi = true; // true if we created the SmartAi instance, false if it was provided
27
-
28
- constructor(options: interfaces.IDualAgentOptions) {
29
- this.options = {
30
- maxIterations: 20,
31
- maxConsecutiveRejections: 3,
32
- defaultProvider: 'openai',
33
- maxResultChars: 15000,
34
- maxHistoryMessages: 20,
35
- ...options,
36
- };
37
-
38
- // Use existing SmartAi instance if provided, otherwise create a new one
39
- if (options.smartAiInstance) {
40
- this.smartai = options.smartAiInstance;
41
- this.ownsSmartAi = false; // Don't manage lifecycle of provided instance
42
- } else {
43
- this.smartai = new plugins.smartai.SmartAi(options);
44
- this.ownsSmartAi = true;
45
- }
46
- // Note: Don't access providers here - they don't exist until start() is called
47
- }
48
-
49
- /**
50
- * Get provider by name
51
- */
52
- private getProviderByName(providerName: plugins.smartai.TProvider): plugins.smartai.MultiModalModel {
53
- switch (providerName) {
54
- case 'openai':
55
- return this.smartai.openaiProvider;
56
- case 'anthropic':
57
- return this.smartai.anthropicProvider;
58
- case 'perplexity':
59
- return this.smartai.perplexityProvider;
60
- case 'ollama':
61
- return this.smartai.ollamaProvider;
62
- case 'groq':
63
- return this.smartai.groqProvider;
64
- case 'xai':
65
- return this.smartai.xaiProvider;
66
- case 'exo':
67
- return this.smartai.exoProvider;
68
- default:
69
- return this.smartai.openaiProvider;
70
- }
71
- }
72
-
73
- /**
74
- * Emit a progress event if callback is configured
75
- */
76
- private emitProgress(event: Omit<interfaces.IProgressEvent, 'timestamp' | 'logLevel' | 'logMessage'>): void {
77
- if (this.options.onProgress) {
78
- const prefix = this.options.logPrefix ? `${this.options.logPrefix} ` : '';
79
- const { logLevel, logMessage } = this.formatProgressEvent(event, prefix);
80
-
81
- this.options.onProgress({
82
- ...event,
83
- timestamp: new Date(),
84
- logLevel,
85
- logMessage,
86
- });
87
- }
88
- }
89
-
90
- /**
91
- * Format a progress event into a log level and message
92
- */
93
- private formatProgressEvent(
94
- event: Omit<interfaces.IProgressEvent, 'timestamp' | 'logLevel' | 'logMessage'>,
95
- prefix: string
96
- ): { logLevel: interfaces.TLogLevel; logMessage: string } {
97
- switch (event.type) {
98
- case 'task_started':
99
- return { logLevel: 'info', logMessage: `${prefix}Task started` };
100
- case 'iteration_started':
101
- return { logLevel: 'info', logMessage: `${prefix}Iteration ${event.iteration}/${event.maxIterations}` };
102
- case 'tool_proposed':
103
- return { logLevel: 'info', logMessage: `${prefix} → Proposing: ${event.toolName}.${event.action}` };
104
- case 'guardian_evaluating':
105
- return { logLevel: 'info', logMessage: `${prefix} ⏳ Guardian evaluating...` };
106
- case 'tool_approved':
107
- return { logLevel: 'info', logMessage: `${prefix} ✓ Approved: ${event.toolName}.${event.action}` };
108
- case 'tool_rejected':
109
- return { logLevel: 'warn', logMessage: `${prefix} ✗ Rejected: ${event.toolName}.${event.action} - ${event.reason}` };
110
- case 'tool_executing':
111
- return { logLevel: 'info', logMessage: `${prefix} ⚡ Executing: ${event.toolName}.${event.action}...` };
112
- case 'tool_completed':
113
- return { logLevel: 'info', logMessage: `${prefix} ✓ Completed: ${event.message}` };
114
- case 'task_completed':
115
- return { logLevel: 'success', logMessage: `${prefix}Task completed in ${event.iteration} iterations` };
116
- case 'clarification_needed':
117
- return { logLevel: 'warn', logMessage: `${prefix}Clarification needed from user` };
118
- case 'max_iterations':
119
- return { logLevel: 'error', logMessage: `${prefix}${event.message}` };
120
- case 'max_rejections':
121
- return { logLevel: 'error', logMessage: `${prefix}${event.message}` };
122
- default:
123
- return { logLevel: 'info', logMessage: `${prefix}${event.type}` };
124
- }
125
- }
126
-
127
- /**
128
- * Register a custom tool
129
- */
130
- public registerTool(tool: BaseToolWrapper): void {
131
- this.tools.set(tool.name, tool);
132
- // Register with agents if they exist (they're created in start())
133
- if (this.driver) {
134
- this.driver.registerTool(tool);
135
- }
136
- if (this.guardian) {
137
- this.guardian.registerTool(tool);
138
- }
139
- }
140
-
141
- /**
142
- * Register all standard tools
143
- */
144
- public registerStandardTools(): void {
145
- const standardTools = [
146
- new FilesystemTool(),
147
- new HttpTool(),
148
- new ShellTool(),
149
- new BrowserTool(),
150
- new DenoTool(),
151
- ];
152
-
153
- for (const tool of standardTools) {
154
- this.registerTool(tool);
155
- }
156
- }
157
-
158
- /**
159
- * Register a scoped filesystem tool that can only access files within the specified directory
160
- * @param basePath The directory to scope filesystem operations to
161
- * @param excludePatterns Optional glob patterns to exclude from listings (e.g., ['.nogit/**', 'node_modules/**'])
162
- */
163
- public registerScopedFilesystemTool(basePath: string, excludePatterns?: string[]): void {
164
- const scopedTool = new FilesystemTool({ basePath, excludePatterns });
165
- this.registerTool(scopedTool);
166
- }
167
-
168
- /**
169
- * Initialize all tools (eager loading)
170
- */
171
- public async start(): Promise<void> {
172
- // Start smartai only if we created it (external instances should already be started)
173
- if (this.ownsSmartAi) {
174
- await this.smartai.start();
175
- }
176
-
177
- // NOW get providers (after they've been initialized by smartai.start())
178
- this.driverProvider = this.getProviderByName(this.options.defaultProvider!);
179
- this.guardianProvider = this.options.guardianProvider
180
- ? this.getProviderByName(this.options.guardianProvider)
181
- : this.driverProvider;
182
-
183
- // NOW create agents with initialized providers
184
- // Set up token callback wrapper if streaming is enabled
185
- const driverOnToken = this.options.onToken
186
- ? (token: string) => this.options.onToken!(token, 'driver')
187
- : undefined;
188
-
189
- this.driver = new DriverAgent(this.driverProvider, {
190
- systemMessage: this.options.driverSystemMessage,
191
- maxHistoryMessages: this.options.maxHistoryMessages,
192
- onToken: driverOnToken,
193
- });
194
- this.guardian = new GuardianAgent(this.guardianProvider, this.options.guardianPolicyPrompt);
195
-
196
- // Register any tools that were added before start() with the agents
197
- for (const tool of this.tools.values()) {
198
- this.driver.registerTool(tool);
199
- this.guardian.registerTool(tool);
200
- }
201
-
202
- // Initialize all tools
203
- const initPromises: Promise<void>[] = [];
204
- for (const tool of this.tools.values()) {
205
- initPromises.push(tool.initialize());
206
- }
207
-
208
- await Promise.all(initPromises);
209
- this.isRunning = true;
210
- }
211
-
212
- /**
213
- * Cleanup all tools
214
- */
215
- public async stop(): Promise<void> {
216
- const cleanupPromises: Promise<void>[] = [];
217
-
218
- for (const tool of this.tools.values()) {
219
- cleanupPromises.push(tool.cleanup());
220
- }
221
-
222
- await Promise.all(cleanupPromises);
223
-
224
- // Only stop smartai if we created it (don't stop external instances)
225
- if (this.ownsSmartAi) {
226
- await this.smartai.stop();
227
- }
228
-
229
- this.isRunning = false;
230
- if (this.driver) {
231
- this.driver.reset();
232
- }
233
- }
234
-
235
- /**
236
- * Run a task through the dual-agent system
237
- * @param task The task description
238
- * @param options Optional task run options (e.g., images for vision tasks)
239
- */
240
- public async run(task: string, options?: interfaces.ITaskRunOptions): Promise<interfaces.IDualAgentRunResult> {
241
- if (!this.isRunning) {
242
- throw new Error('Orchestrator not started. Call start() first.');
243
- }
244
-
245
- // Use native tool calling if enabled
246
- const useNativeTools = this.options.useNativeToolCalling === true;
247
-
248
- this.conversationHistory = [];
249
- let iterations = 0;
250
- let consecutiveRejections = 0;
251
- let completed = false;
252
- let finalResult: string | null = null;
253
-
254
- // Track pending native tool calls
255
- let pendingNativeToolCalls: interfaces.INativeToolCall[] | undefined;
256
-
257
- // Extract images from options
258
- const images = options?.images;
259
-
260
- // Add initial task to history
261
- this.conversationHistory.push({
262
- role: 'user',
263
- content: task,
264
- });
265
-
266
- // Start the driver with the task and optional images
267
- let driverResponse: interfaces.IAgentMessage;
268
-
269
- if (useNativeTools) {
270
- // Native tool calling mode
271
- const result = await this.driver.startTaskWithNativeTools(task, images);
272
- driverResponse = result.message;
273
- pendingNativeToolCalls = result.toolCalls;
274
- } else {
275
- // XML parsing mode
276
- driverResponse = await this.driver.startTask(task, images);
277
- }
278
- this.conversationHistory.push(driverResponse);
279
-
280
- // Emit task started event
281
- this.emitProgress({
282
- type: 'task_started',
283
- message: task.length > 100 ? task.substring(0, 100) + '...' : task,
284
- });
285
-
286
- while (
287
- iterations < this.options.maxIterations! &&
288
- consecutiveRejections < this.options.maxConsecutiveRejections! &&
289
- !completed
290
- ) {
291
- iterations++;
292
-
293
- // Emit iteration started event
294
- this.emitProgress({
295
- type: 'iteration_started',
296
- iteration: iterations,
297
- maxIterations: this.options.maxIterations,
298
- });
299
-
300
- // Check if task is complete (for native mode, no pending tool calls and has content)
301
- const isComplete = useNativeTools
302
- ? (!pendingNativeToolCalls || pendingNativeToolCalls.length === 0) && driverResponse.content.length > 0
303
- : this.driver.isTaskComplete(driverResponse.content);
304
-
305
- if (isComplete) {
306
- completed = true;
307
- finalResult = useNativeTools
308
- ? driverResponse.content
309
- : (this.driver.extractTaskResult(driverResponse.content) || driverResponse.content);
310
-
311
- // Emit task completed event
312
- this.emitProgress({
313
- type: 'task_completed',
314
- iteration: iterations,
315
- message: 'Task completed successfully',
316
- });
317
- break;
318
- }
319
-
320
- // Check if driver needs clarification
321
- if (this.driver.needsClarification(driverResponse.content)) {
322
- // Emit clarification needed event
323
- this.emitProgress({
324
- type: 'clarification_needed',
325
- iteration: iterations,
326
- message: 'Driver needs clarification from user',
327
- });
328
-
329
- // Return with clarification needed status
330
- return {
331
- success: false,
332
- completed: false,
333
- result: driverResponse.content,
334
- iterations,
335
- history: this.conversationHistory,
336
- status: 'clarification_needed',
337
- };
338
- }
339
-
340
- // Parse tool call proposals - native mode uses pendingNativeToolCalls, XML mode parses content
341
- let proposals: interfaces.IToolCallProposal[];
342
-
343
- if (useNativeTools && pendingNativeToolCalls && pendingNativeToolCalls.length > 0) {
344
- // Native tool calling mode - convert native tool calls to proposals
345
- proposals = this.driver.parseNativeToolCalls(pendingNativeToolCalls);
346
- pendingNativeToolCalls = undefined; // Clear after processing
347
- } else if (!useNativeTools) {
348
- // XML parsing mode
349
- proposals = this.driver.parseToolCallProposals(driverResponse.content);
350
- } else {
351
- proposals = [];
352
- }
353
-
354
- if (proposals.length === 0) {
355
- if (useNativeTools) {
356
- // Native mode: no tool calls and no content means we should continue
357
- const result = await this.driver.continueWithNativeTools(
358
- 'Please continue with the task. Use the available tools or provide your final output.'
359
- );
360
- driverResponse = result.message;
361
- pendingNativeToolCalls = result.toolCalls;
362
- this.conversationHistory.push(driverResponse);
363
- continue;
364
- } else {
365
- // XML mode: remind the model of the exact XML format
366
- driverResponse = await this.driver.continueWithMessage(
367
- `No valid tool call was found in your response. To use a tool, you MUST output the exact XML format:
368
-
369
- <tool_call>
370
- <tool>tool_name</tool>
371
- <action>action_name</action>
372
- <params>{"param1": "value1"}</params>
373
- </tool_call>
374
-
375
- For example, to validate JSON:
376
- <tool_call>
377
- <tool>json</tool>
378
- <action>validate</action>
379
- <params>{"jsonString": "{\\"key\\":\\"value\\"}", "requiredFields": ["key"]}</params>
380
- </tool_call>
381
-
382
- Or to complete the task:
383
- <task_complete>your final JSON output here</task_complete>
384
-
385
- Please output the exact XML format above.`
386
- );
387
- this.conversationHistory.push(driverResponse);
388
- continue;
389
- }
390
- }
391
-
392
- // Process the first proposal (one at a time)
393
- const proposal = proposals[0];
394
-
395
- // Emit tool proposed event
396
- this.emitProgress({
397
- type: 'tool_proposed',
398
- iteration: iterations,
399
- toolName: proposal.toolName,
400
- action: proposal.action,
401
- message: `${proposal.toolName}.${proposal.action}`,
402
- });
403
-
404
- // Quick validation first
405
- const quickDecision = this.guardian.quickValidate(proposal);
406
- let decision: interfaces.IGuardianDecision;
407
-
408
- if (quickDecision) {
409
- decision = quickDecision;
410
- } else {
411
- // Emit guardian evaluating event
412
- this.emitProgress({
413
- type: 'guardian_evaluating',
414
- iteration: iterations,
415
- toolName: proposal.toolName,
416
- action: proposal.action,
417
- });
418
-
419
- // Full AI evaluation
420
- decision = await this.guardian.evaluate(proposal, task);
421
- }
422
-
423
- if (decision.decision === 'approve') {
424
- consecutiveRejections = 0;
425
-
426
- // Emit tool approved event
427
- this.emitProgress({
428
- type: 'tool_approved',
429
- iteration: iterations,
430
- toolName: proposal.toolName,
431
- action: proposal.action,
432
- });
433
-
434
- // Execute the tool
435
- const tool = this.tools.get(proposal.toolName);
436
- if (!tool) {
437
- const errorMessage = `Tool "${proposal.toolName}" not found.`;
438
- driverResponse = await this.driver.continueWithMessage(
439
- `TOOL ERROR: ${errorMessage}\n\nPlease try a different approach.`
440
- );
441
- this.conversationHistory.push(driverResponse);
442
- continue;
443
- }
444
-
445
- try {
446
- // Emit tool executing event
447
- this.emitProgress({
448
- type: 'tool_executing',
449
- iteration: iterations,
450
- toolName: proposal.toolName,
451
- action: proposal.action,
452
- });
453
-
454
- const result = await tool.execute(proposal.action, proposal.params);
455
-
456
- // Emit tool completed event
457
- this.emitProgress({
458
- type: 'tool_completed',
459
- iteration: iterations,
460
- toolName: proposal.toolName,
461
- action: proposal.action,
462
- message: result.success ? 'success' : result.error,
463
- });
464
-
465
- // Build result message (prefer summary if provided, otherwise stringify result)
466
- let resultMessage: string;
467
- if (result.success) {
468
- if (result.summary) {
469
- // Use tool-provided summary
470
- resultMessage = `TOOL RESULT (${proposal.toolName}.${proposal.action}):\n${result.summary}`;
471
- } else {
472
- // Stringify and potentially truncate
473
- const resultStr = JSON.stringify(result.result, null, 2);
474
- const maxChars = this.options.maxResultChars ?? 15000;
475
-
476
- if (maxChars > 0 && resultStr.length > maxChars) {
477
- // Truncate the result
478
- const truncated = resultStr.substring(0, maxChars);
479
- const omittedTokens = Math.round((resultStr.length - maxChars) / 4);
480
- resultMessage = `TOOL RESULT (${proposal.toolName}.${proposal.action}):\n${truncated}\n\n[... output truncated, ~${omittedTokens} tokens omitted. Use more specific parameters to reduce output size.]`;
481
- } else {
482
- resultMessage = `TOOL RESULT (${proposal.toolName}.${proposal.action}):\n${resultStr}`;
483
- }
484
- }
485
- } else {
486
- resultMessage = `TOOL ERROR (${proposal.toolName}.${proposal.action}):\n${result.error}`;
487
- }
488
-
489
- this.conversationHistory.push({
490
- role: 'system',
491
- content: resultMessage,
492
- toolCall: proposal,
493
- toolResult: result,
494
- });
495
-
496
- // Continue with appropriate method based on mode
497
- if (useNativeTools) {
498
- const toolNameForHistory = `${proposal.toolName}_${proposal.action}`;
499
- const continueResult = await this.driver.continueWithNativeTools(resultMessage, toolNameForHistory);
500
- driverResponse = continueResult.message;
501
- pendingNativeToolCalls = continueResult.toolCalls;
502
- } else {
503
- driverResponse = await this.driver.continueWithMessage(resultMessage);
504
- }
505
- this.conversationHistory.push(driverResponse);
506
- } catch (error) {
507
- const errorMessage = `Tool execution failed: ${error instanceof Error ? error.message : String(error)}`;
508
- if (useNativeTools) {
509
- const toolNameForHistory = `${proposal.toolName}_${proposal.action}`;
510
- const continueResult = await this.driver.continueWithNativeTools(
511
- `TOOL ERROR: ${errorMessage}\n\nPlease try a different approach.`,
512
- toolNameForHistory
513
- );
514
- driverResponse = continueResult.message;
515
- pendingNativeToolCalls = continueResult.toolCalls;
516
- } else {
517
- driverResponse = await this.driver.continueWithMessage(
518
- `TOOL ERROR: ${errorMessage}\n\nPlease try a different approach.`
519
- );
520
- }
521
- this.conversationHistory.push(driverResponse);
522
- }
523
- } else {
524
- // Rejected
525
- consecutiveRejections++;
526
-
527
- // Emit tool rejected event
528
- this.emitProgress({
529
- type: 'tool_rejected',
530
- iteration: iterations,
531
- toolName: proposal.toolName,
532
- action: proposal.action,
533
- reason: decision.reason,
534
- });
535
-
536
- // Build rejection feedback
537
- let feedback = `TOOL CALL REJECTED by Guardian:\n`;
538
- feedback += `- Reason: ${decision.reason}\n`;
539
-
540
- if (decision.concerns && decision.concerns.length > 0) {
541
- feedback += `- Concerns:\n${decision.concerns.map(c => ` - ${c}`).join('\n')}\n`;
542
- }
543
-
544
- if (decision.suggestions) {
545
- feedback += `- Suggestions: ${decision.suggestions}\n`;
546
- }
547
-
548
- feedback += `\nPlease adapt your approach based on this feedback.`;
549
-
550
- this.conversationHistory.push({
551
- role: 'system',
552
- content: feedback,
553
- toolCall: proposal,
554
- guardianDecision: decision,
555
- });
556
-
557
- // Continue with appropriate method based on mode
558
- if (useNativeTools) {
559
- const continueResult = await this.driver.continueWithNativeTools(feedback);
560
- driverResponse = continueResult.message;
561
- pendingNativeToolCalls = continueResult.toolCalls;
562
- } else {
563
- driverResponse = await this.driver.continueWithMessage(feedback);
564
- }
565
- this.conversationHistory.push(driverResponse);
566
- }
567
- }
568
-
569
- // Determine final status
570
- let status: interfaces.TDualAgentRunStatus = 'completed';
571
- if (!completed) {
572
- if (iterations >= this.options.maxIterations!) {
573
- status = 'max_iterations_reached';
574
- // Emit max iterations event
575
- this.emitProgress({
576
- type: 'max_iterations',
577
- iteration: iterations,
578
- maxIterations: this.options.maxIterations,
579
- message: `Maximum iterations (${this.options.maxIterations}) reached`,
580
- });
581
- } else if (consecutiveRejections >= this.options.maxConsecutiveRejections!) {
582
- status = 'max_rejections_reached';
583
- // Emit max rejections event
584
- this.emitProgress({
585
- type: 'max_rejections',
586
- iteration: iterations,
587
- message: `Maximum consecutive rejections (${this.options.maxConsecutiveRejections}) reached`,
588
- });
589
- }
590
- }
591
-
592
- return {
593
- success: completed,
594
- completed,
595
- result: finalResult || driverResponse.content,
596
- iterations,
597
- history: this.conversationHistory,
598
- status,
599
- };
600
- }
601
-
602
- /**
603
- * Continue an existing task with user input
604
- */
605
- public async continueTask(userInput: string): Promise<interfaces.IDualAgentRunResult> {
606
- if (!this.isRunning) {
607
- throw new Error('Orchestrator not started. Call start() first.');
608
- }
609
-
610
- this.conversationHistory.push({
611
- role: 'user',
612
- content: userInput,
613
- });
614
-
615
- const driverResponse = await this.driver.continueWithMessage(userInput);
616
- this.conversationHistory.push(driverResponse);
617
-
618
- // Continue the run loop
619
- // For simplicity, we return the current state - full continuation would need refactoring
620
- return {
621
- success: false,
622
- completed: false,
623
- result: driverResponse.content,
624
- iterations: 1,
625
- history: this.conversationHistory,
626
- status: 'in_progress',
627
- };
628
- }
629
-
630
- /**
631
- * Get the conversation history
632
- */
633
- public getHistory(): interfaces.IAgentMessage[] {
634
- return [...this.conversationHistory];
635
- }
636
-
637
- /**
638
- * Update the guardian policy
639
- */
640
- public setGuardianPolicy(policyPrompt: string): void {
641
- this.guardian.setPolicy(policyPrompt);
642
- }
643
-
644
- /**
645
- * Check if orchestrator is running
646
- */
647
- public isActive(): boolean {
648
- return this.isRunning;
649
- }
650
-
651
- /**
652
- * Get registered tool names
653
- */
654
- public getToolNames(): string[] {
655
- return Array.from(this.tools.keys());
656
- }
657
- }