@librechat/agents 3.3.5 → 3.3.6

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.
Files changed (127) hide show
  1. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +1 -1
  2. package/dist/cjs/llm/openai/index.cjs +51 -6
  3. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  4. package/dist/cjs/main.cjs +14 -0
  5. package/dist/cjs/session/JsonlSessionStore.cjs +1 -1
  6. package/dist/cjs/stream.cjs +6 -1
  7. package/dist/cjs/stream.cjs.map +1 -1
  8. package/dist/cjs/tools/BashExecutor.cjs +3 -1
  9. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  10. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +2 -0
  11. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  12. package/dist/cjs/tools/CodeExecutor.cjs +19 -16
  13. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  14. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +2 -0
  15. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  16. package/dist/cjs/tools/ReadFile.cjs +8 -4
  17. package/dist/cjs/tools/ReadFile.cjs.map +1 -1
  18. package/dist/cjs/tools/SkillTool.cjs +2 -0
  19. package/dist/cjs/tools/SkillTool.cjs.map +1 -1
  20. package/dist/cjs/tools/SubagentTool.cjs +3 -0
  21. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  22. package/dist/cjs/tools/ToolNode.cjs +88 -27
  23. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  24. package/dist/cjs/tools/ToolSearch.cjs +5 -1
  25. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  26. package/dist/cjs/tools/intentArg.cjs +230 -0
  27. package/dist/cjs/tools/intentArg.cjs.map +1 -0
  28. package/dist/cjs/tools/local/CompileCheckTool.cjs +3 -2
  29. package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -1
  30. package/dist/cjs/tools/local/LocalCodingTools.cjs +13 -12
  31. package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
  32. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +2 -2
  33. package/dist/cjs/tools/ptcTimeout.cjs.map +1 -1
  34. package/dist/cjs/tools/search/schema.cjs +2 -0
  35. package/dist/cjs/tools/search/schema.cjs.map +1 -1
  36. package/dist/cjs/tools/search/tool.cjs +31 -1
  37. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  38. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -0
  39. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  40. package/dist/cjs/tools/toolOutputReferences.cjs +41 -7
  41. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  42. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +1 -1
  43. package/dist/esm/llm/openai/index.mjs +51 -6
  44. package/dist/esm/llm/openai/index.mjs.map +1 -1
  45. package/dist/esm/main.mjs +4 -3
  46. package/dist/esm/session/JsonlSessionStore.mjs +1 -1
  47. package/dist/esm/stream.mjs +6 -1
  48. package/dist/esm/stream.mjs.map +1 -1
  49. package/dist/esm/tools/BashExecutor.mjs +3 -1
  50. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  51. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +2 -0
  52. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  53. package/dist/esm/tools/CodeExecutor.mjs +19 -16
  54. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  55. package/dist/esm/tools/ProgrammaticToolCalling.mjs +2 -0
  56. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  57. package/dist/esm/tools/ReadFile.mjs +8 -4
  58. package/dist/esm/tools/ReadFile.mjs.map +1 -1
  59. package/dist/esm/tools/SkillTool.mjs +2 -0
  60. package/dist/esm/tools/SkillTool.mjs.map +1 -1
  61. package/dist/esm/tools/SubagentTool.mjs +3 -0
  62. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  63. package/dist/esm/tools/ToolNode.mjs +88 -28
  64. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  65. package/dist/esm/tools/ToolSearch.mjs +5 -1
  66. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  67. package/dist/esm/tools/intentArg.mjs +220 -0
  68. package/dist/esm/tools/intentArg.mjs.map +1 -0
  69. package/dist/esm/tools/local/CompileCheckTool.mjs +3 -2
  70. package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -1
  71. package/dist/esm/tools/local/LocalCodingTools.mjs +13 -12
  72. package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
  73. package/dist/esm/tools/local/LocalExecutionEngine.mjs +2 -2
  74. package/dist/esm/tools/ptcTimeout.mjs.map +1 -1
  75. package/dist/esm/tools/search/schema.mjs +2 -0
  76. package/dist/esm/tools/search/schema.mjs.map +1 -1
  77. package/dist/esm/tools/search/tool.mjs +31 -2
  78. package/dist/esm/tools/search/tool.mjs.map +1 -1
  79. package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -0
  80. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  81. package/dist/esm/tools/toolOutputReferences.mjs +41 -7
  82. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  83. package/dist/types/index.d.ts +1 -0
  84. package/dist/types/llm/openai/index.d.ts +0 -11
  85. package/dist/types/tools/BashExecutor.d.ts +18 -0
  86. package/dist/types/tools/CodeExecutor.d.ts +18 -0
  87. package/dist/types/tools/ReadFile.d.ts +18 -0
  88. package/dist/types/tools/SkillTool.d.ts +18 -0
  89. package/dist/types/tools/SubagentTool.d.ts +9 -0
  90. package/dist/types/tools/ToolNode.d.ts +37 -5
  91. package/dist/types/tools/ToolSearch.d.ts +18 -0
  92. package/dist/types/tools/intentArg.d.ts +119 -0
  93. package/dist/types/tools/ptcTimeout.d.ts +2 -0
  94. package/dist/types/tools/search/schema.d.ts +18 -0
  95. package/dist/types/tools/search/tool.d.ts +18 -0
  96. package/dist/types/tools/toolOutputReferences.d.ts +12 -2
  97. package/dist/types/types/stream.d.ts +12 -0
  98. package/dist/types/types/tools.d.ts +27 -2
  99. package/package.json +1 -1
  100. package/src/index.ts +1 -0
  101. package/src/llm/openai/index.ts +74 -10
  102. package/src/llm/openai/llm.spec.ts +105 -0
  103. package/src/stream.ts +12 -1
  104. package/src/tools/BashExecutor.ts +6 -0
  105. package/src/tools/BashProgrammaticToolCalling.ts +2 -0
  106. package/src/tools/CodeExecutor.ts +6 -0
  107. package/src/tools/ProgrammaticToolCalling.ts +2 -0
  108. package/src/tools/ReadFile.ts +2 -0
  109. package/src/tools/SkillTool.ts +2 -0
  110. package/src/tools/SubagentTool.ts +3 -0
  111. package/src/tools/ToolNode.ts +190 -43
  112. package/src/tools/ToolSearch.ts +3 -0
  113. package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +174 -0
  114. package/src/tools/__tests__/intentArg.test.ts +281 -0
  115. package/src/tools/__tests__/intentCoverage.test.ts +139 -0
  116. package/src/tools/__tests__/toolOutputReferences.test.ts +83 -0
  117. package/src/tools/intentArg.ts +323 -0
  118. package/src/tools/local/CompileCheckTool.ts +4 -3
  119. package/src/tools/local/LocalCodingTools.ts +14 -13
  120. package/src/tools/ptcTimeout.ts +2 -0
  121. package/src/tools/search/outcome.test.ts +90 -0
  122. package/src/tools/search/schema.ts +3 -0
  123. package/src/tools/search/tool.ts +47 -1
  124. package/src/tools/subagent/SubagentExecutor.ts +2 -1
  125. package/src/tools/toolOutputReferences.ts +77 -9
  126. package/src/types/stream.ts +12 -0
  127. package/src/types/tools.ts +24 -2
