@memberjunction/ai-agents 2.50.0 → 2.52.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/README.md +774 -3
- package/dist/AgentRunner.d.ts +2 -1
- package/dist/AgentRunner.d.ts.map +1 -1
- package/dist/AgentRunner.js +5 -2
- package/dist/AgentRunner.js.map +1 -1
- package/dist/agent-types/base-agent-type.d.ts +6 -0
- package/dist/agent-types/base-agent-type.d.ts.map +1 -0
- package/dist/agent-types/base-agent-type.js.map +1 -0
- package/dist/agent-types/index.d.ts +2 -1
- package/dist/agent-types/index.d.ts.map +1 -1
- package/dist/agent-types/index.js +4 -3
- package/dist/agent-types/index.js.map +1 -1
- package/dist/agent-types/{LoopAgentType.d.ts → loop-agent-type.d.ts} +4 -4
- package/dist/agent-types/loop-agent-type.d.ts.map +1 -0
- package/dist/agent-types/{LoopAgentType.js → loop-agent-type.js} +71 -42
- package/dist/agent-types/loop-agent-type.js.map +1 -0
- package/dist/base-agent.d.ts +49 -1
- package/dist/base-agent.d.ts.map +1 -1
- package/dist/base-agent.js +1097 -98
- package/dist/base-agent.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +35 -16
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/agent-types/LoopAgentType.d.ts.map +0 -1
- package/dist/agent-types/LoopAgentType.js.map +0 -1
- package/dist/base-agent-type.d.ts +0 -6
- package/dist/base-agent-type.d.ts.map +0 -1
- package/dist/base-agent-type.js.map +0 -1
- /package/dist/{base-agent-type.js → agent-types/base-agent-type.js} +0 -0
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ The MemberJunction AI Agents package provides a comprehensive framework for crea
|
|
|
14
14
|
- **🔧 Factory Pattern**: Enhanced AgentFactory for dynamic agent instantiation and extensibility
|
|
15
15
|
- **🔐 Metadata-Driven**: Database-driven configuration for agents, types, and prompts
|
|
16
16
|
- **📊 Analytics**: Hierarchical execution logging with performance tracking across agent workflows
|
|
17
|
+
- **📡 Streaming Support**: Real-time streaming of execution progress and AI model responses
|
|
18
|
+
- **🛑 Cancellation Support**: Graceful cancellation of long-running operations with AbortSignal
|
|
17
19
|
|
|
18
20
|
## Installation
|
|
19
21
|
|
|
@@ -21,12 +23,25 @@ The MemberJunction AI Agents package provides a comprehensive framework for crea
|
|
|
21
23
|
npm install @memberjunction/ai-agents
|
|
22
24
|
```
|
|
23
25
|
|
|
26
|
+
### Type Organization Update (2025)
|
|
27
|
+
|
|
28
|
+
As part of improving code organization and reducing circular dependencies:
|
|
29
|
+
- **This package** now contains all agent-specific types:
|
|
30
|
+
- Agent execution types (`AgentExecutionParams`, `AgentExecutionResult`, etc.)
|
|
31
|
+
- Agent runner types (`AgentRunnerParams`, `AgentRunnerResult`)
|
|
32
|
+
- Conductor types (`ConductorDecisionInput`, `ConductorDecisionResponse`)
|
|
33
|
+
- Progress and streaming callbacks
|
|
34
|
+
- **Base AI types** are imported from `@memberjunction/ai` (Core)
|
|
35
|
+
- **Prompt types** are imported from `@memberjunction/ai-prompts`
|
|
36
|
+
- **Engine types** (agent type definitions) are imported from `@memberjunction/aiengine`
|
|
37
|
+
|
|
24
38
|
## Requirements
|
|
25
39
|
|
|
26
40
|
- Node.js 16+
|
|
27
41
|
- MemberJunction Core libraries
|
|
42
|
+
- [@memberjunction/ai](../Core/README.md) for base AI types and interfaces
|
|
28
43
|
- [@memberjunction/ai-prompts](../Prompts/README.md) for advanced prompt management
|
|
29
|
-
- [@memberjunction/aiengine](../Engine/README.md) for AI model orchestration
|
|
44
|
+
- [@memberjunction/aiengine](../Engine/README.md) for AI model orchestration and agent type definitions
|
|
30
45
|
|
|
31
46
|
## Core Architecture
|
|
32
47
|
|
|
@@ -208,6 +223,762 @@ const result = await runner.Run({
|
|
|
208
223
|
// The agent run record tracks the compression activity
|
|
209
224
|
```
|
|
210
225
|
|
|
226
|
+
### Streaming and Progress Tracking
|
|
227
|
+
|
|
228
|
+
The AI Agents framework supports real-time streaming of execution progress and AI model responses:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { AgentRunner } from '@memberjunction/ai-agents';
|
|
232
|
+
|
|
233
|
+
const runner = new AgentRunner();
|
|
234
|
+
|
|
235
|
+
// Execute with streaming and progress callbacks
|
|
236
|
+
const result = await runner.RunAgent({
|
|
237
|
+
agent: myAgent,
|
|
238
|
+
conversationMessages: messages,
|
|
239
|
+
contextUser: user,
|
|
240
|
+
|
|
241
|
+
// Progress callback for execution status updates
|
|
242
|
+
onProgress: (progress) => {
|
|
243
|
+
console.log(`[${progress.percentage}%] ${progress.step}: ${progress.message}`);
|
|
244
|
+
|
|
245
|
+
// Progress steps include:
|
|
246
|
+
// - initialization: Setting up the agent
|
|
247
|
+
// - validation: Validating agent configuration
|
|
248
|
+
// - prompt_execution: Executing AI prompts
|
|
249
|
+
// - action_execution: Running actions
|
|
250
|
+
// - subagent_execution: Running sub-agents
|
|
251
|
+
// - decision_processing: Processing next steps
|
|
252
|
+
// - finalization: Completing execution
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
// Streaming callback for real-time AI responses
|
|
256
|
+
onStreaming: (chunk) => {
|
|
257
|
+
process.stdout.write(chunk.content);
|
|
258
|
+
|
|
259
|
+
if (chunk.isComplete) {
|
|
260
|
+
console.log('\n--- Stream complete ---');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Additional metadata available:
|
|
264
|
+
// - chunk.stepType: 'prompt', 'action', 'subagent', or 'chat'
|
|
265
|
+
// - chunk.stepEntityId: ID of the step being executed
|
|
266
|
+
// - chunk.modelName: AI model producing the content (for prompts)
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Cancellation Support
|
|
272
|
+
|
|
273
|
+
Long-running agent operations can be cancelled gracefully using AbortSignal:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import { AgentRunner } from '@memberjunction/ai-agents';
|
|
277
|
+
|
|
278
|
+
const runner = new AgentRunner();
|
|
279
|
+
const controller = new AbortController();
|
|
280
|
+
|
|
281
|
+
// Set up cancellation after 30 seconds
|
|
282
|
+
setTimeout(() => {
|
|
283
|
+
console.log('Cancelling agent execution...');
|
|
284
|
+
controller.abort();
|
|
285
|
+
}, 30000);
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
const result = await runner.RunAgent({
|
|
289
|
+
agent: myAgent,
|
|
290
|
+
conversationMessages: messages,
|
|
291
|
+
contextUser: user,
|
|
292
|
+
cancellationToken: controller.signal,
|
|
293
|
+
onProgress: (progress) => {
|
|
294
|
+
console.log(`Progress: ${progress.message}`);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
if (result.cancelled) {
|
|
299
|
+
console.log('Execution was cancelled:', result.cancellationReason);
|
|
300
|
+
}
|
|
301
|
+
} catch (error) {
|
|
302
|
+
if (controller.signal.aborted) {
|
|
303
|
+
console.log('Operation cancelled by user');
|
|
304
|
+
} else {
|
|
305
|
+
console.error('Execution error:', error);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Cancellation is checked at multiple points:
|
|
310
|
+
// - Before starting execution
|
|
311
|
+
// - After initialization
|
|
312
|
+
// - Before each execution step
|
|
313
|
+
// - After prompt/action/sub-agent completion
|
|
314
|
+
// The agent run is properly marked as 'Cancelled' in the database
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Context Propagation (New in v2.51.0)
|
|
318
|
+
|
|
319
|
+
The AI Agents framework now supports type-safe context propagation throughout the execution hierarchy. This allows runtime-specific information to flow from agents to sub-agents and actions without being part of the formal parameters.
|
|
320
|
+
|
|
321
|
+
**Note**: Context typing is now done at the parameter level rather than the class level, providing better flexibility and type inference.
|
|
322
|
+
|
|
323
|
+
#### Basic Context Usage
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
import { BaseAgent, ExecuteAgentParams } from '@memberjunction/ai-agents';
|
|
327
|
+
|
|
328
|
+
// Define your context type
|
|
329
|
+
interface MyAgentContext {
|
|
330
|
+
apiEndpoint: string;
|
|
331
|
+
apiKey: string;
|
|
332
|
+
environment: 'dev' | 'staging' | 'prod';
|
|
333
|
+
userPreferences: {
|
|
334
|
+
language: string;
|
|
335
|
+
timezone: string;
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Execute agent with typed context
|
|
340
|
+
const agent = new BaseAgent();
|
|
341
|
+
const params: ExecuteAgentParams<MyAgentContext> = {
|
|
342
|
+
agent: myAgentEntity,
|
|
343
|
+
conversationMessages: messages,
|
|
344
|
+
contextUser: currentUser,
|
|
345
|
+
context: {
|
|
346
|
+
apiEndpoint: 'https://api.example.com',
|
|
347
|
+
apiKey: process.env.API_KEY,
|
|
348
|
+
environment: 'prod',
|
|
349
|
+
userPreferences: {
|
|
350
|
+
language: 'en',
|
|
351
|
+
timezone: 'UTC'
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
const result = await agent.Execute(params);
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### Context Flow Through Hierarchy
|
|
359
|
+
|
|
360
|
+
Context automatically flows through the entire execution hierarchy:
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
// Parent agent execution
|
|
364
|
+
const parentParams: ExecuteAgentParams<MyContext> = {
|
|
365
|
+
agent: parentAgentEntity,
|
|
366
|
+
conversationMessages: messages,
|
|
367
|
+
context: myContext // Context passed here
|
|
368
|
+
};
|
|
369
|
+
const parentResult = await parentAgent.Execute(parentParams);
|
|
370
|
+
|
|
371
|
+
// When parent executes sub-agents, context flows automatically
|
|
372
|
+
// Sub-agents receive the same context without manual passing
|
|
373
|
+
|
|
374
|
+
// When agents execute actions, context flows to them as well
|
|
375
|
+
// Actions can access context via params.Context
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
#### Using Context in Custom Agents
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
export class CustomAgent extends BaseAgent {
|
|
382
|
+
protected async preparePromptParams(
|
|
383
|
+
agentType: AIAgentTypeEntity,
|
|
384
|
+
systemPrompt: any,
|
|
385
|
+
childPrompt: any,
|
|
386
|
+
params: ExecuteAgentParams<MyAgentContext>
|
|
387
|
+
): Promise<AIPromptParams> {
|
|
388
|
+
const promptParams = await super.preparePromptParams(agentType, systemPrompt, childPrompt, params);
|
|
389
|
+
|
|
390
|
+
// Access typed context
|
|
391
|
+
if (params.context) {
|
|
392
|
+
promptParams.data.apiEndpoint = params.context.apiEndpoint;
|
|
393
|
+
promptParams.data.environment = params.context.environment;
|
|
394
|
+
|
|
395
|
+
// Use context to modify behavior
|
|
396
|
+
if (params.context.environment === 'dev') {
|
|
397
|
+
promptParams.data.debugMode = true;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return promptParams;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
#### Using Context in Actions
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
import { BaseAction, RunActionParams } from '@memberjunction/actions';
|
|
410
|
+
|
|
411
|
+
export class APICallAction extends BaseAction {
|
|
412
|
+
protected async InternalRunAction(params: RunActionParams<MyAgentContext>): Promise<ActionResultSimple> {
|
|
413
|
+
// Access typed context
|
|
414
|
+
const endpoint = params.Context?.apiEndpoint;
|
|
415
|
+
const apiKey = params.Context?.apiKey;
|
|
416
|
+
|
|
417
|
+
if (!endpoint || !apiKey) {
|
|
418
|
+
return {
|
|
419
|
+
Success: false,
|
|
420
|
+
ResultCode: 'MISSING_CONTEXT',
|
|
421
|
+
Message: 'Required API configuration not found in context'
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Use context for action execution
|
|
426
|
+
const response = await fetch(endpoint, {
|
|
427
|
+
headers: {
|
|
428
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
429
|
+
'Accept-Language': params.Context.userPreferences.language
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
return {
|
|
434
|
+
Success: true,
|
|
435
|
+
ResultCode: 'SUCCESS',
|
|
436
|
+
Message: 'API call completed'
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
#### Common Context Use Cases
|
|
443
|
+
|
|
444
|
+
1. **Environment Configuration**
|
|
445
|
+
```typescript
|
|
446
|
+
interface EnvironmentContext {
|
|
447
|
+
apiEndpoints: Record<string, string>;
|
|
448
|
+
featureFlags: Record<string, boolean>;
|
|
449
|
+
debugMode: boolean;
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
2. **User Session Information**
|
|
454
|
+
```typescript
|
|
455
|
+
interface SessionContext {
|
|
456
|
+
sessionId: string;
|
|
457
|
+
correlationId: string;
|
|
458
|
+
userPreferences: UserPreferences;
|
|
459
|
+
authTokens: Record<string, string>;
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
3. **Runtime Service Connections**
|
|
464
|
+
```typescript
|
|
465
|
+
interface ServiceContext {
|
|
466
|
+
databaseConnection: string;
|
|
467
|
+
cacheClient: CacheClient;
|
|
468
|
+
messageQueue: QueueService;
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
#### Best Practices for Context Usage
|
|
473
|
+
|
|
474
|
+
1. **Define Clear Context Types**: Create well-defined interfaces for your context objects
|
|
475
|
+
2. **Keep Context Focused**: Include only runtime-specific data, not business logic parameters
|
|
476
|
+
3. **Avoid Sensitive Data**: While context can contain API keys when necessary, minimize sensitive data exposure
|
|
477
|
+
4. **Document Context Requirements**: Clearly document what context your agents and actions expect
|
|
478
|
+
5. **Provide Defaults**: Handle cases where context might be undefined or partial
|
|
479
|
+
|
|
480
|
+
#### Context vs Parameters
|
|
481
|
+
|
|
482
|
+
Use **Context** for:
|
|
483
|
+
- Environment-specific configuration
|
|
484
|
+
- Runtime credentials and connections
|
|
485
|
+
- User session information
|
|
486
|
+
- Feature flags and toggles
|
|
487
|
+
- Cross-cutting concerns
|
|
488
|
+
|
|
489
|
+
Use **Parameters** for:
|
|
490
|
+
- Business logic inputs
|
|
491
|
+
- Data to be processed
|
|
492
|
+
- Explicit action configuration
|
|
493
|
+
- Values that should be logged/audited
|
|
494
|
+
- Data that varies per execution
|
|
495
|
+
|
|
496
|
+
## Extending BaseAgent
|
|
497
|
+
|
|
498
|
+
The BaseAgent class provides a flexible execution pipeline that can be extended and customized through protected methods. This allows subclasses to override specific parts of the execution flow while maintaining the overall architecture.
|
|
499
|
+
|
|
500
|
+
### Execution Pipeline Overview
|
|
501
|
+
|
|
502
|
+
The BaseAgent execution pipeline consists of the following overridable methods:
|
|
503
|
+
|
|
504
|
+
1. **`initializeEngines()`** - Initialize AI and Action engines
|
|
505
|
+
2. **`validateAgent()`** - Validate agent readiness
|
|
506
|
+
3. **`loadAgentConfiguration()`** - Load agent type and prompts
|
|
507
|
+
4. **`preparePromptParams()`** - Prepare hierarchical prompt parameters
|
|
508
|
+
5. **`executePrompt()`** - Execute the configured prompts
|
|
509
|
+
6. **`processNextStep()`** - Process agent type decisions
|
|
510
|
+
7. **`handleActionResults()`** - Handle action execution and recursion
|
|
511
|
+
8. **`handleSubAgentResult()`** - Handle sub-agent execution and recursion
|
|
512
|
+
9. **`createActionResultMessage()`** - Format action results as chat messages
|
|
513
|
+
10. **`createSubAgentResultMessage()`** - Format sub-agent results as chat messages
|
|
514
|
+
|
|
515
|
+
### Creating Custom Agent Classes
|
|
516
|
+
|
|
517
|
+
```typescript
|
|
518
|
+
import { BaseAgent, ExecuteAgentParams, ExecuteAgentResult } from '@memberjunction/ai-agents';
|
|
519
|
+
import { AIPromptParams } from '@memberjunction/ai-prompts';
|
|
520
|
+
|
|
521
|
+
export class CustomAnalysisAgent extends BaseAgent {
|
|
522
|
+
// Override initialization to add custom setup
|
|
523
|
+
protected async initializeEngines(contextUser?: UserInfo): Promise<void> {
|
|
524
|
+
await super.initializeEngines(contextUser);
|
|
525
|
+
|
|
526
|
+
// Add custom initialization
|
|
527
|
+
await this.initializeAnalysisTools();
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Override validation to add custom checks
|
|
531
|
+
protected async validateAgent(agent: AIAgentEntity): Promise<ExecuteAgentResult | null> {
|
|
532
|
+
const baseValidation = await super.validateAgent(agent);
|
|
533
|
+
if (baseValidation) return baseValidation;
|
|
534
|
+
|
|
535
|
+
// Add custom validation
|
|
536
|
+
if (!this.hasRequiredPermissions(agent)) {
|
|
537
|
+
return {
|
|
538
|
+
nextStep: 'failed',
|
|
539
|
+
errorMessage: 'Agent lacks required analysis permissions'
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Override prompt preparation to inject custom data
|
|
547
|
+
protected async preparePromptParams(
|
|
548
|
+
agentType: AIAgentTypeEntity,
|
|
549
|
+
systemPrompt: any,
|
|
550
|
+
childPrompt: any,
|
|
551
|
+
params: ExecuteAgentParams
|
|
552
|
+
): Promise<AIPromptParams> {
|
|
553
|
+
const promptParams = await super.preparePromptParams(agentType, systemPrompt, childPrompt, params);
|
|
554
|
+
|
|
555
|
+
// Add custom context data
|
|
556
|
+
promptParams.data = {
|
|
557
|
+
...promptParams.data,
|
|
558
|
+
analysisContext: await this.gatherAnalysisContext(),
|
|
559
|
+
historicalData: await this.loadHistoricalData()
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
return promptParams;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Override action result formatting
|
|
566
|
+
protected createActionResultMessage(actions: AgentAction[], results: any[]): ChatMessage {
|
|
567
|
+
// Custom formatting for analysis results
|
|
568
|
+
const analysisResults = results.map((result, index) => {
|
|
569
|
+
return {
|
|
570
|
+
action: actions[index].name,
|
|
571
|
+
success: result.Success,
|
|
572
|
+
analysisScore: result.Params?.find(p => p.Name === 'score')?.Value,
|
|
573
|
+
insights: result.Params?.find(p => p.Name === 'insights')?.Value
|
|
574
|
+
};
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
return {
|
|
578
|
+
role: 'user',
|
|
579
|
+
content: `Analysis completed:\n${JSON.stringify(analysisResults, null, 2)}`
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
### Selective Method Overriding
|
|
586
|
+
|
|
587
|
+
You can override just the methods you need to customize:
|
|
588
|
+
|
|
589
|
+
```typescript
|
|
590
|
+
export class StreamingAgent extends BaseAgent {
|
|
591
|
+
// Only override prompt execution to add streaming
|
|
592
|
+
protected async executePrompt(promptParams: AIPromptParams): Promise<any> {
|
|
593
|
+
// Add streaming configuration
|
|
594
|
+
promptParams.streaming = true;
|
|
595
|
+
promptParams.streamingCallback = (chunk) => {
|
|
596
|
+
this.handleStreamingChunk(chunk);
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
return await super.executePrompt(promptParams);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
private handleStreamingChunk(chunk: string): void {
|
|
603
|
+
// Process streaming response chunks
|
|
604
|
+
console.log('Streaming:', chunk);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Customizing Recursion Behavior
|
|
610
|
+
|
|
611
|
+
Override the action/sub-agent handling methods to customize recursion:
|
|
612
|
+
|
|
613
|
+
```typescript
|
|
614
|
+
export class BatchProcessingAgent extends BaseAgent {
|
|
615
|
+
protected async handleActionResults(
|
|
616
|
+
params: ExecuteAgentParams,
|
|
617
|
+
nextStep: any,
|
|
618
|
+
promptResult: any
|
|
619
|
+
): Promise<ExecuteAgentResult> {
|
|
620
|
+
// Execute actions
|
|
621
|
+
const actionResults = await this.ExecuteActions(nextStep.actions, params.contextUser);
|
|
622
|
+
|
|
623
|
+
// Batch results instead of immediate recursion
|
|
624
|
+
if (this.shouldBatchResults(actionResults)) {
|
|
625
|
+
this.batchedResults.push(...actionResults);
|
|
626
|
+
|
|
627
|
+
// Continue without recursion if batching
|
|
628
|
+
return {
|
|
629
|
+
nextStep: 'retry',
|
|
630
|
+
returnValue: { batching: true, count: this.batchedResults.length }
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Otherwise use default recursion behavior
|
|
635
|
+
return await super.handleActionResults(params, nextStep, promptResult);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
### Advanced Pipeline Customization
|
|
641
|
+
|
|
642
|
+
For complex scenarios, you can completely override the Execute method while still using the helper methods:
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
export class MultiStageAgent extends BaseAgent {
|
|
646
|
+
public async Execute(params: ExecuteAgentParams): Promise<ExecuteAgentResult> {
|
|
647
|
+
// Stage 1: Initial analysis
|
|
648
|
+
const stage1Result = await this.executeStage1(params);
|
|
649
|
+
if (stage1Result.nextStep === 'failed') return stage1Result;
|
|
650
|
+
|
|
651
|
+
// Stage 2: Deep processing based on stage 1
|
|
652
|
+
const stage2Params = this.prepareStage2Params(params, stage1Result);
|
|
653
|
+
const stage2Result = await this.executeStage2(stage2Params);
|
|
654
|
+
if (stage2Result.nextStep === 'failed') return stage2Result;
|
|
655
|
+
|
|
656
|
+
// Stage 3: Synthesis and final execution
|
|
657
|
+
return await this.executeFinalStage(params, stage1Result, stage2Result);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
private async executeStage1(params: ExecuteAgentParams): Promise<ExecuteAgentResult> {
|
|
661
|
+
// Use base methods for configuration loading
|
|
662
|
+
const config = await this.loadAgentConfiguration(params.agent);
|
|
663
|
+
if (!config.success) {
|
|
664
|
+
return { nextStep: 'failed', errorMessage: config.errorMessage };
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Custom stage 1 logic...
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### Best Practices for Extending BaseAgent
|
|
673
|
+
|
|
674
|
+
1. **Always call super methods** when overriding unless completely replacing functionality
|
|
675
|
+
2. **Maintain the contract** - return the expected types from overridden methods
|
|
676
|
+
3. **Use protected methods** for extensibility rather than duplicating logic
|
|
677
|
+
4. **Document overrides** clearly in your subclass
|
|
678
|
+
5. **Test thoroughly** - ensure your overrides work with the recursion logic
|
|
679
|
+
6. **Handle errors gracefully** - follow the error result pattern
|
|
680
|
+
7. **Preserve metadata** - pass through rawResult and other metadata
|
|
681
|
+
|
|
682
|
+
### Common Extension Patterns
|
|
683
|
+
|
|
684
|
+
#### Adding Pre/Post Processing
|
|
685
|
+
```typescript
|
|
686
|
+
protected async executePrompt(promptParams: AIPromptParams): Promise<any> {
|
|
687
|
+
// Pre-processing
|
|
688
|
+
await this.beforePromptExecution(promptParams);
|
|
689
|
+
|
|
690
|
+
// Execute
|
|
691
|
+
const result = await super.executePrompt(promptParams);
|
|
692
|
+
|
|
693
|
+
// Post-processing
|
|
694
|
+
await this.afterPromptExecution(result);
|
|
695
|
+
|
|
696
|
+
return result;
|
|
697
|
+
}
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
#### Custom Context Injection
|
|
701
|
+
```typescript
|
|
702
|
+
protected async preparePromptParams(...args): Promise<AIPromptParams> {
|
|
703
|
+
const params = await super.preparePromptParams(...args);
|
|
704
|
+
|
|
705
|
+
// Inject custom context
|
|
706
|
+
params.data.customContext = await this.loadCustomContext();
|
|
707
|
+
params.conversationMessages = this.preprocessMessages(params.conversationMessages);
|
|
708
|
+
|
|
709
|
+
return params;
|
|
710
|
+
}
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
#### Conditional Execution Flow
|
|
714
|
+
```typescript
|
|
715
|
+
protected async processNextStep(
|
|
716
|
+
params: ExecuteAgentParams,
|
|
717
|
+
agentType: AIAgentTypeEntity,
|
|
718
|
+
promptResult: any
|
|
719
|
+
): Promise<ExecuteAgentResult> {
|
|
720
|
+
// Check for special conditions
|
|
721
|
+
if (this.shouldUseAlternativeFlow(promptResult)) {
|
|
722
|
+
return await this.executeAlternativeFlow(params, promptResult);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Otherwise use default flow
|
|
726
|
+
return await super.processNextStep(params, agentType, promptResult);
|
|
727
|
+
}
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
## Enhanced Execution Result Structure
|
|
731
|
+
|
|
732
|
+
The AI Agents framework now provides comprehensive execution tracking through the enhanced `ExecuteAgentResult` type. This structure gives complete visibility into every step of agent execution, including all prompts, actions, sub-agents, and decisions made along the way.
|
|
733
|
+
|
|
734
|
+
### ExecuteAgentResult
|
|
735
|
+
|
|
736
|
+
The main result structure returned from agent execution:
|
|
737
|
+
|
|
738
|
+
```typescript
|
|
739
|
+
interface ExecuteAgentResult {
|
|
740
|
+
// Core execution outcome
|
|
741
|
+
success: boolean; // Whether the overall execution was successful
|
|
742
|
+
finalStep: BaseAgentNextStep['step']; // The final step type that terminated execution
|
|
743
|
+
returnValue?: any; // Optional return value from the agent
|
|
744
|
+
errorMessage?: string; // Error message if execution failed
|
|
745
|
+
|
|
746
|
+
// Tracking and history
|
|
747
|
+
agentRun: AIAgentRunEntity; // Database entity tracking this execution
|
|
748
|
+
executionChain: ExecutionChainStep[]; // Complete chain of execution steps
|
|
749
|
+
}
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
### ExecutionChainStep
|
|
753
|
+
|
|
754
|
+
Each step in the execution chain captures:
|
|
755
|
+
|
|
756
|
+
```typescript
|
|
757
|
+
interface ExecutionChainStep {
|
|
758
|
+
stepEntity: AIAgentRunStepEntity; // Database entity for this step
|
|
759
|
+
executionType: 'prompt' | 'action' | 'sub-agent' | 'decision' | 'chat' | 'validation';
|
|
760
|
+
executionResult: StepExecutionResult; // The actual result (varies by type)
|
|
761
|
+
nextStepDecision: NextStepDecision; // What was decided after this step
|
|
762
|
+
startTime: Date; // When the step started
|
|
763
|
+
endTime?: Date; // When the step completed
|
|
764
|
+
durationMs?: number; // Execution duration in milliseconds
|
|
765
|
+
}
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
### Step Execution Results
|
|
769
|
+
|
|
770
|
+
Different execution types have specialized result structures:
|
|
771
|
+
|
|
772
|
+
#### PromptExecutionResult
|
|
773
|
+
```typescript
|
|
774
|
+
{
|
|
775
|
+
type: 'prompt';
|
|
776
|
+
promptId: string;
|
|
777
|
+
promptName: string;
|
|
778
|
+
result: AIPromptRunResult; // Native result from @memberjunction/ai-prompts
|
|
779
|
+
}
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
#### ActionExecutionResult
|
|
783
|
+
```typescript
|
|
784
|
+
{
|
|
785
|
+
type: 'action';
|
|
786
|
+
actionId: string;
|
|
787
|
+
actionName: string;
|
|
788
|
+
result: ActionResult | ActionResultSimple; // Native result from @memberjunction/actions
|
|
789
|
+
}
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
#### SubAgentExecutionResult
|
|
793
|
+
```typescript
|
|
794
|
+
{
|
|
795
|
+
type: 'sub-agent';
|
|
796
|
+
subAgentId: string;
|
|
797
|
+
subAgentName: string;
|
|
798
|
+
result: ExecuteAgentResult; // Recursive - full execution result of sub-agent
|
|
799
|
+
}
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
### Usage Example
|
|
803
|
+
|
|
804
|
+
```typescript
|
|
805
|
+
const runner = new AgentRunner();
|
|
806
|
+
const result = await runner.RunAgent({
|
|
807
|
+
agent: myAgent,
|
|
808
|
+
conversationMessages: messages,
|
|
809
|
+
contextUser: user
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
// Access execution outcome
|
|
813
|
+
console.log(`Success: ${result.success}`);
|
|
814
|
+
console.log(`Final step: ${result.finalStep}`);
|
|
815
|
+
console.log(`Return value:`, result.returnValue);
|
|
816
|
+
|
|
817
|
+
// Access the agent run record
|
|
818
|
+
console.log(`Agent run ID: ${result.agentRun.ID}`);
|
|
819
|
+
console.log(`Started at: ${result.agentRun.StartedAt}`);
|
|
820
|
+
console.log(`Duration: ${result.agentRun.CompletedAt - result.agentRun.StartedAt}ms`);
|
|
821
|
+
|
|
822
|
+
// Analyze the execution chain
|
|
823
|
+
result.executionChain.forEach((step, index) => {
|
|
824
|
+
console.log(`\nStep ${index + 1}: ${step.executionType}`);
|
|
825
|
+
console.log(` Name: ${step.stepEntity.StepName}`);
|
|
826
|
+
console.log(` Duration: ${step.durationMs}ms`);
|
|
827
|
+
console.log(` Success: ${step.stepEntity.Success}`);
|
|
828
|
+
|
|
829
|
+
// Access type-specific results
|
|
830
|
+
switch (step.executionResult.type) {
|
|
831
|
+
case 'prompt':
|
|
832
|
+
console.log(` Prompt: ${step.executionResult.promptName}`);
|
|
833
|
+
console.log(` Tokens used: ${step.executionResult.result.tokensUsed}`);
|
|
834
|
+
break;
|
|
835
|
+
case 'action':
|
|
836
|
+
console.log(` Action: ${step.executionResult.actionName}`);
|
|
837
|
+
console.log(` Result: ${step.executionResult.result.Success}`);
|
|
838
|
+
break;
|
|
839
|
+
case 'sub-agent':
|
|
840
|
+
console.log(` Sub-agent: ${step.executionResult.subAgentName}`);
|
|
841
|
+
console.log(` Sub-steps: ${step.executionResult.result.executionChain.length}`);
|
|
842
|
+
break;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Show what was decided next
|
|
846
|
+
console.log(` Next decision: ${step.nextStepDecision.decision}`);
|
|
847
|
+
console.log(` Reasoning: ${step.nextStepDecision.reasoning}`);
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
// Visualize the execution flow
|
|
851
|
+
const executionFlow = result.executionChain
|
|
852
|
+
.map(step => `${step.executionType} → ${step.nextStepDecision.decision}`)
|
|
853
|
+
.join(' → ');
|
|
854
|
+
console.log(`\nExecution flow: ${executionFlow}`);
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
### Database Persistence
|
|
858
|
+
|
|
859
|
+
All execution data is automatically persisted to the database:
|
|
860
|
+
|
|
861
|
+
- **AIAgentRun**: Tracks the overall agent execution
|
|
862
|
+
- Links to parent runs for sub-agent tracking
|
|
863
|
+
- Stores final results and state
|
|
864
|
+
- Tracks timing and success status
|
|
865
|
+
|
|
866
|
+
- **AIAgentRunStep**: Tracks individual execution steps
|
|
867
|
+
- Links to the parent run
|
|
868
|
+
- Stores step-specific data (input/output)
|
|
869
|
+
- Tracks step timing and success
|
|
870
|
+
|
|
871
|
+
This enables:
|
|
872
|
+
- Historical analysis of agent behavior
|
|
873
|
+
- Performance optimization based on real data
|
|
874
|
+
- Debugging complex agent interactions
|
|
875
|
+
- Compliance and audit trails
|
|
876
|
+
|
|
877
|
+
### Analyzing Sub-Agent Execution
|
|
878
|
+
|
|
879
|
+
Sub-agent results are fully recursive, allowing deep analysis:
|
|
880
|
+
|
|
881
|
+
```typescript
|
|
882
|
+
function analyzeExecutionDepth(result: ExecuteAgentResult, depth = 0): void {
|
|
883
|
+
const indent = ' '.repeat(depth);
|
|
884
|
+
console.log(`${indent}Agent: ${result.agentRun.AgentID}`);
|
|
885
|
+
console.log(`${indent}Steps: ${result.executionChain.length}`);
|
|
886
|
+
|
|
887
|
+
// Find sub-agent executions
|
|
888
|
+
const subAgentSteps = result.executionChain.filter(
|
|
889
|
+
step => step.executionType === 'sub-agent'
|
|
890
|
+
) as Array<{ executionResult: SubAgentExecutionResult }>;
|
|
891
|
+
|
|
892
|
+
// Recursively analyze sub-agents
|
|
893
|
+
for (const step of subAgentSteps) {
|
|
894
|
+
analyzeExecutionDepth(step.executionResult.result, depth + 1);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// Analyze the entire execution tree
|
|
899
|
+
analyzeExecutionDepth(result);
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
### Performance Analysis
|
|
903
|
+
|
|
904
|
+
Use the execution chain for performance optimization:
|
|
905
|
+
|
|
906
|
+
```typescript
|
|
907
|
+
// Calculate time spent in each type of operation
|
|
908
|
+
const timingAnalysis = result.executionChain.reduce((acc, step) => {
|
|
909
|
+
const type = step.executionType;
|
|
910
|
+
acc[type] = (acc[type] || 0) + (step.durationMs || 0);
|
|
911
|
+
return acc;
|
|
912
|
+
}, {} as Record<string, number>);
|
|
913
|
+
|
|
914
|
+
console.log('Time spent by operation type:', timingAnalysis);
|
|
915
|
+
|
|
916
|
+
// Find slowest steps
|
|
917
|
+
const slowestSteps = result.executionChain
|
|
918
|
+
.filter(step => step.durationMs)
|
|
919
|
+
.sort((a, b) => b.durationMs! - a.durationMs!)
|
|
920
|
+
.slice(0, 5);
|
|
921
|
+
|
|
922
|
+
console.log('Top 5 slowest steps:', slowestSteps.map(s => ({
|
|
923
|
+
name: s.stepEntity.StepName,
|
|
924
|
+
duration: s.durationMs,
|
|
925
|
+
type: s.executionType
|
|
926
|
+
})));
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
## Type Exports
|
|
930
|
+
|
|
931
|
+
The Agents package exports comprehensive types for agent operations:
|
|
932
|
+
|
|
933
|
+
### Core Agent Types
|
|
934
|
+
- `AgentExecutionParams` - Parameters for agent execution
|
|
935
|
+
- `AgentExecutionResult` - Result from agent execution
|
|
936
|
+
- `BaseAgentNextStep` - Next step decision structure
|
|
937
|
+
- `ExecutionChainStep` - Individual step in execution chain
|
|
938
|
+
|
|
939
|
+
### Agent Runner Types
|
|
940
|
+
- `AgentRunnerParams` - Parameters for AgentRunner
|
|
941
|
+
- `AgentRunnerResult` - Enhanced result with decision history
|
|
942
|
+
- `AgentProgressUpdate` - Progress tracking structure
|
|
943
|
+
- `AgentStreamingUpdate` - Streaming content structure
|
|
944
|
+
|
|
945
|
+
### Conductor Types
|
|
946
|
+
- `ConductorDecisionInput` - Input for conductor decisions
|
|
947
|
+
- `ConductorDecisionResponse` - Structured decision response
|
|
948
|
+
- `ExecutionStep` - Individual execution plan step
|
|
949
|
+
- `ConductorDecisionType` - Decision type enumeration
|
|
950
|
+
|
|
951
|
+
### Factory and Interface Types
|
|
952
|
+
- `IAgentFactory` - Factory interface for agent creation
|
|
953
|
+
- `BaseAgent` - Base class for all agents
|
|
954
|
+
- `ConductorAgent` - Specialized conductor agent class
|
|
955
|
+
|
|
956
|
+
## Import Examples
|
|
957
|
+
|
|
958
|
+
```typescript
|
|
959
|
+
// Import main classes
|
|
960
|
+
import { BaseAgent, ConductorAgent, AgentRunner } from '@memberjunction/ai-agents';
|
|
961
|
+
import { GetAgentFactory } from '@memberjunction/ai-agents';
|
|
962
|
+
|
|
963
|
+
// Import types
|
|
964
|
+
import {
|
|
965
|
+
AgentExecutionParams,
|
|
966
|
+
AgentExecutionResult,
|
|
967
|
+
AgentRunnerParams,
|
|
968
|
+
AgentRunnerResult,
|
|
969
|
+
ConductorDecisionResponse
|
|
970
|
+
} from '@memberjunction/ai-agents';
|
|
971
|
+
|
|
972
|
+
// Import base AI types from Core
|
|
973
|
+
import { ChatMessage, ChatResult } from '@memberjunction/ai';
|
|
974
|
+
|
|
975
|
+
// Import prompt types when needed
|
|
976
|
+
import { AIPromptParams, AIPromptRunResult } from '@memberjunction/ai-prompts';
|
|
977
|
+
|
|
978
|
+
// Import entity types
|
|
979
|
+
import { AIAgentEntity, AIAgentTypeEntity } from '@memberjunction/core-entities';
|
|
980
|
+
```
|
|
981
|
+
|
|
211
982
|
## API Reference
|
|
212
983
|
|
|
213
984
|
### AgentRunner Class
|
|
@@ -396,8 +1167,8 @@ await agentPrompt.Save();
|
|
|
396
1167
|
- `@memberjunction/core`: ^2.43.0 - MemberJunction core library
|
|
397
1168
|
- `@memberjunction/global`: ^2.43.0 - MemberJunction global utilities
|
|
398
1169
|
- `@memberjunction/core-entities`: ^2.43.0 - MemberJunction entity definitions
|
|
399
|
-
- `@memberjunction/ai`: ^2.43.0 - Base AI
|
|
400
|
-
- `@memberjunction/aiengine`: ^2.43.0 - AI model orchestration
|
|
1170
|
+
- `@memberjunction/ai`: ^2.43.0 - Base AI types and interfaces (imported for core types)
|
|
1171
|
+
- `@memberjunction/aiengine`: ^2.43.0 - AI model orchestration and agent type definitions
|
|
401
1172
|
- `@memberjunction/ai-prompts`: ^2.43.0 - Advanced prompt management
|
|
402
1173
|
- `@memberjunction/templates`: ^2.43.0 - Template rendering support
|
|
403
1174
|
- `rxjs`: ^7.8.1 - Reactive programming support
|