@librechat/agents 3.4.2 → 3.4.4

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 (75) hide show
  1. package/dist/cjs/graphs/Graph.cjs +27 -14
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/graphs/MultiAgentGraph.cjs +1 -1
  4. package/dist/cjs/instrumentation.cjs +3 -3
  5. package/dist/cjs/langfuse.cjs +3 -3
  6. package/dist/cjs/langfuseRuntimeScope.cjs +1 -1
  7. package/dist/cjs/langfuseToolOutputTracing.cjs +2 -2
  8. package/dist/cjs/main.cjs +5 -1
  9. package/dist/cjs/messages/assistantPhase.cjs +59 -0
  10. package/dist/cjs/messages/assistantPhase.cjs.map +1 -0
  11. package/dist/cjs/messages/index.cjs +1 -0
  12. package/dist/cjs/prompts/activityLabel.cjs +76 -0
  13. package/dist/cjs/prompts/activityLabel.cjs.map +1 -1
  14. package/dist/cjs/run.cjs +200 -10
  15. package/dist/cjs/run.cjs.map +1 -1
  16. package/dist/cjs/session/AgentSession.cjs +1 -1
  17. package/dist/cjs/stream.cjs +45 -8
  18. package/dist/cjs/stream.cjs.map +1 -1
  19. package/dist/cjs/tools/ToolNode.cjs +3 -3
  20. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +81 -6
  21. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  22. package/dist/cjs/utils/callbacks.cjs +8 -0
  23. package/dist/cjs/utils/callbacks.cjs.map +1 -1
  24. package/dist/esm/graphs/Graph.mjs +27 -14
  25. package/dist/esm/graphs/Graph.mjs.map +1 -1
  26. package/dist/esm/graphs/MultiAgentGraph.mjs +1 -1
  27. package/dist/esm/instrumentation.mjs +3 -3
  28. package/dist/esm/langfuse.mjs +3 -3
  29. package/dist/esm/langfuseRuntimeScope.mjs +1 -1
  30. package/dist/esm/langfuseToolOutputTracing.mjs +2 -2
  31. package/dist/esm/main.mjs +3 -2
  32. package/dist/esm/messages/assistantPhase.mjs +57 -0
  33. package/dist/esm/messages/assistantPhase.mjs.map +1 -0
  34. package/dist/esm/messages/index.mjs +1 -0
  35. package/dist/esm/prompts/activityLabel.mjs +74 -1
  36. package/dist/esm/prompts/activityLabel.mjs.map +1 -1
  37. package/dist/esm/run.mjs +202 -12
  38. package/dist/esm/run.mjs.map +1 -1
  39. package/dist/esm/session/AgentSession.mjs +1 -1
  40. package/dist/esm/stream.mjs +45 -8
  41. package/dist/esm/stream.mjs.map +1 -1
  42. package/dist/esm/tools/ToolNode.mjs +3 -3
  43. package/dist/esm/tools/subagent/SubagentExecutor.mjs +81 -6
  44. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  45. package/dist/esm/utils/callbacks.mjs +8 -1
  46. package/dist/esm/utils/callbacks.mjs.map +1 -1
  47. package/dist/types/messages/assistantPhase.d.ts +22 -0
  48. package/dist/types/messages/index.d.ts +1 -0
  49. package/dist/types/prompts/activityLabel.d.ts +21 -1
  50. package/dist/types/run.d.ts +15 -2
  51. package/dist/types/types/activityLabel.d.ts +63 -0
  52. package/dist/types/types/assistantPhase.d.ts +6 -0
  53. package/dist/types/types/graph.d.ts +8 -1
  54. package/dist/types/types/index.d.ts +1 -0
  55. package/dist/types/types/stream.d.ts +11 -0
  56. package/dist/types/utils/callbacks.d.ts +1 -0
  57. package/package.json +3 -3
  58. package/src/graphs/Graph.ts +33 -9
  59. package/src/graphs/__tests__/Graph.reasoning.test.ts +57 -0
  60. package/src/messages/assistantPhase.test.ts +75 -0
  61. package/src/messages/assistantPhase.ts +91 -0
  62. package/src/messages/index.ts +1 -0
  63. package/src/prompts/activityLabel.ts +177 -1
  64. package/src/run.ts +403 -21
  65. package/src/specs/activity-label-prompt.test.ts +123 -1
  66. package/src/specs/activity-phase-label.test.ts +306 -0
  67. package/src/stream.ts +69 -12
  68. package/src/tools/__tests__/SubagentExecutor.test.ts +436 -0
  69. package/src/tools/subagent/SubagentExecutor.ts +160 -8
  70. package/src/types/activityLabel.ts +65 -0
  71. package/src/types/assistantPhase.ts +6 -0
  72. package/src/types/graph.ts +8 -0
  73. package/src/types/index.ts +1 -0
  74. package/src/types/stream.ts +9 -0
  75. package/src/utils/callbacks.ts +21 -0
