@librechat/agents 3.9.2 → 3.9.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.
- package/README.md +32 -0
- package/dist/cjs/common/enum.cjs +2 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +11 -0
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +54 -5
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +97 -5
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/graphs/acceptedModelResponse.cjs +168 -0
- package/dist/cjs/graphs/acceptedModelResponse.cjs.map +1 -0
- package/dist/cjs/graphs/handoff.cjs +195 -0
- package/dist/cjs/graphs/handoff.cjs.map +1 -0
- package/dist/cjs/graphs/index.cjs +1 -0
- package/dist/cjs/llm/invoke.cjs +10 -5
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/streamLimits.cjs +1 -1
- package/dist/cjs/llm/streamLimits.cjs.map +1 -1
- package/dist/cjs/main.cjs +4 -0
- package/dist/cjs/messages/fading.cjs +14 -6
- package/dist/cjs/messages/fading.cjs.map +1 -1
- package/dist/cjs/messages/prune.cjs +95 -36
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/openai/index.cjs +2 -0
- package/dist/cjs/openai/index.cjs.map +1 -1
- package/dist/cjs/openai/toolProjection.cjs +196 -0
- package/dist/cjs/openai/toolProjection.cjs.map +1 -0
- package/dist/cjs/run.cjs +41 -4
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +1 -1
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/stream.cjs +9 -4
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +5 -1
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs +4 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
- package/dist/cjs/utils/acceptedToolArguments.cjs +143 -0
- package/dist/cjs/utils/acceptedToolArguments.cjs.map +1 -0
- package/dist/esm/common/enum.mjs +2 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +11 -0
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +54 -5
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +97 -5
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/graphs/acceptedModelResponse.mjs +165 -0
- package/dist/esm/graphs/acceptedModelResponse.mjs.map +1 -0
- package/dist/esm/graphs/handoff.mjs +193 -0
- package/dist/esm/graphs/handoff.mjs.map +1 -0
- package/dist/esm/graphs/index.mjs +1 -0
- package/dist/esm/llm/invoke.mjs +10 -5
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/streamLimits.mjs +1 -1
- package/dist/esm/llm/streamLimits.mjs.map +1 -1
- package/dist/esm/main.mjs +4 -3
- package/dist/esm/messages/fading.mjs +14 -7
- package/dist/esm/messages/fading.mjs.map +1 -1
- package/dist/esm/messages/prune.mjs +95 -37
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/openai/index.mjs +2 -1
- package/dist/esm/openai/index.mjs.map +1 -1
- package/dist/esm/openai/toolProjection.mjs +196 -0
- package/dist/esm/openai/toolProjection.mjs.map +1 -0
- package/dist/esm/run.mjs +41 -4
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +1 -1
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/stream.mjs +9 -4
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +5 -1
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs +5 -2
- package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
- package/dist/esm/utils/acceptedToolArguments.mjs +142 -0
- package/dist/esm/utils/acceptedToolArguments.mjs.map +1 -0
- package/dist/types/common/enum.d.ts +4 -0
- package/dist/types/graphs/Graph.d.ts +5 -1
- package/dist/types/graphs/MultiAgentGraph.d.ts +3 -0
- package/dist/types/graphs/acceptedModelResponse.d.ts +15 -0
- package/dist/types/graphs/handoff.d.ts +28 -0
- package/dist/types/graphs/index.d.ts +1 -0
- package/dist/types/messages/fading.d.ts +14 -2
- package/dist/types/messages/prune.d.ts +7 -0
- package/dist/types/openai/arguments.d.ts +2 -0
- package/dist/types/openai/index.d.ts +2 -0
- package/dist/types/openai/toolProjection.d.ts +30 -0
- package/dist/types/run.d.ts +5 -0
- package/dist/types/tools/ToolNode.d.ts +2 -1
- package/dist/types/types/graph.d.ts +51 -4
- package/dist/types/types/run.d.ts +8 -1
- package/dist/types/types/stream.d.ts +22 -1
- package/dist/types/types/tools.d.ts +5 -0
- package/dist/types/utils/acceptedToolArguments.d.ts +10 -0
- package/package.json +1 -1
- package/src/common/enum.ts +5 -0
- package/src/events.ts +24 -1
- package/src/graphs/Graph.ts +103 -0
- package/src/graphs/MultiAgentGraph.ts +142 -4
- package/src/graphs/acceptedModelResponse.ts +307 -0
- package/src/graphs/handoff.ts +263 -0
- package/src/graphs/index.ts +2 -0
- package/src/llm/invoke.ts +39 -14
- package/src/llm/streamLimits.ts +1 -1
- package/src/messages/fading.ts +30 -5
- package/src/messages/prune.ts +168 -55
- package/src/openai/arguments.ts +2 -0
- package/src/openai/index.ts +6 -0
- package/src/openai/toolProjection.ts +318 -0
- package/src/run.ts +75 -2
- package/src/session/AgentSession.ts +2 -2
- package/src/stream.ts +21 -1
- package/src/tools/ToolNode.ts +19 -6
- package/src/tools/subagent/SubagentReplay.ts +10 -9
- package/src/types/graph.ts +59 -10
- package/src/types/run.ts +8 -1
- package/src/types/stream.ts +26 -0
- package/src/types/tools.ts +5 -0
- package/src/utils/acceptedToolArguments.ts +204 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { types } from 'node:util';
|
|
2
|
+
|
|
3
|
+
const MAX_ARGUMENT_DEPTH = 64;
|
|
4
|
+
const INVALID = 'Accepted tool call arguments are not JSON serializable';
|
|
5
|
+
const LIMIT = 'Tool projection buffer limit exceeded';
|
|
6
|
+
|
|
7
|
+
function invalid(): never {
|
|
8
|
+
throw new Error(INVALID);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** structuredClone and VM providers may return objects from another realm. */
|
|
12
|
+
function hasJSONPrototype(value: object, array: boolean): boolean {
|
|
13
|
+
const proto: unknown = Object.getPrototypeOf(value);
|
|
14
|
+
if (proto === null) return true;
|
|
15
|
+
if (typeof proto !== 'object' || types.isProxy(proto)) return false;
|
|
16
|
+
const ctor: unknown = Object.getOwnPropertyDescriptor(
|
|
17
|
+
proto,
|
|
18
|
+
'constructor'
|
|
19
|
+
)?.value;
|
|
20
|
+
if (typeof ctor !== 'function' || types.isProxy(ctor)) return false;
|
|
21
|
+
return (
|
|
22
|
+
Object.getOwnPropertyDescriptor(ctor, 'prototype')?.value === proto &&
|
|
23
|
+
Function.prototype.toString.call(ctor) ===
|
|
24
|
+
Function.prototype.toString.call(array ? Array : Object)
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Encode JSON data, not arbitrary JS values. No getters, proxies or toJSON hooks run.
|
|
29
|
+
* Repeated references expand like JSON (and count against the budget); cycles fail.
|
|
30
|
+
* Limits bound output and traversal, including deeply nested/alias-heavy input.
|
|
31
|
+
*/
|
|
32
|
+
export function serializeToolArguments(
|
|
33
|
+
value: unknown,
|
|
34
|
+
maxBytes: number
|
|
35
|
+
): string {
|
|
36
|
+
if (maxBytes < 2) throw new Error(LIMIT);
|
|
37
|
+
const parts: string[] = [];
|
|
38
|
+
const ancestors = new Set<object>();
|
|
39
|
+
let remaining = maxBytes;
|
|
40
|
+
const append = (text: string): void => {
|
|
41
|
+
remaining -= Buffer.byteLength(text, 'utf8');
|
|
42
|
+
if (remaining < 0) throw new Error(LIMIT);
|
|
43
|
+
parts.push(text);
|
|
44
|
+
};
|
|
45
|
+
const string = (text: string): void => {
|
|
46
|
+
// Every UTF-16 unit needs at least one encoded byte. Check before allocating escapes.
|
|
47
|
+
if (text.length + 2 > remaining) throw new Error(LIMIT);
|
|
48
|
+
append(JSON.stringify(text));
|
|
49
|
+
};
|
|
50
|
+
const encode = (input: unknown, depth: number): void => {
|
|
51
|
+
if (depth > MAX_ARGUMENT_DEPTH) invalid();
|
|
52
|
+
if (input === null) {
|
|
53
|
+
append('null');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (typeof input === 'string') {
|
|
57
|
+
string(input);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (typeof input === 'boolean') {
|
|
61
|
+
append(input ? 'true' : 'false');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (typeof input === 'number') {
|
|
65
|
+
if (!Number.isFinite(input)) invalid();
|
|
66
|
+
append(Object.is(input, -0) ? '-0' : String(input));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (typeof input !== 'object') invalid();
|
|
70
|
+
if (types.isProxy(input) || ancestors.has(input)) invalid();
|
|
71
|
+
const array = Array.isArray(input);
|
|
72
|
+
if (!hasJSONPrototype(input, array)) invalid();
|
|
73
|
+
const keys = Reflect.ownKeys(input);
|
|
74
|
+
// At least one byte per entry, plus punctuation. Bound descriptor work up front.
|
|
75
|
+
if (keys.length > remaining + (array ? 1 : 0)) throw new Error(LIMIT);
|
|
76
|
+
ancestors.add(input);
|
|
77
|
+
if (array) {
|
|
78
|
+
// Dense arrays only, with no symbols, hidden entries or extra named properties.
|
|
79
|
+
if (keys.length !== input.length + 1) invalid();
|
|
80
|
+
append('[');
|
|
81
|
+
for (let i = 0; i < input.length; i++) {
|
|
82
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, String(i));
|
|
83
|
+
if (
|
|
84
|
+
descriptor == null ||
|
|
85
|
+
descriptor.enumerable !== true ||
|
|
86
|
+
!('value' in descriptor)
|
|
87
|
+
)
|
|
88
|
+
invalid();
|
|
89
|
+
if (i !== 0) append(',');
|
|
90
|
+
encode(descriptor.value, depth + 1);
|
|
91
|
+
}
|
|
92
|
+
append(']');
|
|
93
|
+
} else {
|
|
94
|
+
append('{');
|
|
95
|
+
for (let i = 0; i < keys.length; i++) {
|
|
96
|
+
const key = keys[i];
|
|
97
|
+
if (typeof key !== 'string') invalid();
|
|
98
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
99
|
+
if (
|
|
100
|
+
descriptor == null ||
|
|
101
|
+
descriptor.enumerable !== true ||
|
|
102
|
+
!('value' in descriptor)
|
|
103
|
+
)
|
|
104
|
+
invalid();
|
|
105
|
+
if (i !== 0) append(',');
|
|
106
|
+
string(key);
|
|
107
|
+
append(':');
|
|
108
|
+
encode(descriptor.value, depth + 1);
|
|
109
|
+
}
|
|
110
|
+
append('}');
|
|
111
|
+
}
|
|
112
|
+
ancestors.delete(input);
|
|
113
|
+
};
|
|
114
|
+
if (value != null && typeof value === 'object' && types.isProxy(value))
|
|
115
|
+
invalid();
|
|
116
|
+
if (value == null || typeof value !== 'object' || Array.isArray(value)) {
|
|
117
|
+
throw new Error('Accepted tool call arguments must be an object');
|
|
118
|
+
}
|
|
119
|
+
encode(value, 0);
|
|
120
|
+
return parts.join('');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Detach JSON data without encoding it. Unlike projection, invocation has no
|
|
124
|
+
* formatting budget: preserve shared references and traverse iteratively so a
|
|
125
|
+
* deep or alias-heavy object cannot expand exponentially during validation.
|
|
126
|
+
*/
|
|
127
|
+
export function cloneToolArguments(value: unknown): Record<string, unknown> {
|
|
128
|
+
const copies = new Map<object, object>();
|
|
129
|
+
const ancestors = new Set<object>();
|
|
130
|
+
const stack: Array<{
|
|
131
|
+
input: object;
|
|
132
|
+
output: object;
|
|
133
|
+
keys: (string | symbol)[];
|
|
134
|
+
index: number;
|
|
135
|
+
}> = [];
|
|
136
|
+
const copy = (input: unknown): unknown => {
|
|
137
|
+
if (
|
|
138
|
+
input === null ||
|
|
139
|
+
typeof input === 'string' ||
|
|
140
|
+
typeof input === 'boolean'
|
|
141
|
+
)
|
|
142
|
+
return input;
|
|
143
|
+
if (typeof input === 'number') {
|
|
144
|
+
if (!Number.isFinite(input)) invalid();
|
|
145
|
+
return input;
|
|
146
|
+
}
|
|
147
|
+
if (
|
|
148
|
+
typeof input !== 'object' ||
|
|
149
|
+
types.isProxy(input) ||
|
|
150
|
+
ancestors.has(input)
|
|
151
|
+
)
|
|
152
|
+
invalid();
|
|
153
|
+
const existing = copies.get(input);
|
|
154
|
+
if (existing != null) return existing;
|
|
155
|
+
const array = Array.isArray(input);
|
|
156
|
+
if (!hasJSONPrototype(input, array)) invalid();
|
|
157
|
+
const keys = Reflect.ownKeys(input);
|
|
158
|
+
if (array && keys.length !== input.length + 1) invalid();
|
|
159
|
+
const output: object = array ? [] : {};
|
|
160
|
+
copies.set(input, output);
|
|
161
|
+
ancestors.add(input);
|
|
162
|
+
stack.push({
|
|
163
|
+
input,
|
|
164
|
+
output,
|
|
165
|
+
keys: array ? keys.filter((key) => key !== 'length') : keys,
|
|
166
|
+
index: 0,
|
|
167
|
+
});
|
|
168
|
+
return output;
|
|
169
|
+
};
|
|
170
|
+
if (
|
|
171
|
+
value == null ||
|
|
172
|
+
typeof value !== 'object' ||
|
|
173
|
+
types.isProxy(value) ||
|
|
174
|
+
Array.isArray(value)
|
|
175
|
+
)
|
|
176
|
+
invalid();
|
|
177
|
+
const result = copy(value) as Record<string, unknown>;
|
|
178
|
+
while (stack.length > 0) {
|
|
179
|
+
const frame = stack[stack.length - 1];
|
|
180
|
+
if (frame.index === frame.keys.length) {
|
|
181
|
+
ancestors.delete(frame.input);
|
|
182
|
+
stack.pop();
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const key = frame.keys[frame.index++];
|
|
186
|
+
if (typeof key !== 'string') invalid();
|
|
187
|
+
if (Array.isArray(frame.input) && key !== String(frame.index - 1))
|
|
188
|
+
invalid();
|
|
189
|
+
const descriptor = Object.getOwnPropertyDescriptor(frame.input, key);
|
|
190
|
+
if (
|
|
191
|
+
descriptor == null ||
|
|
192
|
+
!('value' in descriptor) ||
|
|
193
|
+
descriptor.enumerable !== true
|
|
194
|
+
)
|
|
195
|
+
invalid();
|
|
196
|
+
Object.defineProperty(frame.output, key, {
|
|
197
|
+
value: copy(descriptor.value),
|
|
198
|
+
enumerable: true,
|
|
199
|
+
writable: true,
|
|
200
|
+
configurable: true,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|