@librechat/agents 3.1.71-dev.0 → 3.1.71-dev.1
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/cjs/graphs/Graph.cjs +7 -0
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +13 -2
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +84 -55
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/toolOutputReferences.cjs +182 -0
- package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +7 -0
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +13 -2
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +85 -56
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/toolOutputReferences.mjs +182 -1
- package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
- package/dist/types/graphs/Graph.d.ts +9 -2
- package/dist/types/llm/invoke.d.ts +9 -0
- package/dist/types/tools/ToolNode.d.ts +11 -13
- package/dist/types/tools/toolOutputReferences.d.ts +31 -0
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/messages.d.ts +26 -0
- package/package.json +1 -1
- package/src/graphs/Graph.ts +8 -1
- package/src/llm/invoke.test.ts +442 -0
- package/src/llm/invoke.ts +23 -2
- package/src/tools/ToolNode.ts +94 -81
- package/src/tools/__tests__/ToolNode.outputReferences.test.ts +98 -55
- package/src/tools/__tests__/annotateMessagesForLLM.test.ts +419 -0
- package/src/tools/toolOutputReferences.ts +223 -0
- package/src/types/index.ts +1 -0
- package/src/types/messages.ts +27 -0
|
@@ -302,13 +302,17 @@ class ToolNode extends run.RunnableCallable {
|
|
|
302
302
|
const isError = toolMsg.status === 'error';
|
|
303
303
|
if (isError) {
|
|
304
304
|
/**
|
|
305
|
-
* Error ToolMessages bypass registration
|
|
306
|
-
*
|
|
307
|
-
*
|
|
305
|
+
* Error ToolMessages bypass registration but still stamp the
|
|
306
|
+
* unresolved-refs hint into `additional_kwargs` so the lazy
|
|
307
|
+
* annotation transform surfaces it to the LLM, letting the
|
|
308
|
+
* model self-correct when its reference key caused the
|
|
309
|
+
* failure. Persisted `content` stays clean.
|
|
308
310
|
*/
|
|
309
|
-
if (unresolvedRefs.length > 0
|
|
310
|
-
|
|
311
|
-
|
|
311
|
+
if (unresolvedRefs.length > 0) {
|
|
312
|
+
toolMsg.additional_kwargs = {
|
|
313
|
+
...toolMsg.additional_kwargs,
|
|
314
|
+
_unresolvedRefs: unresolvedRefs,
|
|
315
|
+
};
|
|
312
316
|
}
|
|
313
317
|
return toolMsg;
|
|
314
318
|
}
|
|
@@ -316,7 +320,14 @@ class ToolNode extends run.RunnableCallable {
|
|
|
316
320
|
if (typeof toolMsg.content === 'string') {
|
|
317
321
|
const rawContent = toolMsg.content;
|
|
318
322
|
const llmContent = truncation.truncateToolResultContent(rawContent, this.maxToolResultChars);
|
|
319
|
-
toolMsg.content =
|
|
323
|
+
toolMsg.content = llmContent;
|
|
324
|
+
const refMeta = this.recordOutputReference(runId, rawContent, refKey, unresolvedRefs);
|
|
325
|
+
if (refMeta != null) {
|
|
326
|
+
toolMsg.additional_kwargs = {
|
|
327
|
+
...toolMsg.additional_kwargs,
|
|
328
|
+
...refMeta,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
320
331
|
}
|
|
321
332
|
else {
|
|
322
333
|
/**
|
|
@@ -324,22 +335,16 @@ class ToolNode extends run.RunnableCallable {
|
|
|
324
335
|
* image). Known limitation: we cannot register under a
|
|
325
336
|
* reference key because there's no canonical serialized
|
|
326
337
|
* form. Warn once per tool per run when the caller
|
|
327
|
-
* intended to register.
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
* paths already emit. Prepended as a leading text block
|
|
332
|
-
* to keep the original content ordering intact.
|
|
338
|
+
* intended to register. The unresolved-refs hint is still
|
|
339
|
+
* stamped as metadata; the lazy transform prepends a text
|
|
340
|
+
* block at request time so the LLM gets the self-correction
|
|
341
|
+
* signal.
|
|
333
342
|
*/
|
|
334
|
-
if (unresolvedRefs.length > 0
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
343
|
+
if (unresolvedRefs.length > 0) {
|
|
344
|
+
toolMsg.additional_kwargs = {
|
|
345
|
+
...toolMsg.additional_kwargs,
|
|
346
|
+
_unresolvedRefs: unresolvedRefs,
|
|
338
347
|
};
|
|
339
|
-
toolMsg.content = [
|
|
340
|
-
warningBlock,
|
|
341
|
-
...toolMsg.content,
|
|
342
|
-
];
|
|
343
348
|
}
|
|
344
349
|
if (refKey != null &&
|
|
345
350
|
this.toolOutputRegistry.claimWarnOnce(runId, call.name)) {
|
|
@@ -353,12 +358,15 @@ class ToolNode extends run.RunnableCallable {
|
|
|
353
358
|
}
|
|
354
359
|
const rawContent = typeof output === 'string' ? output : JSON.stringify(output);
|
|
355
360
|
const truncated = truncation.truncateToolResultContent(rawContent, this.maxToolResultChars);
|
|
356
|
-
const
|
|
361
|
+
const refMeta = this.recordOutputReference(runId, rawContent, refKey, unresolvedRefs);
|
|
357
362
|
return new messages.ToolMessage({
|
|
358
363
|
status: 'success',
|
|
359
364
|
name: tool.name,
|
|
360
|
-
content,
|
|
365
|
+
content: truncated,
|
|
361
366
|
tool_call_id: call.id,
|
|
367
|
+
...(refMeta != null && {
|
|
368
|
+
additional_kwargs: refMeta,
|
|
369
|
+
}),
|
|
362
370
|
});
|
|
363
371
|
}
|
|
364
372
|
catch (_e) {
|
|
@@ -402,51 +410,64 @@ class ToolNode extends run.RunnableCallable {
|
|
|
402
410
|
});
|
|
403
411
|
}
|
|
404
412
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
413
|
+
const errorContent = `Error: ${e.message}\n Please fix your mistakes.`;
|
|
414
|
+
const refMeta = unresolvedRefs.length > 0
|
|
415
|
+
? this.recordOutputReference(runId, errorContent, undefined, unresolvedRefs)
|
|
416
|
+
: undefined;
|
|
409
417
|
return new messages.ToolMessage({
|
|
410
418
|
status: 'error',
|
|
411
419
|
content: errorContent,
|
|
412
420
|
name: call.name,
|
|
413
421
|
tool_call_id: call.id ?? '',
|
|
422
|
+
...(refMeta != null && {
|
|
423
|
+
additional_kwargs: refMeta,
|
|
424
|
+
}),
|
|
414
425
|
});
|
|
415
426
|
}
|
|
416
427
|
}
|
|
417
428
|
/**
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
429
|
+
* Registers the full, raw output under `refKey` (when provided) and
|
|
430
|
+
* builds the per-message ref metadata stamped onto the resulting
|
|
431
|
+
* `ToolMessage.additional_kwargs`. The metadata is read at LLM-
|
|
432
|
+
* request time by `annotateMessagesForLLM` to produce a transient
|
|
433
|
+
* annotated copy of the message — the persisted `content` itself
|
|
434
|
+
* stays clean.
|
|
421
435
|
*
|
|
422
|
-
* @param llmContent The content string the LLM will see. This is
|
|
423
|
-
* the already-truncated, post-hook view; the annotation is
|
|
424
|
-
* applied on top of it.
|
|
425
436
|
* @param registryContent The full, untruncated output to store in
|
|
426
437
|
* the registry so `{{tool<i>turn<n>}}` substitutions deliver the
|
|
427
438
|
* complete payload. Ignored when `refKey` is undefined.
|
|
428
439
|
* @param refKey Precomputed `tool<i>turn<n>` key, or undefined when
|
|
429
440
|
* the output is not to be registered (errors, disabled feature,
|
|
430
441
|
* unavailable batch/turn).
|
|
431
|
-
* @param unresolved Placeholder keys that did not resolve;
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
* so parallel `invoke()` calls on the same ToolNode cannot race on
|
|
436
|
-
* the shared turn field.
|
|
442
|
+
* @param unresolved Placeholder keys that did not resolve; surfaced
|
|
443
|
+
* to the LLM lazily so it can self-correct.
|
|
444
|
+
* @returns A `ToolMessageRefMetadata` object when there is anything
|
|
445
|
+
* to stamp, otherwise `undefined`.
|
|
437
446
|
*/
|
|
438
|
-
|
|
447
|
+
recordOutputReference(runId, registryContent, refKey, unresolved) {
|
|
439
448
|
if (this.toolOutputRegistry != null && refKey != null) {
|
|
440
449
|
this.toolOutputRegistry.set(runId, refKey, registryContent);
|
|
441
450
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
451
|
+
if (refKey == null && unresolved.length === 0)
|
|
452
|
+
return undefined;
|
|
453
|
+
const meta = {};
|
|
454
|
+
if (refKey != null) {
|
|
455
|
+
meta._refKey = refKey;
|
|
456
|
+
/**
|
|
457
|
+
* Stamp the registry scope alongside the key so the lazy
|
|
458
|
+
* annotation transform can look up the right bucket. Anonymous
|
|
459
|
+
* invocations get a synthetic per-batch scope (`\0anon-<n>`)
|
|
460
|
+
* that `attemptInvoke` cannot derive from
|
|
461
|
+
* `config.configurable.run_id` — without this, anonymous-run
|
|
462
|
+
* refs would silently fail registry lookup and the LLM would
|
|
463
|
+
* never see `[ref: …]` markers for outputs that were registered.
|
|
464
|
+
*/
|
|
465
|
+
if (runId != null)
|
|
466
|
+
meta._refScope = runId;
|
|
467
|
+
}
|
|
468
|
+
if (unresolved.length > 0)
|
|
469
|
+
meta._unresolvedRefs = unresolved;
|
|
470
|
+
return meta;
|
|
450
471
|
}
|
|
451
472
|
/**
|
|
452
473
|
* Builds code session context for injection into event-driven tool calls.
|
|
@@ -781,19 +802,24 @@ class ToolNode extends run.RunnableCallable {
|
|
|
781
802
|
if (result.status === 'error') {
|
|
782
803
|
contentString = `Error: ${result.errorMessage ?? 'Unknown error'}\n Please fix your mistakes.`;
|
|
783
804
|
/**
|
|
784
|
-
* Error results bypass registration
|
|
785
|
-
*
|
|
786
|
-
*
|
|
805
|
+
* Error results bypass registration but stamp the
|
|
806
|
+
* unresolved-refs hint into `additional_kwargs` so the lazy
|
|
807
|
+
* annotation transform surfaces it to the LLM at request
|
|
808
|
+
* time, letting the model self-correct when its reference
|
|
809
|
+
* key caused the failure. Persisted `content` stays clean.
|
|
787
810
|
*/
|
|
788
811
|
const unresolved = unresolvedByCallId.get(result.toolCallId) ?? [];
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
812
|
+
const errorRefMeta = unresolved.length > 0
|
|
813
|
+
? this.recordOutputReference(registryRunId, contentString, undefined, unresolved)
|
|
814
|
+
: undefined;
|
|
792
815
|
toolMessage = new messages.ToolMessage({
|
|
793
816
|
status: 'error',
|
|
794
817
|
content: contentString,
|
|
795
818
|
name: toolName,
|
|
796
819
|
tool_call_id: result.toolCallId,
|
|
820
|
+
...(errorRefMeta != null && {
|
|
821
|
+
additional_kwargs: errorRefMeta,
|
|
822
|
+
}),
|
|
797
823
|
});
|
|
798
824
|
if (hasFailureHook) {
|
|
799
825
|
await executeHooks.executeHooks({
|
|
@@ -855,13 +881,16 @@ class ToolNode extends run.RunnableCallable {
|
|
|
855
881
|
turn != null
|
|
856
882
|
? toolOutputReferences.buildReferenceKey(batchIndex, turn)
|
|
857
883
|
: undefined;
|
|
858
|
-
|
|
884
|
+
const successRefMeta = this.recordOutputReference(registryRunId, registryRaw, refKey, unresolved);
|
|
859
885
|
toolMessage = new messages.ToolMessage({
|
|
860
886
|
status: 'success',
|
|
861
887
|
name: toolName,
|
|
862
888
|
content: contentString,
|
|
863
889
|
artifact: result.artifact,
|
|
864
890
|
tool_call_id: result.toolCallId,
|
|
891
|
+
...(successRefMeta != null && {
|
|
892
|
+
additional_kwargs: successRefMeta,
|
|
893
|
+
}),
|
|
865
894
|
});
|
|
866
895
|
}
|
|
867
896
|
this.dispatchStepCompleted(result.toolCallId, toolName, request?.args ?? {}, contentString, config, request?.turn);
|