@@ -30,6 +30,25 @@ import {
30
30
  HARD_MAX_TOTAL_TOOL_OUTPUT_SIZE,
31
31
  } from '@/utils/truncation';
32
32
  import { isComputerCallOutputMessage } from '@/utils/toolContent';
33
+ import { INTENT_ARG } from '@/tools/intentArg';
34
+
35
+ /** Parses a stringified JSON object arg; undefined for anything else. */
36
+ function parseStringifiedArgsObject(
37
+ value: string
38
+ ): Record<string, unknown> | undefined {
39
+ if (!value.trim().startsWith('{')) {
40
+ return undefined;
41
+ }
42
+ try {
43
+ const parsed = JSON.parse(value) as unknown;
44
+ if (parsed != null && typeof parsed === 'object' && !Array.isArray(parsed)) {
45
+ return parsed as Record<string, unknown>;
46
+ }
47
+ } catch {
48
+ return undefined;
49
+ }
50
+ return undefined;
51
+ }
33
52
 
34
53
  /**
35
54
  * Non-global matcher for a single `{{tool<i>turn<n>}}` placeholder.
@@ -89,9 +108,20 @@ export type ResolveResult<T> = {
89
108
  * point in time, ignoring any subsequent registrations.
90
109
  */
91
110
  export interface ToolOutputResolveView {
92
- resolve<T>(args: T): ResolveResult<T>;
111
+ resolve<T>(args: T, options?: ResolveOptions): ResolveResult<T>;
93
112
  }
