@librechat/agents 4.0.2 → 4.0.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 (162) 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/structuredChat.cjs +2 -8
  4. package/dist/cjs/decisions/structuredChat.cjs.map +1 -1
  5. package/dist/cjs/decisions/structuredOutput.cjs +18 -0
  6. package/dist/cjs/decisions/structuredOutput.cjs.map +1 -0
  7. package/dist/cjs/graphs/Graph.cjs +25 -9
  8. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  9. package/dist/cjs/llm/google/index.cjs +1 -1
  10. package/dist/cjs/llm/invoke.cjs +34 -12
  11. package/dist/cjs/llm/invoke.cjs.map +1 -1
  12. package/dist/cjs/llm/openai/index.cjs +7 -0
  13. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  14. package/dist/cjs/llm/providerTextBoundary.cjs +355 -0
  15. package/dist/cjs/llm/providerTextBoundary.cjs.map +1 -0
  16. package/dist/cjs/llm/providerTextChunk.cjs +14 -0
  17. package/dist/cjs/llm/providerTextChunk.cjs.map +1 -0
  18. package/dist/cjs/llm/providerTextControls.cjs +236 -0
  19. package/dist/cjs/llm/providerTextControls.cjs.map +1 -0
  20. package/dist/cjs/llm/stream/smoother.cjs +2 -1
  21. package/dist/cjs/llm/stream/smoother.cjs.map +1 -1
  22. package/dist/cjs/main.cjs +18 -1
  23. package/dist/cjs/protection/providerText.cjs +224 -0
  24. package/dist/cjs/protection/providerText.cjs.map +1 -0
  25. package/dist/cjs/protection/providerTextInput.cjs +25 -0
  26. package/dist/cjs/protection/providerTextInput.cjs.map +1 -0
  27. package/dist/cjs/run.cjs +7 -1
  28. package/dist/cjs/run.cjs.map +1 -1
  29. package/dist/cjs/stream.cjs +42 -14
  30. package/dist/cjs/stream.cjs.map +1 -1
  31. package/dist/cjs/summarization/node.cjs +26 -8
  32. package/dist/cjs/summarization/node.cjs.map +1 -1
  33. package/dist/cjs/tools/GitHubCompare.cjs +181 -0
  34. package/dist/cjs/tools/GitHubCompare.cjs.map +1 -0
  35. package/dist/cjs/tools/SubagentTool.cjs +11 -3
  36. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  37. package/dist/cjs/tools/ToolNode.cjs +6 -5
  38. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  39. package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs +2 -2
  40. package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs.map +1 -1
  41. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +66 -16
  42. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  43. package/dist/cjs/tools/subagent/SubagentReplay.cjs +4 -2
  44. package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
  45. package/dist/cjs/tools/subagent/childGraphConfig.cjs +3 -1
  46. package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -1
  47. package/dist/cjs/tools/subagent/diagnostics.cjs +48 -5
  48. package/dist/cjs/tools/subagent/diagnostics.cjs.map +1 -1
  49. package/dist/cjs/tools/subagent/hostArgs.cjs +214 -0
  50. package/dist/cjs/tools/subagent/hostArgs.cjs.map +1 -0
  51. package/dist/cjs/tools/subagent/index.cjs +1 -0
  52. package/dist/cjs/tools/toolErrorContent.cjs +1 -1
  53. package/dist/esm/agents/AgentContext.mjs +3 -2
  54. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  55. package/dist/esm/decisions/structuredChat.mjs +2 -8
  56. package/dist/esm/decisions/structuredChat.mjs.map +1 -1
  57. package/dist/esm/decisions/structuredOutput.mjs +18 -0
  58. package/dist/esm/decisions/structuredOutput.mjs.map +1 -0
  59. package/dist/esm/graphs/Graph.mjs +25 -9
  60. package/dist/esm/graphs/Graph.mjs.map +1 -1
  61. package/dist/esm/llm/google/index.mjs +1 -1
  62. package/dist/esm/llm/invoke.mjs +34 -12
  63. package/dist/esm/llm/invoke.mjs.map +1 -1
  64. package/dist/esm/llm/openai/index.mjs +7 -0
  65. package/dist/esm/llm/openai/index.mjs.map +1 -1
  66. package/dist/esm/llm/providerTextBoundary.mjs +355 -0
  67. package/dist/esm/llm/providerTextBoundary.mjs.map +1 -0
  68. package/dist/esm/llm/providerTextChunk.mjs +13 -0
  69. package/dist/esm/llm/providerTextChunk.mjs.map +1 -0
  70. package/dist/esm/llm/providerTextControls.mjs +230 -0
  71. package/dist/esm/llm/providerTextControls.mjs.map +1 -0
  72. package/dist/esm/llm/stream/smoother.mjs +2 -1
  73. package/dist/esm/llm/stream/smoother.mjs.map +1 -1
  74. package/dist/esm/main.mjs +6 -3
  75. package/dist/esm/protection/providerText.mjs +218 -0
  76. package/dist/esm/protection/providerText.mjs.map +1 -0
  77. package/dist/esm/protection/providerTextInput.mjs +24 -0
  78. package/dist/esm/protection/providerTextInput.mjs.map +1 -0
  79. package/dist/esm/run.mjs +7 -1
  80. package/dist/esm/run.mjs.map +1 -1
  81. package/dist/esm/stream.mjs +42 -14
  82. package/dist/esm/stream.mjs.map +1 -1
  83. package/dist/esm/summarization/node.mjs +26 -8
  84. package/dist/esm/summarization/node.mjs.map +1 -1
  85. package/dist/esm/tools/GitHubCompare.mjs +175 -0
  86. package/dist/esm/tools/GitHubCompare.mjs.map +1 -0
  87. package/dist/esm/tools/SubagentTool.mjs +11 -3
  88. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  89. package/dist/esm/tools/ToolNode.mjs +6 -5
  90. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  91. package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs +2 -2
  92. package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs.map +1 -1
  93. package/dist/esm/tools/subagent/SubagentExecutor.mjs +66 -16
  94. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  95. package/dist/esm/tools/subagent/SubagentReplay.mjs +4 -2
  96. package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
  97. package/dist/esm/tools/subagent/childGraphConfig.mjs +3 -1
  98. package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -1
  99. package/dist/esm/tools/subagent/diagnostics.mjs +46 -6
  100. package/dist/esm/tools/subagent/diagnostics.mjs.map +1 -1
  101. package/dist/esm/tools/subagent/hostArgs.mjs +207 -0
  102. package/dist/esm/tools/subagent/hostArgs.mjs.map +1 -0
  103. package/dist/esm/tools/subagent/index.mjs +1 -0
  104. package/dist/esm/tools/toolErrorContent.mjs +1 -1
  105. package/dist/types/decisions/structuredChat.d.ts +3 -2
  106. package/dist/types/decisions/structuredOutput.d.ts +4 -0
  107. package/dist/types/graphs/Graph.d.ts +6 -3
  108. package/dist/types/index.d.ts +3 -0
  109. package/dist/types/llm/invoke.d.ts +4 -1
  110. package/dist/types/llm/providerTextBoundary.d.ts +4 -0
  111. package/dist/types/llm/providerTextChunk.d.ts +7 -0
  112. package/dist/types/llm/providerTextControls.d.ts +18 -0
  113. package/dist/types/protection/providerText.d.ts +77 -0
  114. package/dist/types/protection/providerTextInput.d.ts +3 -0
  115. package/dist/types/run.d.ts +1 -0
  116. package/dist/types/tools/BashExecutor.d.ts +4 -0
  117. package/dist/types/tools/CodeExecutor.d.ts +4 -0
  118. package/dist/types/tools/GitHubCompare.d.ts +104 -0
  119. package/dist/types/tools/ReadFile.d.ts +4 -0
  120. package/dist/types/tools/SkillTool.d.ts +4 -0
  121. package/dist/types/tools/SubagentTool.d.ts +2 -0
  122. package/dist/types/tools/ToolSearch.d.ts +4 -0
  123. package/dist/types/tools/search/schema.d.ts +4 -0
  124. package/dist/types/tools/subagent/SubagentExecutionRegistry.d.ts +2 -0
  125. package/dist/types/tools/subagent/SubagentExecutor.d.ts +10 -2
  126. package/dist/types/tools/subagent/SubagentReplay.d.ts +3 -1
  127. package/dist/types/tools/subagent/diagnostics.d.ts +27 -3
  128. package/dist/types/tools/subagent/hostArgs.d.ts +57 -0
  129. package/dist/types/tools/subagent/index.d.ts +3 -2
  130. package/dist/types/types/graph.d.ts +36 -0
  131. package/dist/types/types/run.d.ts +4 -2
  132. package/dist/types/types/tools.d.ts +2 -0
  133. package/package.json +4 -4
  134. package/src/agents/AgentContext.ts +3 -2
  135. package/src/decisions/structuredChat.ts +9 -15
  136. package/src/decisions/structuredOutput.ts +25 -0
  137. package/src/graphs/Graph.ts +53 -9
  138. package/src/index.ts +8 -0
  139. package/src/llm/invoke.ts +48 -7
  140. package/src/llm/openai/index.ts +8 -0
  141. package/src/llm/providerTextBoundary.ts +446 -0
  142. package/src/llm/providerTextChunk.ts +15 -0
  143. package/src/llm/providerTextControls.ts +173 -0
  144. package/src/llm/stream/smoother.ts +4 -2
  145. package/src/protection/providerText.ts +325 -0
  146. package/src/protection/providerTextInput.ts +21 -0
  147. package/src/run.ts +9 -0
  148. package/src/stream.ts +33 -7
  149. package/src/summarization/node.ts +32 -14
  150. package/src/tools/GitHubCompare.ts +319 -0
  151. package/src/tools/SubagentTool.ts +14 -3
  152. package/src/tools/ToolNode.ts +7 -3
  153. package/src/tools/subagent/SubagentExecutionRegistry.ts +6 -2
  154. package/src/tools/subagent/SubagentExecutor.ts +145 -18
  155. package/src/tools/subagent/SubagentReplay.ts +10 -3
  156. package/src/tools/subagent/childGraphConfig.ts +12 -1
  157. package/src/tools/subagent/diagnostics.ts +98 -6
  158. package/src/tools/subagent/hostArgs.ts +413 -0
  159. package/src/tools/subagent/index.ts +9 -0
  160. package/src/types/graph.ts +41 -0
  161. package/src/types/run.ts +4 -2
  162. package/src/types/tools.ts +6 -1
