@agentforge/patterns 0.15.9 → 0.15.10
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/index.cjs +106 -67
- package/dist/index.js +112 -68
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -343,54 +343,101 @@ function handleNodeError(error, context, verbose = false) {
|
|
|
343
343
|
var reasoningLogger = createPatternLogger("agentforge:patterns:react:reasoning");
|
|
344
344
|
var actionLogger = createPatternLogger("agentforge:patterns:react:action");
|
|
345
345
|
var observationLogger = createPatternLogger("agentforge:patterns:react:observation");
|
|
346
|
+
function normalizeConversationMessage(message) {
|
|
347
|
+
switch (message.role) {
|
|
348
|
+
case "user":
|
|
349
|
+
return new import_messages.HumanMessage(message.content);
|
|
350
|
+
case "assistant":
|
|
351
|
+
return new import_messages.AIMessage(message.content);
|
|
352
|
+
case "system":
|
|
353
|
+
return new import_messages.SystemMessage(message.content);
|
|
354
|
+
case "tool":
|
|
355
|
+
if (!message.tool_call_id) {
|
|
356
|
+
reasoningLogger.warn(
|
|
357
|
+
"Tool message missing tool_call_id; falling back to human message",
|
|
358
|
+
message.name ? { name: message.name } : void 0
|
|
359
|
+
);
|
|
360
|
+
return new import_messages.HumanMessage(message.content);
|
|
361
|
+
}
|
|
362
|
+
return new import_messages.ToolMessage({
|
|
363
|
+
content: message.content,
|
|
364
|
+
tool_call_id: message.tool_call_id,
|
|
365
|
+
name: message.name
|
|
366
|
+
});
|
|
367
|
+
default:
|
|
368
|
+
return new import_messages.HumanMessage(message.content);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function buildReasoningMessages(systemPrompt, stateMessages, scratchpad) {
|
|
372
|
+
const messages = [
|
|
373
|
+
new import_messages.SystemMessage(systemPrompt),
|
|
374
|
+
...stateMessages.map(normalizeConversationMessage)
|
|
375
|
+
];
|
|
376
|
+
if (scratchpad.length > 0) {
|
|
377
|
+
messages.push(new import_messages.SystemMessage(`Previous steps:
|
|
378
|
+
${formatScratchpad(scratchpad)}`));
|
|
379
|
+
}
|
|
380
|
+
return messages;
|
|
381
|
+
}
|
|
382
|
+
function extractToolCalls(response) {
|
|
383
|
+
if (!response.tool_calls || response.tool_calls.length === 0) {
|
|
384
|
+
return [];
|
|
385
|
+
}
|
|
386
|
+
return response.tool_calls.map((toolCall) => ({
|
|
387
|
+
id: toolCall.id || `call_${Date.now()}_${Math.random()}`,
|
|
388
|
+
name: toolCall.name,
|
|
389
|
+
arguments: toolCall.args ?? {},
|
|
390
|
+
timestamp: Date.now()
|
|
391
|
+
}));
|
|
392
|
+
}
|
|
393
|
+
function formatObservationContent(observation) {
|
|
394
|
+
if (observation.error) {
|
|
395
|
+
return `Error: ${observation.error}`;
|
|
396
|
+
}
|
|
397
|
+
return stringifyObservationResult(observation.result, 2);
|
|
398
|
+
}
|
|
399
|
+
function formatActionSummary(actions) {
|
|
400
|
+
return actions.map((action) => `${action.name}(${JSON.stringify(action.arguments)})`).join(", ");
|
|
401
|
+
}
|
|
402
|
+
function formatObservationSummary(observations) {
|
|
403
|
+
return observations.map((observation) => {
|
|
404
|
+
if (observation.error) {
|
|
405
|
+
return `Error: ${observation.error}`;
|
|
406
|
+
}
|
|
407
|
+
return stringifyObservationResult(observation.result);
|
|
408
|
+
}).join("; ");
|
|
409
|
+
}
|
|
410
|
+
function stringifyObservationResult(result, space) {
|
|
411
|
+
if (typeof result === "string") {
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
const stringified = JSON.stringify(result, null, space);
|
|
415
|
+
return stringified ?? String(result);
|
|
416
|
+
}
|
|
417
|
+
function getLatestThought(thoughts) {
|
|
418
|
+
return thoughts[thoughts.length - 1]?.content ?? "";
|
|
419
|
+
}
|
|
420
|
+
function debugIfVerbose(logger4, verbose, message, data) {
|
|
421
|
+
if (verbose) {
|
|
422
|
+
logger4.debug(message, data);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
346
425
|
function createReasoningNode(llm, tools, systemPrompt, maxIterations, verbose = false) {
|
|
347
426
|
const langchainTools = (0, import_core3.toLangChainTools)(tools);
|
|
348
427
|
const llmWithTools = llm.bindTools ? llm.bindTools(langchainTools) : llm;
|
|
349
428
|
return async (state) => {
|
|
350
429
|
const currentIteration = state.iteration || 0;
|
|
351
430
|
const startTime = Date.now();
|
|
352
|
-
reasoningLogger
|
|
431
|
+
debugIfVerbose(reasoningLogger, verbose, "Reasoning iteration started", {
|
|
353
432
|
iteration: currentIteration + 1,
|
|
354
433
|
maxIterations,
|
|
355
|
-
observationCount: state.observations
|
|
356
|
-
hasActions:
|
|
434
|
+
observationCount: state.observations.length,
|
|
435
|
+
hasActions: state.actions.length > 0
|
|
357
436
|
});
|
|
358
|
-
const
|
|
359
|
-
const messages = [
|
|
360
|
-
new import_messages.SystemMessage(systemPrompt),
|
|
361
|
-
...stateMessages.map((msg) => {
|
|
362
|
-
if (msg.role === "user") return new import_messages.HumanMessage(msg.content);
|
|
363
|
-
if (msg.role === "assistant") return new import_messages.AIMessage(msg.content);
|
|
364
|
-
if (msg.role === "system") return new import_messages.SystemMessage(msg.content);
|
|
365
|
-
if (msg.role === "tool") {
|
|
366
|
-
return new import_messages.ToolMessage({
|
|
367
|
-
content: msg.content,
|
|
368
|
-
tool_call_id: msg.tool_call_id,
|
|
369
|
-
name: msg.name
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
return new import_messages.HumanMessage(msg.content);
|
|
373
|
-
})
|
|
374
|
-
];
|
|
375
|
-
const scratchpad = state.scratchpad || [];
|
|
376
|
-
if (scratchpad.length > 0) {
|
|
377
|
-
const scratchpadText = formatScratchpad(scratchpad);
|
|
378
|
-
messages.push(new import_messages.SystemMessage(`Previous steps:
|
|
379
|
-
${scratchpadText}`));
|
|
380
|
-
}
|
|
437
|
+
const messages = buildReasoningMessages(systemPrompt, state.messages, state.scratchpad);
|
|
381
438
|
const response = await llmWithTools.invoke(messages);
|
|
382
439
|
const thought = typeof response.content === "string" ? response.content : "";
|
|
383
|
-
const toolCalls =
|
|
384
|
-
if (response.tool_calls && response.tool_calls.length > 0) {
|
|
385
|
-
for (const toolCall of response.tool_calls) {
|
|
386
|
-
toolCalls.push({
|
|
387
|
-
id: toolCall.id || `call_${Date.now()}_${Math.random()}`,
|
|
388
|
-
name: toolCall.name,
|
|
389
|
-
arguments: toolCall.args || {},
|
|
390
|
-
timestamp: Date.now()
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
}
|
|
440
|
+
const toolCalls = extractToolCalls(response);
|
|
394
441
|
const shouldContinue = toolCalls.length > 0 && currentIteration + 1 < maxIterations;
|
|
395
442
|
reasoningLogger.info("Reasoning complete", {
|
|
396
443
|
iteration: currentIteration + 1,
|
|
@@ -415,11 +462,11 @@ ${scratchpadText}`));
|
|
|
415
462
|
function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
416
463
|
const toolMap = new Map(tools.map((tool) => [tool.metadata.name, tool]));
|
|
417
464
|
return async (state) => {
|
|
418
|
-
const actions = state.actions
|
|
419
|
-
const allObservations = state.observations
|
|
465
|
+
const actions = state.actions;
|
|
466
|
+
const allObservations = state.observations;
|
|
420
467
|
const iteration = state.iteration || 0;
|
|
421
468
|
const startTime = Date.now();
|
|
422
|
-
actionLogger
|
|
469
|
+
debugIfVerbose(actionLogger, verbose, "Action node started", {
|
|
423
470
|
actionCount: actions.length,
|
|
424
471
|
iteration,
|
|
425
472
|
cacheEnabled: enableDeduplication
|
|
@@ -438,7 +485,7 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
438
485
|
}
|
|
439
486
|
}
|
|
440
487
|
if (cacheSize > 0) {
|
|
441
|
-
actionLogger
|
|
488
|
+
debugIfVerbose(actionLogger, verbose, "Deduplication cache built", {
|
|
442
489
|
cacheSize,
|
|
443
490
|
totalObservations: allObservations.length
|
|
444
491
|
});
|
|
@@ -449,7 +496,7 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
449
496
|
for (const action of recentActions) {
|
|
450
497
|
const existingObservation = allObservations.find((obs) => obs.toolCallId === action.id);
|
|
451
498
|
if (existingObservation) {
|
|
452
|
-
actionLogger
|
|
499
|
+
debugIfVerbose(actionLogger, verbose, "Skipping already-processed action", {
|
|
453
500
|
toolName: action.name,
|
|
454
501
|
toolCallId: action.id,
|
|
455
502
|
iteration
|
|
@@ -492,7 +539,7 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
492
539
|
const result = await tool.invoke(action.arguments);
|
|
493
540
|
const executionTime = Date.now() - startTime2;
|
|
494
541
|
toolsExecuted++;
|
|
495
|
-
actionLogger
|
|
542
|
+
debugIfVerbose(actionLogger, verbose, "Tool executed successfully", {
|
|
496
543
|
toolName: action.name,
|
|
497
544
|
executionTime,
|
|
498
545
|
iteration
|
|
@@ -508,7 +555,7 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
508
555
|
executionCache.set(cacheKey, observation);
|
|
509
556
|
}
|
|
510
557
|
} catch (error) {
|
|
511
|
-
const errorMessage = handleNodeError(error, `action:${action.name}`,
|
|
558
|
+
const errorMessage = handleNodeError(error, `action:${action.name}`, verbose);
|
|
512
559
|
actionLogger.error("Tool execution failed", {
|
|
513
560
|
toolName: action.name,
|
|
514
561
|
error: errorMessage,
|
|
@@ -537,39 +584,31 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
537
584
|
}
|
|
538
585
|
function createObservationNode(verbose = false, returnIntermediateSteps = false) {
|
|
539
586
|
return async (state) => {
|
|
540
|
-
const observations = state.observations
|
|
541
|
-
const thoughts = state.thoughts
|
|
542
|
-
const actions = state.actions
|
|
587
|
+
const observations = state.observations;
|
|
588
|
+
const thoughts = state.thoughts;
|
|
589
|
+
const actions = state.actions;
|
|
543
590
|
const iteration = state.iteration || 0;
|
|
544
|
-
observationLogger
|
|
591
|
+
debugIfVerbose(observationLogger, verbose, "Processing observations", {
|
|
545
592
|
observationCount: observations.length,
|
|
546
593
|
iteration
|
|
547
594
|
});
|
|
548
595
|
const recentObservations = observations.slice(-10);
|
|
549
596
|
const latestActions = actions.slice(-10);
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
// Include tool_call_id for proper ToolMessage construction
|
|
558
|
-
};
|
|
559
|
-
});
|
|
597
|
+
const actionNamesById = new Map(latestActions.map((action) => [action.id, action.name]));
|
|
598
|
+
const observationMessages = recentObservations.map((observation) => ({
|
|
599
|
+
role: "tool",
|
|
600
|
+
content: formatObservationContent(observation),
|
|
601
|
+
name: actionNamesById.get(observation.toolCallId),
|
|
602
|
+
tool_call_id: observation.toolCallId
|
|
603
|
+
}));
|
|
560
604
|
const scratchpadEntries = returnIntermediateSteps ? [{
|
|
561
605
|
step: state.iteration,
|
|
562
|
-
thought: thoughts
|
|
563
|
-
action: latestActions
|
|
564
|
-
observation: recentObservations
|
|
565
|
-
if (obs.error) {
|
|
566
|
-
return `Error: ${obs.error}`;
|
|
567
|
-
}
|
|
568
|
-
return typeof obs.result === "string" ? obs.result : JSON.stringify(obs.result);
|
|
569
|
-
}).join("; "),
|
|
606
|
+
thought: getLatestThought(thoughts),
|
|
607
|
+
action: formatActionSummary(latestActions),
|
|
608
|
+
observation: formatObservationSummary(recentObservations),
|
|
570
609
|
timestamp: Date.now()
|
|
571
610
|
}] : [];
|
|
572
|
-
observationLogger
|
|
611
|
+
debugIfVerbose(observationLogger, verbose, "Observation node complete", {
|
|
573
612
|
iteration,
|
|
574
613
|
scratchpadUpdated: returnIntermediateSteps,
|
|
575
614
|
messageCount: observationMessages.length
|
package/dist/index.js
CHANGED
|
@@ -171,7 +171,12 @@ function formatScratchpad(scratchpad) {
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
// src/react/nodes.ts
|
|
174
|
-
import {
|
|
174
|
+
import {
|
|
175
|
+
HumanMessage,
|
|
176
|
+
AIMessage,
|
|
177
|
+
SystemMessage,
|
|
178
|
+
ToolMessage
|
|
179
|
+
} from "@langchain/core/messages";
|
|
175
180
|
import { toLangChainTools } from "@agentforge/core";
|
|
176
181
|
|
|
177
182
|
// src/shared/deduplication.ts
|
|
@@ -240,54 +245,101 @@ function handleNodeError(error, context, verbose = false) {
|
|
|
240
245
|
var reasoningLogger = createPatternLogger("agentforge:patterns:react:reasoning");
|
|
241
246
|
var actionLogger = createPatternLogger("agentforge:patterns:react:action");
|
|
242
247
|
var observationLogger = createPatternLogger("agentforge:patterns:react:observation");
|
|
248
|
+
function normalizeConversationMessage(message) {
|
|
249
|
+
switch (message.role) {
|
|
250
|
+
case "user":
|
|
251
|
+
return new HumanMessage(message.content);
|
|
252
|
+
case "assistant":
|
|
253
|
+
return new AIMessage(message.content);
|
|
254
|
+
case "system":
|
|
255
|
+
return new SystemMessage(message.content);
|
|
256
|
+
case "tool":
|
|
257
|
+
if (!message.tool_call_id) {
|
|
258
|
+
reasoningLogger.warn(
|
|
259
|
+
"Tool message missing tool_call_id; falling back to human message",
|
|
260
|
+
message.name ? { name: message.name } : void 0
|
|
261
|
+
);
|
|
262
|
+
return new HumanMessage(message.content);
|
|
263
|
+
}
|
|
264
|
+
return new ToolMessage({
|
|
265
|
+
content: message.content,
|
|
266
|
+
tool_call_id: message.tool_call_id,
|
|
267
|
+
name: message.name
|
|
268
|
+
});
|
|
269
|
+
default:
|
|
270
|
+
return new HumanMessage(message.content);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function buildReasoningMessages(systemPrompt, stateMessages, scratchpad) {
|
|
274
|
+
const messages = [
|
|
275
|
+
new SystemMessage(systemPrompt),
|
|
276
|
+
...stateMessages.map(normalizeConversationMessage)
|
|
277
|
+
];
|
|
278
|
+
if (scratchpad.length > 0) {
|
|
279
|
+
messages.push(new SystemMessage(`Previous steps:
|
|
280
|
+
${formatScratchpad(scratchpad)}`));
|
|
281
|
+
}
|
|
282
|
+
return messages;
|
|
283
|
+
}
|
|
284
|
+
function extractToolCalls(response) {
|
|
285
|
+
if (!response.tool_calls || response.tool_calls.length === 0) {
|
|
286
|
+
return [];
|
|
287
|
+
}
|
|
288
|
+
return response.tool_calls.map((toolCall) => ({
|
|
289
|
+
id: toolCall.id || `call_${Date.now()}_${Math.random()}`,
|
|
290
|
+
name: toolCall.name,
|
|
291
|
+
arguments: toolCall.args ?? {},
|
|
292
|
+
timestamp: Date.now()
|
|
293
|
+
}));
|
|
294
|
+
}
|
|
295
|
+
function formatObservationContent(observation) {
|
|
296
|
+
if (observation.error) {
|
|
297
|
+
return `Error: ${observation.error}`;
|
|
298
|
+
}
|
|
299
|
+
return stringifyObservationResult(observation.result, 2);
|
|
300
|
+
}
|
|
301
|
+
function formatActionSummary(actions) {
|
|
302
|
+
return actions.map((action) => `${action.name}(${JSON.stringify(action.arguments)})`).join(", ");
|
|
303
|
+
}
|
|
304
|
+
function formatObservationSummary(observations) {
|
|
305
|
+
return observations.map((observation) => {
|
|
306
|
+
if (observation.error) {
|
|
307
|
+
return `Error: ${observation.error}`;
|
|
308
|
+
}
|
|
309
|
+
return stringifyObservationResult(observation.result);
|
|
310
|
+
}).join("; ");
|
|
311
|
+
}
|
|
312
|
+
function stringifyObservationResult(result, space) {
|
|
313
|
+
if (typeof result === "string") {
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
const stringified = JSON.stringify(result, null, space);
|
|
317
|
+
return stringified ?? String(result);
|
|
318
|
+
}
|
|
319
|
+
function getLatestThought(thoughts) {
|
|
320
|
+
return thoughts[thoughts.length - 1]?.content ?? "";
|
|
321
|
+
}
|
|
322
|
+
function debugIfVerbose(logger4, verbose, message, data) {
|
|
323
|
+
if (verbose) {
|
|
324
|
+
logger4.debug(message, data);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
243
327
|
function createReasoningNode(llm, tools, systemPrompt, maxIterations, verbose = false) {
|
|
244
328
|
const langchainTools = toLangChainTools(tools);
|
|
245
329
|
const llmWithTools = llm.bindTools ? llm.bindTools(langchainTools) : llm;
|
|
246
330
|
return async (state) => {
|
|
247
331
|
const currentIteration = state.iteration || 0;
|
|
248
332
|
const startTime = Date.now();
|
|
249
|
-
reasoningLogger
|
|
333
|
+
debugIfVerbose(reasoningLogger, verbose, "Reasoning iteration started", {
|
|
250
334
|
iteration: currentIteration + 1,
|
|
251
335
|
maxIterations,
|
|
252
|
-
observationCount: state.observations
|
|
253
|
-
hasActions:
|
|
336
|
+
observationCount: state.observations.length,
|
|
337
|
+
hasActions: state.actions.length > 0
|
|
254
338
|
});
|
|
255
|
-
const
|
|
256
|
-
const messages = [
|
|
257
|
-
new SystemMessage(systemPrompt),
|
|
258
|
-
...stateMessages.map((msg) => {
|
|
259
|
-
if (msg.role === "user") return new HumanMessage(msg.content);
|
|
260
|
-
if (msg.role === "assistant") return new AIMessage(msg.content);
|
|
261
|
-
if (msg.role === "system") return new SystemMessage(msg.content);
|
|
262
|
-
if (msg.role === "tool") {
|
|
263
|
-
return new ToolMessage({
|
|
264
|
-
content: msg.content,
|
|
265
|
-
tool_call_id: msg.tool_call_id,
|
|
266
|
-
name: msg.name
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
return new HumanMessage(msg.content);
|
|
270
|
-
})
|
|
271
|
-
];
|
|
272
|
-
const scratchpad = state.scratchpad || [];
|
|
273
|
-
if (scratchpad.length > 0) {
|
|
274
|
-
const scratchpadText = formatScratchpad(scratchpad);
|
|
275
|
-
messages.push(new SystemMessage(`Previous steps:
|
|
276
|
-
${scratchpadText}`));
|
|
277
|
-
}
|
|
339
|
+
const messages = buildReasoningMessages(systemPrompt, state.messages, state.scratchpad);
|
|
278
340
|
const response = await llmWithTools.invoke(messages);
|
|
279
341
|
const thought = typeof response.content === "string" ? response.content : "";
|
|
280
|
-
const toolCalls =
|
|
281
|
-
if (response.tool_calls && response.tool_calls.length > 0) {
|
|
282
|
-
for (const toolCall of response.tool_calls) {
|
|
283
|
-
toolCalls.push({
|
|
284
|
-
id: toolCall.id || `call_${Date.now()}_${Math.random()}`,
|
|
285
|
-
name: toolCall.name,
|
|
286
|
-
arguments: toolCall.args || {},
|
|
287
|
-
timestamp: Date.now()
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
}
|
|
342
|
+
const toolCalls = extractToolCalls(response);
|
|
291
343
|
const shouldContinue = toolCalls.length > 0 && currentIteration + 1 < maxIterations;
|
|
292
344
|
reasoningLogger.info("Reasoning complete", {
|
|
293
345
|
iteration: currentIteration + 1,
|
|
@@ -312,11 +364,11 @@ ${scratchpadText}`));
|
|
|
312
364
|
function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
313
365
|
const toolMap = new Map(tools.map((tool) => [tool.metadata.name, tool]));
|
|
314
366
|
return async (state) => {
|
|
315
|
-
const actions = state.actions
|
|
316
|
-
const allObservations = state.observations
|
|
367
|
+
const actions = state.actions;
|
|
368
|
+
const allObservations = state.observations;
|
|
317
369
|
const iteration = state.iteration || 0;
|
|
318
370
|
const startTime = Date.now();
|
|
319
|
-
actionLogger
|
|
371
|
+
debugIfVerbose(actionLogger, verbose, "Action node started", {
|
|
320
372
|
actionCount: actions.length,
|
|
321
373
|
iteration,
|
|
322
374
|
cacheEnabled: enableDeduplication
|
|
@@ -335,7 +387,7 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
335
387
|
}
|
|
336
388
|
}
|
|
337
389
|
if (cacheSize > 0) {
|
|
338
|
-
actionLogger
|
|
390
|
+
debugIfVerbose(actionLogger, verbose, "Deduplication cache built", {
|
|
339
391
|
cacheSize,
|
|
340
392
|
totalObservations: allObservations.length
|
|
341
393
|
});
|
|
@@ -346,7 +398,7 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
346
398
|
for (const action of recentActions) {
|
|
347
399
|
const existingObservation = allObservations.find((obs) => obs.toolCallId === action.id);
|
|
348
400
|
if (existingObservation) {
|
|
349
|
-
actionLogger
|
|
401
|
+
debugIfVerbose(actionLogger, verbose, "Skipping already-processed action", {
|
|
350
402
|
toolName: action.name,
|
|
351
403
|
toolCallId: action.id,
|
|
352
404
|
iteration
|
|
@@ -389,7 +441,7 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
389
441
|
const result = await tool.invoke(action.arguments);
|
|
390
442
|
const executionTime = Date.now() - startTime2;
|
|
391
443
|
toolsExecuted++;
|
|
392
|
-
actionLogger
|
|
444
|
+
debugIfVerbose(actionLogger, verbose, "Tool executed successfully", {
|
|
393
445
|
toolName: action.name,
|
|
394
446
|
executionTime,
|
|
395
447
|
iteration
|
|
@@ -405,7 +457,7 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
405
457
|
executionCache.set(cacheKey, observation);
|
|
406
458
|
}
|
|
407
459
|
} catch (error) {
|
|
408
|
-
const errorMessage = handleNodeError(error, `action:${action.name}`,
|
|
460
|
+
const errorMessage = handleNodeError(error, `action:${action.name}`, verbose);
|
|
409
461
|
actionLogger.error("Tool execution failed", {
|
|
410
462
|
toolName: action.name,
|
|
411
463
|
error: errorMessage,
|
|
@@ -434,39 +486,31 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
434
486
|
}
|
|
435
487
|
function createObservationNode(verbose = false, returnIntermediateSteps = false) {
|
|
436
488
|
return async (state) => {
|
|
437
|
-
const observations = state.observations
|
|
438
|
-
const thoughts = state.thoughts
|
|
439
|
-
const actions = state.actions
|
|
489
|
+
const observations = state.observations;
|
|
490
|
+
const thoughts = state.thoughts;
|
|
491
|
+
const actions = state.actions;
|
|
440
492
|
const iteration = state.iteration || 0;
|
|
441
|
-
observationLogger
|
|
493
|
+
debugIfVerbose(observationLogger, verbose, "Processing observations", {
|
|
442
494
|
observationCount: observations.length,
|
|
443
495
|
iteration
|
|
444
496
|
});
|
|
445
497
|
const recentObservations = observations.slice(-10);
|
|
446
498
|
const latestActions = actions.slice(-10);
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
// Include tool_call_id for proper ToolMessage construction
|
|
455
|
-
};
|
|
456
|
-
});
|
|
499
|
+
const actionNamesById = new Map(latestActions.map((action) => [action.id, action.name]));
|
|
500
|
+
const observationMessages = recentObservations.map((observation) => ({
|
|
501
|
+
role: "tool",
|
|
502
|
+
content: formatObservationContent(observation),
|
|
503
|
+
name: actionNamesById.get(observation.toolCallId),
|
|
504
|
+
tool_call_id: observation.toolCallId
|
|
505
|
+
}));
|
|
457
506
|
const scratchpadEntries = returnIntermediateSteps ? [{
|
|
458
507
|
step: state.iteration,
|
|
459
|
-
thought: thoughts
|
|
460
|
-
action: latestActions
|
|
461
|
-
observation: recentObservations
|
|
462
|
-
if (obs.error) {
|
|
463
|
-
return `Error: ${obs.error}`;
|
|
464
|
-
}
|
|
465
|
-
return typeof obs.result === "string" ? obs.result : JSON.stringify(obs.result);
|
|
466
|
-
}).join("; "),
|
|
508
|
+
thought: getLatestThought(thoughts),
|
|
509
|
+
action: formatActionSummary(latestActions),
|
|
510
|
+
observation: formatObservationSummary(recentObservations),
|
|
467
511
|
timestamp: Date.now()
|
|
468
512
|
}] : [];
|
|
469
|
-
observationLogger
|
|
513
|
+
debugIfVerbose(observationLogger, verbose, "Observation node complete", {
|
|
470
514
|
iteration,
|
|
471
515
|
scratchpadUpdated: returnIntermediateSteps,
|
|
472
516
|
messageCount: observationMessages.length
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentforge/patterns",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.10",
|
|
4
4
|
"description": "Production-ready agent workflow patterns for TypeScript including ReAct and Planner-Executor, built on LangGraph.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
"url": "https://github.com/TVScoundrel/agentforge/issues"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@agentforge/core": "0.15.
|
|
44
|
+
"@agentforge/core": "0.15.10",
|
|
45
45
|
"@langchain/core": "^1.1.17",
|
|
46
46
|
"@langchain/langgraph": "^1.1.2",
|
|
47
47
|
"zod": "^3.23.8"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@agentforge/testing": "0.15.
|
|
50
|
+
"@agentforge/testing": "0.15.10",
|
|
51
51
|
"@eslint/js": "^9.17.0",
|
|
52
52
|
"@types/node": "^22.10.2",
|
|
53
53
|
"eslint": "^9.17.0",
|