@runflow-ai/sdk 1.0.18 → 1.0.19
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/core/agent.d.ts +3 -37
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +227 -529
- package/dist/core/agent.js.map +1 -1
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +1 -11
- package/dist/core/context.js.map +1 -1
- package/dist/core/helpers/agent-context.d.ts +23 -0
- package/dist/core/helpers/agent-context.d.ts.map +1 -0
- package/dist/core/helpers/agent-context.js +90 -0
- package/dist/core/helpers/agent-context.js.map +1 -0
- package/dist/core/helpers/agent-memory.d.ts +17 -0
- package/dist/core/helpers/agent-memory.d.ts.map +1 -0
- package/dist/core/helpers/agent-memory.js +194 -0
- package/dist/core/helpers/agent-memory.js.map +1 -0
- package/dist/core/helpers/agent-rag.d.ts +22 -0
- package/dist/core/helpers/agent-rag.d.ts.map +1 -0
- package/dist/core/helpers/agent-rag.js +216 -0
- package/dist/core/helpers/agent-rag.js.map +1 -0
- package/dist/core/helpers/agent-utils.d.ts +13 -0
- package/dist/core/helpers/agent-utils.d.ts.map +1 -0
- package/dist/core/helpers/agent-utils.js +35 -0
- package/dist/core/helpers/agent-utils.js.map +1 -0
- package/dist/core/logger.d.ts +22 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +91 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/performance-logger.d.ts +45 -0
- package/dist/core/performance-logger.d.ts.map +1 -0
- package/dist/core/performance-logger.js +140 -0
- package/dist/core/performance-logger.js.map +1 -0
- package/dist/observability/trace-collector.d.ts.map +1 -1
- package/dist/observability/trace-collector.js +0 -16
- package/dist/observability/trace-collector.js.map +1 -1
- package/package.json +3 -1
package/dist/core/agent.js
CHANGED
|
@@ -4,33 +4,42 @@ exports.Agent = void 0;
|
|
|
4
4
|
const trace_collector_1 = require("../observability/trace-collector");
|
|
5
5
|
const api_client_1 = require("./api-client");
|
|
6
6
|
const context_1 = require("./context");
|
|
7
|
+
const logger_1 = require("./logger");
|
|
8
|
+
const performance_logger_1 = require("./performance-logger");
|
|
9
|
+
const agent_memory_1 = require("./helpers/agent-memory");
|
|
10
|
+
const agent_rag_1 = require("./helpers/agent-rag");
|
|
11
|
+
const agent_context_1 = require("./helpers/agent-context");
|
|
12
|
+
const agent_utils_1 = require("./helpers/agent-utils");
|
|
7
13
|
// ============================================================================
|
|
8
14
|
// AGENT CLASS
|
|
9
15
|
// ============================================================================
|
|
10
16
|
class Agent {
|
|
11
17
|
constructor(config) {
|
|
12
18
|
this.config = config;
|
|
19
|
+
// Configurar logger
|
|
20
|
+
this.logger = (0, logger_1.createLogger)({
|
|
21
|
+
name: `agent:${config.name}`,
|
|
22
|
+
level: this.resolveLogLevel(config.debug),
|
|
23
|
+
enabled: config.debug !== false,
|
|
24
|
+
});
|
|
13
25
|
// ============================================================================
|
|
14
26
|
// AUTO-CREATE RAG TOOLS (Agentic RAG)
|
|
15
27
|
// ============================================================================
|
|
16
28
|
// Se RAG configurado, criar tools automaticamente
|
|
17
29
|
// LLM decide quando buscar (não busca sempre)
|
|
18
30
|
if (config.rag) {
|
|
19
|
-
|
|
20
|
-
const ragTools =
|
|
31
|
+
this.logger.debug('RAG configuration detected, creating tools');
|
|
32
|
+
const ragTools = (0, agent_rag_1.createRAGTools)(config.rag, this.logger);
|
|
21
33
|
this.config.tools = {
|
|
22
34
|
...ragTools,
|
|
23
35
|
...config.tools,
|
|
24
36
|
};
|
|
25
|
-
console.log(`✅ [SDK Agent] Created ${Object.keys(ragTools).length} RAG tool(s):`, Object.keys(ragTools));
|
|
26
37
|
// Injetar searchPrompt nas instructions (orienta quando buscar)
|
|
27
38
|
if (config.rag.searchPrompt) {
|
|
28
39
|
this.config.instructions += `\n\n${config.rag.searchPrompt}`;
|
|
29
|
-
|
|
40
|
+
this.logger.debug('Search prompt injected into instructions');
|
|
30
41
|
}
|
|
31
42
|
}
|
|
32
|
-
// Configurar debug
|
|
33
|
-
this.debugConfig = this.resolveDebugConfig(config.debug);
|
|
34
43
|
// Auto-initialize API client if not in execution context
|
|
35
44
|
if (!this.apiClient) {
|
|
36
45
|
this.apiClient = (0, api_client_1.createRunflowAPIClient)();
|
|
@@ -40,32 +49,34 @@ class Agent {
|
|
|
40
49
|
batchSize: 1, // Flush imediatamente após cada trace
|
|
41
50
|
flushInterval: 1000,
|
|
42
51
|
});
|
|
43
|
-
console.log('🔍 [SDK Agent] Trace collector initialized in constructor with projectId:', projectId);
|
|
44
52
|
}
|
|
45
53
|
}
|
|
46
54
|
// Injetar API client (feito pela execution engine)
|
|
47
55
|
_setAPIClient(apiClient) {
|
|
48
|
-
this.apiClient = apiClient;
|
|
49
|
-
// Use agentId from environment or config name as fallback
|
|
50
56
|
const projectId = process.env.RUNFLOW_AGENT_ID || this.config.name.toLowerCase().replace(/\s+/g, '-');
|
|
57
|
+
this.logger.debug('Setting API client', { projectId });
|
|
58
|
+
this.apiClient = apiClient;
|
|
51
59
|
this.traceCollector = (0, trace_collector_1.createTraceCollector)(apiClient, projectId, {
|
|
52
60
|
batchSize: 1, // Flush imediatamente após cada trace
|
|
53
61
|
flushInterval: 1000,
|
|
54
62
|
});
|
|
55
|
-
console.log('🔍 [SDK Agent] Trace collector initialized via _setAPIClient with projectId:', projectId);
|
|
56
63
|
}
|
|
57
64
|
// Geração simples (aceita string ou array de messages)
|
|
58
65
|
async generate(input) {
|
|
59
66
|
const isMessagesArray = Array.isArray(input);
|
|
60
|
-
console.log('💬 [SDK Agent] Generate called with', isMessagesArray ? `${input.length} messages` : `prompt length: ${input.length}`);
|
|
61
67
|
if (!this.apiClient) {
|
|
62
|
-
|
|
68
|
+
this.logger.error('API client not initialized');
|
|
63
69
|
throw new Error('Agent not initialized. API client not set.');
|
|
64
70
|
}
|
|
65
|
-
console.log('🌐 [SDK Agent] Calling chat API...');
|
|
66
71
|
const messages = isMessagesArray
|
|
67
72
|
? input
|
|
68
73
|
: [{ role: 'user', content: input }];
|
|
74
|
+
this.logger.debug('Starting generation', {
|
|
75
|
+
messagesCount: messages.length,
|
|
76
|
+
isMessagesArray,
|
|
77
|
+
provider: this.config.model.provider,
|
|
78
|
+
model: this.config.model.model
|
|
79
|
+
});
|
|
69
80
|
const chatRequest = {
|
|
70
81
|
projectId: '', // Será injetado pela engine
|
|
71
82
|
provider: this.config.model.provider,
|
|
@@ -80,22 +91,32 @@ class Agent {
|
|
|
80
91
|
stop: this.config.modelConfig?.stop,
|
|
81
92
|
seed: this.config.modelConfig?.seed,
|
|
82
93
|
};
|
|
83
|
-
console.log('📡 [SDK Agent] Chat request:', JSON.stringify(chatRequest, null, 2));
|
|
84
94
|
try {
|
|
85
95
|
const response = await this.apiClient.chat(chatRequest);
|
|
86
|
-
|
|
96
|
+
this.logger.debug('Generation completed', {
|
|
97
|
+
responseLength: response.text?.length || 0,
|
|
98
|
+
usage: response.usage
|
|
99
|
+
});
|
|
87
100
|
return { text: response.text };
|
|
88
101
|
}
|
|
89
102
|
catch (error) {
|
|
90
|
-
|
|
103
|
+
this.logger.error('Chat API failed', {
|
|
104
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
105
|
+
});
|
|
91
106
|
throw error;
|
|
92
107
|
}
|
|
93
108
|
}
|
|
94
109
|
// Geração com streaming
|
|
95
110
|
async generateStream(prompt) {
|
|
96
111
|
if (!this.apiClient) {
|
|
112
|
+
this.logger.error('API client not initialized for streaming');
|
|
97
113
|
throw new Error('Agent not initialized. API client not set.');
|
|
98
114
|
}
|
|
115
|
+
this.logger.debug('Starting stream generation', {
|
|
116
|
+
promptLength: prompt.length,
|
|
117
|
+
provider: this.config.model.provider,
|
|
118
|
+
model: this.config.model.model
|
|
119
|
+
});
|
|
99
120
|
const stream = this.apiClient.chatStream({
|
|
100
121
|
projectId: '',
|
|
101
122
|
provider: this.config.model.provider,
|
|
@@ -110,26 +131,38 @@ class Agent {
|
|
|
110
131
|
stop: this.config.modelConfig?.stop,
|
|
111
132
|
seed: this.config.modelConfig?.seed,
|
|
112
133
|
});
|
|
113
|
-
return
|
|
134
|
+
return (0, agent_utils_1.processStreamChunks)(stream, this.logger);
|
|
114
135
|
}
|
|
115
136
|
// Geração com tools (implementa loop de tool calling)
|
|
116
137
|
async generateWithTools(input) {
|
|
117
138
|
if (!this.apiClient) {
|
|
139
|
+
this.logger.error('API client not initialized for tool generation');
|
|
118
140
|
throw new Error('Agent not initialized. API client not set.');
|
|
119
141
|
}
|
|
120
142
|
if (!this.config.tools || Object.keys(this.config.tools).length === 0) {
|
|
143
|
+
this.logger.debug('No tools configured, falling back to simple generation');
|
|
121
144
|
return this.generate(input);
|
|
122
145
|
}
|
|
123
146
|
const isMessagesArray = Array.isArray(input);
|
|
124
147
|
let messages = isMessagesArray
|
|
125
148
|
? [...input]
|
|
126
149
|
: [{ role: 'user', content: input }];
|
|
150
|
+
this.logger.debug('Starting generation with tools', {
|
|
151
|
+
messagesCount: messages.length,
|
|
152
|
+
toolsCount: Object.keys(this.config.tools).length,
|
|
153
|
+
toolNames: Object.keys(this.config.tools)
|
|
154
|
+
});
|
|
127
155
|
const maxIterations = this.config.maxToolIterations || 10; // Prevenir loops infinitos
|
|
128
156
|
let iteration = 0;
|
|
129
157
|
while (iteration < maxIterations) {
|
|
130
158
|
iteration++;
|
|
131
|
-
|
|
159
|
+
this.logger.debug('Tool calling iteration', {
|
|
160
|
+
iteration,
|
|
161
|
+
maxIterations,
|
|
162
|
+
messagesCount: messages.length
|
|
163
|
+
});
|
|
132
164
|
// 🔍 Trace: LLM Call
|
|
165
|
+
performance_logger_1.performanceLogger.start(`llm.call.${iteration}`);
|
|
133
166
|
const llmStartTime = Date.now();
|
|
134
167
|
const llmSpan = this.traceCollector?.startSpan('llm_call', {
|
|
135
168
|
provider: this.config.model.provider,
|
|
@@ -138,16 +171,12 @@ class Agent {
|
|
|
138
171
|
hasTools: true,
|
|
139
172
|
toolsCount: Object.keys(this.config.tools).length,
|
|
140
173
|
});
|
|
141
|
-
// 🔍 Input do trace
|
|
174
|
+
// 🔍 Input do trace
|
|
142
175
|
const llmInput = {
|
|
143
176
|
messagesCount: messages.length,
|
|
144
177
|
temperature: this.config.modelConfig?.temperature,
|
|
145
178
|
maxTokens: this.config.modelConfig?.maxTokens,
|
|
146
179
|
};
|
|
147
|
-
if (this.debugConfig.logLLMCalls || this.debugConfig.logMessages) {
|
|
148
|
-
llmInput.messages = messages;
|
|
149
|
-
llmInput.instructions = this.config.instructions;
|
|
150
|
-
}
|
|
151
180
|
llmSpan?.setInput(llmInput);
|
|
152
181
|
const chatRequest = {
|
|
153
182
|
projectId: '', // Será injetado pela engine
|
|
@@ -165,17 +194,26 @@ class Agent {
|
|
|
165
194
|
seed: this.config.modelConfig?.seed,
|
|
166
195
|
};
|
|
167
196
|
const response = await this.apiClient.chat(chatRequest);
|
|
168
|
-
|
|
197
|
+
performance_logger_1.performanceLogger.end(`llm.call.${iteration}`, {
|
|
198
|
+
iteration,
|
|
199
|
+
hasToolCalls: !!response.toolCalls && response.toolCalls.length > 0,
|
|
200
|
+
toolCallsCount: response.toolCalls?.length || 0,
|
|
201
|
+
promptTokens: response.usage?.promptTokens,
|
|
202
|
+
completionTokens: response.usage?.completionTokens
|
|
203
|
+
});
|
|
204
|
+
this.logger.debug('LLM response received', {
|
|
205
|
+
iteration,
|
|
206
|
+
responseLength: response.text?.length || 0,
|
|
207
|
+
hasToolCalls: !!response.toolCalls && response.toolCalls.length > 0,
|
|
208
|
+
toolCallsCount: response.toolCalls?.length || 0,
|
|
209
|
+
usage: response.usage
|
|
210
|
+
});
|
|
211
|
+
// 🔍 Output do trace
|
|
169
212
|
const llmOutput = {
|
|
170
213
|
responseLength: response.text?.length || 0,
|
|
171
214
|
hasToolCalls: !!response.toolCalls && response.toolCalls.length > 0,
|
|
172
215
|
toolCallsCount: response.toolCalls?.length || 0,
|
|
173
216
|
};
|
|
174
|
-
if (this.debugConfig.logLLMCalls) {
|
|
175
|
-
llmOutput.responseText = response.text;
|
|
176
|
-
llmOutput.toolCalls = response.toolCalls;
|
|
177
|
-
llmOutput.usage = response.usage;
|
|
178
|
-
}
|
|
179
217
|
llmSpan?.setOutput(llmOutput);
|
|
180
218
|
llmSpan?.setMetadata({
|
|
181
219
|
provider: this.config.model.provider,
|
|
@@ -199,10 +237,12 @@ class Agent {
|
|
|
199
237
|
llmSpan?.finish();
|
|
200
238
|
// Se não há tool calls, retornar resposta final
|
|
201
239
|
if (!response.toolCalls || response.toolCalls.length === 0) {
|
|
202
|
-
|
|
240
|
+
this.logger.info('Generation completed without tool calls', {
|
|
241
|
+
iteration,
|
|
242
|
+
responseLength: response.text?.length || 0
|
|
243
|
+
});
|
|
203
244
|
return { text: response.text };
|
|
204
245
|
}
|
|
205
|
-
console.log(`🛠️ [SDK Agent] Processing ${response.toolCalls.length} tool call(s)`);
|
|
206
246
|
// Adicionar mensagem do assistente com tool calls
|
|
207
247
|
messages.push({
|
|
208
248
|
role: 'assistant',
|
|
@@ -212,6 +252,11 @@ class Agent {
|
|
|
212
252
|
// Executar cada tool call
|
|
213
253
|
for (const toolCall of response.toolCalls) {
|
|
214
254
|
const toolName = toolCall.name;
|
|
255
|
+
this.logger.debug('Processing tool call', {
|
|
256
|
+
toolName,
|
|
257
|
+
toolCallId: toolCall.id,
|
|
258
|
+
iteration
|
|
259
|
+
});
|
|
215
260
|
// Buscar tool por ID (pode estar com nome diferente da key no config)
|
|
216
261
|
let tool = this.config.tools[toolName];
|
|
217
262
|
// Se não encontrou, buscar por ID da tool
|
|
@@ -222,8 +267,10 @@ class Agent {
|
|
|
222
267
|
}
|
|
223
268
|
}
|
|
224
269
|
if (!tool) {
|
|
225
|
-
|
|
226
|
-
|
|
270
|
+
this.logger.warn('Tool not found', {
|
|
271
|
+
toolName,
|
|
272
|
+
availableTools: Object.keys(this.config.tools)
|
|
273
|
+
});
|
|
227
274
|
// Adicionar mensagem de erro
|
|
228
275
|
messages.push({
|
|
229
276
|
role: 'tool',
|
|
@@ -234,7 +281,6 @@ class Agent {
|
|
|
234
281
|
continue;
|
|
235
282
|
}
|
|
236
283
|
try {
|
|
237
|
-
console.log(`🔧 [SDK Agent] Executing tool: ${toolName}`);
|
|
238
284
|
// 🔍 Iniciar trace da tool execution
|
|
239
285
|
const toolStartTime = Date.now();
|
|
240
286
|
const toolSpan = this.traceCollector?.startSpan('tool_call', {
|
|
@@ -249,20 +295,28 @@ class Agent {
|
|
|
249
295
|
}
|
|
250
296
|
// 🔍 Input sempre vai completo para o trace
|
|
251
297
|
toolSpan?.setInput(args);
|
|
252
|
-
// Executar tool
|
|
253
|
-
const toolResult = await
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
298
|
+
// Executar tool com performance tracking
|
|
299
|
+
const toolResult = await performance_logger_1.performanceLogger.measure(`tool.${toolName}`, async () => {
|
|
300
|
+
return await tool.execute(args, {
|
|
301
|
+
runflowAPI: this.apiClient,
|
|
302
|
+
projectId: process.env.RUNFLOW_AGENT_ID || '',
|
|
303
|
+
companyId: process.env.RUNFLOW_TENANT_ID || '',
|
|
304
|
+
});
|
|
305
|
+
}, { toolId: tool.id, iteration });
|
|
259
306
|
// 🔍 Output sempre vai completo para o trace
|
|
260
307
|
const toolEndTime = Date.now();
|
|
308
|
+
const processingTimeMs = toolEndTime - toolStartTime;
|
|
309
|
+
this.logger.info('Tool execution completed', {
|
|
310
|
+
toolName,
|
|
311
|
+
toolId: tool.id,
|
|
312
|
+
processingTimeMs,
|
|
313
|
+
iteration
|
|
314
|
+
});
|
|
261
315
|
toolSpan?.setOutput(toolResult);
|
|
262
316
|
toolSpan?.setMetadata({
|
|
263
317
|
toolName,
|
|
264
318
|
toolId: tool.id,
|
|
265
|
-
processingTimeMs
|
|
319
|
+
processingTimeMs,
|
|
266
320
|
success: true,
|
|
267
321
|
});
|
|
268
322
|
toolSpan?.finish();
|
|
@@ -275,7 +329,12 @@ class Agent {
|
|
|
275
329
|
});
|
|
276
330
|
}
|
|
277
331
|
catch (error) {
|
|
278
|
-
|
|
332
|
+
this.logger.error('Tool execution failed', {
|
|
333
|
+
toolName,
|
|
334
|
+
toolId: tool.id,
|
|
335
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
336
|
+
iteration
|
|
337
|
+
});
|
|
279
338
|
// 🔍 Registrar erro no trace (se existe)
|
|
280
339
|
const toolSpan = this.traceCollector?.startSpan('tool_call', {
|
|
281
340
|
toolName,
|
|
@@ -303,30 +362,26 @@ class Agent {
|
|
|
303
362
|
}
|
|
304
363
|
}
|
|
305
364
|
// Se chegou aqui, atingiu o limite de iterações
|
|
306
|
-
|
|
365
|
+
this.logger.warn('Max tool calling iterations reached', {
|
|
366
|
+
maxIterations,
|
|
367
|
+
finalMessagesCount: messages.length
|
|
368
|
+
});
|
|
307
369
|
return { text: 'Maximum tool calling iterations reached. Please try again.' };
|
|
308
370
|
}
|
|
309
371
|
// Processamento principal (chamado pela execution engine)
|
|
310
372
|
async process(input, context) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
hasTools: !!(this.config.tools && Object.keys(this.config.tools).length > 0),
|
|
373
|
+
const processStartTime = Date.now();
|
|
374
|
+
performance_logger_1.performanceLogger.start('agent.process');
|
|
375
|
+
this.logger.info('Agent processing started', {
|
|
376
|
+
agentName: this.config.name,
|
|
377
|
+
messageLength: input.message?.length || 0,
|
|
378
|
+
sessionId: input.sessionId,
|
|
379
|
+
companyId: input.companyId
|
|
319
380
|
});
|
|
320
381
|
// Configurar API client com contexto
|
|
321
382
|
if (context?.apiClient) {
|
|
322
|
-
console.log('🔗 [SDK Agent] Using injected API client from context');
|
|
323
383
|
this._setAPIClient(context.apiClient);
|
|
324
384
|
}
|
|
325
|
-
else {
|
|
326
|
-
console.log('🔗 [SDK Agent] Using auto-configured API client');
|
|
327
|
-
// this.apiClient já foi inicializado no constructor
|
|
328
|
-
}
|
|
329
|
-
console.log('🌐 [SDK Agent] API Client configured:', !!this.apiClient);
|
|
330
385
|
// ============================================================================
|
|
331
386
|
// RESOLVER EXECUTION CONTEXT (prioridade: input > state > env > inferência)
|
|
332
387
|
// ============================================================================
|
|
@@ -334,27 +389,26 @@ class Agent {
|
|
|
334
389
|
const executionId = input.executionId
|
|
335
390
|
|| state.executionId
|
|
336
391
|
|| process.env.RUNFLOW_EXECUTION_ID
|
|
337
|
-
||
|
|
392
|
+
|| (0, agent_context_1.generateExecutionId)();
|
|
338
393
|
const threadId = input.threadId
|
|
339
394
|
|| state.threadId
|
|
340
395
|
|| process.env.RUNFLOW_THREAD_ID
|
|
341
|
-
||
|
|
396
|
+
|| (0, agent_context_1.generateThreadId)(input, this.logger);
|
|
342
397
|
const entityType = input.entityType
|
|
343
398
|
|| state.entityType
|
|
344
|
-
||
|
|
399
|
+
|| (0, agent_context_1.inferEntityType)(input, this.logger);
|
|
345
400
|
const entityValue = input.entityValue
|
|
346
401
|
|| state.entityValue
|
|
347
|
-
||
|
|
402
|
+
|| (0, agent_context_1.inferEntityValue)(input, this.logger);
|
|
348
403
|
const userId = input.userId
|
|
349
404
|
|| state.userId
|
|
350
|
-
||
|
|
351
|
-
|
|
405
|
+
|| (0, agent_context_1.inferUserId)(input, this.logger);
|
|
406
|
+
this.logger.debug('Execution context resolved', {
|
|
352
407
|
executionId,
|
|
353
408
|
threadId,
|
|
354
409
|
entityType,
|
|
355
|
-
entityValue
|
|
356
|
-
userId
|
|
357
|
-
source: input.threadId ? 'input' : state.threadId ? 'state' : 'inferred',
|
|
410
|
+
entityValue,
|
|
411
|
+
userId
|
|
358
412
|
});
|
|
359
413
|
// Configurar trace collector com contexto
|
|
360
414
|
if (this.traceCollector) {
|
|
@@ -403,6 +457,10 @@ class Agent {
|
|
|
403
457
|
span?.setInput(input);
|
|
404
458
|
// Se tem multi-agents, usar supervisor pattern
|
|
405
459
|
if (this.config.agents && Object.keys(this.config.agents).length > 0) {
|
|
460
|
+
this.logger.debug('Multi-agent configuration detected, delegating to supervisor', {
|
|
461
|
+
agentsCount: Object.keys(this.config.agents).length,
|
|
462
|
+
agentNames: Object.keys(this.config.agents)
|
|
463
|
+
});
|
|
406
464
|
return this.processMultiAgent(input, context);
|
|
407
465
|
}
|
|
408
466
|
// Memory management se configurado
|
|
@@ -412,21 +470,24 @@ class Agent {
|
|
|
412
470
|
// Prioridade 1: Custom memoryKey (override completo)
|
|
413
471
|
if (this.config.memory.memoryKey) {
|
|
414
472
|
memoryId = this.config.memory.memoryKey;
|
|
415
|
-
console.log('🧠 [SDK Agent] Loading memory with custom key:', memoryId);
|
|
416
473
|
}
|
|
417
474
|
// Prioridade 2: entityType + entityValue (do identify())
|
|
418
475
|
else if (entityType && entityValue) {
|
|
419
476
|
memoryId = `${entityType}:${entityValue}`;
|
|
420
|
-
console.log('🧠 [SDK Agent] Loading memory for entity:', memoryId);
|
|
421
477
|
}
|
|
422
478
|
// Prioridade 3: sessionId (backward compatibility)
|
|
423
479
|
else if (input.sessionId) {
|
|
424
480
|
memoryId = `session:${input.sessionId}`;
|
|
425
|
-
console.log('🧠 [SDK Agent] Loading memory for session (fallback):', memoryId);
|
|
426
481
|
}
|
|
427
482
|
if (memoryId) {
|
|
428
|
-
|
|
429
|
-
|
|
483
|
+
this.logger.debug('Loading memory', {
|
|
484
|
+
memoryId,
|
|
485
|
+
memoryType: this.config.memory.type
|
|
486
|
+
});
|
|
487
|
+
const memoryLoadTime = await performance_logger_1.performanceLogger.measure('memory.load', async () => {
|
|
488
|
+
return await (0, agent_memory_1.loadMemory)(memoryId, this.apiClient, this.config.memory, this.traceCollector, this.logger);
|
|
489
|
+
}, { memoryId, memoryType: this.config.memory.type });
|
|
490
|
+
memoryMessages = memoryLoadTime;
|
|
430
491
|
}
|
|
431
492
|
}
|
|
432
493
|
// ============================================================================
|
|
@@ -438,7 +499,6 @@ class Agent {
|
|
|
438
499
|
let messages = [];
|
|
439
500
|
// 2. Se tem messages[] no input, adicionar como contexto
|
|
440
501
|
if (input.messages && input.messages.length > 0) {
|
|
441
|
-
console.log('💬 [SDK Agent] Using provided messages as context:', input.messages.length);
|
|
442
502
|
const inputMessages = input.messages.map(msg => ({
|
|
443
503
|
role: msg.role,
|
|
444
504
|
content: msg.content // Pode ser string ou array multimodal
|
|
@@ -447,23 +507,33 @@ class Agent {
|
|
|
447
507
|
}
|
|
448
508
|
// 3. Adicionar historical messages da memória
|
|
449
509
|
if (memoryMessages.length > 0) {
|
|
450
|
-
console.log('🧠 [SDK Agent] Adding memory messages:', memoryMessages.length);
|
|
451
510
|
messages.push(...memoryMessages);
|
|
452
511
|
}
|
|
453
512
|
// 4. Adicionar mensagem atual do usuário
|
|
454
513
|
messages.push({ role: 'user', content: input.message });
|
|
455
|
-
console.log('📝 [SDK Agent] Final messages for LLM:', messages.length);
|
|
456
|
-
console.log('🤖 [SDK Agent] Calling LLM...');
|
|
457
514
|
// Processar com ou sem tools
|
|
458
|
-
const
|
|
515
|
+
const hasTools = this.config.tools && Object.keys(this.config.tools).length > 0;
|
|
516
|
+
this.logger.debug('Processing messages', {
|
|
517
|
+
messagesCount: messages.length,
|
|
518
|
+
hasTools,
|
|
519
|
+
toolsCount: hasTools ? Object.keys(this.config.tools).length : 0
|
|
520
|
+
});
|
|
521
|
+
performance_logger_1.performanceLogger.start('llm.processing');
|
|
522
|
+
const result = hasTools
|
|
459
523
|
? await this.generateWithTools(messages)
|
|
460
524
|
: await this.generate(messages);
|
|
461
|
-
|
|
525
|
+
const llmProcessingTime = performance_logger_1.performanceLogger.end('llm.processing', {
|
|
526
|
+
hasTools,
|
|
527
|
+
messagesCount: messages.length
|
|
528
|
+
});
|
|
462
529
|
// Salvar na memória se configurado
|
|
530
|
+
let memorySaveTime = 0;
|
|
463
531
|
if (this.config.memory && memoryId) {
|
|
464
|
-
|
|
465
|
-
await
|
|
466
|
-
|
|
532
|
+
this.logger.debug('Saving to memory', { memoryId });
|
|
533
|
+
await performance_logger_1.performanceLogger.measure('memory.save', async () => {
|
|
534
|
+
await (0, agent_memory_1.saveToMemory)(memoryId, input.message, result.text, this.apiClient, this.config.memory, this.config.model, this.traceCollector, this.logger);
|
|
535
|
+
}, { memoryId });
|
|
536
|
+
memorySaveTime = Date.now() - processStartTime - llmProcessingTime;
|
|
467
537
|
}
|
|
468
538
|
const output = {
|
|
469
539
|
message: result.text,
|
|
@@ -475,16 +545,42 @@ class Agent {
|
|
|
475
545
|
sessionId: input.sessionId,
|
|
476
546
|
},
|
|
477
547
|
};
|
|
478
|
-
console.log('📤 [SDK Agent] Final output:', JSON.stringify(output, null, 2));
|
|
479
548
|
// Finalizar trace com métricas de performance
|
|
480
|
-
const
|
|
481
|
-
|
|
549
|
+
const processingTimeMs = Date.now() - processStartTime;
|
|
550
|
+
// Performance summary (se ativado)
|
|
551
|
+
if (performance_logger_1.performanceLogger.isEnabled()) {
|
|
552
|
+
const memoryLoadTime = memoryMessages.length > 0 ?
|
|
553
|
+
(processStartTime + 100) : 0; // Estimativa se não medido diretamente
|
|
554
|
+
performance_logger_1.performanceLogger.summary('agent.process', {
|
|
555
|
+
'context_resolution': 5, // Tempo mínimo de setup
|
|
556
|
+
'memory_load': memoryLoadTime,
|
|
557
|
+
'llm_processing': llmProcessingTime,
|
|
558
|
+
'memory_save': memorySaveTime,
|
|
559
|
+
}, processingTimeMs);
|
|
560
|
+
}
|
|
561
|
+
performance_logger_1.performanceLogger.end('agent.process', {
|
|
562
|
+
agentName: this.config.name,
|
|
563
|
+
responseLength: result.text?.length || 0,
|
|
564
|
+
memoryUsed: memoryMessages.length > 0,
|
|
565
|
+
toolsUsed: (0, agent_utils_1.getUsedTools)(this.config.tools).length,
|
|
566
|
+
executionId,
|
|
567
|
+
threadId
|
|
568
|
+
});
|
|
569
|
+
this.logger.info('Agent processing completed', {
|
|
570
|
+
agentName: this.config.name,
|
|
571
|
+
processingTimeMs,
|
|
572
|
+
responseLength: result.text?.length || 0,
|
|
573
|
+
memoryUsed: memoryMessages.length > 0,
|
|
574
|
+
toolsUsed: (0, agent_utils_1.getUsedTools)(this.config.tools),
|
|
575
|
+
executionId,
|
|
576
|
+
threadId
|
|
577
|
+
});
|
|
482
578
|
span?.setOutput(output);
|
|
483
579
|
span?.setMetadata({
|
|
484
580
|
// Feature usage atualizado
|
|
485
581
|
ragUsed: false, // Agora detectado via tool calls
|
|
486
582
|
memoryUsed: memoryMessages.length > 0,
|
|
487
|
-
toolsUsed:
|
|
583
|
+
toolsUsed: (0, agent_utils_1.getUsedTools)(this.config.tools),
|
|
488
584
|
// Performance metrics
|
|
489
585
|
processingTimeMs,
|
|
490
586
|
// Quality metrics
|
|
@@ -509,17 +605,19 @@ class Agent {
|
|
|
509
605
|
span?.finish();
|
|
510
606
|
// Forçar flush dos traces pendentes
|
|
511
607
|
if (this.traceCollector) {
|
|
512
|
-
console.log('🚀 [SDK Agent] Forcing trace flush...');
|
|
513
608
|
await this.traceCollector.flush();
|
|
514
609
|
}
|
|
515
|
-
console.log('🎉 [SDK Agent] Process completed successfully');
|
|
516
610
|
return output;
|
|
517
611
|
}
|
|
518
612
|
// Multi-agent processing (supervisor pattern)
|
|
519
613
|
async processMultiAgent(input, context) {
|
|
614
|
+
this.logger.debug('Starting multi-agent processing with supervisor pattern');
|
|
520
615
|
// Criar supervisor automático
|
|
521
616
|
const supervisor = this.createSupervisor();
|
|
522
617
|
// Supervisor decide qual agent usar
|
|
618
|
+
this.logger.debug('Supervisor analyzing agent selection', {
|
|
619
|
+
availableAgents: Object.keys(this.config.agents)
|
|
620
|
+
});
|
|
523
621
|
const decision = await supervisor.generate(`
|
|
524
622
|
Available agents:
|
|
525
623
|
${Object.entries(this.config.agents).map(([name, config]) => `- ${name}: ${config.instructions}`).join('\n')}
|
|
@@ -531,12 +629,19 @@ Which agent should handle this? Respond with just the agent name.
|
|
|
531
629
|
const selectedAgentName = decision.text.trim();
|
|
532
630
|
const selectedAgentConfig = this.config.agents[selectedAgentName];
|
|
533
631
|
if (!selectedAgentConfig) {
|
|
534
|
-
// Fallback para primeiro agent
|
|
535
632
|
const firstAgentName = Object.keys(this.config.agents)[0];
|
|
633
|
+
this.logger.warn('Supervisor selected invalid agent, using fallback', {
|
|
634
|
+
selectedAgentName,
|
|
635
|
+
fallbackAgentName: firstAgentName
|
|
636
|
+
});
|
|
637
|
+
// Fallback para primeiro agent
|
|
536
638
|
const firstAgentConfig = this.config.agents[firstAgentName];
|
|
537
639
|
const agent = new Agent(firstAgentConfig);
|
|
538
640
|
return agent.process(input, context);
|
|
539
641
|
}
|
|
642
|
+
this.logger.info('Supervisor selected agent', {
|
|
643
|
+
selectedAgentName
|
|
644
|
+
});
|
|
540
645
|
// Executar agent selecionado
|
|
541
646
|
const selectedAgent = new Agent(selectedAgentConfig);
|
|
542
647
|
return selectedAgent.process(input, context);
|
|
@@ -550,170 +655,26 @@ Which agent should handle this? Respond with just the agent name.
|
|
|
550
655
|
});
|
|
551
656
|
}
|
|
552
657
|
// ============================================================================
|
|
553
|
-
//
|
|
658
|
+
// LOGGER CONFIGURATION
|
|
554
659
|
// ============================================================================
|
|
555
660
|
/**
|
|
556
|
-
*
|
|
557
|
-
* LLM decide quando buscar (não busca sempre)
|
|
661
|
+
* Resolve o nível de log baseado na configuração de debug
|
|
558
662
|
*/
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
tools['searchKnowledge'] = this.createRAGTool({
|
|
564
|
-
id: 'knowledge',
|
|
565
|
-
name: ragConfig.vectorStore,
|
|
566
|
-
threshold: ragConfig.threshold || 0.7,
|
|
567
|
-
k: ragConfig.k || 5,
|
|
568
|
-
description: ragConfig.toolDescription || `Search in ${ragConfig.vectorStore} knowledge base for relevant information`,
|
|
569
|
-
});
|
|
570
|
-
console.log(`📚 [SDK Agent] Created RAG tool: searchKnowledge (${ragConfig.vectorStore})`);
|
|
663
|
+
resolveLogLevel(debug) {
|
|
664
|
+
// Se debug é false, desativar logs
|
|
665
|
+
if (debug === false) {
|
|
666
|
+
return 'silent';
|
|
571
667
|
}
|
|
572
|
-
//
|
|
573
|
-
if (
|
|
574
|
-
|
|
575
|
-
const toolName = `search_${vs.id}`;
|
|
576
|
-
tools[toolName] = this.createRAGTool({
|
|
577
|
-
id: vs.id,
|
|
578
|
-
name: vs.name,
|
|
579
|
-
threshold: vs.threshold || ragConfig.threshold || 0.7,
|
|
580
|
-
k: vs.k || ragConfig.k || 5,
|
|
581
|
-
description: vs.description || `Search in ${vs.name} knowledge base`,
|
|
582
|
-
});
|
|
583
|
-
console.log(`📚 [SDK Agent] Created RAG tool: ${toolName} (${vs.name})`);
|
|
584
|
-
}
|
|
668
|
+
// Se debug é true, usar debug level
|
|
669
|
+
if (debug === true) {
|
|
670
|
+
return 'debug';
|
|
585
671
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
* Cria uma tool individual de RAG
|
|
590
|
-
*/
|
|
591
|
-
createRAGTool(config) {
|
|
592
|
-
return {
|
|
593
|
-
id: `search-${config.id}`,
|
|
594
|
-
name: `search_${config.id}`,
|
|
595
|
-
description: config.description,
|
|
596
|
-
parameters: {
|
|
597
|
-
query: {
|
|
598
|
-
type: 'string',
|
|
599
|
-
description: 'Search query to find relevant information',
|
|
600
|
-
required: true,
|
|
601
|
-
},
|
|
602
|
-
},
|
|
603
|
-
execute: async (params, context) => {
|
|
604
|
-
console.log(`🔍 [RAG Tool] Searching in ${config.name}...`, {
|
|
605
|
-
query: params.query,
|
|
606
|
-
k: config.k,
|
|
607
|
-
threshold: config.threshold,
|
|
608
|
-
});
|
|
609
|
-
try {
|
|
610
|
-
const results = await context.runflowAPI.vectorSearch(params.query, {
|
|
611
|
-
vectorStore: config.name,
|
|
612
|
-
k: config.k,
|
|
613
|
-
threshold: config.threshold,
|
|
614
|
-
});
|
|
615
|
-
const formattedResults = results.results.map((r) => ({
|
|
616
|
-
content: r.content,
|
|
617
|
-
score: r.score,
|
|
618
|
-
metadata: r.metadata,
|
|
619
|
-
}));
|
|
620
|
-
console.log(`✅ [RAG Tool] Found ${formattedResults.length} results (threshold: ${config.threshold})`);
|
|
621
|
-
// Retornar em formato que o LLM possa usar
|
|
622
|
-
if (formattedResults.length === 0) {
|
|
623
|
-
return {
|
|
624
|
-
found: false,
|
|
625
|
-
message: 'No relevant information found in knowledge base',
|
|
626
|
-
results: [],
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
return {
|
|
630
|
-
found: true,
|
|
631
|
-
count: formattedResults.length,
|
|
632
|
-
results: formattedResults,
|
|
633
|
-
context: formattedResults.map((r, i) => `[Result ${i + 1}] (score: ${r.score.toFixed(2)})\n${r.content}`).join('\n\n---\n\n'),
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
catch (error) {
|
|
637
|
-
console.error(`❌ [RAG Tool] Search failed:`, error);
|
|
638
|
-
return {
|
|
639
|
-
found: false,
|
|
640
|
-
error: error instanceof Error ? error.message : 'Search failed',
|
|
641
|
-
results: [],
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
},
|
|
645
|
-
};
|
|
646
|
-
}
|
|
647
|
-
// RAG automático (DEPRECATED - mantido para compatibilidade temporária)
|
|
648
|
-
async performRAG(query) {
|
|
649
|
-
if (!this.config.rag || !this.apiClient) {
|
|
650
|
-
return null;
|
|
651
|
-
}
|
|
652
|
-
// 🔍 Trace: RAG Search
|
|
653
|
-
const ragStartTime = Date.now();
|
|
654
|
-
const ragSpan = this.traceCollector?.startSpan('rag_search', {
|
|
655
|
-
operation: 'vector_search',
|
|
656
|
-
vectorStore: this.config.rag.vectorStore,
|
|
657
|
-
k: this.config.rag.k || 5,
|
|
658
|
-
threshold: this.config.rag.threshold || 0.7,
|
|
659
|
-
});
|
|
660
|
-
ragSpan?.setInput({ query });
|
|
661
|
-
try {
|
|
662
|
-
const searchResults = await this.apiClient.vectorSearch(query, {
|
|
663
|
-
vectorStore: this.config.rag.vectorStore,
|
|
664
|
-
k: this.config.rag.k || 5,
|
|
665
|
-
threshold: this.config.rag.threshold || 0.7,
|
|
666
|
-
});
|
|
667
|
-
if (searchResults.results.length === 0) {
|
|
668
|
-
ragSpan?.setOutput({ resultsCount: 0, hasResults: false });
|
|
669
|
-
ragSpan?.setMetadata({
|
|
670
|
-
operation: 'vector_search',
|
|
671
|
-
vectorStore: this.config.rag.vectorStore,
|
|
672
|
-
resultsCount: 0,
|
|
673
|
-
processingTimeMs: Date.now() - ragStartTime,
|
|
674
|
-
success: true,
|
|
675
|
-
});
|
|
676
|
-
ragSpan?.finish();
|
|
677
|
-
return null;
|
|
678
|
-
}
|
|
679
|
-
const context = searchResults.results
|
|
680
|
-
.map((result) => result.content)
|
|
681
|
-
.join('\n\n');
|
|
682
|
-
// 🔍 Finalizar trace (com dados completos se debug ativado)
|
|
683
|
-
const ragOutput = {
|
|
684
|
-
resultsCount: searchResults.results.length,
|
|
685
|
-
hasResults: true,
|
|
686
|
-
contextLength: context.length,
|
|
687
|
-
};
|
|
688
|
-
if (this.debugConfig.logRAG) {
|
|
689
|
-
ragOutput.results = searchResults.results;
|
|
690
|
-
ragOutput.contextGenerated = context;
|
|
691
|
-
}
|
|
692
|
-
ragSpan?.setOutput(ragOutput);
|
|
693
|
-
ragSpan?.setMetadata({
|
|
694
|
-
operation: 'vector_search',
|
|
695
|
-
vectorStore: this.config.rag.vectorStore,
|
|
696
|
-
resultsCount: searchResults.results.length,
|
|
697
|
-
k: this.config.rag.k || 5,
|
|
698
|
-
threshold: this.config.rag.threshold || 0.7,
|
|
699
|
-
processingTimeMs: Date.now() - ragStartTime,
|
|
700
|
-
success: true,
|
|
701
|
-
});
|
|
702
|
-
ragSpan?.finish();
|
|
703
|
-
return context;
|
|
704
|
-
}
|
|
705
|
-
catch (error) {
|
|
706
|
-
console.error('RAG search failed:', error);
|
|
707
|
-
ragSpan?.setMetadata({
|
|
708
|
-
operation: 'vector_search',
|
|
709
|
-
vectorStore: this.config.rag.vectorStore,
|
|
710
|
-
success: false,
|
|
711
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
712
|
-
processingTimeMs: Date.now() - ragStartTime,
|
|
713
|
-
});
|
|
714
|
-
ragSpan?.finish();
|
|
715
|
-
return null;
|
|
672
|
+
// Se debug é objeto com level, usar o nível especificado
|
|
673
|
+
if (typeof debug === 'object' && debug.level) {
|
|
674
|
+
return debug.level;
|
|
716
675
|
}
|
|
676
|
+
// Default: info em produção, debug em desenvolvimento
|
|
677
|
+
return process.env.NODE_ENV === 'production' ? 'info' : 'debug';
|
|
717
678
|
}
|
|
718
679
|
// Getters
|
|
719
680
|
get name() {
|
|
@@ -731,293 +692,19 @@ Which agent should handle this? Respond with just the agent name.
|
|
|
731
692
|
get isMultiAgent() {
|
|
732
693
|
return !!(this.config.agents && Object.keys(this.config.agents).length > 0);
|
|
733
694
|
}
|
|
734
|
-
// Obter tools utilizadas (para traces)
|
|
735
|
-
getUsedTools() {
|
|
736
|
-
if (!this.config.tools)
|
|
737
|
-
return [];
|
|
738
|
-
return Object.keys(this.config.tools);
|
|
739
|
-
}
|
|
740
|
-
// ============================================================================
|
|
741
|
-
// DEBUG HELPERS
|
|
742
|
-
// ============================================================================
|
|
743
|
-
/**
|
|
744
|
-
* Resolver configuração de debug
|
|
745
|
-
*/
|
|
746
|
-
resolveDebugConfig(debug) {
|
|
747
|
-
// Verificar variável de ambiente
|
|
748
|
-
const envDebug = process.env.RUNFLOW_DEBUG === 'true' || process.env.RUNFLOW_LOG_LEVEL === 'verbose';
|
|
749
|
-
if (debug === true || envDebug) {
|
|
750
|
-
// Debug simples = todos logs ativados
|
|
751
|
-
return {
|
|
752
|
-
enabled: true,
|
|
753
|
-
logMessages: true,
|
|
754
|
-
logLLMCalls: true,
|
|
755
|
-
logToolCalls: true,
|
|
756
|
-
logRAG: true,
|
|
757
|
-
logMemory: true,
|
|
758
|
-
truncateAt: undefined,
|
|
759
|
-
};
|
|
760
|
-
}
|
|
761
|
-
else if (typeof debug === 'object' && debug.enabled) {
|
|
762
|
-
// Debug customizado
|
|
763
|
-
return {
|
|
764
|
-
enabled: true,
|
|
765
|
-
logMessages: debug.logMessages !== false,
|
|
766
|
-
logLLMCalls: debug.logLLMCalls !== false,
|
|
767
|
-
logToolCalls: debug.logToolCalls !== false,
|
|
768
|
-
logRAG: debug.logRAG !== false,
|
|
769
|
-
logMemory: debug.logMemory !== false,
|
|
770
|
-
truncateAt: debug.truncateAt,
|
|
771
|
-
};
|
|
772
|
-
}
|
|
773
|
-
return { enabled: false };
|
|
774
|
-
}
|
|
775
|
-
// ============================================================================
|
|
776
|
-
// CONTEXT RESOLUTION HELPERS
|
|
777
|
-
// ============================================================================
|
|
778
|
-
/**
|
|
779
|
-
* Generate unique execution ID
|
|
780
|
-
*/
|
|
781
|
-
generateExecutionId() {
|
|
782
|
-
return `exec_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
|
|
783
|
-
}
|
|
784
|
-
/**
|
|
785
|
-
* Generate threadId based on input (fallback quando não fornecido)
|
|
786
|
-
*/
|
|
787
|
-
generateThreadId(input) {
|
|
788
|
-
const companyId = input.companyId || 'default';
|
|
789
|
-
// Se tem sessionId, usar como thread
|
|
790
|
-
if (input.sessionId) {
|
|
791
|
-
return `session_${companyId}_${input.sessionId}`;
|
|
792
|
-
}
|
|
793
|
-
// Fallback: gerar único
|
|
794
|
-
return `thread_${companyId}_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
|
|
795
|
-
}
|
|
796
|
-
/**
|
|
797
|
-
* Infer entityType from input metadata
|
|
798
|
-
*/
|
|
799
|
-
inferEntityType(input) {
|
|
800
|
-
if (input.metadata?.phone)
|
|
801
|
-
return 'phone';
|
|
802
|
-
if (input.metadata?.email)
|
|
803
|
-
return 'email';
|
|
804
|
-
if (input.metadata?.contactId)
|
|
805
|
-
return 'hubspot_contact';
|
|
806
|
-
if (input.sessionId)
|
|
807
|
-
return 'session';
|
|
808
|
-
return 'session'; // Default
|
|
809
|
-
}
|
|
810
|
-
/**
|
|
811
|
-
* Infer entityValue from input metadata
|
|
812
|
-
*/
|
|
813
|
-
inferEntityValue(input) {
|
|
814
|
-
if (input.metadata?.phone)
|
|
815
|
-
return input.metadata.phone;
|
|
816
|
-
if (input.metadata?.email)
|
|
817
|
-
return input.metadata.email;
|
|
818
|
-
if (input.metadata?.contactId)
|
|
819
|
-
return input.metadata.contactId;
|
|
820
|
-
if (input.sessionId)
|
|
821
|
-
return input.sessionId;
|
|
822
|
-
return null;
|
|
823
|
-
}
|
|
824
|
-
/**
|
|
825
|
-
* Infer userId from input metadata
|
|
826
|
-
*/
|
|
827
|
-
inferUserId(input) {
|
|
828
|
-
if (input.metadata?.phone)
|
|
829
|
-
return input.metadata.phone;
|
|
830
|
-
if (input.metadata?.email)
|
|
831
|
-
return input.metadata.email;
|
|
832
|
-
if (input.metadata?.contactId)
|
|
833
|
-
return input.metadata.contactId;
|
|
834
|
-
return null;
|
|
835
|
-
}
|
|
836
|
-
// ============================================================================
|
|
837
|
-
// MEMORY MANAGEMENT
|
|
838
|
-
// ============================================================================
|
|
839
|
-
// Carregar memória da entidade (retorna array de messages)
|
|
840
|
-
async loadMemory(memoryId) {
|
|
841
|
-
if (!this.apiClient || !this.config.memory) {
|
|
842
|
-
return [];
|
|
843
|
-
}
|
|
844
|
-
// 🔍 Trace: Memory Load
|
|
845
|
-
const memoryLoadStartTime = Date.now();
|
|
846
|
-
const memoryLoadSpan = this.traceCollector?.startSpan('memory_operation', {
|
|
847
|
-
operation: 'load',
|
|
848
|
-
memoryId,
|
|
849
|
-
memoryType: this.config.memory.type,
|
|
850
|
-
});
|
|
851
|
-
try {
|
|
852
|
-
const memoryData = await this.apiClient.memory.get(memoryId);
|
|
853
|
-
if (!memoryData.messages || memoryData.messages.length === 0) {
|
|
854
|
-
memoryLoadSpan?.setOutput({ messagesCount: 0, hasHistory: false });
|
|
855
|
-
memoryLoadSpan?.setMetadata({
|
|
856
|
-
operation: 'load',
|
|
857
|
-
memoryId,
|
|
858
|
-
messagesCount: 0,
|
|
859
|
-
processingTimeMs: Date.now() - memoryLoadStartTime,
|
|
860
|
-
success: true,
|
|
861
|
-
});
|
|
862
|
-
memoryLoadSpan?.finish();
|
|
863
|
-
return [];
|
|
864
|
-
}
|
|
865
|
-
// Aplicar configurações de memória
|
|
866
|
-
let messages = memoryData.messages;
|
|
867
|
-
// Limitar por número de turnos
|
|
868
|
-
if (this.config.memory.maxTurns) {
|
|
869
|
-
messages = messages.slice(-this.config.memory.maxTurns * 2); // user + assistant = 2 messages per turn
|
|
870
|
-
}
|
|
871
|
-
// Limitar por tokens (aproximado)
|
|
872
|
-
if (this.config.memory.maxTokens) {
|
|
873
|
-
let totalTokens = 0;
|
|
874
|
-
const filteredMessages = [];
|
|
875
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
876
|
-
const messageTokens = Math.ceil(messages[i].content.length / 4);
|
|
877
|
-
if (totalTokens + messageTokens <= this.config.memory.maxTokens) {
|
|
878
|
-
filteredMessages.unshift(messages[i]);
|
|
879
|
-
totalTokens += messageTokens;
|
|
880
|
-
}
|
|
881
|
-
else {
|
|
882
|
-
break;
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
messages = filteredMessages;
|
|
886
|
-
}
|
|
887
|
-
// Retornar messages como array (formato nativo do LLM)
|
|
888
|
-
const result = messages.map((msg) => ({
|
|
889
|
-
role: msg.role,
|
|
890
|
-
content: msg.content,
|
|
891
|
-
}));
|
|
892
|
-
// 🔍 Finalizar trace (com dados completos se debug ativado)
|
|
893
|
-
const memoryOutput = {
|
|
894
|
-
messagesCount: messages.length,
|
|
895
|
-
hasHistory: result.length > 0,
|
|
896
|
-
};
|
|
897
|
-
if (this.debugConfig.logMemory) {
|
|
898
|
-
memoryOutput.messages = result;
|
|
899
|
-
}
|
|
900
|
-
memoryLoadSpan?.setOutput(memoryOutput);
|
|
901
|
-
memoryLoadSpan?.setMetadata({
|
|
902
|
-
operation: 'load',
|
|
903
|
-
memoryId,
|
|
904
|
-
messagesCount: messages.length,
|
|
905
|
-
maxTurns: this.config.memory.maxTurns,
|
|
906
|
-
processingTimeMs: Date.now() - memoryLoadStartTime,
|
|
907
|
-
success: true,
|
|
908
|
-
});
|
|
909
|
-
memoryLoadSpan?.finish();
|
|
910
|
-
return result;
|
|
911
|
-
}
|
|
912
|
-
catch (error) {
|
|
913
|
-
console.error('Failed to load memory:', error);
|
|
914
|
-
// 🔍 Trace de erro
|
|
915
|
-
memoryLoadSpan?.setMetadata({
|
|
916
|
-
operation: 'load',
|
|
917
|
-
memoryId,
|
|
918
|
-
success: false,
|
|
919
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
920
|
-
processingTimeMs: Date.now() - memoryLoadStartTime,
|
|
921
|
-
});
|
|
922
|
-
memoryLoadSpan?.finish();
|
|
923
|
-
return [];
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
// Salvar na memória
|
|
927
|
-
async saveToMemory(memoryId, userMessage, assistantMessage) {
|
|
928
|
-
if (!this.apiClient || !this.config.memory) {
|
|
929
|
-
return;
|
|
930
|
-
}
|
|
931
|
-
// 🔍 Trace: Memory Save
|
|
932
|
-
const memorySaveStartTime = Date.now();
|
|
933
|
-
const memorySaveSpan = this.traceCollector?.startSpan('memory_operation', {
|
|
934
|
-
operation: 'save',
|
|
935
|
-
memoryId,
|
|
936
|
-
memoryType: this.config.memory.type,
|
|
937
|
-
});
|
|
938
|
-
try {
|
|
939
|
-
// Adicionar mensagem do usuário
|
|
940
|
-
await this.apiClient.memory.append(memoryId, {
|
|
941
|
-
role: 'user',
|
|
942
|
-
content: userMessage,
|
|
943
|
-
timestamp: new Date(),
|
|
944
|
-
});
|
|
945
|
-
// Adicionar resposta do assistant
|
|
946
|
-
await this.apiClient.memory.append(memoryId, {
|
|
947
|
-
role: 'assistant',
|
|
948
|
-
content: assistantMessage,
|
|
949
|
-
timestamp: new Date(),
|
|
950
|
-
metadata: {
|
|
951
|
-
model: this.config.model.model,
|
|
952
|
-
},
|
|
953
|
-
});
|
|
954
|
-
// Resumir se necessário
|
|
955
|
-
let summarized = false;
|
|
956
|
-
if (this.config.memory.summarizeAfter) {
|
|
957
|
-
const currentMemory = await this.apiClient.memory.get(memoryId);
|
|
958
|
-
if (currentMemory.messages.length >= this.config.memory.summarizeAfter) {
|
|
959
|
-
await this.apiClient.memory.summarize(memoryId);
|
|
960
|
-
summarized = true;
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
// 🔍 Finalizar trace (com dados completos se debug ativado)
|
|
964
|
-
const memorySaveOutput = {
|
|
965
|
-
messagesSaved: 2,
|
|
966
|
-
summarized,
|
|
967
|
-
};
|
|
968
|
-
if (this.debugConfig.logMemory) {
|
|
969
|
-
memorySaveOutput.userMessage = userMessage;
|
|
970
|
-
memorySaveOutput.assistantMessage = assistantMessage;
|
|
971
|
-
}
|
|
972
|
-
memorySaveSpan?.setOutput(memorySaveOutput);
|
|
973
|
-
memorySaveSpan?.setMetadata({
|
|
974
|
-
operation: 'save',
|
|
975
|
-
memoryId,
|
|
976
|
-
messagesSaved: 2,
|
|
977
|
-
summarized,
|
|
978
|
-
summarizeAfter: this.config.memory.summarizeAfter,
|
|
979
|
-
processingTimeMs: Date.now() - memorySaveStartTime,
|
|
980
|
-
success: true,
|
|
981
|
-
});
|
|
982
|
-
memorySaveSpan?.finish();
|
|
983
|
-
}
|
|
984
|
-
catch (error) {
|
|
985
|
-
console.error('Failed to save to memory:', error);
|
|
986
|
-
// 🔍 Trace de erro
|
|
987
|
-
memorySaveSpan?.setMetadata({
|
|
988
|
-
operation: 'save',
|
|
989
|
-
memoryId,
|
|
990
|
-
success: false,
|
|
991
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
992
|
-
processingTimeMs: Date.now() - memorySaveStartTime,
|
|
993
|
-
});
|
|
994
|
-
memorySaveSpan?.finish();
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
// Processar stream chunks (helper)
|
|
998
|
-
async *processStreamChunks(stream) {
|
|
999
|
-
for await (const chunk of stream) {
|
|
1000
|
-
if (chunk.type === 'content') {
|
|
1001
|
-
yield { text: chunk.content || '', done: false };
|
|
1002
|
-
}
|
|
1003
|
-
else if (chunk.type === 'done') {
|
|
1004
|
-
yield { text: '', done: true };
|
|
1005
|
-
break;
|
|
1006
|
-
}
|
|
1007
|
-
else if (chunk.type === 'error') {
|
|
1008
|
-
throw new Error(chunk.error || 'Streaming error');
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
695
|
// Streaming com memória
|
|
1013
696
|
async processStream(input, context) {
|
|
697
|
+
this.logger.debug('Starting stream processing', {
|
|
698
|
+
messageLength: input.message?.length || 0,
|
|
699
|
+
sessionId: input.sessionId
|
|
700
|
+
});
|
|
1014
701
|
if (context?.apiClient) {
|
|
1015
702
|
this.apiClient = context.apiClient;
|
|
1016
703
|
}
|
|
1017
704
|
// Resolver entity context
|
|
1018
705
|
const state = context_1.Runflow.getState();
|
|
1019
|
-
const entityType = input.entityType || state.entityType ||
|
|
1020
|
-
const entityValue = input.entityValue || state.entityValue ||
|
|
706
|
+
const entityType = input.entityType || state.entityType || (0, agent_context_1.inferEntityType)(input, this.logger);
|
|
707
|
+
const entityValue = input.entityValue || state.entityValue || (0, agent_context_1.inferEntityValue)(input, this.logger);
|
|
1021
708
|
// Resolver memoryId com mesma prioridade do process()
|
|
1022
709
|
let memoryId = null;
|
|
1023
710
|
if (this.config.memory) {
|
|
@@ -1037,7 +724,8 @@ Which agent should handle this? Respond with just the agent name.
|
|
|
1037
724
|
// Carregar memória se configurado
|
|
1038
725
|
let memoryMessages = [];
|
|
1039
726
|
if (this.config.memory && memoryId) {
|
|
1040
|
-
|
|
727
|
+
this.logger.debug('Loading memory for streaming', { memoryId });
|
|
728
|
+
memoryMessages = await (0, agent_memory_1.loadMemory)(memoryId, this.apiClient, this.config.memory, this.traceCollector, this.logger);
|
|
1041
729
|
}
|
|
1042
730
|
// ============================================================================
|
|
1043
731
|
// RAG agora é TOOL - LLM decide quando buscar
|
|
@@ -1073,6 +761,11 @@ Which agent should handle this? Respond with just the agent name.
|
|
|
1073
761
|
});
|
|
1074
762
|
// Criar async generator
|
|
1075
763
|
const self = this;
|
|
764
|
+
const logger = this.logger;
|
|
765
|
+
const apiClient = this.apiClient;
|
|
766
|
+
const memoryConfig = this.config.memory;
|
|
767
|
+
const modelConfig = this.config.model;
|
|
768
|
+
const traceCollector = this.traceCollector;
|
|
1076
769
|
return (async function* () {
|
|
1077
770
|
let fullResponse = '';
|
|
1078
771
|
for await (const chunk of stream) {
|
|
@@ -1082,13 +775,18 @@ Which agent should handle this? Respond with just the agent name.
|
|
|
1082
775
|
}
|
|
1083
776
|
else if (chunk.type === 'done') {
|
|
1084
777
|
// Salvar na memória quando streaming terminar
|
|
1085
|
-
if (
|
|
1086
|
-
|
|
778
|
+
if (memoryConfig && memoryId && apiClient) {
|
|
779
|
+
logger.debug('Saving stream response to memory', { memoryId });
|
|
780
|
+
await (0, agent_memory_1.saveToMemory)(memoryId, input.message, fullResponse, apiClient, memoryConfig, modelConfig, traceCollector, logger);
|
|
1087
781
|
}
|
|
782
|
+
logger.info('Stream processing completed', {
|
|
783
|
+
responseLength: fullResponse.length
|
|
784
|
+
});
|
|
1088
785
|
yield { text: '', done: true };
|
|
1089
786
|
break;
|
|
1090
787
|
}
|
|
1091
788
|
else if (chunk.type === 'error') {
|
|
789
|
+
logger.error('Streaming error', { error: chunk.error });
|
|
1092
790
|
throw new Error(chunk.error || 'Streaming error');
|
|
1093
791
|
}
|
|
1094
792
|
}
|