agentic-flow 1.8.11 → 1.8.13
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/dist/cli/federation-cli.d.ts +53 -0
- package/dist/cli/federation-cli.js +431 -0
- package/dist/cli-proxy.js +28 -1
- package/dist/federation/EphemeralAgent.js +258 -0
- package/dist/federation/FederationHub.js +283 -0
- package/dist/federation/FederationHubClient.js +212 -0
- package/dist/federation/FederationHubServer.js +436 -0
- package/dist/federation/SecurityManager.js +191 -0
- package/dist/federation/debug/agent-debug-stream.js +474 -0
- package/dist/federation/debug/debug-stream.js +419 -0
- package/dist/federation/index.js +12 -0
- package/dist/federation/integrations/realtime-federation.js +404 -0
- package/dist/federation/integrations/supabase-adapter-debug.js +400 -0
- package/dist/federation/integrations/supabase-adapter.js +258 -0
- package/dist/utils/cli.js +5 -0
- package/docs/architecture/FEDERATION-DATA-LIFECYCLE.md +520 -0
- package/docs/federation/AGENT-DEBUG-STREAMING.md +403 -0
- package/docs/federation/DEBUG-STREAMING-COMPLETE.md +432 -0
- package/docs/federation/DEBUG-STREAMING.md +537 -0
- package/docs/federation/DEPLOYMENT-VALIDATION-SUCCESS.md +394 -0
- package/docs/federation/DOCKER-FEDERATION-DEEP-REVIEW.md +478 -0
- package/docs/issues/ISSUE-SUPABASE-INTEGRATION.md +536 -0
- package/docs/supabase/IMPLEMENTATION-SUMMARY.md +498 -0
- package/docs/supabase/INDEX.md +358 -0
- package/docs/supabase/QUICKSTART.md +365 -0
- package/docs/supabase/README.md +318 -0
- package/docs/supabase/SUPABASE-REALTIME-FEDERATION.md +575 -0
- package/docs/supabase/TEST-REPORT.md +446 -0
- package/docs/supabase/migrations/001_create_federation_tables.sql +339 -0
- package/docs/validation/reports/REGRESSION-TEST-V1.8.11.md +456 -0
- package/package.json +4 -1
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Manager - Authentication, encryption, and access control
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - JWT token generation and validation
|
|
6
|
+
* - AES-256 encryption for data at rest
|
|
7
|
+
* - Tenant isolation
|
|
8
|
+
* - mTLS certificate management
|
|
9
|
+
*/
|
|
10
|
+
import crypto from 'crypto';
|
|
11
|
+
import { logger } from '../utils/logger.js';
|
|
12
|
+
export class SecurityManager {
|
|
13
|
+
algorithm = 'aes-256-gcm';
|
|
14
|
+
jwtSecret;
|
|
15
|
+
encryptionCache = new Map();
|
|
16
|
+
constructor() {
|
|
17
|
+
// In production, load from secure vault (AWS Secrets Manager, HashiCorp Vault, etc.)
|
|
18
|
+
this.jwtSecret = process.env.JWT_SECRET || crypto.randomBytes(32).toString('hex');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Create JWT token for agent authentication
|
|
22
|
+
*/
|
|
23
|
+
async createAgentToken(payload) {
|
|
24
|
+
const header = {
|
|
25
|
+
alg: 'HS256',
|
|
26
|
+
typ: 'JWT'
|
|
27
|
+
};
|
|
28
|
+
const now = Date.now();
|
|
29
|
+
const tokenPayload = {
|
|
30
|
+
...payload,
|
|
31
|
+
iat: now,
|
|
32
|
+
exp: payload.expiresAt,
|
|
33
|
+
iss: 'agentic-flow-federation'
|
|
34
|
+
};
|
|
35
|
+
// Encode header and payload
|
|
36
|
+
const encodedHeader = this.base64UrlEncode(JSON.stringify(header));
|
|
37
|
+
const encodedPayload = this.base64UrlEncode(JSON.stringify(tokenPayload));
|
|
38
|
+
// Create signature
|
|
39
|
+
const signature = crypto
|
|
40
|
+
.createHmac('sha256', this.jwtSecret)
|
|
41
|
+
.update(`${encodedHeader}.${encodedPayload}`)
|
|
42
|
+
.digest('base64url');
|
|
43
|
+
const token = `${encodedHeader}.${encodedPayload}.${signature}`;
|
|
44
|
+
logger.info('Created agent token', {
|
|
45
|
+
agentId: payload.agentId,
|
|
46
|
+
tenantId: payload.tenantId,
|
|
47
|
+
expiresAt: new Date(payload.expiresAt).toISOString()
|
|
48
|
+
});
|
|
49
|
+
return token;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Verify JWT token
|
|
53
|
+
*/
|
|
54
|
+
async verifyAgentToken(token) {
|
|
55
|
+
const parts = token.split('.');
|
|
56
|
+
if (parts.length !== 3) {
|
|
57
|
+
throw new Error('Invalid token format');
|
|
58
|
+
}
|
|
59
|
+
const [encodedHeader, encodedPayload, signature] = parts;
|
|
60
|
+
// Verify signature
|
|
61
|
+
const expectedSignature = crypto
|
|
62
|
+
.createHmac('sha256', this.jwtSecret)
|
|
63
|
+
.update(`${encodedHeader}.${encodedPayload}`)
|
|
64
|
+
.digest('base64url');
|
|
65
|
+
if (signature !== expectedSignature) {
|
|
66
|
+
throw new Error('Invalid token signature');
|
|
67
|
+
}
|
|
68
|
+
// Decode payload
|
|
69
|
+
const payload = JSON.parse(this.base64UrlDecode(encodedPayload));
|
|
70
|
+
// Check expiration
|
|
71
|
+
if (Date.now() >= payload.exp) {
|
|
72
|
+
throw new Error('Token expired');
|
|
73
|
+
}
|
|
74
|
+
logger.debug('Token verified', {
|
|
75
|
+
agentId: payload.agentId,
|
|
76
|
+
tenantId: payload.tenantId
|
|
77
|
+
});
|
|
78
|
+
return payload;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get or create encryption keys for a tenant
|
|
82
|
+
*/
|
|
83
|
+
async getEncryptionKeys(tenantId) {
|
|
84
|
+
// Check cache
|
|
85
|
+
if (this.encryptionCache.has(tenantId)) {
|
|
86
|
+
return this.encryptionCache.get(tenantId);
|
|
87
|
+
}
|
|
88
|
+
// Generate new keys for tenant
|
|
89
|
+
// In production, these would be stored in a secure key management service
|
|
90
|
+
const encryptionKey = crypto.randomBytes(32); // 256-bit key
|
|
91
|
+
const iv = crypto.randomBytes(16); // 128-bit IV
|
|
92
|
+
const keys = { encryptionKey, iv };
|
|
93
|
+
// Cache keys
|
|
94
|
+
this.encryptionCache.set(tenantId, keys);
|
|
95
|
+
logger.info('Generated encryption keys for tenant', { tenantId });
|
|
96
|
+
return keys;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Encrypt data with AES-256-GCM
|
|
100
|
+
*/
|
|
101
|
+
async encrypt(data, tenantId) {
|
|
102
|
+
const keys = await this.getEncryptionKeys(tenantId);
|
|
103
|
+
const cipher = crypto.createCipheriv(this.algorithm, keys.encryptionKey, keys.iv);
|
|
104
|
+
let encrypted = cipher.update(data, 'utf8', 'base64');
|
|
105
|
+
encrypted += cipher.final('base64');
|
|
106
|
+
const authTag = cipher.getAuthTag().toString('base64');
|
|
107
|
+
logger.debug('Data encrypted', {
|
|
108
|
+
tenantId,
|
|
109
|
+
originalLength: data.length,
|
|
110
|
+
encryptedLength: encrypted.length
|
|
111
|
+
});
|
|
112
|
+
return { encrypted, authTag };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Decrypt data with AES-256-GCM
|
|
116
|
+
*/
|
|
117
|
+
async decrypt(encrypted, authTag, tenantId) {
|
|
118
|
+
const keys = await this.getEncryptionKeys(tenantId);
|
|
119
|
+
const decipher = crypto.createDecipheriv(this.algorithm, keys.encryptionKey, keys.iv);
|
|
120
|
+
decipher.setAuthTag(Buffer.from(authTag, 'base64'));
|
|
121
|
+
let decrypted = decipher.update(encrypted, 'base64', 'utf8');
|
|
122
|
+
decrypted += decipher.final('utf8');
|
|
123
|
+
logger.debug('Data decrypted', {
|
|
124
|
+
tenantId,
|
|
125
|
+
decryptedLength: decrypted.length
|
|
126
|
+
});
|
|
127
|
+
return decrypted;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Generate mTLS certificates for agent-to-hub communication
|
|
131
|
+
*/
|
|
132
|
+
async generateMTLSCertificates(agentId) {
|
|
133
|
+
// Placeholder: Actual implementation would use OpenSSL or similar
|
|
134
|
+
// to generate X.509 certificates with proper CA chain
|
|
135
|
+
logger.info('Generating mTLS certificates', { agentId });
|
|
136
|
+
return {
|
|
137
|
+
cert: 'PLACEHOLDER_CERT',
|
|
138
|
+
key: 'PLACEHOLDER_KEY',
|
|
139
|
+
ca: 'PLACEHOLDER_CA'
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Validate tenant access to data
|
|
144
|
+
*/
|
|
145
|
+
validateTenantAccess(requestTenantId, dataTenantId) {
|
|
146
|
+
if (requestTenantId !== dataTenantId) {
|
|
147
|
+
logger.warn('Tenant access violation detected', {
|
|
148
|
+
requestTenantId,
|
|
149
|
+
dataTenantId
|
|
150
|
+
});
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Hash sensitive data for storage (one-way)
|
|
157
|
+
*/
|
|
158
|
+
hashData(data) {
|
|
159
|
+
return crypto.createHash('sha256').update(data).digest('hex');
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Generate secure random ID
|
|
163
|
+
*/
|
|
164
|
+
generateSecureId() {
|
|
165
|
+
return crypto.randomBytes(16).toString('hex');
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Base64 URL-safe encoding
|
|
169
|
+
*/
|
|
170
|
+
base64UrlEncode(str) {
|
|
171
|
+
return Buffer.from(str)
|
|
172
|
+
.toString('base64')
|
|
173
|
+
.replace(/\+/g, '-')
|
|
174
|
+
.replace(/\//g, '_')
|
|
175
|
+
.replace(/=/g, '');
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Base64 URL-safe decoding
|
|
179
|
+
*/
|
|
180
|
+
base64UrlDecode(str) {
|
|
181
|
+
const base64 = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
182
|
+
return Buffer.from(base64, 'base64').toString('utf8');
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Clear cached keys (for testing or security refresh)
|
|
186
|
+
*/
|
|
187
|
+
clearCache() {
|
|
188
|
+
this.encryptionCache.clear();
|
|
189
|
+
logger.info('Encryption cache cleared');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single Agent Debug Streaming
|
|
3
|
+
*
|
|
4
|
+
* Provides detailed visibility into a single agent's operations,
|
|
5
|
+
* lifecycle, and internal state changes.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Agent lifecycle tracking (spawn → work → shutdown)
|
|
9
|
+
* - Task execution tracing
|
|
10
|
+
* - Memory operations
|
|
11
|
+
* - Communication events
|
|
12
|
+
* - Decision logging
|
|
13
|
+
* - State transitions
|
|
14
|
+
* - Performance metrics
|
|
15
|
+
* - Timeline visualization
|
|
16
|
+
*/
|
|
17
|
+
import { EventEmitter } from 'events';
|
|
18
|
+
import { DebugLevel, createDebugStream } from './debug-stream.js';
|
|
19
|
+
// Re-export DebugLevel for convenience
|
|
20
|
+
export { DebugLevel } from './debug-stream.js';
|
|
21
|
+
export class AgentDebugStream extends EventEmitter {
|
|
22
|
+
config;
|
|
23
|
+
debug;
|
|
24
|
+
state;
|
|
25
|
+
decisions = [];
|
|
26
|
+
tasks = new Map();
|
|
27
|
+
communications = [];
|
|
28
|
+
timeline = [];
|
|
29
|
+
performanceMetrics = new Map();
|
|
30
|
+
constructor(config) {
|
|
31
|
+
super();
|
|
32
|
+
this.config = config;
|
|
33
|
+
// Initialize base debug stream
|
|
34
|
+
this.debug = createDebugStream({
|
|
35
|
+
level: config.level ?? DebugLevel.VERBOSE,
|
|
36
|
+
format: config.format === 'timeline' ? 'human' : config.format,
|
|
37
|
+
output: config.output ?? 'console',
|
|
38
|
+
outputFile: config.outputFile,
|
|
39
|
+
colorize: config.colorize ?? true,
|
|
40
|
+
});
|
|
41
|
+
// Initialize state
|
|
42
|
+
this.state = {
|
|
43
|
+
phase: 'spawning',
|
|
44
|
+
startTime: new Date().toISOString(),
|
|
45
|
+
metadata: {},
|
|
46
|
+
};
|
|
47
|
+
this.logAgentPhase('spawning', { agentId: config.agentId });
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Log agent lifecycle phase change
|
|
51
|
+
*/
|
|
52
|
+
logAgentPhase(phase, data) {
|
|
53
|
+
const oldPhase = this.state.phase;
|
|
54
|
+
this.state.phase = phase;
|
|
55
|
+
this.state.lastActivity = new Date().toISOString();
|
|
56
|
+
this.debug.log({
|
|
57
|
+
level: DebugLevel.BASIC,
|
|
58
|
+
category: 'agent_lifecycle',
|
|
59
|
+
operation: `phase_${phase}`,
|
|
60
|
+
agentId: this.config.agentId,
|
|
61
|
+
tenantId: this.config.tenantId,
|
|
62
|
+
data: {
|
|
63
|
+
old_phase: oldPhase,
|
|
64
|
+
new_phase: phase,
|
|
65
|
+
...data,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
if (this.config.timeline) {
|
|
69
|
+
this.timeline.push({
|
|
70
|
+
timestamp: new Date().toISOString(),
|
|
71
|
+
type: 'phase_change',
|
|
72
|
+
from: oldPhase,
|
|
73
|
+
to: phase,
|
|
74
|
+
data,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
this.emit('phase_change', { from: oldPhase, to: phase, data });
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Log agent initialization
|
|
81
|
+
*/
|
|
82
|
+
logInitialization(config) {
|
|
83
|
+
this.logAgentPhase('initializing', { config });
|
|
84
|
+
this.debug.log({
|
|
85
|
+
level: DebugLevel.DETAILED,
|
|
86
|
+
category: 'agent_lifecycle',
|
|
87
|
+
operation: 'initialize',
|
|
88
|
+
agentId: this.config.agentId,
|
|
89
|
+
tenantId: this.config.tenantId,
|
|
90
|
+
data: config,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Log agent ready
|
|
95
|
+
*/
|
|
96
|
+
logReady(capabilities) {
|
|
97
|
+
this.logAgentPhase('ready', { capabilities });
|
|
98
|
+
this.debug.log({
|
|
99
|
+
level: DebugLevel.BASIC,
|
|
100
|
+
category: 'agent_lifecycle',
|
|
101
|
+
operation: 'ready',
|
|
102
|
+
agentId: this.config.agentId,
|
|
103
|
+
tenantId: this.config.tenantId,
|
|
104
|
+
data: { capabilities },
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Start tracking a task
|
|
109
|
+
*/
|
|
110
|
+
startTask(taskId, description, data) {
|
|
111
|
+
const task = {
|
|
112
|
+
taskId,
|
|
113
|
+
description,
|
|
114
|
+
startTime: new Date().toISOString(),
|
|
115
|
+
status: 'running',
|
|
116
|
+
steps: [],
|
|
117
|
+
};
|
|
118
|
+
this.tasks.set(taskId, task);
|
|
119
|
+
this.state.task = description;
|
|
120
|
+
this.state.taskId = taskId;
|
|
121
|
+
this.logAgentPhase('working', { taskId, description });
|
|
122
|
+
this.debug.log({
|
|
123
|
+
level: DebugLevel.VERBOSE,
|
|
124
|
+
category: 'task',
|
|
125
|
+
operation: 'task_start',
|
|
126
|
+
agentId: this.config.agentId,
|
|
127
|
+
tenantId: this.config.tenantId,
|
|
128
|
+
data: { taskId, description, ...data },
|
|
129
|
+
});
|
|
130
|
+
if (this.config.timeline) {
|
|
131
|
+
this.timeline.push({
|
|
132
|
+
timestamp: new Date().toISOString(),
|
|
133
|
+
type: 'task_start',
|
|
134
|
+
taskId,
|
|
135
|
+
description,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Log task step
|
|
141
|
+
*/
|
|
142
|
+
logTaskStep(taskId, step, operation, data) {
|
|
143
|
+
const task = this.tasks.get(taskId);
|
|
144
|
+
if (!task)
|
|
145
|
+
return;
|
|
146
|
+
const stepData = {
|
|
147
|
+
step,
|
|
148
|
+
operation,
|
|
149
|
+
startTime: new Date().toISOString(),
|
|
150
|
+
data,
|
|
151
|
+
};
|
|
152
|
+
task.steps.push(stepData);
|
|
153
|
+
this.debug.log({
|
|
154
|
+
level: DebugLevel.VERBOSE,
|
|
155
|
+
category: 'task_step',
|
|
156
|
+
operation,
|
|
157
|
+
agentId: this.config.agentId,
|
|
158
|
+
tenantId: this.config.tenantId,
|
|
159
|
+
data: {
|
|
160
|
+
taskId,
|
|
161
|
+
step,
|
|
162
|
+
operation,
|
|
163
|
+
...data,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Complete task step
|
|
169
|
+
*/
|
|
170
|
+
completeTaskStep(taskId, step, duration, data) {
|
|
171
|
+
const task = this.tasks.get(taskId);
|
|
172
|
+
if (!task || !task.steps[step])
|
|
173
|
+
return;
|
|
174
|
+
task.steps[step].endTime = new Date().toISOString();
|
|
175
|
+
task.steps[step].duration = duration;
|
|
176
|
+
task.steps[step].data = { ...task.steps[step].data, ...data };
|
|
177
|
+
this.debug.log({
|
|
178
|
+
level: DebugLevel.VERBOSE,
|
|
179
|
+
category: 'task_step',
|
|
180
|
+
operation: 'step_complete',
|
|
181
|
+
agentId: this.config.agentId,
|
|
182
|
+
tenantId: this.config.tenantId,
|
|
183
|
+
data: {
|
|
184
|
+
taskId,
|
|
185
|
+
step,
|
|
186
|
+
duration,
|
|
187
|
+
...data,
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
// Track performance
|
|
191
|
+
this.trackPerformance(`step_${task.steps[step].operation}`, duration);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Complete task
|
|
195
|
+
*/
|
|
196
|
+
completeTask(taskId, result) {
|
|
197
|
+
const task = this.tasks.get(taskId);
|
|
198
|
+
if (!task)
|
|
199
|
+
return;
|
|
200
|
+
task.endTime = new Date().toISOString();
|
|
201
|
+
task.status = 'completed';
|
|
202
|
+
task.result = result;
|
|
203
|
+
const duration = new Date(task.endTime).getTime() - new Date(task.startTime).getTime();
|
|
204
|
+
this.debug.log({
|
|
205
|
+
level: DebugLevel.VERBOSE,
|
|
206
|
+
category: 'task',
|
|
207
|
+
operation: 'task_complete',
|
|
208
|
+
agentId: this.config.agentId,
|
|
209
|
+
tenantId: this.config.tenantId,
|
|
210
|
+
data: {
|
|
211
|
+
taskId,
|
|
212
|
+
duration,
|
|
213
|
+
steps: task.steps.length,
|
|
214
|
+
result,
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
if (this.config.timeline) {
|
|
218
|
+
this.timeline.push({
|
|
219
|
+
timestamp: new Date().toISOString(),
|
|
220
|
+
type: 'task_complete',
|
|
221
|
+
taskId,
|
|
222
|
+
duration,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
this.trackPerformance('task_completion', duration);
|
|
226
|
+
this.state.task = undefined;
|
|
227
|
+
this.state.taskId = undefined;
|
|
228
|
+
this.logAgentPhase('idle');
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Fail task
|
|
232
|
+
*/
|
|
233
|
+
failTask(taskId, error) {
|
|
234
|
+
const task = this.tasks.get(taskId);
|
|
235
|
+
if (!task)
|
|
236
|
+
return;
|
|
237
|
+
task.endTime = new Date().toISOString();
|
|
238
|
+
task.status = 'failed';
|
|
239
|
+
task.error = error;
|
|
240
|
+
this.debug.log({
|
|
241
|
+
level: DebugLevel.BASIC,
|
|
242
|
+
category: 'task',
|
|
243
|
+
operation: 'task_failed',
|
|
244
|
+
agentId: this.config.agentId,
|
|
245
|
+
tenantId: this.config.tenantId,
|
|
246
|
+
data: {
|
|
247
|
+
taskId,
|
|
248
|
+
error: error.message,
|
|
249
|
+
},
|
|
250
|
+
error,
|
|
251
|
+
});
|
|
252
|
+
this.state.task = undefined;
|
|
253
|
+
this.state.taskId = undefined;
|
|
254
|
+
this.logAgentPhase('idle');
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Log a decision
|
|
258
|
+
*/
|
|
259
|
+
logDecision(context, options, selected, reasoning, confidence) {
|
|
260
|
+
if (!this.config.trackDecisions)
|
|
261
|
+
return;
|
|
262
|
+
const decision = {
|
|
263
|
+
timestamp: new Date().toISOString(),
|
|
264
|
+
context,
|
|
265
|
+
options,
|
|
266
|
+
selected,
|
|
267
|
+
reasoning,
|
|
268
|
+
confidence,
|
|
269
|
+
};
|
|
270
|
+
this.decisions.push(decision);
|
|
271
|
+
this.debug.log({
|
|
272
|
+
level: DebugLevel.VERBOSE,
|
|
273
|
+
category: 'decision',
|
|
274
|
+
operation: 'decision_made',
|
|
275
|
+
agentId: this.config.agentId,
|
|
276
|
+
tenantId: this.config.tenantId,
|
|
277
|
+
data: {
|
|
278
|
+
context,
|
|
279
|
+
options_count: options.length,
|
|
280
|
+
selected,
|
|
281
|
+
reasoning,
|
|
282
|
+
confidence,
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
this.emit('decision', decision);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Log communication
|
|
289
|
+
*/
|
|
290
|
+
logCommunication(type, target, message) {
|
|
291
|
+
if (!this.config.trackCommunication)
|
|
292
|
+
return;
|
|
293
|
+
const comm = {
|
|
294
|
+
timestamp: new Date().toISOString(),
|
|
295
|
+
type,
|
|
296
|
+
target,
|
|
297
|
+
message,
|
|
298
|
+
};
|
|
299
|
+
this.communications.push(comm);
|
|
300
|
+
this.debug.log({
|
|
301
|
+
level: DebugLevel.VERBOSE,
|
|
302
|
+
category: 'communication',
|
|
303
|
+
operation: type === 'send' ? 'message_sent' : 'message_received',
|
|
304
|
+
agentId: this.config.agentId,
|
|
305
|
+
tenantId: this.config.tenantId,
|
|
306
|
+
data: {
|
|
307
|
+
target,
|
|
308
|
+
message_type: typeof message === 'object' ? message.type : 'unknown',
|
|
309
|
+
size: JSON.stringify(message).length,
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
this.emit('communication', comm);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Log memory operation
|
|
316
|
+
*/
|
|
317
|
+
logMemoryOperation(operation, data, duration) {
|
|
318
|
+
this.debug.logMemory(operation, this.config.agentId, this.config.tenantId, data, duration);
|
|
319
|
+
if (duration) {
|
|
320
|
+
this.trackPerformance(`memory_${operation}`, duration);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Log thought/reasoning
|
|
325
|
+
*/
|
|
326
|
+
logThought(thought, context) {
|
|
327
|
+
this.debug.log({
|
|
328
|
+
level: DebugLevel.TRACE,
|
|
329
|
+
category: 'reasoning',
|
|
330
|
+
operation: 'thought',
|
|
331
|
+
agentId: this.config.agentId,
|
|
332
|
+
tenantId: this.config.tenantId,
|
|
333
|
+
data: {
|
|
334
|
+
thought,
|
|
335
|
+
context,
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Log agent shutdown
|
|
341
|
+
*/
|
|
342
|
+
logShutdown(reason) {
|
|
343
|
+
this.logAgentPhase('shutting_down', { reason });
|
|
344
|
+
const uptime = new Date().getTime() - new Date(this.state.startTime).getTime();
|
|
345
|
+
this.debug.log({
|
|
346
|
+
level: DebugLevel.BASIC,
|
|
347
|
+
category: 'agent_lifecycle',
|
|
348
|
+
operation: 'shutdown',
|
|
349
|
+
agentId: this.config.agentId,
|
|
350
|
+
tenantId: this.config.tenantId,
|
|
351
|
+
data: {
|
|
352
|
+
reason,
|
|
353
|
+
uptime_ms: uptime,
|
|
354
|
+
total_tasks: this.tasks.size,
|
|
355
|
+
total_decisions: this.decisions.length,
|
|
356
|
+
total_communications: this.communications.length,
|
|
357
|
+
},
|
|
358
|
+
});
|
|
359
|
+
// Print final summary
|
|
360
|
+
this.printSummary();
|
|
361
|
+
this.logAgentPhase('dead');
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Track performance metric
|
|
365
|
+
*/
|
|
366
|
+
trackPerformance(operation, duration) {
|
|
367
|
+
if (!this.performanceMetrics.has(operation)) {
|
|
368
|
+
this.performanceMetrics.set(operation, []);
|
|
369
|
+
}
|
|
370
|
+
this.performanceMetrics.get(operation).push(duration);
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Print agent summary
|
|
374
|
+
*/
|
|
375
|
+
printSummary() {
|
|
376
|
+
const uptime = new Date().getTime() - new Date(this.state.startTime).getTime();
|
|
377
|
+
console.log('\n' + '='.repeat(60));
|
|
378
|
+
console.log(`📊 Agent Summary: ${this.config.agentId}`);
|
|
379
|
+
console.log('='.repeat(60));
|
|
380
|
+
console.log('');
|
|
381
|
+
console.log(`Uptime: ${(uptime / 1000).toFixed(2)}s`);
|
|
382
|
+
console.log(`Tasks Completed: ${Array.from(this.tasks.values()).filter(t => t.status === 'completed').length}`);
|
|
383
|
+
console.log(`Tasks Failed: ${Array.from(this.tasks.values()).filter(t => t.status === 'failed').length}`);
|
|
384
|
+
console.log(`Decisions Made: ${this.decisions.length}`);
|
|
385
|
+
console.log(`Messages Sent: ${this.communications.filter(c => c.type === 'send').length}`);
|
|
386
|
+
console.log(`Messages Recv: ${this.communications.filter(c => c.type === 'receive').length}`);
|
|
387
|
+
console.log('');
|
|
388
|
+
// Performance metrics
|
|
389
|
+
if (this.performanceMetrics.size > 0) {
|
|
390
|
+
console.log('Performance Metrics:');
|
|
391
|
+
console.log('-'.repeat(60));
|
|
392
|
+
for (const [operation, durations] of this.performanceMetrics.entries()) {
|
|
393
|
+
const avg = durations.reduce((a, b) => a + b, 0) / durations.length;
|
|
394
|
+
const min = Math.min(...durations);
|
|
395
|
+
const max = Math.max(...durations);
|
|
396
|
+
console.log(` ${operation.padEnd(30)} ${durations.length}x avg: ${avg.toFixed(1)}ms min: ${min.toFixed(1)}ms max: ${max.toFixed(1)}ms`);
|
|
397
|
+
}
|
|
398
|
+
console.log('');
|
|
399
|
+
}
|
|
400
|
+
console.log('='.repeat(60) + '\n');
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Print timeline
|
|
404
|
+
*/
|
|
405
|
+
printTimeline() {
|
|
406
|
+
if (!this.config.timeline || this.timeline.length === 0)
|
|
407
|
+
return;
|
|
408
|
+
console.log('\n' + '='.repeat(60));
|
|
409
|
+
console.log('📅 Agent Timeline');
|
|
410
|
+
console.log('='.repeat(60) + '\n');
|
|
411
|
+
const startTime = new Date(this.timeline[0].timestamp).getTime();
|
|
412
|
+
for (const event of this.timeline) {
|
|
413
|
+
const elapsed = new Date(event.timestamp).getTime() - startTime;
|
|
414
|
+
const time = `+${(elapsed / 1000).toFixed(3)}s`;
|
|
415
|
+
console.log(`${time.padStart(10)} | ${event.type.padEnd(20)} | ${JSON.stringify(event.data || event)}`);
|
|
416
|
+
}
|
|
417
|
+
console.log('\n' + '='.repeat(60) + '\n');
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Get current state
|
|
421
|
+
*/
|
|
422
|
+
getState() {
|
|
423
|
+
return { ...this.state };
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Get task history
|
|
427
|
+
*/
|
|
428
|
+
getTasks() {
|
|
429
|
+
return Array.from(this.tasks.values());
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Get decisions
|
|
433
|
+
*/
|
|
434
|
+
getDecisions() {
|
|
435
|
+
return [...this.decisions];
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Get communications
|
|
439
|
+
*/
|
|
440
|
+
getCommunications() {
|
|
441
|
+
return [...this.communications];
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Close debug stream
|
|
445
|
+
*/
|
|
446
|
+
close() {
|
|
447
|
+
this.debug.close();
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Create agent debug stream
|
|
452
|
+
*/
|
|
453
|
+
export function createAgentDebugStream(config) {
|
|
454
|
+
return new AgentDebugStream(config);
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Create from environment variables
|
|
458
|
+
*/
|
|
459
|
+
export function createAgentDebugStreamFromEnv(agentId, tenantId) {
|
|
460
|
+
const debugLevel = process.env.DEBUG_LEVEL?.toUpperCase() || 'VERBOSE';
|
|
461
|
+
return new AgentDebugStream({
|
|
462
|
+
agentId,
|
|
463
|
+
tenantId: tenantId || process.env.FEDERATION_TENANT_ID,
|
|
464
|
+
level: DebugLevel[debugLevel] || DebugLevel.VERBOSE,
|
|
465
|
+
format: process.env.DEBUG_FORMAT || 'human',
|
|
466
|
+
output: process.env.DEBUG_OUTPUT || 'console',
|
|
467
|
+
outputFile: process.env.DEBUG_OUTPUT_FILE,
|
|
468
|
+
colorize: process.env.DEBUG_COLORIZE !== 'false',
|
|
469
|
+
trackState: process.env.DEBUG_TRACK_STATE !== 'false',
|
|
470
|
+
trackDecisions: process.env.DEBUG_TRACK_DECISIONS !== 'false',
|
|
471
|
+
trackCommunication: process.env.DEBUG_TRACK_COMMUNICATION !== 'false',
|
|
472
|
+
timeline: process.env.DEBUG_TIMELINE === 'true',
|
|
473
|
+
});
|
|
474
|
+
}
|