@librechat/agents 4.0.1 → 4.0.3

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 (245) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +3 -2
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/decisions/deadline.cjs +52 -0
  4. package/dist/cjs/decisions/deadline.cjs.map +1 -0
  5. package/dist/cjs/decisions/dialect.cjs +88 -0
  6. package/dist/cjs/decisions/dialect.cjs.map +1 -0
  7. package/dist/cjs/decisions/http.cjs +77 -0
  8. package/dist/cjs/decisions/http.cjs.map +1 -0
  9. package/dist/cjs/decisions/index.cjs +7 -0
  10. package/dist/cjs/decisions/presets.cjs +82 -0
  11. package/dist/cjs/decisions/presets.cjs.map +1 -0
  12. package/dist/cjs/decisions/questions.cjs +70 -0
  13. package/dist/cjs/decisions/questions.cjs.map +1 -0
  14. package/dist/cjs/decisions/structuredChat.cjs +172 -0
  15. package/dist/cjs/decisions/structuredChat.cjs.map +1 -0
  16. package/dist/cjs/decisions/structuredOutput.cjs +18 -0
  17. package/dist/cjs/decisions/structuredOutput.cjs.map +1 -0
  18. package/dist/cjs/decisions/traceMarker.cjs +6 -0
  19. package/dist/cjs/decisions/traceMarker.cjs.map +1 -0
  20. package/dist/cjs/decisions/transport.cjs +166 -0
  21. package/dist/cjs/decisions/transport.cjs.map +1 -0
  22. package/dist/cjs/decisions/types.cjs +44 -0
  23. package/dist/cjs/decisions/types.cjs.map +1 -0
  24. package/dist/cjs/graphs/Graph.cjs +28 -9
  25. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  26. package/dist/cjs/langfuseToolOutputTracing.cjs +6 -1
  27. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  28. package/dist/cjs/llm/google/index.cjs +1 -1
  29. package/dist/cjs/llm/invoke.cjs +34 -12
  30. package/dist/cjs/llm/invoke.cjs.map +1 -1
  31. package/dist/cjs/llm/openai/index.cjs +7 -0
  32. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  33. package/dist/cjs/llm/providerTextBoundary.cjs +355 -0
  34. package/dist/cjs/llm/providerTextBoundary.cjs.map +1 -0
  35. package/dist/cjs/llm/providerTextChunk.cjs +14 -0
  36. package/dist/cjs/llm/providerTextChunk.cjs.map +1 -0
  37. package/dist/cjs/llm/providerTextControls.cjs +236 -0
  38. package/dist/cjs/llm/providerTextControls.cjs.map +1 -0
  39. package/dist/cjs/llm/stream/smoother.cjs +2 -1
  40. package/dist/cjs/llm/stream/smoother.cjs.map +1 -1
  41. package/dist/cjs/main.cjs +49 -1
  42. package/dist/cjs/protection/providerText.cjs +224 -0
  43. package/dist/cjs/protection/providerText.cjs.map +1 -0
  44. package/dist/cjs/protection/providerTextInput.cjs +25 -0
  45. package/dist/cjs/protection/providerTextInput.cjs.map +1 -0
  46. package/dist/cjs/rerank/index.cjs +2 -0
  47. package/dist/cjs/rerank/search.cjs +45 -0
  48. package/dist/cjs/rerank/search.cjs.map +1 -0
  49. package/dist/cjs/rerank/systemone.cjs +70 -0
  50. package/dist/cjs/rerank/systemone.cjs.map +1 -0
  51. package/dist/cjs/run.cjs +11 -1
  52. package/dist/cjs/run.cjs.map +1 -1
  53. package/dist/cjs/stream.cjs +42 -14
  54. package/dist/cjs/stream.cjs.map +1 -1
  55. package/dist/cjs/summarization/node.cjs +26 -8
  56. package/dist/cjs/summarization/node.cjs.map +1 -1
  57. package/dist/cjs/tools/SubagentTool.cjs +11 -3
  58. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  59. package/dist/cjs/tools/ToolNode.cjs +6 -5
  60. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  61. package/dist/cjs/tools/search/rerankers.cjs +1 -0
  62. package/dist/cjs/tools/search/search.cjs +3 -3
  63. package/dist/cjs/tools/search/search.cjs.map +1 -1
  64. package/dist/cjs/tools/search/tool.cjs +4 -3
  65. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  66. package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs +13 -2
  67. package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs.map +1 -1
  68. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +149 -26
  69. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  70. package/dist/cjs/tools/subagent/SubagentReplay.cjs +4 -2
  71. package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
  72. package/dist/cjs/tools/subagent/childGraphConfig.cjs +3 -1
  73. package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -1
  74. package/dist/cjs/tools/subagent/diagnostics.cjs +88 -2
  75. package/dist/cjs/tools/subagent/diagnostics.cjs.map +1 -1
  76. package/dist/cjs/tools/subagent/hostArgs.cjs +214 -0
  77. package/dist/cjs/tools/subagent/hostArgs.cjs.map +1 -0
  78. package/dist/cjs/tools/subagent/index.cjs +2 -0
  79. package/dist/cjs/tools/toolErrorContent.cjs +1 -1
  80. package/dist/esm/agents/AgentContext.mjs +3 -2
  81. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  82. package/dist/esm/decisions/deadline.mjs +52 -0
  83. package/dist/esm/decisions/deadline.mjs.map +1 -0
  84. package/dist/esm/decisions/dialect.mjs +87 -0
  85. package/dist/esm/decisions/dialect.mjs.map +1 -0
  86. package/dist/esm/decisions/http.mjs +75 -0
  87. package/dist/esm/decisions/http.mjs.map +1 -0
  88. package/dist/esm/decisions/index.mjs +8 -0
  89. package/dist/esm/decisions/presets.mjs +77 -0
  90. package/dist/esm/decisions/presets.mjs.map +1 -0
  91. package/dist/esm/decisions/questions.mjs +67 -0
  92. package/dist/esm/decisions/questions.mjs.map +1 -0
  93. package/dist/esm/decisions/structuredChat.mjs +172 -0
  94. package/dist/esm/decisions/structuredChat.mjs.map +1 -0
  95. package/dist/esm/decisions/structuredOutput.mjs +18 -0
  96. package/dist/esm/decisions/structuredOutput.mjs.map +1 -0
  97. package/dist/esm/decisions/traceMarker.mjs +6 -0
  98. package/dist/esm/decisions/traceMarker.mjs.map +1 -0
  99. package/dist/esm/decisions/transport.mjs +164 -0
  100. package/dist/esm/decisions/transport.mjs.map +1 -0
  101. package/dist/esm/decisions/types.mjs +39 -0
  102. package/dist/esm/decisions/types.mjs.map +1 -0
  103. package/dist/esm/graphs/Graph.mjs +28 -9
  104. package/dist/esm/graphs/Graph.mjs.map +1 -1
  105. package/dist/esm/langfuseToolOutputTracing.mjs +6 -1
  106. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  107. package/dist/esm/llm/google/index.mjs +1 -1
  108. package/dist/esm/llm/invoke.mjs +34 -12
  109. package/dist/esm/llm/invoke.mjs.map +1 -1
  110. package/dist/esm/llm/openai/index.mjs +7 -0
  111. package/dist/esm/llm/openai/index.mjs.map +1 -1
  112. package/dist/esm/llm/providerTextBoundary.mjs +355 -0
  113. package/dist/esm/llm/providerTextBoundary.mjs.map +1 -0
  114. package/dist/esm/llm/providerTextChunk.mjs +13 -0
  115. package/dist/esm/llm/providerTextChunk.mjs.map +1 -0
  116. package/dist/esm/llm/providerTextControls.mjs +230 -0
  117. package/dist/esm/llm/providerTextControls.mjs.map +1 -0
  118. package/dist/esm/llm/stream/smoother.mjs +2 -1
  119. package/dist/esm/llm/stream/smoother.mjs.map +1 -1
  120. package/dist/esm/main.mjs +16 -2
  121. package/dist/esm/protection/providerText.mjs +218 -0
  122. package/dist/esm/protection/providerText.mjs.map +1 -0
  123. package/dist/esm/protection/providerTextInput.mjs +24 -0
  124. package/dist/esm/protection/providerTextInput.mjs.map +1 -0
  125. package/dist/esm/rerank/index.mjs +3 -0
  126. package/dist/esm/rerank/search.mjs +45 -0
  127. package/dist/esm/rerank/search.mjs.map +1 -0
  128. package/dist/esm/rerank/systemone.mjs +70 -0
  129. package/dist/esm/rerank/systemone.mjs.map +1 -0
  130. package/dist/esm/run.mjs +11 -1
  131. package/dist/esm/run.mjs.map +1 -1
  132. package/dist/esm/stream.mjs +42 -14
  133. package/dist/esm/stream.mjs.map +1 -1
  134. package/dist/esm/summarization/node.mjs +26 -8
  135. package/dist/esm/summarization/node.mjs.map +1 -1
  136. package/dist/esm/tools/SubagentTool.mjs +11 -3
  137. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  138. package/dist/esm/tools/ToolNode.mjs +6 -5
  139. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  140. package/dist/esm/tools/search/rerankers.mjs +1 -1
  141. package/dist/esm/tools/search/search.mjs +3 -3
  142. package/dist/esm/tools/search/search.mjs.map +1 -1
  143. package/dist/esm/tools/search/tool.mjs +4 -3
  144. package/dist/esm/tools/search/tool.mjs.map +1 -1
  145. package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs +13 -2
  146. package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs.map +1 -1
  147. package/dist/esm/tools/subagent/SubagentExecutor.mjs +149 -26
  148. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  149. package/dist/esm/tools/subagent/SubagentReplay.mjs +4 -2
  150. package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
  151. package/dist/esm/tools/subagent/childGraphConfig.mjs +3 -1
  152. package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -1
  153. package/dist/esm/tools/subagent/diagnostics.mjs +84 -3
  154. package/dist/esm/tools/subagent/diagnostics.mjs.map +1 -1
  155. package/dist/esm/tools/subagent/hostArgs.mjs +207 -0
  156. package/dist/esm/tools/subagent/hostArgs.mjs.map +1 -0
  157. package/dist/esm/tools/subagent/index.mjs +2 -0
  158. package/dist/esm/tools/toolErrorContent.mjs +1 -1
  159. package/dist/types/decisions/deadline.d.ts +3 -0
  160. package/dist/types/decisions/dialect.d.ts +11 -0
  161. package/dist/types/decisions/http.d.ts +22 -0
  162. package/dist/types/decisions/index.d.ts +10 -0
  163. package/dist/types/decisions/presets.d.ts +17 -0
  164. package/dist/types/decisions/questions.d.ts +8 -0
  165. package/dist/types/decisions/structuredChat.d.ts +17 -0
  166. package/dist/types/decisions/structuredOutput.d.ts +4 -0
  167. package/dist/types/decisions/traceMarker.d.ts +2 -0
  168. package/dist/types/decisions/transport.d.ts +29 -0
  169. package/dist/types/decisions/types.d.ts +119 -0
  170. package/dist/types/graphs/Graph.d.ts +7 -3
  171. package/dist/types/index.d.ts +4 -0
  172. package/dist/types/llm/invoke.d.ts +4 -1
  173. package/dist/types/llm/providerTextBoundary.d.ts +4 -0
  174. package/dist/types/llm/providerTextChunk.d.ts +7 -0
  175. package/dist/types/llm/providerTextControls.d.ts +18 -0
  176. package/dist/types/protection/providerText.d.ts +77 -0
  177. package/dist/types/protection/providerTextInput.d.ts +3 -0
  178. package/dist/types/rerank/index.d.ts +4 -0
  179. package/dist/types/rerank/search.d.ts +7 -0
  180. package/dist/types/rerank/systemone.d.ts +13 -0
  181. package/dist/types/rerank/types.d.ts +24 -0
  182. package/dist/types/run.d.ts +2 -0
  183. package/dist/types/tools/BashExecutor.d.ts +4 -0
  184. package/dist/types/tools/CodeExecutor.d.ts +4 -0
  185. package/dist/types/tools/ReadFile.d.ts +4 -0
  186. package/dist/types/tools/SkillTool.d.ts +4 -0
  187. package/dist/types/tools/SubagentTool.d.ts +2 -0
  188. package/dist/types/tools/ToolSearch.d.ts +4 -0
  189. package/dist/types/tools/search/schema.d.ts +4 -0
  190. package/dist/types/tools/search/types.d.ts +3 -1
  191. package/dist/types/tools/subagent/SubagentExecutionRegistry.d.ts +6 -0
  192. package/dist/types/tools/subagent/SubagentExecutor.d.ts +22 -1
  193. package/dist/types/tools/subagent/SubagentReplay.d.ts +3 -1
  194. package/dist/types/tools/subagent/diagnostics.d.ts +56 -8
  195. package/dist/types/tools/subagent/hostArgs.d.ts +57 -0
  196. package/dist/types/tools/subagent/index.d.ts +3 -0
  197. package/dist/types/types/graph.d.ts +39 -0
  198. package/dist/types/types/run.d.ts +6 -2
  199. package/dist/types/types/tools.d.ts +2 -0
  200. package/package.json +4 -4
  201. package/src/agents/AgentContext.ts +3 -2
  202. package/src/decisions/deadline.ts +92 -0
  203. package/src/decisions/dialect.ts +200 -0
  204. package/src/decisions/http.ts +175 -0
  205. package/src/decisions/index.ts +14 -0
  206. package/src/decisions/presets.ts +111 -0
  207. package/src/decisions/questions.ts +128 -0
  208. package/src/decisions/structuredChat.ts +358 -0
  209. package/src/decisions/structuredOutput.ts +25 -0
  210. package/src/decisions/traceMarker.ts +2 -0
  211. package/src/decisions/transport.ts +335 -0
  212. package/src/decisions/types.ts +193 -0
  213. package/src/graphs/Graph.ts +57 -9
  214. package/src/index.ts +9 -0
  215. package/src/langfuseToolOutputTracing.ts +8 -1
  216. package/src/llm/invoke.ts +48 -7
  217. package/src/llm/openai/index.ts +8 -0
  218. package/src/llm/providerTextBoundary.ts +446 -0
  219. package/src/llm/providerTextChunk.ts +15 -0
  220. package/src/llm/providerTextControls.ts +173 -0
  221. package/src/llm/stream/smoother.ts +4 -2
  222. package/src/protection/providerText.ts +325 -0
  223. package/src/protection/providerTextInput.ts +21 -0
  224. package/src/rerank/index.ts +4 -0
  225. package/src/rerank/search.ts +85 -0
  226. package/src/rerank/systemone.ts +140 -0
  227. package/src/rerank/types.ts +28 -0
  228. package/src/run.ts +13 -0
  229. package/src/stream.ts +33 -7
  230. package/src/summarization/node.ts +32 -14
  231. package/src/tools/SubagentTool.ts +14 -3
  232. package/src/tools/ToolNode.ts +7 -3
  233. package/src/tools/search/search.ts +4 -4
  234. package/src/tools/search/tool.ts +27 -25
  235. package/src/tools/search/types.ts +4 -1
  236. package/src/tools/subagent/SubagentExecutionRegistry.ts +27 -2
  237. package/src/tools/subagent/SubagentExecutor.ts +323 -28
  238. package/src/tools/subagent/SubagentReplay.ts +10 -3
  239. package/src/tools/subagent/childGraphConfig.ts +12 -1
  240. package/src/tools/subagent/diagnostics.ts +180 -9
  241. package/src/tools/subagent/hostArgs.ts +413 -0
  242. package/src/tools/subagent/index.ts +20 -0
  243. package/src/types/graph.ts +44 -0
  244. package/src/types/run.ts +6 -2
  245. package/src/types/tools.ts +6 -1
