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