@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 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 functionality
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