tasq/node_modules/agentic-flow/dist/federation/debug/agent-debug-stream.js

475 lines
15 KiB
JavaScript

/**
* Single Agent Debug Streaming
*
* Provides detailed visibility into a single agent's operations,
* lifecycle, and internal state changes.
*
* Features:
* - Agent lifecycle tracking (spawn → work → shutdown)
* - Task execution tracing
* - Memory operations
* - Communication events
* - Decision logging
* - State transitions
* - Performance metrics
* - Timeline visualization
*/
import { EventEmitter } from 'events';
import { DebugLevel, createDebugStream } from './debug-stream.js';
// Re-export DebugLevel for convenience
export { DebugLevel } from './debug-stream.js';
export class AgentDebugStream extends EventEmitter {
config;
debug;
state;
decisions = [];
tasks = new Map();
communications = [];
timeline = [];
performanceMetrics = new Map();
constructor(config) {
super();
this.config = config;
// Initialize base debug stream
this.debug = createDebugStream({
level: config.level ?? DebugLevel.VERBOSE,
format: config.format === 'timeline' ? 'human' : config.format,
output: config.output ?? 'console',
outputFile: config.outputFile,
colorize: config.colorize ?? true,
});
// Initialize state
this.state = {
phase: 'spawning',
startTime: new Date().toISOString(),
metadata: {},
};
this.logAgentPhase('spawning', { agentId: config.agentId });
}
/**
* Log agent lifecycle phase change
*/
logAgentPhase(phase, data) {
const oldPhase = this.state.phase;
this.state.phase = phase;
this.state.lastActivity = new Date().toISOString();
this.debug.log({
level: DebugLevel.BASIC,
category: 'agent_lifecycle',
operation: `phase_${phase}`,
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: {
old_phase: oldPhase,
new_phase: phase,
...data,
},
});
if (this.config.timeline) {
this.timeline.push({
timestamp: new Date().toISOString(),
type: 'phase_change',
from: oldPhase,
to: phase,
data,
});
}
this.emit('phase_change', { from: oldPhase, to: phase, data });
}
/**
* Log agent initialization
*/
logInitialization(config) {
this.logAgentPhase('initializing', { config });
this.debug.log({
level: DebugLevel.DETAILED,
category: 'agent_lifecycle',
operation: 'initialize',
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: config,
});
}
/**
* Log agent ready
*/
logReady(capabilities) {
this.logAgentPhase('ready', { capabilities });
this.debug.log({
level: DebugLevel.BASIC,
category: 'agent_lifecycle',
operation: 'ready',
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: { capabilities },
});
}
/**
* Start tracking a task
*/
startTask(taskId, description, data) {
const task = {
taskId,
description,
startTime: new Date().toISOString(),
status: 'running',
steps: [],
};
this.tasks.set(taskId, task);
this.state.task = description;
this.state.taskId = taskId;
this.logAgentPhase('working', { taskId, description });
this.debug.log({
level: DebugLevel.VERBOSE,
category: 'task',
operation: 'task_start',
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: { taskId, description, ...data },
});
if (this.config.timeline) {
this.timeline.push({
timestamp: new Date().toISOString(),
type: 'task_start',
taskId,
description,
});
}
}
/**
* Log task step
*/
logTaskStep(taskId, step, operation, data) {
const task = this.tasks.get(taskId);
if (!task)
return;
const stepData = {
step,
operation,
startTime: new Date().toISOString(),
data,
};
task.steps.push(stepData);
this.debug.log({
level: DebugLevel.VERBOSE,
category: 'task_step',
operation,
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: {
taskId,
step,
operation,
...data,
},
});
}
/**
* Complete task step
*/
completeTaskStep(taskId, step, duration, data) {
const task = this.tasks.get(taskId);
if (!task || !task.steps[step])
return;
task.steps[step].endTime = new Date().toISOString();
task.steps[step].duration = duration;
task.steps[step].data = { ...task.steps[step].data, ...data };
this.debug.log({
level: DebugLevel.VERBOSE,
category: 'task_step',
operation: 'step_complete',
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: {
taskId,
step,
duration,
...data,
},
});
// Track performance
this.trackPerformance(`step_${task.steps[step].operation}`, duration);
}
/**
* Complete task
*/
completeTask(taskId, result) {
const task = this.tasks.get(taskId);
if (!task)
return;
task.endTime = new Date().toISOString();
task.status = 'completed';
task.result = result;
const duration = new Date(task.endTime).getTime() - new Date(task.startTime).getTime();
this.debug.log({
level: DebugLevel.VERBOSE,
category: 'task',
operation: 'task_complete',
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: {
taskId,
duration,
steps: task.steps.length,
result,
},
});
if (this.config.timeline) {
this.timeline.push({
timestamp: new Date().toISOString(),
type: 'task_complete',
taskId,
duration,
});
}
this.trackPerformance('task_completion', duration);
this.state.task = undefined;
this.state.taskId = undefined;
this.logAgentPhase('idle');
}
/**
* Fail task
*/
failTask(taskId, error) {
const task = this.tasks.get(taskId);
if (!task)
return;
task.endTime = new Date().toISOString();
task.status = 'failed';
task.error = error;
this.debug.log({
level: DebugLevel.BASIC,
category: 'task',
operation: 'task_failed',
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: {
taskId,
error: error.message,
},
error,
});
this.state.task = undefined;
this.state.taskId = undefined;
this.logAgentPhase('idle');
}
/**
* Log a decision
*/
logDecision(context, options, selected, reasoning, confidence) {
if (!this.config.trackDecisions)
return;
const decision = {
timestamp: new Date().toISOString(),
context,
options,
selected,
reasoning,
confidence,
};
this.decisions.push(decision);
this.debug.log({
level: DebugLevel.VERBOSE,
category: 'decision',
operation: 'decision_made',
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: {
context,
options_count: options.length,
selected,
reasoning,
confidence,
},
});
this.emit('decision', decision);
}
/**
* Log communication
*/
logCommunication(type, target, message) {
if (!this.config.trackCommunication)
return;
const comm = {
timestamp: new Date().toISOString(),
type,
target,
message,
};
this.communications.push(comm);
this.debug.log({
level: DebugLevel.VERBOSE,
category: 'communication',
operation: type === 'send' ? 'message_sent' : 'message_received',
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: {
target,
message_type: typeof message === 'object' ? message.type : 'unknown',
size: JSON.stringify(message).length,
},
});
this.emit('communication', comm);
}
/**
* Log memory operation
*/
logMemoryOperation(operation, data, duration) {
this.debug.logMemory(operation, this.config.agentId, this.config.tenantId, data, duration);
if (duration) {
this.trackPerformance(`memory_${operation}`, duration);
}
}
/**
* Log thought/reasoning
*/
logThought(thought, context) {
this.debug.log({
level: DebugLevel.TRACE,
category: 'reasoning',
operation: 'thought',
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: {
thought,
context,
},
});
}
/**
* Log agent shutdown
*/
logShutdown(reason) {
this.logAgentPhase('shutting_down', { reason });
const uptime = new Date().getTime() - new Date(this.state.startTime).getTime();
this.debug.log({
level: DebugLevel.BASIC,
category: 'agent_lifecycle',
operation: 'shutdown',
agentId: this.config.agentId,
tenantId: this.config.tenantId,
data: {
reason,
uptime_ms: uptime,
total_tasks: this.tasks.size,
total_decisions: this.decisions.length,
total_communications: this.communications.length,
},
});
// Print final summary
this.printSummary();
this.logAgentPhase('dead');
}
/**
* Track performance metric
*/
trackPerformance(operation, duration) {
if (!this.performanceMetrics.has(operation)) {
this.performanceMetrics.set(operation, []);
}
this.performanceMetrics.get(operation).push(duration);
}
/**
* Print agent summary
*/
printSummary() {
const uptime = new Date().getTime() - new Date(this.state.startTime).getTime();
console.log('\n' + '='.repeat(60));
console.log(`📊 Agent Summary: ${this.config.agentId}`);
console.log('='.repeat(60));
console.log('');
console.log(`Uptime: ${(uptime / 1000).toFixed(2)}s`);
console.log(`Tasks Completed: ${Array.from(this.tasks.values()).filter(t => t.status === 'completed').length}`);
console.log(`Tasks Failed: ${Array.from(this.tasks.values()).filter(t => t.status === 'failed').length}`);
console.log(`Decisions Made: ${this.decisions.length}`);
console.log(`Messages Sent: ${this.communications.filter(c => c.type === 'send').length}`);
console.log(`Messages Recv: ${this.communications.filter(c => c.type === 'receive').length}`);
console.log('');
// Performance metrics
if (this.performanceMetrics.size > 0) {
console.log('Performance Metrics:');
console.log('-'.repeat(60));
for (const [operation, durations] of this.performanceMetrics.entries()) {
const avg = durations.reduce((a, b) => a + b, 0) / durations.length;
const min = Math.min(...durations);
const max = Math.max(...durations);
console.log(` ${operation.padEnd(30)} ${durations.length}x avg: ${avg.toFixed(1)}ms min: ${min.toFixed(1)}ms max: ${max.toFixed(1)}ms`);
}
console.log('');
}
console.log('='.repeat(60) + '\n');
}
/**
* Print timeline
*/
printTimeline() {
if (!this.config.timeline || this.timeline.length === 0)
return;
console.log('\n' + '='.repeat(60));
console.log('📅 Agent Timeline');
console.log('='.repeat(60) + '\n');
const startTime = new Date(this.timeline[0].timestamp).getTime();
for (const event of this.timeline) {
const elapsed = new Date(event.timestamp).getTime() - startTime;
const time = `+${(elapsed / 1000).toFixed(3)}s`;
console.log(`${time.padStart(10)} | ${event.type.padEnd(20)} | ${JSON.stringify(event.data || event)}`);
}
console.log('\n' + '='.repeat(60) + '\n');
}
/**
* Get current state
*/
getState() {
return { ...this.state };
}
/**
* Get task history
*/
getTasks() {
return Array.from(this.tasks.values());
}
/**
* Get decisions
*/
getDecisions() {
return [...this.decisions];
}
/**
* Get communications
*/
getCommunications() {
return [...this.communications];
}
/**
* Close debug stream
*/
close() {
this.debug.close();
}
}
/**
* Create agent debug stream
*/
export function createAgentDebugStream(config) {
return new AgentDebugStream(config);
}
/**
* Create from environment variables
*/
export function createAgentDebugStreamFromEnv(agentId, tenantId) {
const debugLevel = process.env.DEBUG_LEVEL?.toUpperCase() || 'VERBOSE';
return new AgentDebugStream({
agentId,
tenantId: tenantId || process.env.FEDERATION_TENANT_ID,
level: DebugLevel[debugLevel] || DebugLevel.VERBOSE,
format: process.env.DEBUG_FORMAT || 'human',
output: process.env.DEBUG_OUTPUT || 'console',
outputFile: process.env.DEBUG_OUTPUT_FILE,
colorize: process.env.DEBUG_COLORIZE !== 'false',
trackState: process.env.DEBUG_TRACK_STATE !== 'false',
trackDecisions: process.env.DEBUG_TRACK_DECISIONS !== 'false',
trackCommunication: process.env.DEBUG_TRACK_COMMUNICATION !== 'false',
timeline: process.env.DEBUG_TIMELINE === 'true',
});
}
//# sourceMappingURL=agent-debug-stream.js.map