@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.
- package/dist/cjs/agents/AgentContext.cjs +3 -2
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/decisions/deadline.cjs +52 -0
- package/dist/cjs/decisions/deadline.cjs.map +1 -0
- package/dist/cjs/decisions/dialect.cjs +88 -0
- package/dist/cjs/decisions/dialect.cjs.map +1 -0
- package/dist/cjs/decisions/http.cjs +77 -0
- package/dist/cjs/decisions/http.cjs.map +1 -0
- package/dist/cjs/decisions/index.cjs +7 -0
- package/dist/cjs/decisions/presets.cjs +82 -0
- package/dist/cjs/decisions/presets.cjs.map +1 -0
- package/dist/cjs/decisions/questions.cjs +70 -0
- package/dist/cjs/decisions/questions.cjs.map +1 -0
- package/dist/cjs/decisions/structuredChat.cjs +172 -0
- package/dist/cjs/decisions/structuredChat.cjs.map +1 -0
- package/dist/cjs/decisions/structuredOutput.cjs +18 -0
- package/dist/cjs/decisions/structuredOutput.cjs.map +1 -0
- package/dist/cjs/decisions/traceMarker.cjs +6 -0
- package/dist/cjs/decisions/traceMarker.cjs.map +1 -0
- package/dist/cjs/decisions/transport.cjs +166 -0
- package/dist/cjs/decisions/transport.cjs.map +1 -0
- package/dist/cjs/decisions/types.cjs +44 -0
- package/dist/cjs/decisions/types.cjs.map +1 -0
- package/dist/cjs/graphs/Graph.cjs +28 -9
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/langfuseToolOutputTracing.cjs +6 -1
- package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
- package/dist/cjs/llm/google/index.cjs +1 -1
- package/dist/cjs/llm/invoke.cjs +34 -12
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +7 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/providerTextBoundary.cjs +355 -0
- package/dist/cjs/llm/providerTextBoundary.cjs.map +1 -0
- package/dist/cjs/llm/providerTextChunk.cjs +14 -0
- package/dist/cjs/llm/providerTextChunk.cjs.map +1 -0
- package/dist/cjs/llm/providerTextControls.cjs +236 -0
- package/dist/cjs/llm/providerTextControls.cjs.map +1 -0
- package/dist/cjs/llm/stream/smoother.cjs +2 -1
- package/dist/cjs/llm/stream/smoother.cjs.map +1 -1
- package/dist/cjs/main.cjs +49 -1
- package/dist/cjs/protection/providerText.cjs +224 -0
- package/dist/cjs/protection/providerText.cjs.map +1 -0
- package/dist/cjs/protection/providerTextInput.cjs +25 -0
- package/dist/cjs/protection/providerTextInput.cjs.map +1 -0
- package/dist/cjs/rerank/index.cjs +2 -0
- package/dist/cjs/rerank/search.cjs +45 -0
- package/dist/cjs/rerank/search.cjs.map +1 -0
- package/dist/cjs/rerank/systemone.cjs +70 -0
- package/dist/cjs/rerank/systemone.cjs.map +1 -0
- package/dist/cjs/run.cjs +11 -1
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +42 -14
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +26 -8
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/SubagentTool.cjs +11 -3
- package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +6 -5
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/search/rerankers.cjs +1 -0
- package/dist/cjs/tools/search/search.cjs +3 -3
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +4 -3
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs +13 -2
- package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +149 -26
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs +4 -2
- package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
- package/dist/cjs/tools/subagent/childGraphConfig.cjs +3 -1
- package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -1
- package/dist/cjs/tools/subagent/diagnostics.cjs +88 -2
- package/dist/cjs/tools/subagent/diagnostics.cjs.map +1 -1
- package/dist/cjs/tools/subagent/hostArgs.cjs +214 -0
- package/dist/cjs/tools/subagent/hostArgs.cjs.map +1 -0
- package/dist/cjs/tools/subagent/index.cjs +2 -0
- package/dist/cjs/tools/toolErrorContent.cjs +1 -1
- package/dist/esm/agents/AgentContext.mjs +3 -2
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/decisions/deadline.mjs +52 -0
- package/dist/esm/decisions/deadline.mjs.map +1 -0
- package/dist/esm/decisions/dialect.mjs +87 -0
- package/dist/esm/decisions/dialect.mjs.map +1 -0
- package/dist/esm/decisions/http.mjs +75 -0
- package/dist/esm/decisions/http.mjs.map +1 -0
- package/dist/esm/decisions/index.mjs +8 -0
- package/dist/esm/decisions/presets.mjs +77 -0
- package/dist/esm/decisions/presets.mjs.map +1 -0
- package/dist/esm/decisions/questions.mjs +67 -0
- package/dist/esm/decisions/questions.mjs.map +1 -0
- package/dist/esm/decisions/structuredChat.mjs +172 -0
- package/dist/esm/decisions/structuredChat.mjs.map +1 -0
- package/dist/esm/decisions/structuredOutput.mjs +18 -0
- package/dist/esm/decisions/structuredOutput.mjs.map +1 -0
- package/dist/esm/decisions/traceMarker.mjs +6 -0
- package/dist/esm/decisions/traceMarker.mjs.map +1 -0
- package/dist/esm/decisions/transport.mjs +164 -0
- package/dist/esm/decisions/transport.mjs.map +1 -0
- package/dist/esm/decisions/types.mjs +39 -0
- package/dist/esm/decisions/types.mjs.map +1 -0
- package/dist/esm/graphs/Graph.mjs +28 -9
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/langfuseToolOutputTracing.mjs +6 -1
- package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
- package/dist/esm/llm/google/index.mjs +1 -1
- package/dist/esm/llm/invoke.mjs +34 -12
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +7 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/providerTextBoundary.mjs +355 -0
- package/dist/esm/llm/providerTextBoundary.mjs.map +1 -0
- package/dist/esm/llm/providerTextChunk.mjs +13 -0
- package/dist/esm/llm/providerTextChunk.mjs.map +1 -0
- package/dist/esm/llm/providerTextControls.mjs +230 -0
- package/dist/esm/llm/providerTextControls.mjs.map +1 -0
- package/dist/esm/llm/stream/smoother.mjs +2 -1
- package/dist/esm/llm/stream/smoother.mjs.map +1 -1
- package/dist/esm/main.mjs +16 -2
- package/dist/esm/protection/providerText.mjs +218 -0
- package/dist/esm/protection/providerText.mjs.map +1 -0
- package/dist/esm/protection/providerTextInput.mjs +24 -0
- package/dist/esm/protection/providerTextInput.mjs.map +1 -0
- package/dist/esm/rerank/index.mjs +3 -0
- package/dist/esm/rerank/search.mjs +45 -0
- package/dist/esm/rerank/search.mjs.map +1 -0
- package/dist/esm/rerank/systemone.mjs +70 -0
- package/dist/esm/rerank/systemone.mjs.map +1 -0
- package/dist/esm/run.mjs +11 -1
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +42 -14
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +26 -8
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/SubagentTool.mjs +11 -3
- package/dist/esm/tools/SubagentTool.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +6 -5
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/search/rerankers.mjs +1 -1
- package/dist/esm/tools/search/search.mjs +3 -3
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +4 -3
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs +13 -2
- package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +149 -26
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs +4 -2
- package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
- package/dist/esm/tools/subagent/childGraphConfig.mjs +3 -1
- package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -1
- package/dist/esm/tools/subagent/diagnostics.mjs +84 -3
- package/dist/esm/tools/subagent/diagnostics.mjs.map +1 -1
- package/dist/esm/tools/subagent/hostArgs.mjs +207 -0
- package/dist/esm/tools/subagent/hostArgs.mjs.map +1 -0
- package/dist/esm/tools/subagent/index.mjs +2 -0
- package/dist/esm/tools/toolErrorContent.mjs +1 -1
- package/dist/types/decisions/deadline.d.ts +3 -0
- package/dist/types/decisions/dialect.d.ts +11 -0
- package/dist/types/decisions/http.d.ts +22 -0
- package/dist/types/decisions/index.d.ts +10 -0
- package/dist/types/decisions/presets.d.ts +17 -0
- package/dist/types/decisions/questions.d.ts +8 -0
- package/dist/types/decisions/structuredChat.d.ts +17 -0
- package/dist/types/decisions/structuredOutput.d.ts +4 -0
- package/dist/types/decisions/traceMarker.d.ts +2 -0
- package/dist/types/decisions/transport.d.ts +29 -0
- package/dist/types/decisions/types.d.ts +119 -0
- package/dist/types/graphs/Graph.d.ts +7 -3
- package/dist/types/index.d.ts +4 -0
- package/dist/types/llm/invoke.d.ts +4 -1
- package/dist/types/llm/providerTextBoundary.d.ts +4 -0
- package/dist/types/llm/providerTextChunk.d.ts +7 -0
- package/dist/types/llm/providerTextControls.d.ts +18 -0
- package/dist/types/protection/providerText.d.ts +77 -0
- package/dist/types/protection/providerTextInput.d.ts +3 -0
- package/dist/types/rerank/index.d.ts +4 -0
- package/dist/types/rerank/search.d.ts +7 -0
- package/dist/types/rerank/systemone.d.ts +13 -0
- package/dist/types/rerank/types.d.ts +24 -0
- package/dist/types/run.d.ts +2 -0
- package/dist/types/tools/BashExecutor.d.ts +4 -0
- package/dist/types/tools/CodeExecutor.d.ts +4 -0
- package/dist/types/tools/ReadFile.d.ts +4 -0
- package/dist/types/tools/SkillTool.d.ts +4 -0
- package/dist/types/tools/SubagentTool.d.ts +2 -0
- package/dist/types/tools/ToolSearch.d.ts +4 -0
- package/dist/types/tools/search/schema.d.ts +4 -0
- package/dist/types/tools/search/types.d.ts +3 -1
- package/dist/types/tools/subagent/SubagentExecutionRegistry.d.ts +6 -0
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +22 -1
- package/dist/types/tools/subagent/SubagentReplay.d.ts +3 -1
- package/dist/types/tools/subagent/diagnostics.d.ts +56 -8
- package/dist/types/tools/subagent/hostArgs.d.ts +57 -0
- package/dist/types/tools/subagent/index.d.ts +3 -0
- package/dist/types/types/graph.d.ts +39 -0
- package/dist/types/types/run.d.ts +6 -2
- package/dist/types/types/tools.d.ts +2 -0
- package/package.json +4 -4
- package/src/agents/AgentContext.ts +3 -2
- package/src/decisions/deadline.ts +92 -0
- package/src/decisions/dialect.ts +200 -0
- package/src/decisions/http.ts +175 -0
- package/src/decisions/index.ts +14 -0
- package/src/decisions/presets.ts +111 -0
- package/src/decisions/questions.ts +128 -0
- package/src/decisions/structuredChat.ts +358 -0
- package/src/decisions/structuredOutput.ts +25 -0
- package/src/decisions/traceMarker.ts +2 -0
- package/src/decisions/transport.ts +335 -0
- package/src/decisions/types.ts +193 -0
- package/src/graphs/Graph.ts +57 -9
- package/src/index.ts +9 -0
- package/src/langfuseToolOutputTracing.ts +8 -1
- package/src/llm/invoke.ts +48 -7
- package/src/llm/openai/index.ts +8 -0
- package/src/llm/providerTextBoundary.ts +446 -0
- package/src/llm/providerTextChunk.ts +15 -0
- package/src/llm/providerTextControls.ts +173 -0
- package/src/llm/stream/smoother.ts +4 -2
- package/src/protection/providerText.ts +325 -0
- package/src/protection/providerTextInput.ts +21 -0
- package/src/rerank/index.ts +4 -0
- package/src/rerank/search.ts +85 -0
- package/src/rerank/systemone.ts +140 -0
- package/src/rerank/types.ts +28 -0
- package/src/run.ts +13 -0
- package/src/stream.ts +33 -7
- package/src/summarization/node.ts +32 -14
- package/src/tools/SubagentTool.ts +14 -3
- package/src/tools/ToolNode.ts +7 -3
- package/src/tools/search/search.ts +4 -4
- package/src/tools/search/tool.ts +27 -25
- package/src/tools/search/types.ts +4 -1
- package/src/tools/subagent/SubagentExecutionRegistry.ts +27 -2
- package/src/tools/subagent/SubagentExecutor.ts +323 -28
- package/src/tools/subagent/SubagentReplay.ts +10 -3
- package/src/tools/subagent/childGraphConfig.ts +12 -1
- package/src/tools/subagent/diagnostics.ts +180 -9
- package/src/tools/subagent/hostArgs.ts +413 -0
- package/src/tools/subagent/index.ts +20 -0
- package/src/types/graph.ts +44 -0
- package/src/types/run.ts +6 -2
- package/src/types/tools.ts +6 -1
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import type {
|
|
3
|
+
SubagentHostArgs,
|
|
4
|
+
SubagentHostArgSpec,
|
|
5
|
+
SubagentHostArgSpecs,
|
|
6
|
+
} from '@/types/graph';
|
|
7
|
+
import type { JsonSchemaType } from '@/types/tools';
|
|
8
|
+
|
|
9
|
+
/** Bounds on host-declared subagent call arguments and their values. */
|
|
10
|
+
export const SUBAGENT_HOST_ARG_LIMITS = Object.freeze({
|
|
11
|
+
argsPerSubagent: 8,
|
|
12
|
+
distinctArgs: 16,
|
|
13
|
+
enumValues: 64,
|
|
14
|
+
mergedEnumValues: 256,
|
|
15
|
+
valueLength: 256,
|
|
16
|
+
descriptionLength: 1024,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const HOST_ARG_NAME_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
|
|
20
|
+
/** Advertises the runtime's no-control-character rule; fixed and linear-time. */
|
|
21
|
+
const FREE_FORM_SCHEMA_PATTERN = '^[^\\u0000-\\u001f\\u007f]*$';
|
|
22
|
+
const RESERVED_HOST_ARG_NAMES: ReadonlySet<string> = new Set([
|
|
23
|
+
'intent',
|
|
24
|
+
'description',
|
|
25
|
+
'subagent_type',
|
|
26
|
+
'run_in_background',
|
|
27
|
+
'subagent_thread_id',
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
/** Any subagent entry that may declare host arguments. */
|
|
31
|
+
export type SubagentHostArgDeclaration = {
|
|
32
|
+
type: string;
|
|
33
|
+
hostArgs?: SubagentHostArgSpecs;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type SubagentHostArgsResult =
|
|
37
|
+
| { ok: true; hostArgs?: SubagentHostArgs }
|
|
38
|
+
| { ok: false; message: string };
|
|
39
|
+
|
|
40
|
+
type HostArgEntry = readonly [string, SubagentHostArgSpec];
|
|
41
|
+
|
|
42
|
+
type MergedHostArg = {
|
|
43
|
+
description: string;
|
|
44
|
+
values: string[];
|
|
45
|
+
seenValues: Set<string>;
|
|
46
|
+
freeForm: boolean;
|
|
47
|
+
maxLength: number;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** A name a host may declare: lowercase snake case, not a built-in subagent argument. */
|
|
51
|
+
export function isSubagentHostArgName(name: string): boolean {
|
|
52
|
+
return HOST_ARG_NAME_PATTERN.test(name) && !RESERVED_HOST_ARG_NAMES.has(name);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Length in Unicode code points, the unit JSON Schema `maxLength` counts. */
|
|
56
|
+
function countCodePoints(value: string): number {
|
|
57
|
+
let count = 0;
|
|
58
|
+
for (const _ of value) {
|
|
59
|
+
count += 1;
|
|
60
|
+
}
|
|
61
|
+
return count;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function hasControlCharacter(value: string): boolean {
|
|
65
|
+
for (let i = 0; i < value.length; i++) {
|
|
66
|
+
const code = value.charCodeAt(i);
|
|
67
|
+
if (code < 0x20 || code === 0x7f) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function isBoundedText(value: unknown, maxLength: number): value is string {
|
|
75
|
+
return (
|
|
76
|
+
typeof value === 'string' &&
|
|
77
|
+
value.trim().length > 0 &&
|
|
78
|
+
countCodePoints(value) <= maxLength &&
|
|
79
|
+
!hasControlCharacter(value)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getFreeFormMaxLength(spec: SubagentHostArgSpec): number {
|
|
84
|
+
return spec.maxLength ?? SUBAGENT_HOST_ARG_LIMITS.valueLength;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function validateEnum(label: string, values: readonly string[]): void {
|
|
88
|
+
if (
|
|
89
|
+
!Array.isArray(values) ||
|
|
90
|
+
values.length === 0 ||
|
|
91
|
+
values.length > SUBAGENT_HOST_ARG_LIMITS.enumValues
|
|
92
|
+
) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`${label} enum must list 1-${SUBAGENT_HOST_ARG_LIMITS.enumValues} values.`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
const seen = new Set<string>();
|
|
98
|
+
for (const value of values) {
|
|
99
|
+
if (!isBoundedText(value, SUBAGENT_HOST_ARG_LIMITS.valueLength)) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`${label} enum values must be non-blank strings of at most ${SUBAGENT_HOST_ARG_LIMITS.valueLength} characters without control characters.`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
if (seen.has(value)) {
|
|
105
|
+
throw new Error(`${label} enum values must be unique.`);
|
|
106
|
+
}
|
|
107
|
+
seen.add(value);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function validateFreeForm(label: string, spec: SubagentHostArgSpec): void {
|
|
112
|
+
const maxLength = getFreeFormMaxLength(spec);
|
|
113
|
+
if (
|
|
114
|
+
!Number.isSafeInteger(maxLength) ||
|
|
115
|
+
maxLength < 1 ||
|
|
116
|
+
maxLength > SUBAGENT_HOST_ARG_LIMITS.valueLength
|
|
117
|
+
) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`${label} maxLength must be an integer from 1 to ${SUBAGENT_HOST_ARG_LIMITS.valueLength}.`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function validateSpec(
|
|
125
|
+
type: string,
|
|
126
|
+
name: string,
|
|
127
|
+
spec: SubagentHostArgSpec | undefined
|
|
128
|
+
): asserts spec is SubagentHostArgSpec {
|
|
129
|
+
const label = `Subagent "${type}" host argument "${name}"`;
|
|
130
|
+
if (!isSubagentHostArgName(name)) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`${label} must match ${HOST_ARG_NAME_PATTERN.source} and must not reuse a built-in subagent argument name.`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
if (spec == null) {
|
|
136
|
+
throw new Error(`${label} must be an object.`);
|
|
137
|
+
}
|
|
138
|
+
if ((spec as { pattern?: unknown }).pattern !== undefined) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
`${label} cannot declare a pattern; validate the format in the resolver.`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
if (
|
|
144
|
+
typeof spec.description !== 'string' ||
|
|
145
|
+
spec.description.trim().length === 0 ||
|
|
146
|
+
spec.description.length > SUBAGENT_HOST_ARG_LIMITS.descriptionLength
|
|
147
|
+
) {
|
|
148
|
+
throw new Error(
|
|
149
|
+
`${label} needs a description of at most ${SUBAGENT_HOST_ARG_LIMITS.descriptionLength} characters.`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
if (spec.enum == null) {
|
|
153
|
+
validateFreeForm(label, spec);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (spec.maxLength != null) {
|
|
157
|
+
throw new Error(`${label} cannot combine enum with maxLength.`);
|
|
158
|
+
}
|
|
159
|
+
validateEnum(label, spec.enum);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Returns a subagent's validated host argument declarations in declaration
|
|
164
|
+
* order. Throws on a malformed or oversized declaration.
|
|
165
|
+
*/
|
|
166
|
+
export function getSubagentHostArgSpecs(
|
|
167
|
+
config: SubagentHostArgDeclaration
|
|
168
|
+
): readonly HostArgEntry[] {
|
|
169
|
+
const { hostArgs } = config;
|
|
170
|
+
if (hostArgs == null) {
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
if (typeof hostArgs !== 'object' || Array.isArray(hostArgs)) {
|
|
174
|
+
throw new Error(`Subagent "${config.type}" hostArgs must be an object.`);
|
|
175
|
+
}
|
|
176
|
+
const entries = Object.entries(hostArgs);
|
|
177
|
+
if (entries.length > SUBAGENT_HOST_ARG_LIMITS.argsPerSubagent) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Subagent "${config.type}" declares more than ${SUBAGENT_HOST_ARG_LIMITS.argsPerSubagent} host arguments.`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
for (const [name, spec] of entries) {
|
|
183
|
+
validateSpec(config.type, name, spec);
|
|
184
|
+
}
|
|
185
|
+
return entries;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Every host argument name declared by at least one subagent. */
|
|
189
|
+
export function collectSubagentHostArgNames(
|
|
190
|
+
configs: readonly SubagentHostArgDeclaration[]
|
|
191
|
+
): ReadonlySet<string> {
|
|
192
|
+
const names = new Set<string>();
|
|
193
|
+
for (const config of configs) {
|
|
194
|
+
for (const [name] of getSubagentHostArgSpecs(config)) {
|
|
195
|
+
names.add(name);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (names.size > SUBAGENT_HOST_ARG_LIMITS.distinctArgs) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
`Subagents declare more than ${SUBAGENT_HOST_ARG_LIMITS.distinctArgs} distinct host arguments.`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
return names;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function mergeSpec(
|
|
207
|
+
merged: Map<string, MergedHostArg>,
|
|
208
|
+
name: string,
|
|
209
|
+
spec: SubagentHostArgSpec
|
|
210
|
+
): void {
|
|
211
|
+
let entry = merged.get(name);
|
|
212
|
+
if (entry == null) {
|
|
213
|
+
entry = {
|
|
214
|
+
description: spec.description,
|
|
215
|
+
values: [],
|
|
216
|
+
seenValues: new Set(),
|
|
217
|
+
freeForm: false,
|
|
218
|
+
maxLength: 0,
|
|
219
|
+
};
|
|
220
|
+
merged.set(name, entry);
|
|
221
|
+
}
|
|
222
|
+
if (spec.enum == null) {
|
|
223
|
+
entry.freeForm = true;
|
|
224
|
+
entry.maxLength = Math.max(entry.maxLength, getFreeFormMaxLength(spec));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
for (const value of spec.enum) {
|
|
228
|
+
entry.maxLength = Math.max(entry.maxLength, countCodePoints(value));
|
|
229
|
+
if (!entry.seenValues.has(value)) {
|
|
230
|
+
entry.seenValues.add(value);
|
|
231
|
+
entry.values.push(value);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (entry.values.length > SUBAGENT_HOST_ARG_LIMITS.mergedEnumValues) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`Subagent host argument "${name}" lists more than ${SUBAGENT_HOST_ARG_LIMITS.mergedEnumValues} distinct values across subagents.`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function toPropertySchema(entry: MergedHostArg): JsonSchemaType {
|
|
242
|
+
if (!entry.freeForm) {
|
|
243
|
+
return {
|
|
244
|
+
type: 'string',
|
|
245
|
+
description: entry.description,
|
|
246
|
+
enum: entry.values,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
type: 'string',
|
|
251
|
+
description: entry.description,
|
|
252
|
+
maxLength: entry.maxLength,
|
|
253
|
+
pattern: FREE_FORM_SCHEMA_PATTERN,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function summarizeSpecs(entries: readonly HostArgEntry[]): string {
|
|
258
|
+
return entries
|
|
259
|
+
.map(
|
|
260
|
+
([name, spec]) =>
|
|
261
|
+
`${name}: ${
|
|
262
|
+
spec.enum == null
|
|
263
|
+
? `any text up to ${getFreeFormMaxLength(spec)} characters`
|
|
264
|
+
: spec.enum.join(' | ')
|
|
265
|
+
}`
|
|
266
|
+
)
|
|
267
|
+
.join('; ');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Builds one optional tool property per declared host argument plus a
|
|
272
|
+
* per-type summary of the values each subagent accepts. The first
|
|
273
|
+
* declaration's description wins; enums are unioned across subagents.
|
|
274
|
+
*/
|
|
275
|
+
export function buildSubagentHostArgProperties(
|
|
276
|
+
configs: readonly SubagentHostArgDeclaration[]
|
|
277
|
+
): {
|
|
278
|
+
properties: Record<string, JsonSchemaType>;
|
|
279
|
+
summaries: ReadonlyMap<string, string>;
|
|
280
|
+
} {
|
|
281
|
+
const merged = new Map<string, MergedHostArg>();
|
|
282
|
+
const summaries = new Map<string, string>();
|
|
283
|
+
for (const config of configs) {
|
|
284
|
+
const entries = getSubagentHostArgSpecs(config);
|
|
285
|
+
if (entries.length === 0) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
for (const [name, spec] of entries) {
|
|
289
|
+
mergeSpec(merged, name, spec);
|
|
290
|
+
}
|
|
291
|
+
summaries.set(config.type, summarizeSpecs(entries));
|
|
292
|
+
}
|
|
293
|
+
if (merged.size > SUBAGENT_HOST_ARG_LIMITS.distinctArgs) {
|
|
294
|
+
throw new Error(
|
|
295
|
+
`Subagents declare more than ${SUBAGENT_HOST_ARG_LIMITS.distinctArgs} distinct host arguments.`
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
const properties: Record<string, JsonSchemaType> = {};
|
|
299
|
+
for (const [name, entry] of merged) {
|
|
300
|
+
properties[name] = toPropertySchema(entry);
|
|
301
|
+
}
|
|
302
|
+
return { properties, summaries };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Reads the declared host argument properties from raw tool input. Missing,
|
|
307
|
+
* null, and blank values count as omitted; other non-string values are
|
|
308
|
+
* rejected rather than coerced.
|
|
309
|
+
*/
|
|
310
|
+
export function pickSubagentHostArgInput(
|
|
311
|
+
input: object,
|
|
312
|
+
names: ReadonlySet<string>
|
|
313
|
+
): SubagentHostArgsResult {
|
|
314
|
+
if (names.size === 0) {
|
|
315
|
+
return { ok: true };
|
|
316
|
+
}
|
|
317
|
+
const values = input as Readonly<Record<string, unknown>>;
|
|
318
|
+
const picked: Record<string, string> = {};
|
|
319
|
+
let count = 0;
|
|
320
|
+
for (const name of names) {
|
|
321
|
+
if (!Object.prototype.hasOwnProperty.call(values, name)) {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
const value = values[name];
|
|
325
|
+
if (value == null) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (typeof value !== 'string') {
|
|
329
|
+
return { ok: false, message: `Error: "${name}" must be a string.` };
|
|
330
|
+
}
|
|
331
|
+
if (value.trim() === '') {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
picked[name] = value;
|
|
335
|
+
count += 1;
|
|
336
|
+
}
|
|
337
|
+
return count === 0 ? { ok: true } : { ok: true, hostArgs: picked };
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function checkValue(
|
|
341
|
+
type: string,
|
|
342
|
+
name: string,
|
|
343
|
+
spec: SubagentHostArgSpec,
|
|
344
|
+
value: string
|
|
345
|
+
): string | undefined {
|
|
346
|
+
const omit = `Omit "${name}" to let the host choose.`;
|
|
347
|
+
if (spec.enum != null) {
|
|
348
|
+
return spec.enum.includes(value)
|
|
349
|
+
? undefined
|
|
350
|
+
: `Error: "${name}" for subagent "${type}" must be one of: ${spec.enum.join(', ')}. ${omit}`;
|
|
351
|
+
}
|
|
352
|
+
const maxLength = getFreeFormMaxLength(spec);
|
|
353
|
+
return isBoundedText(value, maxLength)
|
|
354
|
+
? undefined
|
|
355
|
+
: `Error: "${name}" for subagent "${type}" must be at most ${maxLength} characters without control characters. ${omit}`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Checks call values against the selected subagent's declarations and
|
|
360
|
+
* returns them frozen in canonical key order. Rejects arguments the selected
|
|
361
|
+
* subagent does not declare, including ones declared by a sibling.
|
|
362
|
+
*/
|
|
363
|
+
export function resolveSubagentHostArgs(
|
|
364
|
+
config: SubagentHostArgDeclaration,
|
|
365
|
+
hostArgs: SubagentHostArgs | undefined
|
|
366
|
+
): SubagentHostArgsResult {
|
|
367
|
+
if (hostArgs == null) {
|
|
368
|
+
return { ok: true };
|
|
369
|
+
}
|
|
370
|
+
const names = Object.keys(hostArgs).sort();
|
|
371
|
+
if (names.length === 0) {
|
|
372
|
+
return { ok: true };
|
|
373
|
+
}
|
|
374
|
+
const specs = new Map(getSubagentHostArgSpecs(config));
|
|
375
|
+
const resolved: Record<string, string> = {};
|
|
376
|
+
for (const name of names) {
|
|
377
|
+
const spec = specs.get(name);
|
|
378
|
+
if (spec == null) {
|
|
379
|
+
return {
|
|
380
|
+
ok: false,
|
|
381
|
+
message: isSubagentHostArgName(name)
|
|
382
|
+
? `Error: Subagent "${config.type}" does not accept "${name}". Omit it for this subagent type.`
|
|
383
|
+
: `Error: Subagent "${config.type}" received an unsupported argument.`,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
const value = hostArgs[name];
|
|
387
|
+
if (typeof value !== 'string') {
|
|
388
|
+
return { ok: false, message: `Error: "${name}" must be a string.` };
|
|
389
|
+
}
|
|
390
|
+
const error = checkValue(config.type, name, spec, value);
|
|
391
|
+
if (error != null) {
|
|
392
|
+
return { ok: false, message: error };
|
|
393
|
+
}
|
|
394
|
+
resolved[name] = value;
|
|
395
|
+
}
|
|
396
|
+
return { ok: true, hostArgs: Object.freeze(resolved) };
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/** Opaque, value-free identity of a call's host arguments for replay records. */
|
|
400
|
+
export function getSubagentHostArgsDigest(
|
|
401
|
+
hostArgs: SubagentHostArgs | undefined
|
|
402
|
+
): string | undefined {
|
|
403
|
+
if (hostArgs == null) {
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
const entries = Object.entries(hostArgs).sort(([left], [right]) =>
|
|
407
|
+
left < right ? -1 : 1
|
|
408
|
+
);
|
|
409
|
+
if (entries.length === 0) {
|
|
410
|
+
return undefined;
|
|
411
|
+
}
|
|
412
|
+
return createHash('sha256').update(JSON.stringify(entries)).digest('hex');
|
|
413
|
+
}
|
|
@@ -19,3 +19,23 @@ export type {
|
|
|
19
19
|
} from './SubagentExecutor';
|
|
20
20
|
export { InMemorySubagentTaskStore } from './InMemorySubagentTaskStore';
|
|
21
21
|
export type { InMemorySubagentTaskStoreOptions } from './InMemorySubagentTaskStore';
|
|
22
|
+
export {
|
|
23
|
+
SubagentResolutionError,
|
|
24
|
+
SubagentHostArgumentError,
|
|
25
|
+
getSubagentResolutionFailureMessage,
|
|
26
|
+
getSubagentHostArgumentFailureMessage,
|
|
27
|
+
} from './diagnostics';
|
|
28
|
+
export {
|
|
29
|
+
SUBAGENT_HOST_ARG_LIMITS,
|
|
30
|
+
buildSubagentHostArgProperties,
|
|
31
|
+
resolveSubagentHostArgs,
|
|
32
|
+
} from './hostArgs';
|
|
33
|
+
export type {
|
|
34
|
+
SubagentHostArgumentFailure,
|
|
35
|
+
SubagentHostArgumentRejection,
|
|
36
|
+
SubagentResolutionPhase,
|
|
37
|
+
SubagentResolutionCause,
|
|
38
|
+
SubagentResolutionContext,
|
|
39
|
+
SubagentResolutionDiagnostic,
|
|
40
|
+
SubagentResolutionFailureHandler,
|
|
41
|
+
} from './diagnostics';
|
package/src/types/graph.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProviderTextProtection } from '@/protection/providerText';
|
|
1
2
|
// src/types/graph.ts
|
|
2
3
|
import type {
|
|
3
4
|
BaseMessage,
|
|
@@ -44,6 +45,7 @@ import type {
|
|
|
44
45
|
StreamPreemption,
|
|
45
46
|
TokenBudgetBreakdown,
|
|
46
47
|
} from '@/types/run';
|
|
48
|
+
import type { SubagentResolutionFailureHandler } from '@/tools/subagent/diagnostics';
|
|
47
49
|
import type { SubagentTaskConfig } from '@/types/subagentTasks';
|
|
48
50
|
import type { StandardGraph, MultiAgentGraph } from '@/graphs';
|
|
49
51
|
import type { ProviderClientOptionsConfig } from '@/types/llm';
|
|
@@ -407,6 +409,7 @@ export type ModelEndData =
|
|
|
407
409
|
| undefined;
|
|
408
410
|
export type GraphTools = GenericTool[] | BindToolsInput[] | GoogleAIToolType[];
|
|
409
411
|
export type StandardGraphInput = {
|
|
412
|
+
providerTextProtection?: ProviderTextProtection;
|
|
410
413
|
runId?: string;
|
|
411
414
|
signal?: AbortSignal;
|
|
412
415
|
agents: AgentInputs[];
|
|
@@ -441,6 +444,8 @@ export type StandardGraphInput = {
|
|
|
441
444
|
subagentTasks?: SubagentTaskConfig;
|
|
442
445
|
/** Host-owned context and result projection for each isolated child execution. */
|
|
443
446
|
subagentContext?: SubagentContextAdapter;
|
|
447
|
+
/** Receives private startup errors; returns only an SDK-owned public cause. */
|
|
448
|
+
onSubagentResolutionFailure?: SubagentResolutionFailureHandler;
|
|
444
449
|
/**
|
|
445
450
|
* True when this graph IS a subagent child run (set by `SubagentExecutor`
|
|
446
451
|
* when it constructs the child graph). Drives the hook-input `agentId`
|
|
@@ -571,6 +576,31 @@ export interface SubagentResolveConfigurable {
|
|
|
571
576
|
user_id?: string;
|
|
572
577
|
}
|
|
573
578
|
|
|
579
|
+
/**
|
|
580
|
+
* Optional string argument a host lets the parent model pass on a subagent
|
|
581
|
+
* call, such as where the child should run. The SDK checks the declared shape
|
|
582
|
+
* before resolution; the host still authorizes the value in its resolver.
|
|
583
|
+
*/
|
|
584
|
+
export interface SubagentHostArgSpec {
|
|
585
|
+
/** Model-facing explanation of the argument and when to pass it. */
|
|
586
|
+
description: string;
|
|
587
|
+
/**
|
|
588
|
+
* Values this subagent accepts. Omit to accept a bounded free-form string,
|
|
589
|
+
* whose format the resolver must check.
|
|
590
|
+
*/
|
|
591
|
+
enum?: readonly string[];
|
|
592
|
+
/** Maximum length of a free-form value (at most 256). */
|
|
593
|
+
maxLength?: number;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/** Host argument declarations keyed by tool-call property name. */
|
|
597
|
+
export type SubagentHostArgSpecs = Readonly<
|
|
598
|
+
Record<string, SubagentHostArgSpec>
|
|
599
|
+
>;
|
|
600
|
+
|
|
601
|
+
/** Validated host argument values from one subagent call. */
|
|
602
|
+
export type SubagentHostArgs = Readonly<Record<string, string>>;
|
|
603
|
+
|
|
574
604
|
/** Runtime context supplied when a host lazily resolves a selected subagent. */
|
|
575
605
|
export interface SubagentResolveContext {
|
|
576
606
|
/** Stable subagent identity selected by the model. */
|
|
@@ -589,6 +619,13 @@ export interface SubagentResolveContext {
|
|
|
589
619
|
signal: AbortSignal;
|
|
590
620
|
/** Stable, sanitized host context from the parent tool invocation. */
|
|
591
621
|
configurable?: Readonly<SubagentResolveConfigurable>;
|
|
622
|
+
/**
|
|
623
|
+
* Values the parent passed for this subagent's declared `hostArgs`, already
|
|
624
|
+
* checked against the declaration. Omitted when the call passed none. Bound
|
|
625
|
+
* to the execution: a reconstruction with different values is rejected
|
|
626
|
+
* before the resolver runs.
|
|
627
|
+
*/
|
|
628
|
+
hostArgs?: SubagentHostArgs;
|
|
592
629
|
}
|
|
593
630
|
|
|
594
631
|
/** Host contract for resolving a selected subagent's full graph inputs. */
|
|
@@ -620,6 +657,12 @@ export interface SubagentConfig extends SubagentConfigBase {
|
|
|
620
657
|
* `(context.executionId, context.descriptor.configId)`.
|
|
621
658
|
*/
|
|
622
659
|
resolveAgentInputs?: SubagentAgentInputsResolver;
|
|
660
|
+
/**
|
|
661
|
+
* Optional per-call arguments the parent model may pass for this subagent,
|
|
662
|
+
* delivered to `resolveAgentInputs` as `context.hostArgs`. Only lazy
|
|
663
|
+
* configs accept them. Declaring none leaves the tool schema unchanged.
|
|
664
|
+
*/
|
|
665
|
+
hostArgs?: SubagentHostArgSpecs;
|
|
623
666
|
/** When true, reuse the parent's AgentInputs (context isolation without separate config). */
|
|
624
667
|
self?: boolean;
|
|
625
668
|
}
|
|
@@ -636,6 +679,7 @@ export interface GraphSubagentConfig extends SubagentConfigBase {
|
|
|
636
679
|
kind: 'graph';
|
|
637
680
|
configId?: never;
|
|
638
681
|
resolveAgentInputs?: never;
|
|
682
|
+
hostArgs?: never;
|
|
639
683
|
allowNested?: false;
|
|
640
684
|
agents: AgentInputs[];
|
|
641
685
|
/**
|
package/src/types/run.ts
CHANGED
|
@@ -33,8 +33,9 @@ export type LegacyGraphConfig = BaseGraphConfig & {
|
|
|
33
33
|
g.StandardGraphInput,
|
|
34
34
|
/** `streamLimits` is excluded because legacy graphs receive limits only
|
|
35
35
|
* via the top-level `RunConfig.streamLimits`; accepting the field here
|
|
36
|
-
* would type-check but be silently ignored by `createLegacyGraph`.
|
|
37
|
-
|
|
36
|
+
* would type-check but be silently ignored by `createLegacyGraph`.
|
|
37
|
+
* Required provider-text protection also belongs only to RunConfig. */
|
|
38
|
+
'provider' | 'clientOptions' | 'agents' | 'streamLimits' | 'providerTextProtection'
|
|
38
39
|
> &
|
|
39
40
|
Omit<g.AgentInputs, 'provider' | 'clientOptions' | 'agentId'>;
|
|
40
41
|
|
|
@@ -300,6 +301,8 @@ export type RunConfig = {
|
|
|
300
301
|
subagentTasks?: SubagentTaskConfig;
|
|
301
302
|
/** Authorizes and supplies host-owned context to isolated child runs. */
|
|
302
303
|
subagentContext?: g.SubagentContextAdapter;
|
|
304
|
+
/** Host diagnostic sink for foreground, detached, and nested startup failures. */
|
|
305
|
+
onSubagentResolutionFailure?: g.StandardGraphInput['onSubagentResolutionFailure'];
|
|
303
306
|
/**
|
|
304
307
|
* Pre-constructed hook registry for this run. Hooks fire at lifecycle
|
|
305
308
|
* points in `processStream` (RunStart, UserPromptSubmit, Stop,
|
|
@@ -334,6 +337,7 @@ export type RunConfig = {
|
|
|
334
337
|
* tool-call argument byte cap is ON by default, the per-turn event cap is
|
|
335
338
|
* opt-in. See {@link StreamLimits}.
|
|
336
339
|
*/
|
|
340
|
+
providerTextProtection?: g.StandardGraphInput['providerTextProtection'];
|
|
337
341
|
streamLimits?: StreamLimits;
|
|
338
342
|
returnContent?: boolean;
|
|
339
343
|
tokenCounter?: TokenCounter;
|
package/src/types/tools.ts
CHANGED
|
@@ -314,7 +314,10 @@ export type ToolNodeOptions = {
|
|
|
314
314
|
/** SDK-owned checkpoint snapshot for open run-step lifecycle state. */
|
|
315
315
|
createRunStepResumeState?: () => RunStepResumeState;
|
|
316
316
|
/** Internal ownership bridge, awaited before ToolNode can execute a batch. */
|
|
317
|
-
onToolCallsClaimed?: (
|
|
317
|
+
onToolCallsClaimed?: (
|
|
318
|
+
messageId: string,
|
|
319
|
+
config: RunnableConfig
|
|
320
|
+
) => Promise<void>;
|
|
318
321
|
};
|
|
319
322
|
|
|
320
323
|
export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
|
|
@@ -550,6 +553,8 @@ export type JsonSchemaType = {
|
|
|
550
553
|
properties?: Record<string, JsonSchemaType>;
|
|
551
554
|
required?: string[];
|
|
552
555
|
description?: string;
|
|
556
|
+
pattern?: string;
|
|
557
|
+
maxLength?: number;
|
|
553
558
|
additionalProperties?: boolean | JsonSchemaType;
|
|
554
559
|
};
|
|
555
560
|
|