@@ -1,5 +1,8 @@
1
+ import type {
2
+ ActivityLabelToolEntry,
3
+ ActivityPhaseEntry,
4
+ } from '@/types/activityLabel';
1
5
  import type { ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeContext';
2
- import type { ActivityLabelToolEntry } from '@/types/activityLabel';
3
6
  import { shouldRedactTool } from '@/langfuseToolOutputTracing';
4
7
 
5
8
  /**
@@ -25,6 +28,29 @@ Examples:
25
28
  - Read project config and dependency manifests
26
29
  - Attempted database migration, hit permission errors`;
27
30
 
31
+ /** Default system prompt for a run-wide parent activity phase. */
32
+ export const ACTIVITY_PHASE_LABEL_PROMPT = `Summarize what this phase of an agent run accomplished. The result appears as the header of one collapsed parent group containing several activities.
33
+
34
+ Rules:
35
+ - One line, 8 to 18 words, past tense
36
+ - Lead with the concrete outcome and name the most distinctive subject
37
+ - Synthesize the phase; do not enumerate, count, or restate individual activities
38
+ - Describe failures plainly when they are the phase's material outcome
39
+ - Never mention tool names, calls, arguments, reasoning, commentary, or activity counts
40
+ - Output only the summary — no quotes, no trailing punctuation, no preamble
41
+
42
+ Examples:
43
+ - Reconciled authentication behavior and fixed the failing session refresh path
44
+ - Compared deployment options and documented the safest production rollout
45
+ - Investigated database latency but could not confirm the suspected index regression
46
+
47
+ Bad examples:
48
+ - Used three tools to inspect files and run tests
49
+ - Searched code, read configuration, and updated middleware`;
50
+
51
+ /** Hard ceiling across every activity/context section in one phase request. */
52
+ export const ACTIVITY_PHASE_PROMPT_MAX_LENGTH = 12_000;
53
+
28
54
  /** Truncates a serialized value for the label prompt. */
29
55
  export function truncateForLabel(value: string, maxLength: number): string {
30
56
  if (value.length <= maxLength) {
@@ -105,6 +131,10 @@ const PREVIOUS_LABEL_LIMIT = 200;
105
131
  * produce one, and the cap keeps a 200-call programmatic batch from
106
132
  * building an enormous prompt out of per-field-bounded pieces. */
107
133
  const MAX_PROMPT_ENTRIES = 12;
134
+ const MAX_PHASE_ACTIVITIES = 12;
135
+ const MAX_PHASE_CONTEXT = 3;
136
+ const MAX_PHASE_TOOL_ENTRIES = 6;
137
+ export const ACTIVITY_PHASE_LABEL_MAX_LENGTH = 160;
108
138
 
109
139
  export type BuildActivityLabelPromptParams = {
110
140
  entries: ActivityLabelToolEntry[];
@@ -240,3 +270,149 @@ export function buildActivityLabelPrompt({
240
270
  sections.push('Header:');
241
271
  return sections.join('\n\n');
242
272
  }
273
+
274
+ export type BuildActivityPhaseLabelPromptParams = {
275
+ activities: ActivityPhaseEntry[];
276
+ totalActivityCount?: number;
277
+ charLimit: number;
278
+ assistantContext?: string[];
279
+ redaction?: ResolvedLangfuseToolOutputTracingConfig;
280
+ };
281
+
282
+ /**
283
+ * Builds bounded, redaction-aware evidence for a parent activity phase.
284
+ * Committed child labels are preferred; raw tool/reasoning evidence is only
285
+ * used when no child label exists.
286
+ */
287
+ export function buildActivityPhaseLabelPrompt({
288
+ activities,
289
+ totalActivityCount,
290
+ charLimit,
291
+ assistantContext,
292
+ redaction,
293
+ }: BuildActivityPhaseLabelPromptParams): string {
294
+ const freeFormSuppressed =
295
+ redaction != null &&
296
+ (redaction.enabled === false || redaction.redactedToolNames.size > 0);
297
+ const sections: string[] = [];
298
+ if (
299
+ !freeFormSuppressed &&
300
+ assistantContext != null &&
301
+ assistantContext.length > 0
302
+ ) {
303
+ const context = assistantContext
304
+ .slice(-MAX_PHASE_CONTEXT)
305
+ .map((text) =>
306
+ truncateForLabel(text.replace(/\s+/g, ' ').trim(), charLimit)
307
+ )
308
+ .filter((text) => text.length > 0);
309
+ if (context.length > 0) {
310
+ sections.push(
311
+ 'Intermediate assistant context (do not quote or restate):\n' +
312
+ context.map((text) => `- ${text}`).join('\n')
313
+ );
314
+ }
315
+ }
316
+
317
+ let hasDescribableEvidence = false;
318
+ const activityLines = activities
319
+ .slice(0, MAX_PHASE_ACTIVITIES)
320
+ .map((activity, index) => {
321
+ let status = 'completed';
322
+ if (activity.status === 'error') {
323
+ status = 'failed';
324
+ } else if (activity.status === 'partial') {
325
+ status = 'partial';
326
+ }
327
+ if (
328
+ !freeFormSuppressed &&
329
+ activity.label != null &&
330
+ activity.label.trim() !== ''
331
+ ) {
332
+ hasDescribableEvidence = true;
333
+ return `${index + 1}. ${status}: ${truncateForLabel(activity.label.replace(/\s+/g, ' ').trim(), charLimit)}`;
334
+ }
335
+
336
+ const evidence: string[] = [];
337
+ if (
338
+ !freeFormSuppressed &&
339
+ activity.thinkingExcerpts != null &&
340
+ activity.thinkingExcerpts.length > 0
341
+ ) {
342
+ evidence.push(
343
+ ...activity.thinkingExcerpts
344
+ .slice(0, MAX_THINKING_EXCERPTS)
345
+ .map((excerpt) =>
346
+ truncateForLabel(excerpt.replace(/\s+/g, ' ').trim(), charLimit)
347
+ )
348
+ .filter((excerpt) => excerpt.length > 0)
349
+ .map((excerpt) => `context=${excerpt}`)
350
+ );
351
+ }
352
+ if (activity.entries != null && activity.entries.length > 0) {
353
+ evidence.push(
354
+ ...activity.entries.slice(0, MAX_PHASE_TOOL_ENTRIES).map((entry) => {
355
+ const entryRedacted =
356
+ redaction != null && shouldRedactTool(entry.toolName, redaction);
357
+ const input = truncateForLabel(
358
+ serializeForLabel(entry.toolInput, charLimit),
359
+ charLimit
360
+ );
361
+ let outcome: string;
362
+ if (entryRedacted) {
363
+ outcome = redaction.redactionText;
364
+ } else if (entry.status === 'error') {
365
+ outcome = `ERROR: ${truncateForLabel(
366
+ entry.error ?? 'unknown error',
367
+ charLimit
368
+ )}`;
369
+ } else {
370
+ outcome = truncateForLabel(
371
+ serializeForLabel(entry.toolOutput, charLimit),
372
+ charLimit
373
+ );
374
+ }
375
+ return `${entry.toolName}(${input}) → ${outcome}`;
376
+ })
377
+ );
378
+ }
379
+ if (evidence.length > 0) {
380
+ hasDescribableEvidence = true;
381
+ }
382
+ return `${index + 1}. ${status}${evidence.length > 0 ? `: ${evidence.join('; ')}` : ''}`;
383
+ });
384
+
385
+ if (!hasDescribableEvidence) {
386
+ return '';
387
+ }
388
+
389
+ const activityCount = Math.max(activities.length, totalActivityCount ?? 0);
390
+ if (activityCount > MAX_PHASE_ACTIVITIES) {
391
+ activityLines.push(
392
+ `${MAX_PHASE_ACTIVITIES + 1}. …and ${activityCount - MAX_PHASE_ACTIVITIES} more activities`
393
+ );
394
+ }
395
+ sections.push(
396
+ 'Activities in this phase (synthesize; do not restate):\n' +
397
+ activityLines.join('\n')
398
+ );
399
+ const terminalCue = '\n\nPhase summary:';
400
+ const evidence = sections.join('\n\n');
401
+ const prompt = evidence + terminalCue;
402
+ if (prompt.length <= ACTIVITY_PHASE_PROMPT_MAX_LENGTH) {
403
+ return prompt;
404
+ }
405
+ const evidenceLimit =
406
+ ACTIVITY_PHASE_PROMPT_MAX_LENGTH - terminalCue.length - 1;
407
+ return `${evidence.slice(0, evidenceLimit).trimEnd()}…${terminalCue}`;
408
+ }
409
+
410
+ /** Normalizes a model result for safe single-row persistence and display. */
411
+ export function normalizeActivityPhaseLabel(label: string): string {
412
+ const normalized = label
413
+ .replace(/\s+/g, ' ')
414
+ .trim()
415
+ .replace(/^["']|["']$/g, '')
416
+ .replace(/[.!?]+$/g, '');
417
+ return truncateForLabel(normalized, ACTIVITY_PHASE_LABEL_MAX_LENGTH);
418
+ }