@@ -0,0 +1,319 @@
1
+ import { DynamicStructuredTool } from '@langchain/core/tools';
2
+ import { INTENT_PROPERTY } from '@/tools/intentArg';
3
+
4
+ export const GitHubCompareToolName = 'github_compare';
5
+ export const GitHubCompareToolDescription =
6
+ 'Read-only GitHub comparison of two full commit SHAs in a public repository. Returns the merge-base, relation and commit counts without Git, a worktree, or worker admission. Does not fetch code or execute commands. Private repositories and arbitrary URLs are not supported.';
7
+ export const GitHubCompareToolSchema = {
8
+ type: 'object',
9
+ properties: {
10
+ intent: { ...INTENT_PROPERTY },
11
+ owner: { type: 'string', description: 'GitHub repository owner.' },
12
+ repo: { type: 'string', description: 'GitHub repository name.' },
13
+ base: {
14
+ type: 'string',
15
+ description: 'Full lowercase base commit SHA, not a moving branch.',
16
+ },
17
+ head: {
18
+ type: 'string',
19
+ description: 'Full lowercase head commit SHA, not a moving branch.',
20
+ },
21
+ },
22
+ required: ['owner', 'repo', 'base', 'head'],
23
+ } as const;
24
+ export const GitHubCompareToolDefinition = {
25
+ name: GitHubCompareToolName,
26
+ description: GitHubCompareToolDescription,
27
+ parameters: GitHubCompareToolSchema,
28
+ } as const;
29
+
30
+ export interface GitHubComparisonInput {
31
+ owner: string;
32
+ repo: string;
33
+ base: string;
34
+ head: string;
35
+ }
36
+
37
+ export interface GitHubComparison {
38
+ base: string;
39
+ head: string;
40
+ mergeBase: string;
41
+ status: 'ahead' | 'behind' | 'identical' | 'diverged';
42
+ aheadBy: number;
43
+ behindBy: number;
44
+ totalCommits: number;
45
+ }
46
+
47
+ export interface GitHubCompareOptions {
48
+ /** Caller-owned transport, including proxy and instrumentation policy. */
49
+ fetch: typeof fetch;
50
+ /** Entire request budget, including body reads. Defaults to 10 seconds; maximum 30 seconds. */
51
+ timeoutMs?: number;
52
+ }
53
+
54
+ export type GitHubComparisonErrorCode =
55
+ | 'INVALID_INPUT'
56
+ | 'INVALID_CONFIGURATION'
57
+ | 'HTTP_ERROR'
58
+ | 'INVALID_RESPONSE'
59
+ | 'RESPONSE_TOO_LARGE'
60
+ | 'TRANSPORT_ERROR';
61
+
62
+ export class GitHubComparisonError extends Error {
63
+ constructor(
64
+ public readonly code: GitHubComparisonErrorCode,
65
+ message: string,
66
+ public readonly status?: number
67
+ ) {
68
+ super(message);
69
+ this.name = 'GitHubComparisonError';
70
+ }
71
+ }
72
+
73
+ interface GitHubComparisonResponse {
74
+ base_commit?: { sha?: string };
75
+ merge_base_commit?: { sha?: string };
76
+ status?: GitHubComparison['status'];
77
+ ahead_by?: number;
78
+ behind_by?: number;
79
+ total_commits?: number;
80
+ }
81
+
82
+ const SHA = /^[a-f0-9]{40}$/;
83
+ const REPO = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,99}$/;
84
+ const MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
85
+
86
+ function awaitWithSignal<T>(
87
+ operation: () => Promise<T>,
88
+ signal: AbortSignal
89
+ ): Promise<T> {
90
+ signal.throwIfAborted();
91
+ return new Promise<T>((resolve, reject) => {
92
+ const onAbort = (): void => {
93
+ signal.removeEventListener('abort', onAbort);
94
+ reject(signal.reason);
95
+ };
96
+ signal.addEventListener('abort', onAbort, { once: true });
97
+ try {
98
+ operation().then(
99
+ (value) => {
100
+ signal.removeEventListener('abort', onAbort);
101
+ resolve(value);
102
+ },
103
+ (error) => {
104
+ signal.removeEventListener('abort', onAbort);
105
+ reject(error);
106
+ }
107
+ );
108
+ } catch (error) {
109
+ signal.removeEventListener('abort', onAbort);
110
+ reject(error);
111
+ }
112
+ });
113
+ }
114
+
115
+ function cancelBody(response: Response): void {
116
+ void response.body?.cancel().catch(() => undefined);
117
+ }
118
+
119
+ async function readResponse(
120
+ response: Response,
121
+ signal: AbortSignal
122
+ ): Promise<string> {
123
+ const reader = response.body?.getReader();
124
+ if (reader == null) {
125
+ throw new GitHubComparisonError(
126
+ 'INVALID_RESPONSE',
127
+ 'GitHub comparison returned an invalid response.'
128
+ );
129
+ }
130
+ const chunks: Uint8Array[] = [];
131
+ let bytes = 0;
132
+ try {
133
+ for (;;) {
134
+ const item = await awaitWithSignal(() => reader.read(), signal);
135
+ if (item.done) {
136
+ break;
137
+ }
138
+ bytes += item.value.byteLength;
139
+ if (bytes > MAX_RESPONSE_BYTES) {
140
+ throw new GitHubComparisonError(
141
+ 'RESPONSE_TOO_LARGE',
142
+ 'GitHub comparison response exceeded its bound.'
143
+ );
144
+ }
145
+ chunks.push(item.value);
146
+ }
147
+ return Buffer.concat(chunks, bytes).toString('utf8');
148
+ } finally {
149
+ void reader.cancel().catch(() => undefined);
150
+ reader.releaseLock();
151
+ }
152
+ }
153
+
154
+ function parseComparison(
155
+ text: string,
156
+ input: GitHubComparisonInput
157
+ ): GitHubComparison {
158
+ let data: GitHubComparisonResponse | null;
159
+ try {
160
+ data = JSON.parse(text) as GitHubComparisonResponse | null;
161
+ } catch {
162
+ throw new GitHubComparisonError(
163
+ 'INVALID_RESPONSE',
164
+ 'GitHub comparison returned an invalid response.'
165
+ );
166
+ }
167
+ const mergeBase = data?.merge_base_commit?.sha;
168
+ const status = data?.status;
169
+ const aheadBy = data?.ahead_by;
170
+ const behindBy = data?.behind_by;
171
+ const totalCommits = data?.total_commits;
172
+ if (
173
+ data?.base_commit?.sha !== input.base ||
174
+ typeof mergeBase !== 'string' ||
175
+ !SHA.test(mergeBase) ||
176
+ (status !== 'ahead' &&
177
+ status !== 'behind' &&
178
+ status !== 'identical' &&
179
+ status !== 'diverged') ||
180
+ typeof aheadBy !== 'number' ||
181
+ !Number.isSafeInteger(aheadBy) ||
182
+ aheadBy < 0 ||
183
+ typeof behindBy !== 'number' ||
184
+ !Number.isSafeInteger(behindBy) ||
185
+ behindBy < 0 ||
186
+ typeof totalCommits !== 'number' ||
187
+ !Number.isSafeInteger(totalCommits) ||
188
+ totalCommits < 0
189
+ ) {
190
+ throw new GitHubComparisonError(
191
+ 'INVALID_RESPONSE',
192
+ 'GitHub comparison returned an invalid response.'
193
+ );
194
+ }
195
+ return {
196
+ base: input.base,
197
+ head: input.head,
198
+ mergeBase,
199
+ status,
200
+ aheadBy,
201
+ behindBy,
202
+ totalCommits,
203
+ };
204
+ }
205
+
206
+ export async function compareGitHubCommits(
207
+ input: GitHubComparisonInput,
208
+ options: GitHubCompareOptions,
209
+ signal?: AbortSignal
210
+ ): Promise<GitHubComparison> {
211
+ signal?.throwIfAborted();
212
+ if (
213
+ typeof input.owner !== 'string' ||
214
+ !REPO.test(input.owner) ||
215
+ typeof input.repo !== 'string' ||
216
+ !REPO.test(input.repo) ||
217
+ typeof input.base !== 'string' ||
218
+ !SHA.test(input.base) ||
219
+ typeof input.head !== 'string' ||
220
+ !SHA.test(input.head)
221
+ ) {
222
+ throw new GitHubComparisonError(
223
+ 'INVALID_INPUT',
224
+ 'Supply a repository and full lowercase commit SHAs.'
225
+ );
226
+ }
227
+ const timeoutMs = options.timeoutMs ?? 10000;
228
+ if (
229
+ typeof options.fetch !== 'function' ||
230
+ !Number.isSafeInteger(timeoutMs) ||
231
+ timeoutMs < 1 ||
232
+ timeoutMs > 30000
233
+ ) {
234
+ throw new GitHubComparisonError(
235
+ 'INVALID_CONFIGURATION',
236
+ 'Supply a GitHub transport and a timeout between 1 and 30000 ms.'
237
+ );
238
+ }
239
+ const timeout = new AbortController();
240
+ const timer = setTimeout(
241
+ () =>
242
+ timeout.abort(
243
+ new DOMException('GitHub comparison timed out.', 'TimeoutError')
244
+ ),
245
+ timeoutMs
246
+ );
247
+ timer.unref();
248
+ let pendingResponse: Response | undefined;
249
+ const requestSignal =
250
+ signal == null ? timeout.signal : AbortSignal.any([signal, timeout.signal]);
251
+ try {
252
+ const response = await awaitWithSignal(
253
+ () =>
254
+ options
255
+ .fetch(
256
+ `https://api.github.com/repos/${encodeURIComponent(input.owner)}/${encodeURIComponent(input.repo)}/compare/${input.base}...${input.head}?per_page=1&page=2`,
257
+ {
258
+ method: 'GET',
259
+ redirect: 'error',
260
+ credentials: 'omit',
261
+ signal: requestSignal,
262
+ headers: {
263
+ Accept: 'application/vnd.github+json',
264
+ 'X-GitHub-Api-Version': '2022-11-28',
265
+ },
266
+ }
267
+ )
268
+ .then((response) => {
269
+ pendingResponse = response;
270
+ if (requestSignal.aborted) {
271
+ pendingResponse = undefined;
272
+ cancelBody(response);
273
+ requestSignal.throwIfAborted();
274
+ }
275
+ return response;
276
+ }),
277
+ requestSignal
278
+ );
279
+ if (!response.ok) {
280
+ throw new GitHubComparisonError(
281
+ 'HTTP_ERROR',
282
+ `GitHub comparison unavailable (HTTP ${response.status}).`,
283
+ response.status
284
+ );
285
+ }
286
+ pendingResponse = undefined;
287
+ const text = await readResponse(response, requestSignal);
288
+ requestSignal.throwIfAborted();
289
+ return parseComparison(text, input);
290
+ } catch (error) {
291
+ requestSignal.throwIfAborted();
292
+ if (error instanceof GitHubComparisonError) {
293
+ throw error;
294
+ }
295
+ throw new GitHubComparisonError(
296
+ 'TRANSPORT_ERROR',
297
+ 'GitHub comparison transport failed.'
298
+ );
299
+ } finally {
300
+ if (pendingResponse != null) {
301
+ cancelBody(pendingResponse);
302
+ }
303
+ clearTimeout(timer);
304
+ }
305
+ }
306
+
307
+ export class GitHubCompareTool extends DynamicStructuredTool {
308
+ constructor(options: GitHubCompareOptions) {
309
+ super({
310
+ name: GitHubCompareToolName,
311
+ description: GitHubCompareToolDescription,
312
+ schema: structuredClone(GitHubCompareToolSchema),
313
+ func: async (input: GitHubComparisonInput, _manager, config) =>
314
+ JSON.stringify(
315
+ await compareGitHubCommits(input, options, config?.signal)
316
+ ),
317
+ });
318
+ }
319
+ }
@@ -1,5 +1,6 @@
1
1
  import type { JsonSchemaType, LCTool } from '@/types/tools';