@@ -1,20 +1,20 @@
1
1
  import type { ToolCall, ToolMessage } from '@langchain/core/messages/tool';
2
2
  import type { RunnableConfig } from '@langchain/core/runnables';
3
- import type { ToolOutputReferenceState } from '@/tools/toolOutputReferences';
4
- import type { ToolApprovalReplaySnapshot } from '@/hooks';
5
3
  import type {
6
4
  FadingTier,
7
5
  FadingTiers,
8
6
  RunStepResumeState,
9
7
  ToolSessionContext,
10
8
  } from '@/types';
11
- import { isFadingTier, isLegacyFadingTier } from '@/messages/fading';
9
+ import type { ToolOutputReferenceState } from '@/tools/toolOutputReferences';
10
+ import type { ToolApprovalReplaySnapshot } from '@/hooks';
12
11
  import {
13
12
  attachRunStepResumeState,
14
13
  getRunStepResumeState,
15
14
  isRunStepResumeState,
16
15
  stripRunStepResumeState,
17
16
  } from '@/tools/runStepResume';
17
+ import { isFadingTier, isLegacyFadingTier } from '@/messages/fading';
18
18
 
19
19
  export const SUBAGENT_RESUME_MANIFEST_CONFIG_KEY =
20
20
  '__librechat_subagent_resume_manifest';