94
113
 
114
+ /**
115
+ * Per-call resolution options. `substituteIntentKey` opts the top-level
116
+ * `intent` key back INTO placeholder substitution: the exemption protects
117
+ * the injected display label, but a tool whose own schema declares a
118
+ * business parameter named `intent` (the injectors skip such tools) still
119
+ * needs references piped into it like any other argument.
120
+ */
121
+ export type ResolveOptions = {
122
+ substituteIntentKey?: boolean;
123
+ };
124
+
95
125
  /**
96
126
  * Pre-resolved arg map keyed by `toolCallId`. Used by the mixed
97
127
  * direct+event dispatch path to feed event calls' resolved args
@@ -333,12 +363,16 @@ export class ToolOutputReferenceRegistry {
333
363
  * the serialized args, the original input is returned without
334
364
  * walking the tree.
335
365
  */
336
- resolve<T>(runId: string | undefined, args: T): ResolveResult<T> {
366
+ resolve<T>(
367
+ runId: string | undefined,
368
+ args: T,
369
+ options?: ResolveOptions
370
+ ): ResolveResult<T> {
337
371
  if (!hasAnyPlaceholder(args)) {
338
372
  return { resolved: args, unresolved: [] };
339
373
  }
340
374
  const bucket = this.runStates.get(this.keyFor(runId));
341
- return this.resolveAgainst(bucket?.entries ?? EMPTY_ENTRIES, args);
375
+ return this.resolveAgainst(bucket?.entries ?? EMPTY_ENTRIES, args, options);
342
376
  }
343
377
 
344
378
  /**
@@ -358,27 +392,52 @@ export class ToolOutputReferenceRegistry {
358
392
  ? new Map(bucket.entries)
359
393
  : EMPTY_ENTRIES;
360
394
  return {
361
- resolve: <T>(args: T): ResolveResult<T> =>
362
- this.resolveAgainst(entries, args),
395
+ resolve: <T>(args: T, options?: ResolveOptions): ResolveResult<T> =>
396
+ this.resolveAgainst(entries, args, options),
363
397
  };
364
398
  }
365
399
 
366
400
  private resolveAgainst<T>(
367
401
  entries: ReadonlyMap<string, string>,
368
- args: T
402
+ args: T,
403
+ options?: ResolveOptions
369
404
  ): ResolveResult<T> {
370
405
  if (!hasAnyPlaceholder(args)) {
371
406
  return { resolved: args, unresolved: [] };
372
407
  }
408
+ const exemptIntentKey = options?.substituteIntentKey !== true;
373
409
  const unresolved = new Set<string>();
374
- const resolved = this.transform(entries, args, unresolved) as T;
410
+ /**
411
+ * Providers may deliver the args OBJECT as a JSON string. A plain
412
+ * string-root transform would expand placeholders inside the `intent`
413
+ * label too, bypassing the top-level exclusion below — parse, transform
414
+ * key-aware, and re-serialize so the label stays verbatim while every
415
+ * other field still substitutes. Only taken when an `intent` key is
416
+ * actually present; other strings keep the fast raw-string path.
417
+ */
418
+ if (exemptIntentKey && typeof args === 'string') {
419
+ const parsedRoot = parseStringifiedArgsObject(args);
420
+ if (parsedRoot != null && INTENT_ARG in parsedRoot) {
421
+ const resolved = JSON.stringify(
422
+ this.transform(entries, parsedRoot, unresolved, true)
423
+ ) as T;
424
+ return { resolved, unresolved: Array.from(unresolved) };
425
+ }
426
+ }
427
+ const resolved = this.transform(
428
+ entries,
429
+ args,
430
+ unresolved,
431
+ exemptIntentKey
432
+ ) as T;
375
433
  return { resolved, unresolved: Array.from(unresolved) };
376
434
  }
377
435
 
