@agentforge/patterns 0.15.10 → 0.15.12
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 +86 -47
- package/dist/index.js +86 -47
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -273,10 +273,12 @@ function formatScratchpad(scratchpad) {
|
|
|
273
273
|
}).join("\n\n");
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
-
// src/react/nodes.ts
|
|
277
|
-
var import_messages = require("@langchain/core/messages");
|
|
276
|
+
// src/react/nodes/reasoning.ts
|
|
278
277
|
var import_core3 = require("@agentforge/core");
|
|
279
278
|
|
|
279
|
+
// src/react/nodes/shared.ts
|
|
280
|
+
var import_messages = require("@langchain/core/messages");
|
|
281
|
+
|
|
280
282
|
// src/shared/deduplication.ts
|
|
281
283
|
var import_core2 = require("@agentforge/core");
|
|
282
284
|
function normalizeObject(obj) {
|
|
@@ -321,25 +323,7 @@ function buildDeduplicationMetrics(toolsExecuted, duplicatesSkipped, totalObserv
|
|
|
321
323
|
};
|
|
322
324
|
}
|
|
323
325
|
|
|
324
|
-
// src/shared
|
|
325
|
-
function isGraphInterrupt(error) {
|
|
326
|
-
return error !== null && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt";
|
|
327
|
-
}
|
|
328
|
-
function handleNodeError(error, context, verbose = false) {
|
|
329
|
-
if (isGraphInterrupt(error)) {
|
|
330
|
-
throw error;
|
|
331
|
-
}
|
|
332
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
333
|
-
if (verbose) {
|
|
334
|
-
console.error(`[${context}] Error:`, errorMessage);
|
|
335
|
-
if (error instanceof Error && error.stack) {
|
|
336
|
-
console.error(`[${context}] Stack:`, error.stack);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
return errorMessage;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// src/react/nodes.ts
|
|
326
|
+
// src/react/nodes/shared.ts
|
|
343
327
|
var reasoningLogger = createPatternLogger("agentforge:patterns:react:reasoning");
|
|
344
328
|
var actionLogger = createPatternLogger("agentforge:patterns:react:action");
|
|
345
329
|
var observationLogger = createPatternLogger("agentforge:patterns:react:observation");
|
|
@@ -397,7 +381,7 @@ function formatObservationContent(observation) {
|
|
|
397
381
|
return stringifyObservationResult(observation.result, 2);
|
|
398
382
|
}
|
|
399
383
|
function formatActionSummary(actions) {
|
|
400
|
-
return actions.map((action) => `${action.name}(${
|
|
384
|
+
return actions.map((action) => `${action.name}(${stringifyActionArguments(action.arguments)})`).join(", ");
|
|
401
385
|
}
|
|
402
386
|
function formatObservationSummary(observations) {
|
|
403
387
|
return observations.map((observation) => {
|
|
@@ -411,8 +395,15 @@ function stringifyObservationResult(result, space) {
|
|
|
411
395
|
if (typeof result === "string") {
|
|
412
396
|
return result;
|
|
413
397
|
}
|
|
414
|
-
|
|
415
|
-
|
|
398
|
+
try {
|
|
399
|
+
const stringified = JSON.stringify(result, null, space);
|
|
400
|
+
return stringified ?? String(result);
|
|
401
|
+
} catch {
|
|
402
|
+
return String(result);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
function stringifyActionArguments(arguments_) {
|
|
406
|
+
return stringifyObservationResult(arguments_);
|
|
416
407
|
}
|
|
417
408
|
function getLatestThought(thoughts) {
|
|
418
409
|
return thoughts[thoughts.length - 1]?.content ?? "";
|
|
@@ -422,6 +413,8 @@ function debugIfVerbose(logger4, verbose, message, data) {
|
|
|
422
413
|
logger4.debug(message, data);
|
|
423
414
|
}
|
|
424
415
|
}
|
|
416
|
+
|
|
417
|
+
// src/react/nodes/reasoning.ts
|
|
425
418
|
function createReasoningNode(llm, tools, systemPrompt, maxIterations, verbose = false) {
|
|
426
419
|
const langchainTools = (0, import_core3.toLangChainTools)(tools);
|
|
427
420
|
const llmWithTools = llm.bindTools ? llm.bindTools(langchainTools) : llm;
|
|
@@ -452,15 +445,43 @@ function createReasoningNode(llm, tools, systemPrompt, maxIterations, verbose =
|
|
|
452
445
|
thoughts: thought ? [{ content: thought, timestamp: Date.now() }] : [],
|
|
453
446
|
actions: toolCalls,
|
|
454
447
|
iteration: 1,
|
|
455
|
-
// Add 1 to iteration counter (uses additive reducer)
|
|
456
448
|
shouldContinue,
|
|
457
449
|
response: toolCalls.length === 0 ? thought : void 0
|
|
458
|
-
// Final response if no tool calls
|
|
459
450
|
};
|
|
460
451
|
};
|
|
461
452
|
}
|
|
453
|
+
|
|
454
|
+
// src/shared/error-handling.ts
|
|
455
|
+
function isGraphInterrupt(error) {
|
|
456
|
+
return error !== null && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt";
|
|
457
|
+
}
|
|
458
|
+
function handleNodeError(error, context, verbose = false) {
|
|
459
|
+
if (isGraphInterrupt(error)) {
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
462
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
463
|
+
if (verbose) {
|
|
464
|
+
console.error(`[${context}] Error:`, errorMessage);
|
|
465
|
+
if (error instanceof Error && error.stack) {
|
|
466
|
+
console.error(`[${context}] Stack:`, error.stack);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return errorMessage;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// src/react/nodes/action.ts
|
|
462
473
|
function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
463
474
|
const toolMap = new Map(tools.map((tool) => [tool.metadata.name, tool]));
|
|
475
|
+
function buildCacheKey(toolName, args) {
|
|
476
|
+
try {
|
|
477
|
+
return generateToolCallCacheKey(toolName, args);
|
|
478
|
+
} catch {
|
|
479
|
+
debugIfVerbose(actionLogger, verbose, "Skipping deduplication for unserializable tool call", {
|
|
480
|
+
toolName
|
|
481
|
+
});
|
|
482
|
+
return void 0;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
464
485
|
return async (state) => {
|
|
465
486
|
const actions = state.actions;
|
|
466
487
|
const allObservations = state.observations;
|
|
@@ -474,14 +495,23 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
474
495
|
const recentActions = actions.slice(-10);
|
|
475
496
|
const observations = [];
|
|
476
497
|
const executionCache = /* @__PURE__ */ new Map();
|
|
498
|
+
const actionsById = new Map(actions.map((action) => [action.id, action]));
|
|
499
|
+
const observedToolCallIds = new Set(
|
|
500
|
+
allObservations.map((observation) => observation.toolCallId)
|
|
501
|
+
);
|
|
477
502
|
let cacheSize = 0;
|
|
478
503
|
if (enableDeduplication) {
|
|
479
504
|
for (const observation of allObservations) {
|
|
480
|
-
const correspondingAction =
|
|
505
|
+
const correspondingAction = actionsById.get(observation.toolCallId);
|
|
481
506
|
if (correspondingAction) {
|
|
482
|
-
const cacheKey =
|
|
483
|
-
|
|
484
|
-
|
|
507
|
+
const cacheKey = buildCacheKey(
|
|
508
|
+
correspondingAction.name,
|
|
509
|
+
correspondingAction.arguments
|
|
510
|
+
);
|
|
511
|
+
if (cacheKey) {
|
|
512
|
+
executionCache.set(cacheKey, observation);
|
|
513
|
+
cacheSize++;
|
|
514
|
+
}
|
|
485
515
|
}
|
|
486
516
|
}
|
|
487
517
|
if (cacheSize > 0) {
|
|
@@ -494,8 +524,7 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
494
524
|
let duplicatesSkipped = 0;
|
|
495
525
|
let toolsExecuted = 0;
|
|
496
526
|
for (const action of recentActions) {
|
|
497
|
-
|
|
498
|
-
if (existingObservation) {
|
|
527
|
+
if (observedToolCallIds.has(action.id)) {
|
|
499
528
|
debugIfVerbose(actionLogger, verbose, "Skipping already-processed action", {
|
|
500
529
|
toolName: action.name,
|
|
501
530
|
toolCallId: action.id,
|
|
@@ -504,13 +533,13 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
504
533
|
continue;
|
|
505
534
|
}
|
|
506
535
|
if (enableDeduplication) {
|
|
507
|
-
const cacheKey =
|
|
508
|
-
const cachedResult = executionCache.get(cacheKey);
|
|
536
|
+
const cacheKey = buildCacheKey(action.name, action.arguments);
|
|
537
|
+
const cachedResult = cacheKey ? executionCache.get(cacheKey) : void 0;
|
|
509
538
|
if (cachedResult) {
|
|
510
539
|
duplicatesSkipped++;
|
|
511
540
|
actionLogger.info("Duplicate tool call prevented", {
|
|
512
541
|
toolName: action.name,
|
|
513
|
-
|
|
542
|
+
argumentKeys: Object.keys(action.arguments),
|
|
514
543
|
iteration,
|
|
515
544
|
cacheHit: true
|
|
516
545
|
});
|
|
@@ -535,9 +564,9 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
535
564
|
continue;
|
|
536
565
|
}
|
|
537
566
|
try {
|
|
538
|
-
const
|
|
567
|
+
const toolStartTime = Date.now();
|
|
539
568
|
const result = await tool.invoke(action.arguments);
|
|
540
|
-
const executionTime = Date.now() -
|
|
569
|
+
const executionTime = Date.now() - toolStartTime;
|
|
541
570
|
toolsExecuted++;
|
|
542
571
|
debugIfVerbose(actionLogger, verbose, "Tool executed successfully", {
|
|
543
572
|
toolName: action.name,
|
|
@@ -551,8 +580,10 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
551
580
|
};
|
|
552
581
|
observations.push(observation);
|
|
553
582
|
if (enableDeduplication) {
|
|
554
|
-
const cacheKey =
|
|
555
|
-
|
|
583
|
+
const cacheKey = buildCacheKey(action.name, action.arguments);
|
|
584
|
+
if (cacheKey) {
|
|
585
|
+
executionCache.set(cacheKey, observation);
|
|
586
|
+
}
|
|
556
587
|
}
|
|
557
588
|
} catch (error) {
|
|
558
589
|
const errorMessage = handleNodeError(error, `action:${action.name}`, verbose);
|
|
@@ -570,7 +601,11 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
570
601
|
}
|
|
571
602
|
}
|
|
572
603
|
if (duplicatesSkipped > 0 || toolsExecuted > 0) {
|
|
573
|
-
const metrics = buildDeduplicationMetrics(
|
|
604
|
+
const metrics = buildDeduplicationMetrics(
|
|
605
|
+
toolsExecuted,
|
|
606
|
+
duplicatesSkipped,
|
|
607
|
+
observations.length
|
|
608
|
+
);
|
|
574
609
|
actionLogger.info("Action node complete", {
|
|
575
610
|
iteration,
|
|
576
611
|
...metrics,
|
|
@@ -582,6 +617,8 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
582
617
|
};
|
|
583
618
|
};
|
|
584
619
|
}
|
|
620
|
+
|
|
621
|
+
// src/react/nodes/observation.ts
|
|
585
622
|
function createObservationNode(verbose = false, returnIntermediateSteps = false) {
|
|
586
623
|
return async (state) => {
|
|
587
624
|
const observations = state.observations;
|
|
@@ -601,13 +638,15 @@ function createObservationNode(verbose = false, returnIntermediateSteps = false)
|
|
|
601
638
|
name: actionNamesById.get(observation.toolCallId),
|
|
602
639
|
tool_call_id: observation.toolCallId
|
|
603
640
|
}));
|
|
604
|
-
const scratchpadEntries = returnIntermediateSteps ? [
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
641
|
+
const scratchpadEntries = returnIntermediateSteps ? [
|
|
642
|
+
{
|
|
643
|
+
step: iteration,
|
|
644
|
+
thought: getLatestThought(thoughts),
|
|
645
|
+
action: formatActionSummary(latestActions),
|
|
646
|
+
observation: formatObservationSummary(recentObservations),
|
|
647
|
+
timestamp: Date.now()
|
|
648
|
+
}
|
|
649
|
+
] : [];
|
|
611
650
|
debugIfVerbose(observationLogger, verbose, "Observation node complete", {
|
|
612
651
|
iteration,
|
|
613
652
|
scratchpadUpdated: returnIntermediateSteps,
|
package/dist/index.js
CHANGED
|
@@ -170,14 +170,16 @@ function formatScratchpad(scratchpad) {
|
|
|
170
170
|
}).join("\n\n");
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
// src/react/nodes.ts
|
|
173
|
+
// src/react/nodes/reasoning.ts
|
|
174
|
+
import { toLangChainTools } from "@agentforge/core";
|
|
175
|
+
|
|
176
|
+
// src/react/nodes/shared.ts
|
|
174
177
|
import {
|
|
175
178
|
HumanMessage,
|
|
176
179
|
AIMessage,
|
|
177
180
|
SystemMessage,
|
|
178
181
|
ToolMessage
|
|
179
182
|
} from "@langchain/core/messages";
|
|
180
|
-
import { toLangChainTools } from "@agentforge/core";
|
|
181
183
|
|
|
182
184
|
// src/shared/deduplication.ts
|
|
183
185
|
import { createLogger } from "@agentforge/core";
|
|
@@ -223,25 +225,7 @@ function buildDeduplicationMetrics(toolsExecuted, duplicatesSkipped, totalObserv
|
|
|
223
225
|
};
|
|
224
226
|
}
|
|
225
227
|
|
|
226
|
-
// src/shared
|
|
227
|
-
function isGraphInterrupt(error) {
|
|
228
|
-
return error !== null && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt";
|
|
229
|
-
}
|
|
230
|
-
function handleNodeError(error, context, verbose = false) {
|
|
231
|
-
if (isGraphInterrupt(error)) {
|
|
232
|
-
throw error;
|
|
233
|
-
}
|
|
234
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
235
|
-
if (verbose) {
|
|
236
|
-
console.error(`[${context}] Error:`, errorMessage);
|
|
237
|
-
if (error instanceof Error && error.stack) {
|
|
238
|
-
console.error(`[${context}] Stack:`, error.stack);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return errorMessage;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// src/react/nodes.ts
|
|
228
|
+
// src/react/nodes/shared.ts
|
|
245
229
|
var reasoningLogger = createPatternLogger("agentforge:patterns:react:reasoning");
|
|
246
230
|
var actionLogger = createPatternLogger("agentforge:patterns:react:action");
|
|
247
231
|
var observationLogger = createPatternLogger("agentforge:patterns:react:observation");
|
|
@@ -299,7 +283,7 @@ function formatObservationContent(observation) {
|
|
|
299
283
|
return stringifyObservationResult(observation.result, 2);
|
|
300
284
|
}
|
|
301
285
|
function formatActionSummary(actions) {
|
|
302
|
-
return actions.map((action) => `${action.name}(${
|
|
286
|
+
return actions.map((action) => `${action.name}(${stringifyActionArguments(action.arguments)})`).join(", ");
|
|
303
287
|
}
|
|
304
288
|
function formatObservationSummary(observations) {
|
|
305
289
|
return observations.map((observation) => {
|
|
@@ -313,8 +297,15 @@ function stringifyObservationResult(result, space) {
|
|
|
313
297
|
if (typeof result === "string") {
|
|
314
298
|
return result;
|
|
315
299
|
}
|
|
316
|
-
|
|
317
|
-
|
|
300
|
+
try {
|
|
301
|
+
const stringified = JSON.stringify(result, null, space);
|
|
302
|
+
return stringified ?? String(result);
|
|
303
|
+
} catch {
|
|
304
|
+
return String(result);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function stringifyActionArguments(arguments_) {
|
|
308
|
+
return stringifyObservationResult(arguments_);
|
|
318
309
|
}
|
|
319
310
|
function getLatestThought(thoughts) {
|
|
320
311
|
return thoughts[thoughts.length - 1]?.content ?? "";
|
|
@@ -324,6 +315,8 @@ function debugIfVerbose(logger4, verbose, message, data) {
|
|
|
324
315
|
logger4.debug(message, data);
|
|
325
316
|
}
|
|
326
317
|
}
|
|
318
|
+
|
|
319
|
+
// src/react/nodes/reasoning.ts
|
|
327
320
|
function createReasoningNode(llm, tools, systemPrompt, maxIterations, verbose = false) {
|
|
328
321
|
const langchainTools = toLangChainTools(tools);
|
|
329
322
|
const llmWithTools = llm.bindTools ? llm.bindTools(langchainTools) : llm;
|
|
@@ -354,15 +347,43 @@ function createReasoningNode(llm, tools, systemPrompt, maxIterations, verbose =
|
|
|
354
347
|
thoughts: thought ? [{ content: thought, timestamp: Date.now() }] : [],
|
|
355
348
|
actions: toolCalls,
|
|
356
349
|
iteration: 1,
|
|
357
|
-
// Add 1 to iteration counter (uses additive reducer)
|
|
358
350
|
shouldContinue,
|
|
359
351
|
response: toolCalls.length === 0 ? thought : void 0
|
|
360
|
-
// Final response if no tool calls
|
|
361
352
|
};
|
|
362
353
|
};
|
|
363
354
|
}
|
|
355
|
+
|
|
356
|
+
// src/shared/error-handling.ts
|
|
357
|
+
function isGraphInterrupt(error) {
|
|
358
|
+
return error !== null && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt";
|
|
359
|
+
}
|
|
360
|
+
function handleNodeError(error, context, verbose = false) {
|
|
361
|
+
if (isGraphInterrupt(error)) {
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
365
|
+
if (verbose) {
|
|
366
|
+
console.error(`[${context}] Error:`, errorMessage);
|
|
367
|
+
if (error instanceof Error && error.stack) {
|
|
368
|
+
console.error(`[${context}] Stack:`, error.stack);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return errorMessage;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/react/nodes/action.ts
|
|
364
375
|
function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
365
376
|
const toolMap = new Map(tools.map((tool) => [tool.metadata.name, tool]));
|
|
377
|
+
function buildCacheKey(toolName, args) {
|
|
378
|
+
try {
|
|
379
|
+
return generateToolCallCacheKey(toolName, args);
|
|
380
|
+
} catch {
|
|
381
|
+
debugIfVerbose(actionLogger, verbose, "Skipping deduplication for unserializable tool call", {
|
|
382
|
+
toolName
|
|
383
|
+
});
|
|
384
|
+
return void 0;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
366
387
|
return async (state) => {
|
|
367
388
|
const actions = state.actions;
|
|
368
389
|
const allObservations = state.observations;
|
|
@@ -376,14 +397,23 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
376
397
|
const recentActions = actions.slice(-10);
|
|
377
398
|
const observations = [];
|
|
378
399
|
const executionCache = /* @__PURE__ */ new Map();
|
|
400
|
+
const actionsById = new Map(actions.map((action) => [action.id, action]));
|
|
401
|
+
const observedToolCallIds = new Set(
|
|
402
|
+
allObservations.map((observation) => observation.toolCallId)
|
|
403
|
+
);
|
|
379
404
|
let cacheSize = 0;
|
|
380
405
|
if (enableDeduplication) {
|
|
381
406
|
for (const observation of allObservations) {
|
|
382
|
-
const correspondingAction =
|
|
407
|
+
const correspondingAction = actionsById.get(observation.toolCallId);
|
|
383
408
|
if (correspondingAction) {
|
|
384
|
-
const cacheKey =
|
|
385
|
-
|
|
386
|
-
|
|
409
|
+
const cacheKey = buildCacheKey(
|
|
410
|
+
correspondingAction.name,
|
|
411
|
+
correspondingAction.arguments
|
|
412
|
+
);
|
|
413
|
+
if (cacheKey) {
|
|
414
|
+
executionCache.set(cacheKey, observation);
|
|
415
|
+
cacheSize++;
|
|
416
|
+
}
|
|
387
417
|
}
|
|
388
418
|
}
|
|
389
419
|
if (cacheSize > 0) {
|
|
@@ -396,8 +426,7 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
396
426
|
let duplicatesSkipped = 0;
|
|
397
427
|
let toolsExecuted = 0;
|
|
398
428
|
for (const action of recentActions) {
|
|
399
|
-
|
|
400
|
-
if (existingObservation) {
|
|
429
|
+
if (observedToolCallIds.has(action.id)) {
|
|
401
430
|
debugIfVerbose(actionLogger, verbose, "Skipping already-processed action", {
|
|
402
431
|
toolName: action.name,
|
|
403
432
|
toolCallId: action.id,
|
|
@@ -406,13 +435,13 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
406
435
|
continue;
|
|
407
436
|
}
|
|
408
437
|
if (enableDeduplication) {
|
|
409
|
-
const cacheKey =
|
|
410
|
-
const cachedResult = executionCache.get(cacheKey);
|
|
438
|
+
const cacheKey = buildCacheKey(action.name, action.arguments);
|
|
439
|
+
const cachedResult = cacheKey ? executionCache.get(cacheKey) : void 0;
|
|
411
440
|
if (cachedResult) {
|
|
412
441
|
duplicatesSkipped++;
|
|
413
442
|
actionLogger.info("Duplicate tool call prevented", {
|
|
414
443
|
toolName: action.name,
|
|
415
|
-
|
|
444
|
+
argumentKeys: Object.keys(action.arguments),
|
|
416
445
|
iteration,
|
|
417
446
|
cacheHit: true
|
|
418
447
|
});
|
|
@@ -437,9 +466,9 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
437
466
|
continue;
|
|
438
467
|
}
|
|
439
468
|
try {
|
|
440
|
-
const
|
|
469
|
+
const toolStartTime = Date.now();
|
|
441
470
|
const result = await tool.invoke(action.arguments);
|
|
442
|
-
const executionTime = Date.now() -
|
|
471
|
+
const executionTime = Date.now() - toolStartTime;
|
|
443
472
|
toolsExecuted++;
|
|
444
473
|
debugIfVerbose(actionLogger, verbose, "Tool executed successfully", {
|
|
445
474
|
toolName: action.name,
|
|
@@ -453,8 +482,10 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
453
482
|
};
|
|
454
483
|
observations.push(observation);
|
|
455
484
|
if (enableDeduplication) {
|
|
456
|
-
const cacheKey =
|
|
457
|
-
|
|
485
|
+
const cacheKey = buildCacheKey(action.name, action.arguments);
|
|
486
|
+
if (cacheKey) {
|
|
487
|
+
executionCache.set(cacheKey, observation);
|
|
488
|
+
}
|
|
458
489
|
}
|
|
459
490
|
} catch (error) {
|
|
460
491
|
const errorMessage = handleNodeError(error, `action:${action.name}`, verbose);
|
|
@@ -472,7 +503,11 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
472
503
|
}
|
|
473
504
|
}
|
|
474
505
|
if (duplicatesSkipped > 0 || toolsExecuted > 0) {
|
|
475
|
-
const metrics = buildDeduplicationMetrics(
|
|
506
|
+
const metrics = buildDeduplicationMetrics(
|
|
507
|
+
toolsExecuted,
|
|
508
|
+
duplicatesSkipped,
|
|
509
|
+
observations.length
|
|
510
|
+
);
|
|
476
511
|
actionLogger.info("Action node complete", {
|
|
477
512
|
iteration,
|
|
478
513
|
...metrics,
|
|
@@ -484,6 +519,8 @@ function createActionNode(tools, verbose = false, enableDeduplication = true) {
|
|
|
484
519
|
};
|
|
485
520
|
};
|
|
486
521
|
}
|
|
522
|
+
|
|
523
|
+
// src/react/nodes/observation.ts
|
|
487
524
|
function createObservationNode(verbose = false, returnIntermediateSteps = false) {
|
|
488
525
|
return async (state) => {
|
|
489
526
|
const observations = state.observations;
|
|
@@ -503,13 +540,15 @@ function createObservationNode(verbose = false, returnIntermediateSteps = false)
|
|
|
503
540
|
name: actionNamesById.get(observation.toolCallId),
|
|
504
541
|
tool_call_id: observation.toolCallId
|
|
505
542
|
}));
|
|
506
|
-
const scratchpadEntries = returnIntermediateSteps ? [
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
543
|
+
const scratchpadEntries = returnIntermediateSteps ? [
|
|
544
|
+
{
|
|
545
|
+
step: iteration,
|
|
546
|
+
thought: getLatestThought(thoughts),
|
|
547
|
+
action: formatActionSummary(latestActions),
|
|
548
|
+
observation: formatObservationSummary(recentObservations),
|
|
549
|
+
timestamp: Date.now()
|
|
550
|
+
}
|
|
551
|
+
] : [];
|
|
513
552
|
debugIfVerbose(observationLogger, verbose, "Observation node complete", {
|
|
514
553
|
iteration,
|
|
515
554
|
scratchpadUpdated: returnIntermediateSteps,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentforge/patterns",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.12",
|
|
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.12",
|
|
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.12",
|
|
51
51
|
"@eslint/js": "^9.17.0",
|
|
52
52
|
"@types/node": "^22.10.2",
|
|
53
53
|
"eslint": "^9.17.0",
|