@@ -35,6 +35,7 @@ const SUBAGENT_RESUME_PRIVATE_PAYLOAD_KEYS = [
35
35
  SUBAGENT_RESUME_WRAPPER_VERSION_KEY,
36
36
  ] as const;
37
37
  const MAX_RESUME_MANIFEST_DEPTH = 32;
38
+ const HOST_ARGS_DIGEST_PATTERN = /^[a-f0-9]{64}$/;
38
39
 
39
40
  export interface SubagentCheckpointReference {
40
41
  threadId: string;
@@ -83,6 +84,8 @@ export interface SubagentResumeExecution {
83
84
  subagentType?: string;
84
85
  /** Lazy child revision bound when this execution first resolved. */
85
86
  configId?: string;
87
+ /** SHA-256 identity of the host arguments bound to this execution; never the values. */
88
+ hostArgsDigest?: string;
86
89
  approvalExecutionScope: string;
87
90
  checkpoints: SubagentCheckpointReference[];
88
91
  graphState: SubagentGraphResumeState;
@@ -354,6 +357,7 @@ function isSubagentResumeExecution(
354
357
  const childRunId = execution.childRunId;
355
358
  const subagentType = execution.subagentType;
356
359
  const configId = execution.configId;
360
+ const hostArgsDigest = execution.hostArgsDigest;
357
361
  const approvalExecutionScope = execution.approvalExecutionScope;
358
362
  const checkpoints = execution.checkpoints;
359
363
  const graphState = execution.graphState;
@@ -363,6 +367,9 @@ function isSubagentResumeExecution(
363
367
  !isString(childRunId) ||
364
368
  (subagentType != null && !isString(subagentType)) ||
365
369
  (configId != null && !isString(configId)) ||
370
+ (hostArgsDigest != null &&
371
+ (typeof hostArgsDigest !== 'string' ||
372
+ !HOST_ARGS_DIGEST_PATTERN.test(hostArgsDigest))) ||
366
373
  !isString(approvalExecutionScope) ||
367
374
  !Array.isArray(checkpoints) ||
368
375
  checkpoints.length === 0 ||
@@ -15,6 +15,7 @@ import {
15
15
  MAX_GRAPH_SUBAGENT_MEMBERS,
16
16
  MAX_GRAPH_SUBAGENT_TURNS,
17
17
  } from './runtimeLimits';
18
+ import { getSubagentHostArgSpecs } from './hostArgs';
18
19
 
19
20
  const RESERVED_GRAPH_MEMBER_IDS = new Set([
20
21
  '__start__',
@@ -69,6 +70,7 @@ type GraphSubagentConfigCandidate = {
69
70
  configId?: unknown;
70
71
  agentInputs?: unknown;
71
72
  resolveAgentInputs?: unknown;
73
+ hostArgs?: unknown;
72
74
  self?: unknown;
73
75
  };
74
76
 
@@ -156,10 +158,11 @@ function assertGraphSubagentConfigShape(
156
158
  candidate.agentInputs !== undefined ||
157
159
  candidate.resolveAgentInputs !== undefined ||
158
160
  candidate.configId !== undefined ||
161
+ candidate.hostArgs !== undefined ||
159
162
  candidate.self !== undefined
160
163
  ) {
161
164
  throw new Error(
162
- `Graph subagent "${configType}" cannot define agentInputs or self, or lazy fields configId/resolveAgentInputs.`
165
+ `Graph subagent "${configType}" cannot define agentInputs or self, or lazy fields configId/resolveAgentInputs/hostArgs.`
163
166
  );
164
167
  }
165
168
  }
@@ -482,6 +485,14 @@ function normalizeSingleAgentConfig(
482
485
  `Subagent "${config.type}" cannot combine self with resolveAgentInputs.`
483
486
  );
484
487
  }
488
+ if (
489
+ getSubagentHostArgSpecs(config).length > 0 &&
490
+ (config.resolveAgentInputs == null || config.agentInputs != null)
491
+ ) {
492
+ throw new Error(
493
+ `Subagent "${config.type}" declares hostArgs, which only a lazy resolveAgentInputs config without eager agentInputs can receive.`
494
+ );
495
+ }
485
496
  if (config.agentInputs != null) {
486
497
  return config as ResolvedSingleAgentSubagentConfig;
487
498
  }
@@ -1,3 +1,4 @@
1
+ import type { SubagentHostArgs } from '@/types/graph';
1
2
  import {
2
3
  SubagentSettlementBindingError,
3
4
  SubagentDefinitionBindingError,
@@ -5,11 +6,39 @@ import {
5
6
  SubagentExecutionInvalidatedError,
6
7
  } from './SubagentExecutionRegistry';
7
8
  import { describeCodeApiError } from '@/tools/diagnostics';
9
+ import { isSubagentHostArgName } from './hostArgs';
8
10
 
9
11
  /** Which step of child start-up failed: execution identity, then host config resolution. */
10
12
  export type SubagentResolutionPhase = 'identity' | 'config';
11
13
 
14
+ /** Why a host resolver refused a declared host argument value. */
15
+ export type SubagentHostArgumentRejection = 'unavailable' | 'not_allowed';
16
+
17
+ /**
18
+ * Thrown by a lazy resolver to refuse one declared host argument value. The
19
+ * parent model receives a fixed message naming the argument; the value and
20
+ * any error text stay private.
21
+ */
22
+ export class SubagentHostArgumentError extends Error {
23
+ readonly argument: string;
24
+ readonly rejection: SubagentHostArgumentRejection;
25
+
26
+ constructor(argument: string, rejection: SubagentHostArgumentRejection) {
27
+ super('Subagent host argument was rejected.');
28
+ this.name = 'SubagentHostArgumentError';
29
+ this.argument = argument;
30
+ this.rejection = rejection;
31
+ }
32
+ }
33
+
34
+ /** Safe host-argument refusal retained across the detached delivery boundary. */
35
+ export type SubagentHostArgumentFailure = {
36
+ argument: string;
37
+ rejection: SubagentHostArgumentRejection;
38
+ };
39
+
12
40
  const SUBAGENT_ERROR_TYPES = [
41
+ ['SubagentHostArgumentError', SubagentHostArgumentError],
13
42
  ['SubagentExecutionInvalidatedError', SubagentExecutionInvalidatedError],
14
43
  ['SubagentDefinitionBindingError', SubagentDefinitionBindingError],
15
44
  ['SubagentInvocationBindingError', SubagentInvocationBindingError],
@@ -20,18 +49,132 @@ type SubagentErrorLabel =
20
49
  | (typeof SUBAGENT_ERROR_TYPES)[number][0]
21
50
  | ReturnType<typeof describeCodeApiError>['type'];
22
51
 
23
- /**
24
- * Follows the rule in `@/tools/diagnostics`: every field is a value this
25
- * module owns or a host-registered subagent type, never text from the error.
26
- * The failure the model sees is a fixed sentence, so this line is the only
27
- * operator account of it; the host logs its own error text where it throws.
28
- */
52
+ const SUBAGENT_RESOLUTION_MESSAGES = {
53
+ workspace_unavailable:
54
+ 'Subagent error: Workspace unavailable. Retry later or choose another workspace.',
55
+ agent_unavailable: 'Subagent error: Agent not found or not accessible.',
56
+ model_unavailable: 'Subagent error: Model or provider unavailable.',
57
+ configuration_changed:
58
+ 'Subagent error: Subagent configuration changed. Start a new execution.',
59
+ host_argument_rejected:
60
+ 'Subagent error: A requested subagent argument is not available. Omit it to let the host choose, or pass a different value.',
61
+ unknown: 'Subagent error: Unable to initialize the selected subagent.',
62
+ } as const;
63
+
64
+ /** Host classifications accepted at the public failure boundary. */
65
+ export type SubagentResolutionCause = keyof typeof SUBAGENT_RESOLUTION_MESSAGES;
66
+
67
+ export type SubagentResolutionContext = {
68
+ parentRunId: string;
69
+ parentAgentId?: string;
70
+ parentToolCallId?: string;
71
+ threadId?: string;
72
+ childRunId: string;
73
+ childThreadId: string;
74
+ taskId?: string;
75
+ };
76
+
77
+ /** No received error text, writable error names, or stacks enter this payload. */
29
78
  export type SubagentResolutionDiagnostic = {
30
79
  phase: SubagentResolutionPhase;
31
80
  subagentType: string;
32
81
  aborted: boolean;
33
82
  type: SubagentErrorLabel;
34
- };
83
+ cause: SubagentResolutionCause;
84
+ message: (typeof SUBAGENT_RESOLUTION_MESSAGES)[SubagentResolutionCause];
85
+ } & Partial<SubagentResolutionContext>;
86
+
87
+ /** The original error is private. Return a classification, never error text. */
88
+ export type SubagentResolutionFailureHandler = (
89
+ detail: Readonly<SubagentResolutionDiagnostic>,
90
+ error: unknown
91
+ ) => SubagentResolutionCause | void;
92
+
93
+ function normalizeResolutionCause(
94
+ cause: SubagentResolutionCause | void
95
+ ): SubagentResolutionCause {
96
+ switch (cause) {
97
+ case 'workspace_unavailable':
98
+ case 'agent_unavailable':
99
+ case 'model_unavailable':
100
+ case 'configuration_changed':
101
+ case 'host_argument_rejected':
102
+ return cause;
103
+ default:
104
+ return 'unknown';
105
+ }
106
+ }
107
+
108
+ export function getSubagentResolutionFailureMessage(
109
+ cause: SubagentResolutionCause
110
+ ): SubagentResolutionDiagnostic['message'] {
111
+ return SUBAGENT_RESOLUTION_MESSAGES[normalizeResolutionCause(cause)];
112
+ }
113
+
114
+ /** Returns a resolver's typed host-argument refusal when its name is safe to show. */
115
+ export function getSubagentHostArgumentFailure(
116
+ error: unknown,
117
+ suppliedHostArgs: SubagentHostArgs | undefined
118
+ ): SubagentHostArgumentFailure | undefined {
119
+ try {
120
+ if (
121
+ !(error instanceof SubagentHostArgumentError) ||
122
+ suppliedHostArgs == null
123
+ ) {
124
+ return undefined;
125
+ }
126
+ const { argument, rejection } = error;
127
+ if (
128
+ typeof argument !== 'string' ||
129
+ !isSubagentHostArgName(argument) ||
130
+ !Object.prototype.hasOwnProperty.call(suppliedHostArgs, argument)
131
+ ) {
132
+ return undefined;
133
+ }
134
+ return {
135
+ argument,
136
+ rejection: rejection === 'unavailable' ? 'unavailable' : 'not_allowed',
137
+ };
138
+ } catch {
139
+ return undefined;
140
+ }
141
+ }
142
+
143
+ /** Model-facing message for a refused host argument. */
144
+ export function getSubagentHostArgumentFailureMessage(
145
+ failure: SubagentHostArgumentFailure
146
+ ): string {
147
+ const { argument } = failure;
148
+ const omit = `Omit "${argument}" to let the host choose, or pass a different value.`;
149
+ return failure.rejection === 'unavailable'
150
+ ? `Subagent error: The requested "${argument}" is unavailable right now. ${omit}`
151
+ : `Subagent error: The requested "${argument}" is not allowed for this subagent. ${omit}`;
152
+ }
153
+
154
+ /** Safe typed failure retained when detached execution crosses the host boundary. */
155
+ export class SubagentResolutionError extends Error {
156
+ readonly phase: SubagentResolutionPhase;
157
+ readonly resolutionCause: SubagentResolutionCause;
158
+ readonly hostArgument?: SubagentHostArgumentFailure;
159
+
160
+ constructor(
161
+ phase: SubagentResolutionPhase,
162
+ cause: SubagentResolutionCause,
163
+ hostArgument?: SubagentHostArgumentFailure
164
+ ) {
165
+ super(
166
+ hostArgument == null
167
+ ? getSubagentResolutionFailureMessage(cause)
168
+ : getSubagentHostArgumentFailureMessage(hostArgument)
169
+ );
170
+ this.name = 'SubagentResolutionError';
171
+ this.phase = phase;
172
+ this.resolutionCause = normalizeResolutionCause(cause);
173
+ if (hostArgument != null) {
174
+ this.hostArgument = hostArgument;
175
+ }
176
+ }
177
+ }
35
178
 
36
179
  function describeSubagentError(error: unknown): SubagentErrorLabel {
37
180
  try {
@@ -50,14 +193,42 @@ export function logSubagentResolutionFailure(
50
193
  phase: SubagentResolutionPhase,
51
194
  subagentType: string,
52
195
  signal: AbortSignal,
53
- error: unknown
54
- ): void {
196
+ error: unknown,
197
+ context?: SubagentResolutionContext,
198
+ onResolutionFailure?: SubagentResolutionFailureHandler,
199
+ suppliedHostArgs?: SubagentHostArgs
200
+ ): SubagentResolutionDiagnostic {
55
201
  const detail: SubagentResolutionDiagnostic = {
202
+ ...context,
56
203
  phase,
57
204
  subagentType,
58
205
  aborted: signal.aborted,
59
206
  type: describeSubagentError(error),
207
+ cause: 'unknown',
208
+ message: SUBAGENT_RESOLUTION_MESSAGES.unknown,
60
209
  };
210
+ const hostArgumentRejected =
211
+ getSubagentHostArgumentFailure(error, suppliedHostArgs) != null;
212
+ if (hostArgumentRejected) {
213
+ detail.cause = 'host_argument_rejected';
214
+ detail.message = SUBAGENT_RESOLUTION_MESSAGES.host_argument_rejected;
215
+ }
216
+ if (onResolutionFailure != null) {
217
+ try {
218
+ const reported = onResolutionFailure(Object.freeze({ ...detail }), error);
219
+ const cause = hostArgumentRejected
220
+ ? detail.cause
221
+ : normalizeResolutionCause(reported);
222
+ return {
223
+ ...detail,
224
+ cause,
225
+ message: getSubagentResolutionFailureMessage(cause),
226
+ };
227
+ } catch {
228
+ // A broken diagnostic sink must not replace or expose the original failure.
229
+ }
230
+ }
61
231
  // eslint-disable-next-line no-console
62
232
  console.warn('[SubagentExecutor] Subagent resolution failed', detail);
233
+ return detail;
63
234
  }