2
2
  import type { SubagentConfig } from '@/types';
3
+ import { buildSubagentHostArgProperties } from '@/tools/subagent/hostArgs';
3
4
  import { INTENT_PROPERTY } from '@/tools/intentArg';
4
5
  import { Constants } from '@/common';
5
6
 
@@ -33,6 +34,9 @@ const RUN_IN_BACKGROUND_PROP_DESCRIPTION =
33
34
  const SUBAGENT_THREAD_PROP_DESCRIPTION =
34
35
  'Continue a host-owned child thread using a fresh execution lease. The saved thread must belong to this scope and subagent type. Only available with run_in_background.';
35
36
 
37
+ const HOST_ARGS_DESCRIPTION =
38
+ '\n\nOPTIONAL ARGUMENTS:\n- Some types accept extra arguments, listed in brackets after the type. Each is optional: omit it to let the host choose. Where values are listed, pass one listed for the selected type; where it says any text, pass a short value of your own.';
39
+
36
40
  export const SubagentToolSchema = {
37
41
  type: 'object',
38
42
  properties: {
@@ -69,8 +73,13 @@ export function buildSubagentToolParams(
69
73
  description: string;
70
74
  } {
71
75
  const types = configs.map((c) => c.type);
76
+ const hostArgs = buildSubagentHostArgProperties(configs);
72
77
  const typeDescriptions = configs
73
- .map((c) => `- "${c.type}" (${c.name}): ${c.description}`)
78
+ .map((c) => {
79
+ const summary = hostArgs.summaries.get(c.type);
80
+ const line = `- "${c.type}" (${c.name}): ${c.description}`;
81
+ return summary == null ? line : `${line} [optional ${summary}]`;
82
+ })
74
83
  .join('\n');
75
84
 
76
85
  return {
@@ -96,8 +105,7 @@ export function buildSubagentToolParams(
96
105
  },
97
106
  }
98
107
  : {}),
99
- ...(options.background === true &&
100
- options.threadContinuation === true
108
+ ...(options.background === true && options.threadContinuation === true
101
109
  ? {
102
110
  subagent_thread_id: {
103
111
  type: 'string',
@@ -105,10 +113,13 @@ export function buildSubagentToolParams(
105
113
  },
106
114
  }
107
115
  : {}),
116
+ ...hostArgs.properties,
108
117
  },
109
118
  required: ['description', 'subagent_type'],
110
119
  },
111
120
  description: `${SubagentToolDescription}${
121
+ hostArgs.summaries.size > 0 ? HOST_ARGS_DESCRIPTION : ''
122
+ }${
112
123
  options.background === true
113
124
  ? '\n\nBACKGROUND EXECUTION:\n- Set run_in_background to true when you do not need the result immediately. The call returns a background_task_id; use the host background-task tools to poll, steer, queue, interrupt, or cancel it.'
114
125
  : ''
@@ -130,6 +130,7 @@ import {
130
130
  } from '@/tools/local';
131
131
  import { stripCodeSessionFileSummary } from '@/tools/CodeSessionFileSummary';
132
132
  import { Constants, GraphEvents, CODE_EXECUTION_TOOLS } from '@/common';
133
+ import { ProviderTextProtectionError } from '@/protection/providerText';
133
134
  import { formatToolErrorContent } from '@/tools/toolErrorContent';
134
135
  import { PreparedSubagentError } from '@/tools/preparedSubagents';
135
136
  import { attachRunStepResumeState } from '@/tools/runStepResume';
@@ -2146,7 +2147,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
2146
2147
  */
2147
2148
  if (
2148
2149
  e instanceof StreamLimitExceededError ||
2149
- e instanceof PreparedSubagentError
2150
+ e instanceof PreparedSubagentError ||
2151
+ e instanceof ProviderTextProtectionError
2150
2152
  ) {
2151
2153
  throw e;
2152
2154
  }
@@ -3486,7 +3488,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
3486
3488
  if (
3487
3489
  signal?.aborted === true &&
3488
3490
  (signal.reason instanceof StreamLimitExceededError ||
3489
- signal.reason instanceof PreparedSubagentError)
3491
+ signal.reason instanceof PreparedSubagentError ||
3492
+ signal.reason instanceof ProviderTextProtectionError)
3490
3493
  ) {
3491
3494
  throw signal.reason;
3492
3495
  }
@@ -5467,7 +5470,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
5467
5470
  if (
5468
5471
  composedSignal?.aborted === true &&
5469
5472
  (composedSignal.reason instanceof StreamLimitExceededError ||
5470
- composedSignal.reason instanceof PreparedSubagentError)
5473
+ composedSignal.reason instanceof PreparedSubagentError ||
5474
+ composedSignal.reason instanceof ProviderTextProtectionError)
5471
5475
  ) {
5472
5476
  throw composedSignal.reason;
5473
5477
  }
@@ -63,6 +63,8 @@ export type SubagentInvocationBinding = Readonly<{
63
63
  description: string;
64
64
  subagentType: string;
65
65
  configId?: string;
66
+ /** Value-free identity of the call's validated host arguments. */
67
+ hostArgsDigest?: string;
66
68
  }>;
67
69
 
68
70
  export type SubagentSettlementBinding = Readonly<{
@@ -340,7 +342,8 @@ function assertCompatibleResumeExecution(
340
342
  current.parentToolCallId === next.parentToolCallId &&
341
343
  current.childRunId === next.childRunId &&
342
344
  current.subagentType === next.subagentType &&
343
- current.configId === next.configId
345
+ current.configId === next.configId &&
346
+ current.hostArgsDigest === next.hostArgsDigest
344
347
  ) {
345
348
  return;
346
349
  }
@@ -354,7 +357,8 @@ function assertSameInvocation(
354
357
  if (
355
358
  current.description === next.description &&
356
359
  current.subagentType === next.subagentType &&
357
- current.configId === next.configId
360
+ current.configId === next.configId &&
361
+ current.hostArgsDigest === next.hostArgsDigest
358
362
  ) {
359
363
  return;
360
364
  }