378
436
  private transform(
379
437
  entries: ReadonlyMap<string, string>,
380
438
  value: unknown,
381
- unresolved: Set<string>
439
+ unresolved: Set<string>,
440
+ exemptRootIntent = false
382
441
  ): unknown {
383
442
  if (typeof value === 'string') {
384
443
  return this.replaceInString(entries, value, unresolved);
@@ -390,7 +449,16 @@ export class ToolOutputReferenceRegistry {
390
449
  const source = value as Record<string, unknown>;
391
450
  const next: Record<string, unknown> = {};
392
451
  for (const [key, item] of Object.entries(source)) {
393
- next[key] = this.transform(entries, item, unresolved);
452
+ /**
453
+ * The top-level `intent` arg is a display label, never a data
454
+ * channel: expanding a `{{tool<i>turn<n>}}` placeholder there would
455
+ * dump a stored output (up to the registry cap) into a single-line
456
+ * UI label and persist it with the message. Left verbatim instead.
457
+ */
458
+ next[key] =
459
+ exemptRootIntent && key === INTENT_ARG
460
+ ? item
461
+ : this.transform(entries, item, unresolved);
394
462
  }
395
463
  return next;
396
464
  }
@@ -142,6 +142,13 @@ export type ProcessedToolCall = {
142
142
  id: string;
143
143
  output: string;
144
144
  progress: number;
145
+ /**
146
+ * Settled label for the call, resolved from the tool-supplied
147
+ * `outcome`/`outcome_patch` result fields against the model-authored
148
+ * `intent` arg. Only present when the tool authored one — hosts apply
149
+ * the mechanical intent transform themselves when absent.
150
+ */
151
+ outcome?: string;
145
152
  };
146
153
 
147
154
  export type ProcessedContent = {
@@ -336,6 +343,11 @@ export type ToolCallPart = {
336
343
  id?: string;
337
344
  /** If provided, the output of the tool call */
338
345
  output?: ToolResultContent['content'];
346
+ /**
347
+ * Tool-authored settled label for the call (see `ProcessedToolCall.outcome`),
348
+ * preserved through aggregation so it survives persistence/reload.
349
+ */
350
+ outcome?: string;
339
351
  /** Auth URL */
340
352
  auth?: string;
341
353
  /** Expiration time */
@@ -236,8 +236,12 @@ export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
236
236
  export type ToolEndEvent = {
237
237
  /** The Step Id of the Tool Call */
238
238
  id: string;
239
- /** The Completed Tool Call */
240
- tool_call: ToolCall;
239
+ /**
240
+ * The Completed Tool Call. Carries the tool-authored `outcome` label when
241
+ * present (see `ProcessedToolCall.outcome`) so `ON_RUN_STEP_COMPLETED`
242
+ * consumers can read it without an unsafe cast.
243
+ */
244
+ tool_call: ToolCall & { output?: string; progress?: number; outcome?: string };
241
245
  /** The content index of the tool call */
242
246
  index: number;
243
247
  type?: 'tool_call';
@@ -521,6 +525,17 @@ export type InjectedMessage = {
521
525
  skillName?: string;
522
526
  };
523
527
 
528
+ /**
529
+ * In-place edit of a call's model-authored `intent` label: the first
530
+ * occurrence of `from` in the intent is replaced with `to` (case-sensitive).
531
+ * Lets a tool settle the label while preserving the model's own phrasing,
532
+ * e.g. `{ from: 'Searching', to: 'Searched' }`.
533
+ */
534
+ export type OutcomePatch = {
535
+ from: string;
536
+ to: string;
537
+ };
538
+
524
539
  /** Result for a single tool call in event-driven execution */
525
540
  export type ToolExecuteResult = {
526
541
  /** Matches ToolCallRequest.id */
@@ -533,6 +548,13 @@ export type ToolExecuteResult = {
533
548
  status: 'success' | 'error';
534
549
  /** Error message if status is 'error' */
535
550
  errorMessage?: string;
551
+ /**
552
+ * Settled human-readable label for this call, replacing the model-authored
553
+ * `intent` arg in the UI. Full replacement; wins over `outcome_patch`.
554
+ */
555
+ outcome?: string;
556
+ /** In-place edit of the model-authored `intent` label (see {@link OutcomePatch}). */
557
+ outcome_patch?: OutcomePatch;
536
558
  /**
537
559
  * Messages to inject into graph state after the ToolMessage for this call.
538
560
  * Placed after tool results to respect provider message ordering (tool_call -> tool_result adjacency).