@modelrelay/sdk 1.25.0 → 1.28.0
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/chunk-BL7GWXRZ.js +1196 -0
- package/dist/chunk-G5H7EY4F.js +1196 -0
- package/dist/index.cjs +75 -681
- package/dist/index.d.cts +3 -1315
- package/dist/index.d.ts +3 -1315
- package/dist/index.js +627 -2276
- package/dist/node.cjs +878 -0
- package/dist/node.d.cts +149 -0
- package/dist/node.d.ts +149 -0
- package/dist/node.js +611 -0
- package/dist/tools-Db-F5rIL.d.cts +1169 -0
- package/dist/tools-Db-F5rIL.d.ts +1169 -0
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -1,283 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
super(`stream ${label} timeout after ${timeoutMs}ms`, { category: "transport", status: 408 });
|
|
75
|
-
this.kind = streamKind;
|
|
76
|
-
this.timeoutMs = timeoutMs;
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
var APIError = class extends ModelRelayError {
|
|
80
|
-
constructor(message, opts) {
|
|
81
|
-
super(message, {
|
|
82
|
-
category: "api",
|
|
83
|
-
status: opts.status,
|
|
84
|
-
code: opts.code,
|
|
85
|
-
requestId: opts.requestId,
|
|
86
|
-
fields: opts.fields,
|
|
87
|
-
data: opts.data,
|
|
88
|
-
retries: opts.retries
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
/** Returns true if the error is a not found error. */
|
|
92
|
-
isNotFound() {
|
|
93
|
-
return this.code === ErrorCodes.NOT_FOUND;
|
|
94
|
-
}
|
|
95
|
-
/** Returns true if the error is a validation error. */
|
|
96
|
-
isValidation() {
|
|
97
|
-
return this.code === ErrorCodes.VALIDATION_ERROR || this.code === ErrorCodes.INVALID_INPUT;
|
|
98
|
-
}
|
|
99
|
-
/** Returns true if the error is a rate limit error. */
|
|
100
|
-
isRateLimit() {
|
|
101
|
-
return this.code === ErrorCodes.RATE_LIMIT;
|
|
102
|
-
}
|
|
103
|
-
/** Returns true if the error is an unauthorized error. */
|
|
104
|
-
isUnauthorized() {
|
|
105
|
-
return this.code === ErrorCodes.UNAUTHORIZED;
|
|
106
|
-
}
|
|
107
|
-
/** Returns true if the error is a forbidden error. */
|
|
108
|
-
isForbidden() {
|
|
109
|
-
return this.code === ErrorCodes.FORBIDDEN;
|
|
110
|
-
}
|
|
111
|
-
/** Returns true if the error is a service unavailable error. */
|
|
112
|
-
isUnavailable() {
|
|
113
|
-
return this.code === ErrorCodes.SERVICE_UNAVAILABLE;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Returns true if the error indicates identity is missing/invalid for identity-based auth.
|
|
117
|
-
*/
|
|
118
|
-
isIdentityRequired() {
|
|
119
|
-
return this.code === ErrorCodes.IDENTITY_REQUIRED;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Returns true if auto-provisioning is disabled for the project.
|
|
123
|
-
* To resolve: configure customer auto-provisioning on the project (select a default tier).
|
|
124
|
-
*/
|
|
125
|
-
isAutoProvisionDisabled() {
|
|
126
|
-
return this.code === ErrorCodes.AUTO_PROVISION_DISABLED;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Returns true if email is required for auto-provisioning a new customer.
|
|
130
|
-
* To resolve: provide the 'email' field in your frontend token request.
|
|
131
|
-
*/
|
|
132
|
-
isEmailRequired() {
|
|
133
|
-
return this.code === ErrorCodes.EMAIL_REQUIRED;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Returns true if auto-provisioning is misconfigured for the project.
|
|
137
|
-
* To resolve: ensure the configured auto-provision tier exists and belongs to the project.
|
|
138
|
-
*/
|
|
139
|
-
isAutoProvisionMisconfigured() {
|
|
140
|
-
return this.code === ErrorCodes.AUTO_PROVISION_MISCONFIGURED;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Returns true if this is a customer provisioning error (identity not found + auto-provision disabled/misconfigured, or email required).
|
|
144
|
-
*/
|
|
145
|
-
isProvisioningError() {
|
|
146
|
-
return this.isAutoProvisionDisabled() || this.isAutoProvisionMisconfigured() || this.isEmailRequired();
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
var WorkflowValidationError = class extends ModelRelayError {
|
|
150
|
-
constructor(opts) {
|
|
151
|
-
const msg = opts.issues.length === 0 ? "workflow validation error" : opts.issues[0]?.message || "workflow validation error";
|
|
152
|
-
super(msg, {
|
|
153
|
-
category: "api",
|
|
154
|
-
status: opts.status,
|
|
155
|
-
requestId: opts.requestId,
|
|
156
|
-
data: opts.data,
|
|
157
|
-
retries: opts.retries
|
|
158
|
-
});
|
|
159
|
-
this.issues = opts.issues;
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
var ToolArgumentError = class extends ModelRelayError {
|
|
163
|
-
constructor(opts) {
|
|
164
|
-
super(opts.message, {
|
|
165
|
-
category: "config",
|
|
166
|
-
status: 400,
|
|
167
|
-
cause: opts.cause
|
|
168
|
-
});
|
|
169
|
-
this.toolCallId = opts.toolCallId;
|
|
170
|
-
this.toolName = opts.toolName;
|
|
171
|
-
this.rawArguments = opts.rawArguments;
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
var PathEscapeError = class extends ModelRelayError {
|
|
175
|
-
constructor(opts) {
|
|
176
|
-
super(`path escapes sandbox: ${opts.requestedPath}`, {
|
|
177
|
-
category: "config",
|
|
178
|
-
status: 403
|
|
179
|
-
});
|
|
180
|
-
this.requestedPath = opts.requestedPath;
|
|
181
|
-
this.resolvedPath = opts.resolvedPath;
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
function isEmailRequired(err) {
|
|
185
|
-
return err instanceof APIError && err.isEmailRequired();
|
|
186
|
-
}
|
|
187
|
-
function isIdentityRequired(err) {
|
|
188
|
-
return err instanceof APIError && err.isIdentityRequired();
|
|
189
|
-
}
|
|
190
|
-
function isAutoProvisionDisabled(err) {
|
|
191
|
-
return err instanceof APIError && err.isAutoProvisionDisabled();
|
|
192
|
-
}
|
|
193
|
-
function isAutoProvisionMisconfigured(err) {
|
|
194
|
-
return err instanceof APIError && err.isAutoProvisionMisconfigured();
|
|
195
|
-
}
|
|
196
|
-
function isProvisioningError(err) {
|
|
197
|
-
return err instanceof APIError && err.isProvisioningError();
|
|
198
|
-
}
|
|
199
|
-
async function parseErrorResponse(response, retries) {
|
|
200
|
-
const requestId = response.headers.get("X-ModelRelay-Request-Id") || response.headers.get("X-Request-Id") || void 0;
|
|
201
|
-
const fallbackMessage = response.statusText || "Request failed";
|
|
202
|
-
const status = response.status || 500;
|
|
203
|
-
let bodyText = "";
|
|
204
|
-
let bodyReadErr;
|
|
205
|
-
try {
|
|
206
|
-
bodyText = await response.text();
|
|
207
|
-
} catch (err) {
|
|
208
|
-
bodyReadErr = err;
|
|
209
|
-
}
|
|
210
|
-
if (!bodyText) {
|
|
211
|
-
return new APIError(fallbackMessage, {
|
|
212
|
-
status,
|
|
213
|
-
requestId,
|
|
214
|
-
retries,
|
|
215
|
-
data: bodyReadErr ? {
|
|
216
|
-
body_read_error: bodyReadErr instanceof Error ? bodyReadErr.message : String(bodyReadErr)
|
|
217
|
-
} : void 0
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
try {
|
|
221
|
-
const parsed = JSON.parse(bodyText);
|
|
222
|
-
const parsedObj = typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
223
|
-
const issues = Array.isArray(parsedObj?.issues) ? parsedObj?.issues : null;
|
|
224
|
-
if (status === 400 && issues && issues.length > 0) {
|
|
225
|
-
const normalized = [];
|
|
226
|
-
for (const raw of issues) {
|
|
227
|
-
if (!raw || typeof raw !== "object") continue;
|
|
228
|
-
const obj = raw;
|
|
229
|
-
const code = typeof obj.code === "string" ? obj.code : "";
|
|
230
|
-
const path2 = typeof obj.path === "string" ? obj.path : "";
|
|
231
|
-
const message = typeof obj.message === "string" ? obj.message : "";
|
|
232
|
-
if (!code || !path2 || !message) continue;
|
|
233
|
-
normalized.push({ code, path: path2, message });
|
|
234
|
-
}
|
|
235
|
-
if (normalized.length > 0) {
|
|
236
|
-
return new WorkflowValidationError({
|
|
237
|
-
status,
|
|
238
|
-
requestId,
|
|
239
|
-
issues: normalized,
|
|
240
|
-
retries,
|
|
241
|
-
data: parsed
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
if (parsedObj?.error && typeof parsedObj.error === "object") {
|
|
246
|
-
const errPayload = parsedObj.error;
|
|
247
|
-
const message = errPayload?.message || fallbackMessage;
|
|
248
|
-
const code = errPayload?.code || void 0;
|
|
249
|
-
const fields = Array.isArray(errPayload?.fields) ? errPayload?.fields : void 0;
|
|
250
|
-
const parsedStatus = typeof errPayload?.status === "number" ? errPayload.status : status;
|
|
251
|
-
return new APIError(message, {
|
|
252
|
-
status: parsedStatus,
|
|
253
|
-
code,
|
|
254
|
-
fields,
|
|
255
|
-
requestId: parsedObj?.request_id || parsedObj?.requestId || requestId,
|
|
256
|
-
data: parsed,
|
|
257
|
-
retries
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
if (parsedObj?.message || parsedObj?.code) {
|
|
261
|
-
const message = parsedObj.message || fallbackMessage;
|
|
262
|
-
return new APIError(message, {
|
|
263
|
-
status,
|
|
264
|
-
code: parsedObj.code,
|
|
265
|
-
fields: parsedObj.fields,
|
|
266
|
-
requestId: parsedObj?.request_id || parsedObj?.requestId || requestId,
|
|
267
|
-
data: parsed,
|
|
268
|
-
retries
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
return new APIError(fallbackMessage, {
|
|
272
|
-
status,
|
|
273
|
-
requestId,
|
|
274
|
-
data: parsed,
|
|
275
|
-
retries
|
|
276
|
-
});
|
|
277
|
-
} catch {
|
|
278
|
-
return new APIError(bodyText, { status, requestId, retries });
|
|
279
|
-
}
|
|
280
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
APIError,
|
|
3
|
+
BillingProviders,
|
|
4
|
+
ConfigError,
|
|
5
|
+
ContentPartTypes,
|
|
6
|
+
DEFAULT_BASE_URL,
|
|
7
|
+
DEFAULT_CLIENT_HEADER,
|
|
8
|
+
DEFAULT_CONNECT_TIMEOUT_MS,
|
|
9
|
+
DEFAULT_REQUEST_TIMEOUT_MS,
|
|
10
|
+
ErrorCodes,
|
|
11
|
+
InputItemTypes,
|
|
12
|
+
MessageRoles,
|
|
13
|
+
ModelRelayError,
|
|
14
|
+
OutputFormatTypes,
|
|
15
|
+
OutputItemTypes,
|
|
16
|
+
PathEscapeError,
|
|
17
|
+
SDK_VERSION,
|
|
18
|
+
StopReasons,
|
|
19
|
+
StreamProtocolError,
|
|
20
|
+
StreamTimeoutError,
|
|
21
|
+
SubscriptionStatuses,
|
|
22
|
+
ToolArgsError,
|
|
23
|
+
ToolArgumentError,
|
|
24
|
+
ToolCallAccumulator,
|
|
25
|
+
ToolChoiceTypes,
|
|
26
|
+
ToolRegistry,
|
|
27
|
+
ToolTypes,
|
|
28
|
+
TransportError,
|
|
29
|
+
WebToolIntents,
|
|
30
|
+
WorkflowValidationError,
|
|
31
|
+
__export,
|
|
32
|
+
asModelId,
|
|
33
|
+
asProviderId,
|
|
34
|
+
asTierCode,
|
|
35
|
+
assistantMessageWithToolCalls,
|
|
36
|
+
createAssistantMessage,
|
|
37
|
+
createFunctionCall,
|
|
38
|
+
createFunctionTool,
|
|
39
|
+
createFunctionToolFromSchema,
|
|
40
|
+
createRetryMessages,
|
|
41
|
+
createSystemMessage,
|
|
42
|
+
createToolCall,
|
|
43
|
+
createUsage,
|
|
44
|
+
createUserMessage,
|
|
45
|
+
createWebTool,
|
|
46
|
+
executeWithRetry,
|
|
47
|
+
firstToolCall,
|
|
48
|
+
formatToolErrorForModel,
|
|
49
|
+
getRetryableErrors,
|
|
50
|
+
hasRetryableErrors,
|
|
51
|
+
hasToolCalls,
|
|
52
|
+
isAutoProvisionDisabled,
|
|
53
|
+
isAutoProvisionMisconfigured,
|
|
54
|
+
isEmailRequired,
|
|
55
|
+
isIdentityRequired,
|
|
56
|
+
isProvisioningError,
|
|
57
|
+
mergeMetrics,
|
|
58
|
+
mergeTrace,
|
|
59
|
+
modelToString,
|
|
60
|
+
normalizeModelId,
|
|
61
|
+
normalizeStopReason,
|
|
62
|
+
parseErrorResponse,
|
|
63
|
+
parseToolArgs,
|
|
64
|
+
parseToolArgsRaw,
|
|
65
|
+
respondToToolCall,
|
|
66
|
+
stopReasonToString,
|
|
67
|
+
toolChoiceAuto,
|
|
68
|
+
toolChoiceNone,
|
|
69
|
+
toolChoiceRequired,
|
|
70
|
+
toolResultMessage,
|
|
71
|
+
tryParseToolArgs,
|
|
72
|
+
zodToJsonSchema
|
|
73
|
+
} from "./chunk-G5H7EY4F.js";
|
|
281
74
|
|
|
282
75
|
// src/api_keys.ts
|
|
283
76
|
var PUBLISHABLE_PREFIX = "mr_pk_";
|
|
@@ -580,8 +373,8 @@ var AuthClient = class {
|
|
|
580
373
|
params.set("provider", request.provider);
|
|
581
374
|
}
|
|
582
375
|
const queryString = params.toString();
|
|
583
|
-
const
|
|
584
|
-
const apiResp = await this.http.json(
|
|
376
|
+
const path = queryString ? `/auth/device/start?${queryString}` : "/auth/device/start";
|
|
377
|
+
const apiResp = await this.http.json(path, {
|
|
585
378
|
method: "POST",
|
|
586
379
|
apiKey: this.apiKey
|
|
587
380
|
});
|
|
@@ -701,1216 +494,378 @@ function isTokenReusable(token) {
|
|
|
701
494
|
return token.expiresAt.getTime() - Date.now() > 6e4;
|
|
702
495
|
}
|
|
703
496
|
|
|
704
|
-
//
|
|
705
|
-
var
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
module: "dist/index.js",
|
|
712
|
-
types: "dist/index.d.ts",
|
|
713
|
-
exports: {
|
|
714
|
-
".": {
|
|
715
|
-
types: "./dist/index.d.ts",
|
|
716
|
-
import: "./dist/index.js",
|
|
717
|
-
require: "./dist/index.cjs"
|
|
718
|
-
}
|
|
719
|
-
},
|
|
720
|
-
publishConfig: {
|
|
721
|
-
access: "public"
|
|
722
|
-
},
|
|
723
|
-
files: [
|
|
724
|
-
"dist"
|
|
725
|
-
],
|
|
726
|
-
scripts: {
|
|
727
|
-
build: "tsup src/index.ts --format esm,cjs --dts --external playwright",
|
|
728
|
-
dev: "tsup src/index.ts --format esm,cjs --dts --watch",
|
|
729
|
-
lint: "tsc --noEmit --project tsconfig.lint.json",
|
|
730
|
-
test: "vitest run",
|
|
731
|
-
"generate:types": "openapi-typescript ../../api/openapi/api.json -o src/generated/api.ts"
|
|
732
|
-
},
|
|
733
|
-
keywords: [
|
|
734
|
-
"modelrelay",
|
|
735
|
-
"llm",
|
|
736
|
-
"sdk",
|
|
737
|
-
"typescript"
|
|
738
|
-
],
|
|
739
|
-
author: "Shane Vitarana",
|
|
740
|
-
license: "Apache-2.0",
|
|
741
|
-
dependencies: {
|
|
742
|
-
"fast-json-patch": "^3.1.1",
|
|
743
|
-
zod: "^3.23.0"
|
|
744
|
-
},
|
|
745
|
-
peerDependencies: {
|
|
746
|
-
playwright: ">=1.40.0"
|
|
747
|
-
},
|
|
748
|
-
peerDependenciesMeta: {
|
|
749
|
-
playwright: {
|
|
750
|
-
optional: true
|
|
751
|
-
}
|
|
752
|
-
},
|
|
753
|
-
devDependencies: {
|
|
754
|
-
"@types/node": "^25.0.3",
|
|
755
|
-
"openapi-typescript": "^7.4.4",
|
|
756
|
-
playwright: "^1.49.0",
|
|
757
|
-
tsup: "^8.2.4",
|
|
758
|
-
typescript: "^5.6.3",
|
|
759
|
-
vitest: "^2.1.4"
|
|
497
|
+
// src/structured.ts
|
|
498
|
+
var StructuredDecodeError = class extends Error {
|
|
499
|
+
constructor(message, rawJson, attempt) {
|
|
500
|
+
super(`structured output decode error (attempt ${attempt}): ${message}`);
|
|
501
|
+
this.name = "StructuredDecodeError";
|
|
502
|
+
this.rawJson = rawJson;
|
|
503
|
+
this.attempt = attempt;
|
|
760
504
|
}
|
|
761
505
|
};
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
EndTurn: "end_turn",
|
|
774
|
-
MaxTokens: "max_tokens",
|
|
775
|
-
MaxLength: "max_len",
|
|
776
|
-
MaxContext: "max_context",
|
|
777
|
-
ToolCalls: "tool_calls",
|
|
778
|
-
TimeLimit: "time_limit",
|
|
779
|
-
ContentFilter: "content_filter",
|
|
780
|
-
Incomplete: "incomplete",
|
|
781
|
-
Unknown: "unknown"
|
|
782
|
-
};
|
|
783
|
-
function asProviderId(value) {
|
|
784
|
-
return value;
|
|
785
|
-
}
|
|
786
|
-
function asModelId(value) {
|
|
787
|
-
return value;
|
|
788
|
-
}
|
|
789
|
-
function asTierCode(value) {
|
|
790
|
-
return value;
|
|
791
|
-
}
|
|
792
|
-
var SubscriptionStatuses = {
|
|
793
|
-
Active: "active",
|
|
794
|
-
Trialing: "trialing",
|
|
795
|
-
PastDue: "past_due",
|
|
796
|
-
Canceled: "canceled",
|
|
797
|
-
Unpaid: "unpaid",
|
|
798
|
-
Incomplete: "incomplete",
|
|
799
|
-
IncompleteExpired: "incomplete_expired",
|
|
800
|
-
Paused: "paused"
|
|
801
|
-
};
|
|
802
|
-
var BillingProviders = {
|
|
803
|
-
Stripe: "stripe",
|
|
804
|
-
Crypto: "crypto",
|
|
805
|
-
AppStore: "app_store",
|
|
806
|
-
External: "external"
|
|
807
|
-
};
|
|
808
|
-
function createUsage(inputTokens, outputTokens, totalTokens) {
|
|
809
|
-
return {
|
|
810
|
-
inputTokens,
|
|
811
|
-
outputTokens,
|
|
812
|
-
totalTokens: totalTokens ?? inputTokens + outputTokens
|
|
813
|
-
};
|
|
814
|
-
}
|
|
815
|
-
var MessageRoles = {
|
|
816
|
-
User: "user",
|
|
817
|
-
Assistant: "assistant",
|
|
818
|
-
System: "system",
|
|
819
|
-
Tool: "tool"
|
|
820
|
-
};
|
|
821
|
-
var ContentPartTypes = {
|
|
822
|
-
Text: "text"
|
|
823
|
-
};
|
|
824
|
-
var InputItemTypes = {
|
|
825
|
-
Message: "message"
|
|
826
|
-
};
|
|
827
|
-
var OutputItemTypes = {
|
|
828
|
-
Message: "message"
|
|
829
|
-
};
|
|
830
|
-
var ToolTypes = {
|
|
831
|
-
Function: "function",
|
|
832
|
-
Web: "web",
|
|
833
|
-
XSearch: "x_search",
|
|
834
|
-
CodeExecution: "code_execution"
|
|
835
|
-
};
|
|
836
|
-
var WebToolModes = {
|
|
837
|
-
Auto: "auto",
|
|
838
|
-
SearchOnly: "search_only",
|
|
839
|
-
FetchOnly: "fetch_only",
|
|
840
|
-
SearchAndFetch: "search_and_fetch"
|
|
841
|
-
};
|
|
842
|
-
var ToolChoiceTypes = {
|
|
843
|
-
Auto: "auto",
|
|
844
|
-
Required: "required",
|
|
845
|
-
None: "none"
|
|
506
|
+
var StructuredExhaustedError = class extends Error {
|
|
507
|
+
constructor(lastRawJson, allAttempts, finalError) {
|
|
508
|
+
const errorMsg = finalError.kind === "decode" ? finalError.message : finalError.issues.map((i) => i.message).join("; ");
|
|
509
|
+
super(
|
|
510
|
+
`structured output failed after ${allAttempts.length} attempts: ${errorMsg}`
|
|
511
|
+
);
|
|
512
|
+
this.name = "StructuredExhaustedError";
|
|
513
|
+
this.lastRawJson = lastRawJson;
|
|
514
|
+
this.allAttempts = allAttempts;
|
|
515
|
+
this.finalError = finalError;
|
|
516
|
+
}
|
|
846
517
|
};
|
|
847
|
-
var
|
|
848
|
-
|
|
849
|
-
|
|
518
|
+
var defaultRetryHandler = {
|
|
519
|
+
onValidationError(_attempt, _rawJson, error, _originalInput) {
|
|
520
|
+
const errorMsg = error.kind === "decode" ? error.message : error.issues.map((i) => `${i.path ?? ""}: ${i.message}`).join("; ");
|
|
521
|
+
return [{
|
|
522
|
+
type: "message",
|
|
523
|
+
role: "user",
|
|
524
|
+
content: [{ type: "text", text: `The previous response did not match the expected schema. Error: ${errorMsg}. Please provide a response that matches the schema exactly.` }]
|
|
525
|
+
}];
|
|
526
|
+
}
|
|
850
527
|
};
|
|
851
|
-
function
|
|
852
|
-
|
|
853
|
-
return {
|
|
854
|
-
...base || {},
|
|
855
|
-
...override || {}
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
function mergeTrace(base, override) {
|
|
859
|
-
if (!base && !override) return void 0;
|
|
528
|
+
function outputFormatFromZod(schema, name = "response") {
|
|
529
|
+
const jsonSchema = zodToJsonSchema(schema);
|
|
860
530
|
return {
|
|
861
|
-
|
|
862
|
-
|
|
531
|
+
type: "json_schema",
|
|
532
|
+
json_schema: {
|
|
533
|
+
name,
|
|
534
|
+
schema: jsonSchema,
|
|
535
|
+
strict: true
|
|
536
|
+
}
|
|
863
537
|
};
|
|
864
538
|
}
|
|
865
|
-
function
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
for (const reason of Object.values(StopReasons)) {
|
|
870
|
-
if (lower === reason) return reason;
|
|
871
|
-
}
|
|
872
|
-
switch (lower) {
|
|
873
|
-
case "length":
|
|
874
|
-
return StopReasons.MaxLength;
|
|
875
|
-
default:
|
|
876
|
-
return { other: str };
|
|
539
|
+
function validateWithZod(schema, data) {
|
|
540
|
+
const result = schema.safeParse(data);
|
|
541
|
+
if (result.success) {
|
|
542
|
+
return { success: true, data: result.data };
|
|
877
543
|
}
|
|
544
|
+
const err = result.error;
|
|
545
|
+
const issuesRaw = err && typeof err === "object" && "issues" in err ? err.issues : void 0;
|
|
546
|
+
if (Array.isArray(issuesRaw)) {
|
|
547
|
+
return {
|
|
548
|
+
success: false,
|
|
549
|
+
issues: issuesRaw.map((i) => {
|
|
550
|
+
const ii = i && typeof i === "object" ? i : {};
|
|
551
|
+
return {
|
|
552
|
+
path: Array.isArray(ii.path) ? ii.path.filter((p) => typeof p === "string" || typeof p === "number").join(".") : void 0,
|
|
553
|
+
message: typeof ii.message === "string" && ii.message.trim() ? ii.message : "validation failed"
|
|
554
|
+
};
|
|
555
|
+
})
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
const message = err && typeof err === "object" && "message" in err ? String(err.message) : "validation failed";
|
|
559
|
+
return { success: false, issues: [{ message }] };
|
|
878
560
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
function
|
|
885
|
-
|
|
886
|
-
const str = String(value).trim();
|
|
887
|
-
if (!str) return void 0;
|
|
888
|
-
return str;
|
|
561
|
+
|
|
562
|
+
// src/responses_request.ts
|
|
563
|
+
var RESPONSES_PATH = "/responses";
|
|
564
|
+
var CUSTOMER_ID_HEADER = "X-ModelRelay-Customer-Id";
|
|
565
|
+
var REQUEST_ID_HEADER = "X-ModelRelay-Request-Id";
|
|
566
|
+
function makeResponsesRequest(body, options) {
|
|
567
|
+
return { body, options };
|
|
889
568
|
}
|
|
890
|
-
function
|
|
891
|
-
return
|
|
569
|
+
function asInternal(req) {
|
|
570
|
+
return req;
|
|
892
571
|
}
|
|
893
|
-
|
|
894
|
-
// src/tools.ts
|
|
895
|
-
function createUserMessage(content) {
|
|
572
|
+
function mergeOptions(base, override) {
|
|
896
573
|
return {
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
574
|
+
...base,
|
|
575
|
+
...override,
|
|
576
|
+
headers: {
|
|
577
|
+
...base.headers || {},
|
|
578
|
+
...override.headers || {}
|
|
579
|
+
}
|
|
900
580
|
};
|
|
901
581
|
}
|
|
902
|
-
function
|
|
903
|
-
return
|
|
904
|
-
type: "message",
|
|
905
|
-
role: "assistant",
|
|
906
|
-
content: [{ type: "text", text: content }]
|
|
907
|
-
};
|
|
908
|
-
}
|
|
909
|
-
function createSystemMessage(content) {
|
|
910
|
-
return {
|
|
911
|
-
type: "message",
|
|
912
|
-
role: "system",
|
|
913
|
-
content: [{ type: "text", text: content }]
|
|
914
|
-
};
|
|
915
|
-
}
|
|
916
|
-
function createToolCall(id, name, args, type = ToolTypes.Function) {
|
|
917
|
-
return {
|
|
918
|
-
id,
|
|
919
|
-
type,
|
|
920
|
-
function: createFunctionCall(name, args)
|
|
921
|
-
};
|
|
922
|
-
}
|
|
923
|
-
function createFunctionCall(name, args) {
|
|
924
|
-
return { name, arguments: args };
|
|
582
|
+
function requestIdFromHeaders(headers) {
|
|
583
|
+
return headers.get(REQUEST_ID_HEADER);
|
|
925
584
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
585
|
+
|
|
586
|
+
// src/responses_builder.ts
|
|
587
|
+
var ResponseBuilder = class _ResponseBuilder {
|
|
588
|
+
constructor(body = { input: [] }, options = {}) {
|
|
589
|
+
this.body = body;
|
|
590
|
+
this.options = options;
|
|
931
591
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
switch (typeName) {
|
|
938
|
-
case "ZodString":
|
|
939
|
-
return convertZodString(def);
|
|
940
|
-
case "ZodNumber":
|
|
941
|
-
return convertZodNumber(def);
|
|
942
|
-
case "ZodBoolean":
|
|
943
|
-
return { type: "boolean" };
|
|
944
|
-
case "ZodNull":
|
|
945
|
-
return { type: "null" };
|
|
946
|
-
case "ZodArray":
|
|
947
|
-
return convertZodArray(def);
|
|
948
|
-
case "ZodObject":
|
|
949
|
-
return convertZodObject(def);
|
|
950
|
-
case "ZodEnum":
|
|
951
|
-
return convertZodEnum(def);
|
|
952
|
-
case "ZodNativeEnum":
|
|
953
|
-
return convertZodNativeEnum(def);
|
|
954
|
-
case "ZodLiteral":
|
|
955
|
-
return { const: def.value };
|
|
956
|
-
case "ZodUnion":
|
|
957
|
-
return convertZodUnion(def);
|
|
958
|
-
case "ZodOptional": {
|
|
959
|
-
const inner = convertZodType(def.innerType);
|
|
960
|
-
if (def.description && !inner.description) {
|
|
961
|
-
inner.description = def.description;
|
|
962
|
-
}
|
|
963
|
-
return inner;
|
|
964
|
-
}
|
|
965
|
-
case "ZodNullable":
|
|
966
|
-
return convertZodNullable(def);
|
|
967
|
-
case "ZodDefault":
|
|
968
|
-
return { ...convertZodType(def.innerType), default: def.defaultValue() };
|
|
969
|
-
case "ZodEffects":
|
|
970
|
-
return convertZodType(def.schema);
|
|
971
|
-
case "ZodRecord":
|
|
972
|
-
return convertZodRecord(def);
|
|
973
|
-
case "ZodTuple":
|
|
974
|
-
return convertZodTuple(def);
|
|
975
|
-
case "ZodAny":
|
|
976
|
-
case "ZodUnknown":
|
|
977
|
-
return {};
|
|
978
|
-
default:
|
|
979
|
-
throw new ConfigError(
|
|
980
|
-
`sdk: unsupported Zod schema type ${JSON.stringify(typeName)}; pass JSON Schema directly or use a full converter like zod-to-json-schema`,
|
|
981
|
-
{ typeName }
|
|
982
|
-
);
|
|
592
|
+
with(patch) {
|
|
593
|
+
return new _ResponseBuilder(
|
|
594
|
+
patch.body ? { ...this.body, ...patch.body } : this.body,
|
|
595
|
+
patch.options ? { ...this.options, ...patch.options } : this.options
|
|
596
|
+
);
|
|
983
597
|
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
const checks = def.checks;
|
|
988
|
-
if (checks) {
|
|
989
|
-
for (const check of checks) {
|
|
990
|
-
switch (check.kind) {
|
|
991
|
-
case "min":
|
|
992
|
-
result.minLength = check.value;
|
|
993
|
-
break;
|
|
994
|
-
case "max":
|
|
995
|
-
result.maxLength = check.value;
|
|
996
|
-
break;
|
|
997
|
-
case "length":
|
|
998
|
-
result.minLength = check.value;
|
|
999
|
-
result.maxLength = check.value;
|
|
1000
|
-
break;
|
|
1001
|
-
case "email":
|
|
1002
|
-
result.format = "email";
|
|
1003
|
-
break;
|
|
1004
|
-
case "url":
|
|
1005
|
-
result.format = "uri";
|
|
1006
|
-
break;
|
|
1007
|
-
case "uuid":
|
|
1008
|
-
result.format = "uuid";
|
|
1009
|
-
break;
|
|
1010
|
-
case "datetime":
|
|
1011
|
-
result.format = "date-time";
|
|
1012
|
-
break;
|
|
1013
|
-
case "regex":
|
|
1014
|
-
result.pattern = check.value.source;
|
|
1015
|
-
break;
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
598
|
+
/** @returns A new builder with the provider set. */
|
|
599
|
+
provider(provider) {
|
|
600
|
+
return this.with({ body: { provider } });
|
|
1018
601
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
602
|
+
/** @returns A new builder with the model set. */
|
|
603
|
+
model(model) {
|
|
604
|
+
return this.with({ body: { model } });
|
|
1021
605
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
const result = { type: "number" };
|
|
1026
|
-
const checks = def.checks;
|
|
1027
|
-
if (checks) {
|
|
1028
|
-
for (const check of checks) {
|
|
1029
|
-
switch (check.kind) {
|
|
1030
|
-
case "int":
|
|
1031
|
-
result.type = "integer";
|
|
1032
|
-
break;
|
|
1033
|
-
case "min":
|
|
1034
|
-
if (check.inclusive === false) {
|
|
1035
|
-
result.exclusiveMinimum = check.value;
|
|
1036
|
-
} else {
|
|
1037
|
-
result.minimum = check.value;
|
|
1038
|
-
}
|
|
1039
|
-
break;
|
|
1040
|
-
case "max":
|
|
1041
|
-
if (check.inclusive === false) {
|
|
1042
|
-
result.exclusiveMaximum = check.value;
|
|
1043
|
-
} else {
|
|
1044
|
-
result.maximum = check.value;
|
|
1045
|
-
}
|
|
1046
|
-
break;
|
|
1047
|
-
case "multipleOf":
|
|
1048
|
-
result.multipleOf = check.value;
|
|
1049
|
-
break;
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
606
|
+
/** @returns A new builder with the full input array replaced. */
|
|
607
|
+
input(items) {
|
|
608
|
+
return this.with({ body: { input: items.slice() } });
|
|
1052
609
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
610
|
+
/** @returns A new builder with the input item appended. */
|
|
611
|
+
item(item) {
|
|
612
|
+
const input = [...this.body.input ?? [], item];
|
|
613
|
+
return this.with({ body: { input } });
|
|
1055
614
|
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
if (def.minLength !== void 0 && def.minLength !== null) {
|
|
1064
|
-
result.minItems = def.minLength.value;
|
|
615
|
+
/** @returns A new builder with a message input item appended. */
|
|
616
|
+
message(role, content) {
|
|
617
|
+
return this.item({
|
|
618
|
+
type: "message",
|
|
619
|
+
role,
|
|
620
|
+
content: [{ type: "text", text: content }]
|
|
621
|
+
});
|
|
1065
622
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
623
|
+
/** @returns A new builder with a system message appended. */
|
|
624
|
+
system(content) {
|
|
625
|
+
return this.message("system", content);
|
|
1068
626
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
627
|
+
/** @returns A new builder with a user message appended. */
|
|
628
|
+
user(content) {
|
|
629
|
+
return this.message("user", content);
|
|
1071
630
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
const shape = def.shape;
|
|
1076
|
-
const shapeObj = typeof shape === "function" ? shape() : shape;
|
|
1077
|
-
const properties = {};
|
|
1078
|
-
const required = [];
|
|
1079
|
-
for (const [key, value] of Object.entries(shapeObj)) {
|
|
1080
|
-
properties[key] = convertZodType(value);
|
|
1081
|
-
const valueDef = value._def;
|
|
1082
|
-
const isOptional = valueDef.typeName === "ZodOptional" || valueDef.typeName === "ZodDefault" || valueDef.typeName === "ZodNullable" && valueDef.innerType?._def?.typeName === "ZodDefault";
|
|
1083
|
-
if (!isOptional) {
|
|
1084
|
-
required.push(key);
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
const result = {
|
|
1088
|
-
type: "object",
|
|
1089
|
-
properties
|
|
1090
|
-
};
|
|
1091
|
-
if (required.length > 0) {
|
|
1092
|
-
result.required = required;
|
|
631
|
+
/** @returns A new builder with an assistant message appended. */
|
|
632
|
+
assistant(content) {
|
|
633
|
+
return this.message("assistant", content);
|
|
1093
634
|
}
|
|
1094
|
-
|
|
1095
|
-
|
|
635
|
+
/** @returns A new builder with a tool result message appended. */
|
|
636
|
+
toolResultText(toolCallId, content) {
|
|
637
|
+
return this.item({
|
|
638
|
+
type: "message",
|
|
639
|
+
role: "tool",
|
|
640
|
+
toolCallId: toolCallId.trim(),
|
|
641
|
+
content: [{ type: "text", text: content }]
|
|
642
|
+
});
|
|
1096
643
|
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
644
|
+
/** @returns A new builder with the output format set. */
|
|
645
|
+
outputFormat(format) {
|
|
646
|
+
return this.with({ body: { output_format: format } });
|
|
1100
647
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
const result = {
|
|
1105
|
-
type: "string",
|
|
1106
|
-
enum: def.values
|
|
1107
|
-
};
|
|
1108
|
-
if (def.description) {
|
|
1109
|
-
result.description = def.description;
|
|
648
|
+
/** @returns A new builder with max output tokens set. */
|
|
649
|
+
maxOutputTokens(max) {
|
|
650
|
+
return this.with({ body: { max_output_tokens: max } });
|
|
1110
651
|
}
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
const enumValues = def.values;
|
|
1115
|
-
const values = Object.values(enumValues).filter(
|
|
1116
|
-
(v) => typeof v === "string" || typeof v === "number"
|
|
1117
|
-
);
|
|
1118
|
-
const result = { enum: values };
|
|
1119
|
-
if (def.description) {
|
|
1120
|
-
result.description = def.description;
|
|
652
|
+
/** @returns A new builder with temperature set. */
|
|
653
|
+
temperature(temp) {
|
|
654
|
+
return this.with({ body: { temperature: temp } });
|
|
1121
655
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
const result = {
|
|
1127
|
-
anyOf: options.map(convertZodType)
|
|
1128
|
-
};
|
|
1129
|
-
if (def.description) {
|
|
1130
|
-
result.description = def.description;
|
|
656
|
+
/** @returns A new builder with stop sequences set. */
|
|
657
|
+
stop(...stop) {
|
|
658
|
+
const clean = stop.map((s) => s.trim()).filter(Boolean);
|
|
659
|
+
return this.with({ body: { stop: clean.length ? clean : void 0 } });
|
|
1131
660
|
}
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
const inner = convertZodType(def.innerType);
|
|
1136
|
-
return {
|
|
1137
|
-
anyOf: [inner, { type: "null" }]
|
|
1138
|
-
};
|
|
1139
|
-
}
|
|
1140
|
-
function convertZodRecord(def) {
|
|
1141
|
-
const result = {
|
|
1142
|
-
type: "object",
|
|
1143
|
-
additionalProperties: convertZodType(def.valueType)
|
|
1144
|
-
};
|
|
1145
|
-
if (def.description) {
|
|
1146
|
-
result.description = def.description;
|
|
661
|
+
/** @returns A new builder with tools replaced. */
|
|
662
|
+
tools(tools) {
|
|
663
|
+
return this.with({ body: { tools: tools.slice() } });
|
|
1147
664
|
}
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
const result = {
|
|
1153
|
-
type: "array",
|
|
1154
|
-
items: items.map(convertZodType),
|
|
1155
|
-
minItems: items.length,
|
|
1156
|
-
maxItems: items.length
|
|
1157
|
-
};
|
|
1158
|
-
if (def.description) {
|
|
1159
|
-
result.description = def.description;
|
|
665
|
+
/** @returns A new builder with a tool appended. */
|
|
666
|
+
tool(tool) {
|
|
667
|
+
const tools = [...this.body.tools ?? [], tool];
|
|
668
|
+
return this.with({ body: { tools } });
|
|
1160
669
|
}
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
const jsonSchema = zodToJsonSchema(schema, options);
|
|
1165
|
-
return createFunctionTool(name, description, jsonSchema);
|
|
1166
|
-
}
|
|
1167
|
-
function createFunctionTool(name, description, parameters) {
|
|
1168
|
-
const fn = { name, description };
|
|
1169
|
-
if (parameters) {
|
|
1170
|
-
fn.parameters = parameters;
|
|
670
|
+
/** @returns A new builder with tool choice set. */
|
|
671
|
+
toolChoice(choice) {
|
|
672
|
+
return this.with({ body: { tool_choice: choice } });
|
|
1171
673
|
}
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
};
|
|
1176
|
-
}
|
|
1177
|
-
function createWebTool(options) {
|
|
1178
|
-
return {
|
|
1179
|
-
type: ToolTypes.Web,
|
|
1180
|
-
web: options ? {
|
|
1181
|
-
mode: options.mode,
|
|
1182
|
-
allowedDomains: options.allowedDomains,
|
|
1183
|
-
excludedDomains: options.excludedDomains,
|
|
1184
|
-
maxUses: options.maxUses
|
|
1185
|
-
} : void 0
|
|
1186
|
-
};
|
|
1187
|
-
}
|
|
1188
|
-
function toolChoiceAuto() {
|
|
1189
|
-
return { type: ToolChoiceTypes.Auto };
|
|
1190
|
-
}
|
|
1191
|
-
function toolChoiceRequired() {
|
|
1192
|
-
return { type: ToolChoiceTypes.Required };
|
|
1193
|
-
}
|
|
1194
|
-
function toolChoiceNone() {
|
|
1195
|
-
return { type: ToolChoiceTypes.None };
|
|
1196
|
-
}
|
|
1197
|
-
function hasToolCalls(response) {
|
|
1198
|
-
for (const item of response.output || []) {
|
|
1199
|
-
if (item?.toolCalls?.length) return true;
|
|
674
|
+
/** @returns A new builder with tool choice set to auto. */
|
|
675
|
+
toolChoiceAuto() {
|
|
676
|
+
return this.toolChoice({ type: "auto" });
|
|
1200
677
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
function
|
|
1204
|
-
for (const item of response.output || []) {
|
|
1205
|
-
const call = item?.toolCalls?.[0];
|
|
1206
|
-
if (call) return call;
|
|
678
|
+
/** @returns A new builder with tool choice set to required. */
|
|
679
|
+
toolChoiceRequired(functionName) {
|
|
680
|
+
return this.toolChoice({ type: "required", function: functionName });
|
|
1207
681
|
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
const content = typeof result === "string" ? result : JSON.stringify(result);
|
|
1212
|
-
return {
|
|
1213
|
-
type: "message",
|
|
1214
|
-
role: "tool",
|
|
1215
|
-
toolCallId,
|
|
1216
|
-
content: [{ type: "text", text: content }]
|
|
1217
|
-
};
|
|
1218
|
-
}
|
|
1219
|
-
function respondToToolCall(call, result) {
|
|
1220
|
-
return toolResultMessage(call.id, result);
|
|
1221
|
-
}
|
|
1222
|
-
function assistantMessageWithToolCalls(content, toolCalls) {
|
|
1223
|
-
return {
|
|
1224
|
-
type: "message",
|
|
1225
|
-
role: "assistant",
|
|
1226
|
-
content: [{ type: "text", text: content }],
|
|
1227
|
-
toolCalls
|
|
1228
|
-
};
|
|
1229
|
-
}
|
|
1230
|
-
var ToolCallAccumulator = class {
|
|
1231
|
-
constructor() {
|
|
1232
|
-
this.calls = /* @__PURE__ */ new Map();
|
|
682
|
+
/** @returns A new builder with tool choice set to none. */
|
|
683
|
+
toolChoiceNone() {
|
|
684
|
+
return this.toolChoice({ type: "none" });
|
|
1233
685
|
}
|
|
1234
|
-
/**
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
*/
|
|
1238
|
-
processDelta(delta) {
|
|
1239
|
-
const existing = this.calls.get(delta.index);
|
|
1240
|
-
if (!existing) {
|
|
1241
|
-
this.calls.set(delta.index, {
|
|
1242
|
-
id: delta.id ?? "",
|
|
1243
|
-
type: delta.type ?? ToolTypes.Function,
|
|
1244
|
-
function: {
|
|
1245
|
-
name: delta.function?.name ?? "",
|
|
1246
|
-
arguments: delta.function?.arguments ?? ""
|
|
1247
|
-
}
|
|
1248
|
-
});
|
|
1249
|
-
return true;
|
|
1250
|
-
}
|
|
1251
|
-
if (delta.function) {
|
|
1252
|
-
if (delta.function.name) {
|
|
1253
|
-
existing.function = existing.function ?? { name: "", arguments: "" };
|
|
1254
|
-
existing.function.name = delta.function.name;
|
|
1255
|
-
}
|
|
1256
|
-
if (delta.function.arguments) {
|
|
1257
|
-
existing.function = existing.function ?? { name: "", arguments: "" };
|
|
1258
|
-
existing.function.arguments += delta.function.arguments;
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
return false;
|
|
686
|
+
/** @returns A new builder with the customer ID option set. */
|
|
687
|
+
customerId(customerId) {
|
|
688
|
+
return this.with({ options: { customerId: customerId.trim() } });
|
|
1262
689
|
}
|
|
1263
|
-
/**
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
getToolCalls() {
|
|
1267
|
-
if (this.calls.size === 0) {
|
|
1268
|
-
return [];
|
|
1269
|
-
}
|
|
1270
|
-
const maxIdx = Math.max(...this.calls.keys());
|
|
1271
|
-
const result = [];
|
|
1272
|
-
for (let i = 0; i <= maxIdx; i++) {
|
|
1273
|
-
const call = this.calls.get(i);
|
|
1274
|
-
if (call) {
|
|
1275
|
-
result.push(call);
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
return result;
|
|
690
|
+
/** @returns A new builder with the request ID option set. */
|
|
691
|
+
requestId(requestId) {
|
|
692
|
+
return this.with({ options: { requestId: requestId.trim() } });
|
|
1279
693
|
}
|
|
1280
|
-
/**
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
return this.calls.get(index);
|
|
694
|
+
/** @returns A new builder with a single header set/overridden. */
|
|
695
|
+
header(key, value) {
|
|
696
|
+
const headers = { ...this.options.headers || {}, [key]: value };
|
|
697
|
+
return this.with({ options: { headers } });
|
|
1285
698
|
}
|
|
1286
|
-
/**
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
this.calls.clear();
|
|
699
|
+
/** @returns A new builder with headers merged. */
|
|
700
|
+
headers(headers) {
|
|
701
|
+
const merged = { ...this.options.headers || {}, ...headers };
|
|
702
|
+
return this.with({ options: { headers: merged } });
|
|
1291
703
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
super(message);
|
|
1296
|
-
this.name = "ToolArgsError";
|
|
1297
|
-
this.toolCallId = toolCallId;
|
|
1298
|
-
this.toolName = toolName;
|
|
1299
|
-
this.rawArguments = rawArguments;
|
|
704
|
+
/** @returns A new builder with the request timeout option set. */
|
|
705
|
+
timeoutMs(timeoutMs) {
|
|
706
|
+
return this.with({ options: { timeoutMs: Math.max(0, timeoutMs) } });
|
|
1300
707
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
try {
|
|
1307
|
-
parsed = rawArgs ? JSON.parse(rawArgs) : {};
|
|
1308
|
-
} catch (err) {
|
|
1309
|
-
const message = err instanceof Error ? err.message : "Invalid JSON in arguments";
|
|
1310
|
-
throw new ToolArgsError(
|
|
1311
|
-
`Failed to parse arguments for tool '${toolName}': ${message}`,
|
|
1312
|
-
call.id,
|
|
1313
|
-
toolName,
|
|
1314
|
-
rawArgs
|
|
1315
|
-
);
|
|
708
|
+
/** @returns A new builder with the connect timeout option set. */
|
|
709
|
+
connectTimeoutMs(connectTimeoutMs) {
|
|
710
|
+
return this.with({
|
|
711
|
+
options: { connectTimeoutMs: Math.max(0, connectTimeoutMs) }
|
|
712
|
+
});
|
|
1316
713
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
let message;
|
|
1321
|
-
if (err instanceof Error) {
|
|
1322
|
-
const zodErr = err;
|
|
1323
|
-
if (zodErr.errors && Array.isArray(zodErr.errors)) {
|
|
1324
|
-
const issues = zodErr.errors.map((e) => {
|
|
1325
|
-
const path2 = e.path.length > 0 ? `${e.path.join(".")}: ` : "";
|
|
1326
|
-
return `${path2}${e.message}`;
|
|
1327
|
-
}).join("; ");
|
|
1328
|
-
message = issues;
|
|
1329
|
-
} else {
|
|
1330
|
-
message = err.message;
|
|
1331
|
-
}
|
|
1332
|
-
} else {
|
|
1333
|
-
message = String(err);
|
|
1334
|
-
}
|
|
1335
|
-
throw new ToolArgsError(
|
|
1336
|
-
`Invalid arguments for tool '${toolName}': ${message}`,
|
|
1337
|
-
call.id,
|
|
1338
|
-
toolName,
|
|
1339
|
-
rawArgs
|
|
1340
|
-
);
|
|
714
|
+
/** @returns A new builder with retry configuration set. */
|
|
715
|
+
retry(cfg) {
|
|
716
|
+
return this.with({ options: { retry: cfg } });
|
|
1341
717
|
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
const data = parseToolArgs(call, schema);
|
|
1346
|
-
return { success: true, data };
|
|
1347
|
-
} catch (err) {
|
|
1348
|
-
if (err instanceof ToolArgsError) {
|
|
1349
|
-
return { success: false, error: err };
|
|
1350
|
-
}
|
|
1351
|
-
const toolName = call.function?.name ?? "unknown";
|
|
1352
|
-
const rawArgs = call.function?.arguments ?? "";
|
|
1353
|
-
return {
|
|
1354
|
-
success: false,
|
|
1355
|
-
error: new ToolArgsError(
|
|
1356
|
-
err instanceof Error ? err.message : String(err),
|
|
1357
|
-
call.id,
|
|
1358
|
-
toolName,
|
|
1359
|
-
rawArgs
|
|
1360
|
-
)
|
|
1361
|
-
};
|
|
718
|
+
/** @returns A new builder with retries disabled. */
|
|
719
|
+
disableRetry() {
|
|
720
|
+
return this.with({ options: { retry: false } });
|
|
1362
721
|
}
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
const rawArgs = call.function?.arguments ?? "";
|
|
1367
|
-
try {
|
|
1368
|
-
return rawArgs ? JSON.parse(rawArgs) : {};
|
|
1369
|
-
} catch (err) {
|
|
1370
|
-
const message = err instanceof Error ? err.message : "Invalid JSON in arguments";
|
|
1371
|
-
throw new ToolArgsError(
|
|
1372
|
-
`Failed to parse arguments for tool '${toolName}': ${message}`,
|
|
1373
|
-
call.id,
|
|
1374
|
-
toolName,
|
|
1375
|
-
rawArgs
|
|
1376
|
-
);
|
|
722
|
+
/** @returns A new builder with metrics callbacks set. */
|
|
723
|
+
metrics(metrics) {
|
|
724
|
+
return this.with({ options: { metrics } });
|
|
1377
725
|
}
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
this.handlers = /* @__PURE__ */ new Map();
|
|
726
|
+
/** @returns A new builder with trace callbacks set. */
|
|
727
|
+
trace(trace) {
|
|
728
|
+
return this.with({ options: { trace } });
|
|
1382
729
|
}
|
|
1383
|
-
/**
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
*/
|
|
1389
|
-
register(name, handler) {
|
|
1390
|
-
this.handlers.set(name, handler);
|
|
1391
|
-
return this;
|
|
730
|
+
/** @returns A new builder with stream time-to-first-token timeout set. */
|
|
731
|
+
streamTTFTTimeoutMs(timeoutMs) {
|
|
732
|
+
return this.with({
|
|
733
|
+
options: { streamTTFTTimeoutMs: Math.max(0, timeoutMs) }
|
|
734
|
+
});
|
|
1392
735
|
}
|
|
1393
|
-
/**
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
unregister(name) {
|
|
1399
|
-
return this.handlers.delete(name);
|
|
736
|
+
/** @returns A new builder with stream idle timeout set. */
|
|
737
|
+
streamIdleTimeoutMs(timeoutMs) {
|
|
738
|
+
return this.with({
|
|
739
|
+
options: { streamIdleTimeoutMs: Math.max(0, timeoutMs) }
|
|
740
|
+
});
|
|
1400
741
|
}
|
|
1401
|
-
/**
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
742
|
+
/** @returns A new builder with total stream timeout set. */
|
|
743
|
+
streamTotalTimeoutMs(timeoutMs) {
|
|
744
|
+
return this.with({
|
|
745
|
+
options: { streamTotalTimeoutMs: Math.max(0, timeoutMs) }
|
|
746
|
+
});
|
|
1406
747
|
}
|
|
1407
|
-
/**
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
getRegisteredTools() {
|
|
1411
|
-
return Array.from(this.handlers.keys());
|
|
748
|
+
/** @returns A new builder with the abort signal set. */
|
|
749
|
+
signal(signal) {
|
|
750
|
+
return this.with({ options: { signal } });
|
|
1412
751
|
}
|
|
1413
|
-
/**
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
async execute(call) {
|
|
1419
|
-
const toolName = call.function?.name ?? "";
|
|
1420
|
-
const handler = this.handlers.get(toolName);
|
|
1421
|
-
if (!handler) {
|
|
1422
|
-
return {
|
|
1423
|
-
toolCallId: call.id,
|
|
1424
|
-
toolName,
|
|
1425
|
-
result: null,
|
|
1426
|
-
error: `Unknown tool: '${toolName}'. Available tools: ${this.getRegisteredTools().join(", ") || "none"}`
|
|
1427
|
-
};
|
|
1428
|
-
}
|
|
1429
|
-
let args;
|
|
1430
|
-
try {
|
|
1431
|
-
args = call.function?.arguments ? JSON.parse(call.function.arguments) : {};
|
|
1432
|
-
} catch (err) {
|
|
1433
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1434
|
-
return {
|
|
1435
|
-
toolCallId: call.id,
|
|
1436
|
-
toolName,
|
|
1437
|
-
result: null,
|
|
1438
|
-
error: `Invalid JSON in arguments: ${errorMessage}`,
|
|
1439
|
-
isRetryable: true
|
|
1440
|
-
};
|
|
1441
|
-
}
|
|
1442
|
-
try {
|
|
1443
|
-
const result = await handler(args, call);
|
|
1444
|
-
return {
|
|
1445
|
-
toolCallId: call.id,
|
|
1446
|
-
toolName,
|
|
1447
|
-
result
|
|
1448
|
-
};
|
|
1449
|
-
} catch (err) {
|
|
1450
|
-
const isRetryable = err instanceof ToolArgsError || err instanceof ToolArgumentError;
|
|
1451
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1452
|
-
return {
|
|
1453
|
-
toolCallId: call.id,
|
|
1454
|
-
toolName,
|
|
1455
|
-
result: null,
|
|
1456
|
-
error: errorMessage,
|
|
1457
|
-
isRetryable
|
|
1458
|
-
};
|
|
752
|
+
/** @returns A finalized, immutable request payload. */
|
|
753
|
+
build() {
|
|
754
|
+
const input = (this.body.input ?? []).slice();
|
|
755
|
+
if (input.length === 0) {
|
|
756
|
+
throw new ConfigError("at least one input item is required");
|
|
1459
757
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
* @param results - Array of execution results
|
|
1473
|
-
* @returns Array of tool result input items (role "tool")
|
|
1474
|
-
*/
|
|
1475
|
-
resultsToMessages(results) {
|
|
1476
|
-
return results.map((r) => {
|
|
1477
|
-
const content = r.error ? `Error: ${r.error}` : typeof r.result === "string" ? r.result : JSON.stringify(r.result);
|
|
1478
|
-
return toolResultMessage(r.toolCallId, content);
|
|
1479
|
-
});
|
|
758
|
+
const body = {
|
|
759
|
+
provider: this.body.provider,
|
|
760
|
+
model: this.body.model,
|
|
761
|
+
input,
|
|
762
|
+
output_format: this.body.output_format,
|
|
763
|
+
max_output_tokens: this.body.max_output_tokens,
|
|
764
|
+
temperature: this.body.temperature,
|
|
765
|
+
stop: this.body.stop,
|
|
766
|
+
tools: this.body.tools,
|
|
767
|
+
tool_choice: this.body.tool_choice
|
|
768
|
+
};
|
|
769
|
+
return makeResponsesRequest(body, { ...this.options || {} });
|
|
1480
770
|
}
|
|
1481
771
|
};
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
if (result.isRetryable) {
|
|
1487
|
-
lines.push("");
|
|
1488
|
-
lines.push("Please correct the arguments and try again.");
|
|
1489
|
-
}
|
|
1490
|
-
return lines.join("\n");
|
|
1491
|
-
}
|
|
1492
|
-
function hasRetryableErrors(results) {
|
|
1493
|
-
return results.some((r) => r.error && r.isRetryable);
|
|
1494
|
-
}
|
|
1495
|
-
function getRetryableErrors(results) {
|
|
1496
|
-
return results.filter((r) => r.error && r.isRetryable);
|
|
772
|
+
|
|
773
|
+
// src/responses_normalize.ts
|
|
774
|
+
function isRecord(value) {
|
|
775
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1497
776
|
}
|
|
1498
|
-
function
|
|
1499
|
-
|
|
777
|
+
function normalizeUsage(value) {
|
|
778
|
+
if (!isRecord(value)) {
|
|
779
|
+
return void 0;
|
|
780
|
+
}
|
|
781
|
+
const input = Number(value.input_tokens ?? 0);
|
|
782
|
+
const output = Number(value.output_tokens ?? 0);
|
|
783
|
+
const total = value.total_tokens === void 0 || value.total_tokens === null ? void 0 : Number(value.total_tokens);
|
|
784
|
+
return createUsage(
|
|
785
|
+
input,
|
|
786
|
+
output,
|
|
787
|
+
Number.isFinite(total) ? total : void 0
|
|
788
|
+
);
|
|
1500
789
|
}
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
const
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
}
|
|
1513
|
-
const retryableResults = getRetryableErrors(results);
|
|
1514
|
-
if (retryableResults.length === 0 || !options.onRetry) {
|
|
1515
|
-
for (const result of results) {
|
|
1516
|
-
if (result.error && result.isRetryable) {
|
|
1517
|
-
successfulResults.set(result.toolCallId, result);
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
return Array.from(successfulResults.values());
|
|
1521
|
-
}
|
|
1522
|
-
attempt++;
|
|
1523
|
-
if (attempt > maxRetries) {
|
|
1524
|
-
for (const result of retryableResults) {
|
|
1525
|
-
successfulResults.set(result.toolCallId, result);
|
|
1526
|
-
}
|
|
1527
|
-
return Array.from(successfulResults.values());
|
|
1528
|
-
}
|
|
1529
|
-
const errorMessages = createRetryMessages(retryableResults);
|
|
1530
|
-
const newCalls = await options.onRetry(errorMessages, attempt);
|
|
1531
|
-
if (newCalls.length === 0) {
|
|
1532
|
-
for (const result of retryableResults) {
|
|
1533
|
-
successfulResults.set(result.toolCallId, result);
|
|
1534
|
-
}
|
|
1535
|
-
return Array.from(successfulResults.values());
|
|
1536
|
-
}
|
|
1537
|
-
currentCalls = newCalls;
|
|
790
|
+
function normalizeCitations(value) {
|
|
791
|
+
if (!Array.isArray(value) || value.length === 0) return void 0;
|
|
792
|
+
const citations = [];
|
|
793
|
+
for (const item of value) {
|
|
794
|
+
if (!isRecord(item)) continue;
|
|
795
|
+
const url = item.url;
|
|
796
|
+
const title = item.title;
|
|
797
|
+
citations.push({
|
|
798
|
+
...typeof url === "string" && url.trim() ? { url } : {},
|
|
799
|
+
...typeof title === "string" && title.trim() ? { title } : {}
|
|
800
|
+
});
|
|
1538
801
|
}
|
|
1539
|
-
return
|
|
802
|
+
return citations.length ? citations : void 0;
|
|
1540
803
|
}
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
constructor(message, rawJson, attempt) {
|
|
1545
|
-
super(`structured output decode error (attempt ${attempt}): ${message}`);
|
|
1546
|
-
this.name = "StructuredDecodeError";
|
|
1547
|
-
this.rawJson = rawJson;
|
|
1548
|
-
this.attempt = attempt;
|
|
804
|
+
function normalizeResponsesResponse(payload, requestId) {
|
|
805
|
+
if (!isRecord(payload)) {
|
|
806
|
+
throw new APIError("invalid response payload", { status: 200, data: payload });
|
|
1549
807
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
super(
|
|
1555
|
-
`structured output failed after ${allAttempts.length} attempts: ${errorMsg}`
|
|
1556
|
-
);
|
|
1557
|
-
this.name = "StructuredExhaustedError";
|
|
1558
|
-
this.lastRawJson = lastRawJson;
|
|
1559
|
-
this.allAttempts = allAttempts;
|
|
1560
|
-
this.finalError = finalError;
|
|
808
|
+
const output = Array.isArray(payload.output) ? payload.output : [];
|
|
809
|
+
const usage = normalizeUsage(payload.usage);
|
|
810
|
+
if (!usage) {
|
|
811
|
+
throw new APIError("missing usage in response", { status: 200, data: payload });
|
|
1561
812
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
const errorMsg = error.kind === "decode" ? error.message : error.issues.map((i) => `${i.path ?? ""}: ${i.message}`).join("; ");
|
|
1566
|
-
return [{
|
|
1567
|
-
type: "message",
|
|
1568
|
-
role: "user",
|
|
1569
|
-
content: [{ type: "text", text: `The previous response did not match the expected schema. Error: ${errorMsg}. Please provide a response that matches the schema exactly.` }]
|
|
1570
|
-
}];
|
|
813
|
+
const model = normalizeModelId(payload.model);
|
|
814
|
+
if (!model) {
|
|
815
|
+
throw new APIError("missing model in response", { status: 200, data: payload });
|
|
1571
816
|
}
|
|
1572
|
-
};
|
|
1573
|
-
function outputFormatFromZod(schema, name = "response") {
|
|
1574
|
-
const jsonSchema = zodToJsonSchema(schema);
|
|
1575
817
|
return {
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
818
|
+
id: typeof payload.id === "string" ? payload.id : String(payload.id || ""),
|
|
819
|
+
output,
|
|
820
|
+
stopReason: normalizeStopReason(payload.stop_reason),
|
|
821
|
+
model,
|
|
822
|
+
usage,
|
|
823
|
+
provider: typeof payload.provider === "string" ? asProviderId(payload.provider) : void 0,
|
|
824
|
+
citations: normalizeCitations(payload.citations),
|
|
825
|
+
requestId
|
|
1582
826
|
};
|
|
1583
827
|
}
|
|
1584
|
-
function
|
|
1585
|
-
const result = schema.safeParse(data);
|
|
1586
|
-
if (result.success) {
|
|
1587
|
-
return { success: true, data: result.data };
|
|
1588
|
-
}
|
|
1589
|
-
const err = result.error;
|
|
1590
|
-
const issuesRaw = err && typeof err === "object" && "issues" in err ? err.issues : void 0;
|
|
1591
|
-
if (Array.isArray(issuesRaw)) {
|
|
1592
|
-
return {
|
|
1593
|
-
success: false,
|
|
1594
|
-
issues: issuesRaw.map((i) => {
|
|
1595
|
-
const ii = i && typeof i === "object" ? i : {};
|
|
1596
|
-
return {
|
|
1597
|
-
path: Array.isArray(ii.path) ? ii.path.filter((p) => typeof p === "string" || typeof p === "number").join(".") : void 0,
|
|
1598
|
-
message: typeof ii.message === "string" && ii.message.trim() ? ii.message : "validation failed"
|
|
1599
|
-
};
|
|
1600
|
-
})
|
|
1601
|
-
};
|
|
1602
|
-
}
|
|
1603
|
-
const message = err && typeof err === "object" && "message" in err ? String(err.message) : "validation failed";
|
|
1604
|
-
return { success: false, issues: [{ message }] };
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
// src/responses_request.ts
|
|
1608
|
-
var RESPONSES_PATH = "/responses";
|
|
1609
|
-
var CUSTOMER_ID_HEADER = "X-ModelRelay-Customer-Id";
|
|
1610
|
-
var REQUEST_ID_HEADER = "X-ModelRelay-Request-Id";
|
|
1611
|
-
function makeResponsesRequest(body, options) {
|
|
1612
|
-
return { body, options };
|
|
1613
|
-
}
|
|
1614
|
-
function asInternal(req) {
|
|
1615
|
-
return req;
|
|
1616
|
-
}
|
|
1617
|
-
function mergeOptions(base, override) {
|
|
828
|
+
function assistantItem(content) {
|
|
1618
829
|
return {
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
...base.headers || {},
|
|
1623
|
-
...override.headers || {}
|
|
1624
|
-
}
|
|
830
|
+
type: "message",
|
|
831
|
+
role: "assistant",
|
|
832
|
+
content: [{ type: "text", text: content }]
|
|
1625
833
|
};
|
|
1626
834
|
}
|
|
1627
|
-
function
|
|
1628
|
-
|
|
835
|
+
function extractAssistantText(output) {
|
|
836
|
+
const parts = [];
|
|
837
|
+
for (const item of output || []) {
|
|
838
|
+
if (item.type !== "message") continue;
|
|
839
|
+
if (item.role !== "assistant") continue;
|
|
840
|
+
if (Array.isArray(item.content)) {
|
|
841
|
+
parts.push(...item.content);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
const text = parts.filter((p) => p.type === "text").map((p) => p.type === "text" ? p.text : "").join("");
|
|
845
|
+
if (!text.trim()) {
|
|
846
|
+
throw new TransportError("response contained no assistant text output", {
|
|
847
|
+
kind: "empty_response"
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
return text;
|
|
1629
851
|
}
|
|
1630
852
|
|
|
1631
|
-
// src/
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
patch.options ? { ...this.options, ...patch.options } : this.options
|
|
853
|
+
// src/responses_ndjson.ts
|
|
854
|
+
function mapNDJSONResponseEvent(line, requestId) {
|
|
855
|
+
let parsed;
|
|
856
|
+
try {
|
|
857
|
+
parsed = JSON.parse(line);
|
|
858
|
+
} catch (err) {
|
|
859
|
+
throw new TransportError(
|
|
860
|
+
`Failed to parse NDJSON line: ${err instanceof Error ? err.message : String(err)}`,
|
|
861
|
+
{ kind: "request", cause: err }
|
|
1641
862
|
);
|
|
1642
863
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
model(model) {
|
|
1649
|
-
return this.with({ body: { model } });
|
|
1650
|
-
}
|
|
1651
|
-
/** @returns A new builder with the full input array replaced. */
|
|
1652
|
-
input(items) {
|
|
1653
|
-
return this.with({ body: { input: items.slice() } });
|
|
1654
|
-
}
|
|
1655
|
-
/** @returns A new builder with the input item appended. */
|
|
1656
|
-
item(item) {
|
|
1657
|
-
const input = [...this.body.input ?? [], item];
|
|
1658
|
-
return this.with({ body: { input } });
|
|
1659
|
-
}
|
|
1660
|
-
/** @returns A new builder with a message input item appended. */
|
|
1661
|
-
message(role, content) {
|
|
1662
|
-
return this.item({
|
|
1663
|
-
type: "message",
|
|
1664
|
-
role,
|
|
1665
|
-
content: [{ type: "text", text: content }]
|
|
1666
|
-
});
|
|
1667
|
-
}
|
|
1668
|
-
/** @returns A new builder with a system message appended. */
|
|
1669
|
-
system(content) {
|
|
1670
|
-
return this.message("system", content);
|
|
1671
|
-
}
|
|
1672
|
-
/** @returns A new builder with a user message appended. */
|
|
1673
|
-
user(content) {
|
|
1674
|
-
return this.message("user", content);
|
|
1675
|
-
}
|
|
1676
|
-
/** @returns A new builder with an assistant message appended. */
|
|
1677
|
-
assistant(content) {
|
|
1678
|
-
return this.message("assistant", content);
|
|
1679
|
-
}
|
|
1680
|
-
/** @returns A new builder with a tool result message appended. */
|
|
1681
|
-
toolResultText(toolCallId, content) {
|
|
1682
|
-
return this.item({
|
|
1683
|
-
type: "message",
|
|
1684
|
-
role: "tool",
|
|
1685
|
-
toolCallId: toolCallId.trim(),
|
|
1686
|
-
content: [{ type: "text", text: content }]
|
|
1687
|
-
});
|
|
1688
|
-
}
|
|
1689
|
-
/** @returns A new builder with the output format set. */
|
|
1690
|
-
outputFormat(format) {
|
|
1691
|
-
return this.with({ body: { output_format: format } });
|
|
1692
|
-
}
|
|
1693
|
-
/** @returns A new builder with max output tokens set. */
|
|
1694
|
-
maxOutputTokens(max) {
|
|
1695
|
-
return this.with({ body: { max_output_tokens: max } });
|
|
1696
|
-
}
|
|
1697
|
-
/** @returns A new builder with temperature set. */
|
|
1698
|
-
temperature(temp) {
|
|
1699
|
-
return this.with({ body: { temperature: temp } });
|
|
1700
|
-
}
|
|
1701
|
-
/** @returns A new builder with stop sequences set. */
|
|
1702
|
-
stop(...stop) {
|
|
1703
|
-
const clean = stop.map((s) => s.trim()).filter(Boolean);
|
|
1704
|
-
return this.with({ body: { stop: clean.length ? clean : void 0 } });
|
|
1705
|
-
}
|
|
1706
|
-
/** @returns A new builder with tools replaced. */
|
|
1707
|
-
tools(tools) {
|
|
1708
|
-
return this.with({ body: { tools: tools.slice() } });
|
|
1709
|
-
}
|
|
1710
|
-
/** @returns A new builder with a tool appended. */
|
|
1711
|
-
tool(tool) {
|
|
1712
|
-
const tools = [...this.body.tools ?? [], tool];
|
|
1713
|
-
return this.with({ body: { tools } });
|
|
1714
|
-
}
|
|
1715
|
-
/** @returns A new builder with tool choice set. */
|
|
1716
|
-
toolChoice(choice) {
|
|
1717
|
-
return this.with({ body: { tool_choice: choice } });
|
|
1718
|
-
}
|
|
1719
|
-
/** @returns A new builder with tool choice set to auto. */
|
|
1720
|
-
toolChoiceAuto() {
|
|
1721
|
-
return this.toolChoice({ type: "auto" });
|
|
1722
|
-
}
|
|
1723
|
-
/** @returns A new builder with tool choice set to required. */
|
|
1724
|
-
toolChoiceRequired(functionName) {
|
|
1725
|
-
return this.toolChoice({ type: "required", function: functionName });
|
|
1726
|
-
}
|
|
1727
|
-
/** @returns A new builder with tool choice set to none. */
|
|
1728
|
-
toolChoiceNone() {
|
|
1729
|
-
return this.toolChoice({ type: "none" });
|
|
1730
|
-
}
|
|
1731
|
-
/** @returns A new builder with the customer ID option set. */
|
|
1732
|
-
customerId(customerId) {
|
|
1733
|
-
return this.with({ options: { customerId: customerId.trim() } });
|
|
1734
|
-
}
|
|
1735
|
-
/** @returns A new builder with the request ID option set. */
|
|
1736
|
-
requestId(requestId) {
|
|
1737
|
-
return this.with({ options: { requestId: requestId.trim() } });
|
|
1738
|
-
}
|
|
1739
|
-
/** @returns A new builder with a single header set/overridden. */
|
|
1740
|
-
header(key, value) {
|
|
1741
|
-
const headers = { ...this.options.headers || {}, [key]: value };
|
|
1742
|
-
return this.with({ options: { headers } });
|
|
1743
|
-
}
|
|
1744
|
-
/** @returns A new builder with headers merged. */
|
|
1745
|
-
headers(headers) {
|
|
1746
|
-
const merged = { ...this.options.headers || {}, ...headers };
|
|
1747
|
-
return this.with({ options: { headers: merged } });
|
|
1748
|
-
}
|
|
1749
|
-
/** @returns A new builder with the request timeout option set. */
|
|
1750
|
-
timeoutMs(timeoutMs) {
|
|
1751
|
-
return this.with({ options: { timeoutMs: Math.max(0, timeoutMs) } });
|
|
1752
|
-
}
|
|
1753
|
-
/** @returns A new builder with the connect timeout option set. */
|
|
1754
|
-
connectTimeoutMs(connectTimeoutMs) {
|
|
1755
|
-
return this.with({
|
|
1756
|
-
options: { connectTimeoutMs: Math.max(0, connectTimeoutMs) }
|
|
1757
|
-
});
|
|
1758
|
-
}
|
|
1759
|
-
/** @returns A new builder with retry configuration set. */
|
|
1760
|
-
retry(cfg) {
|
|
1761
|
-
return this.with({ options: { retry: cfg } });
|
|
1762
|
-
}
|
|
1763
|
-
/** @returns A new builder with retries disabled. */
|
|
1764
|
-
disableRetry() {
|
|
1765
|
-
return this.with({ options: { retry: false } });
|
|
1766
|
-
}
|
|
1767
|
-
/** @returns A new builder with metrics callbacks set. */
|
|
1768
|
-
metrics(metrics) {
|
|
1769
|
-
return this.with({ options: { metrics } });
|
|
1770
|
-
}
|
|
1771
|
-
/** @returns A new builder with trace callbacks set. */
|
|
1772
|
-
trace(trace) {
|
|
1773
|
-
return this.with({ options: { trace } });
|
|
1774
|
-
}
|
|
1775
|
-
/** @returns A new builder with stream time-to-first-token timeout set. */
|
|
1776
|
-
streamTTFTTimeoutMs(timeoutMs) {
|
|
1777
|
-
return this.with({
|
|
1778
|
-
options: { streamTTFTTimeoutMs: Math.max(0, timeoutMs) }
|
|
1779
|
-
});
|
|
1780
|
-
}
|
|
1781
|
-
/** @returns A new builder with stream idle timeout set. */
|
|
1782
|
-
streamIdleTimeoutMs(timeoutMs) {
|
|
1783
|
-
return this.with({
|
|
1784
|
-
options: { streamIdleTimeoutMs: Math.max(0, timeoutMs) }
|
|
1785
|
-
});
|
|
1786
|
-
}
|
|
1787
|
-
/** @returns A new builder with total stream timeout set. */
|
|
1788
|
-
streamTotalTimeoutMs(timeoutMs) {
|
|
1789
|
-
return this.with({
|
|
1790
|
-
options: { streamTotalTimeoutMs: Math.max(0, timeoutMs) }
|
|
1791
|
-
});
|
|
1792
|
-
}
|
|
1793
|
-
/** @returns A new builder with the abort signal set. */
|
|
1794
|
-
signal(signal) {
|
|
1795
|
-
return this.with({ options: { signal } });
|
|
1796
|
-
}
|
|
1797
|
-
/** @returns A finalized, immutable request payload. */
|
|
1798
|
-
build() {
|
|
1799
|
-
const input = (this.body.input ?? []).slice();
|
|
1800
|
-
if (input.length === 0) {
|
|
1801
|
-
throw new ConfigError("at least one input item is required");
|
|
1802
|
-
}
|
|
1803
|
-
const body = {
|
|
1804
|
-
provider: this.body.provider,
|
|
1805
|
-
model: this.body.model,
|
|
1806
|
-
input,
|
|
1807
|
-
output_format: this.body.output_format,
|
|
1808
|
-
max_output_tokens: this.body.max_output_tokens,
|
|
1809
|
-
temperature: this.body.temperature,
|
|
1810
|
-
stop: this.body.stop,
|
|
1811
|
-
tools: this.body.tools,
|
|
1812
|
-
tool_choice: this.body.tool_choice
|
|
1813
|
-
};
|
|
1814
|
-
return makeResponsesRequest(body, { ...this.options || {} });
|
|
1815
|
-
}
|
|
1816
|
-
};
|
|
1817
|
-
|
|
1818
|
-
// src/responses_normalize.ts
|
|
1819
|
-
function isRecord(value) {
|
|
1820
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1821
|
-
}
|
|
1822
|
-
function normalizeUsage(value) {
|
|
1823
|
-
if (!isRecord(value)) {
|
|
1824
|
-
return void 0;
|
|
1825
|
-
}
|
|
1826
|
-
const input = Number(value.input_tokens ?? 0);
|
|
1827
|
-
const output = Number(value.output_tokens ?? 0);
|
|
1828
|
-
const total = value.total_tokens === void 0 || value.total_tokens === null ? void 0 : Number(value.total_tokens);
|
|
1829
|
-
return createUsage(
|
|
1830
|
-
input,
|
|
1831
|
-
output,
|
|
1832
|
-
Number.isFinite(total) ? total : void 0
|
|
1833
|
-
);
|
|
1834
|
-
}
|
|
1835
|
-
function normalizeCitations(value) {
|
|
1836
|
-
if (!Array.isArray(value) || value.length === 0) return void 0;
|
|
1837
|
-
const citations = [];
|
|
1838
|
-
for (const item of value) {
|
|
1839
|
-
if (!isRecord(item)) continue;
|
|
1840
|
-
const url = item.url;
|
|
1841
|
-
const title = item.title;
|
|
1842
|
-
citations.push({
|
|
1843
|
-
...typeof url === "string" && url.trim() ? { url } : {},
|
|
1844
|
-
...typeof title === "string" && title.trim() ? { title } : {}
|
|
1845
|
-
});
|
|
1846
|
-
}
|
|
1847
|
-
return citations.length ? citations : void 0;
|
|
1848
|
-
}
|
|
1849
|
-
function normalizeResponsesResponse(payload, requestId) {
|
|
1850
|
-
if (!isRecord(payload)) {
|
|
1851
|
-
throw new APIError("invalid response payload", { status: 200, data: payload });
|
|
1852
|
-
}
|
|
1853
|
-
const output = Array.isArray(payload.output) ? payload.output : [];
|
|
1854
|
-
const usage = normalizeUsage(payload.usage);
|
|
1855
|
-
if (!usage) {
|
|
1856
|
-
throw new APIError("missing usage in response", { status: 200, data: payload });
|
|
1857
|
-
}
|
|
1858
|
-
const model = normalizeModelId(payload.model);
|
|
1859
|
-
if (!model) {
|
|
1860
|
-
throw new APIError("missing model in response", { status: 200, data: payload });
|
|
1861
|
-
}
|
|
1862
|
-
return {
|
|
1863
|
-
id: typeof payload.id === "string" ? payload.id : String(payload.id || ""),
|
|
1864
|
-
output,
|
|
1865
|
-
stopReason: normalizeStopReason(payload.stop_reason),
|
|
1866
|
-
model,
|
|
1867
|
-
usage,
|
|
1868
|
-
provider: typeof payload.provider === "string" ? asProviderId(payload.provider) : void 0,
|
|
1869
|
-
citations: normalizeCitations(payload.citations),
|
|
1870
|
-
requestId
|
|
1871
|
-
};
|
|
1872
|
-
}
|
|
1873
|
-
function assistantItem(content) {
|
|
1874
|
-
return {
|
|
1875
|
-
type: "message",
|
|
1876
|
-
role: "assistant",
|
|
1877
|
-
content: [{ type: "text", text: content }]
|
|
1878
|
-
};
|
|
1879
|
-
}
|
|
1880
|
-
function extractAssistantText(output) {
|
|
1881
|
-
const parts = [];
|
|
1882
|
-
for (const item of output || []) {
|
|
1883
|
-
if (item.type !== "message") continue;
|
|
1884
|
-
if (item.role !== "assistant") continue;
|
|
1885
|
-
if (Array.isArray(item.content)) {
|
|
1886
|
-
parts.push(...item.content);
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
|
-
const text = parts.filter((p) => p.type === "text").map((p) => p.type === "text" ? p.text : "").join("");
|
|
1890
|
-
if (!text.trim()) {
|
|
1891
|
-
throw new TransportError("response contained no assistant text output", {
|
|
1892
|
-
kind: "empty_response"
|
|
1893
|
-
});
|
|
1894
|
-
}
|
|
1895
|
-
return text;
|
|
1896
|
-
}
|
|
1897
|
-
|
|
1898
|
-
// src/responses_ndjson.ts
|
|
1899
|
-
function mapNDJSONResponseEvent(line, requestId) {
|
|
1900
|
-
let parsed;
|
|
1901
|
-
try {
|
|
1902
|
-
parsed = JSON.parse(line);
|
|
1903
|
-
} catch (err) {
|
|
1904
|
-
throw new TransportError(
|
|
1905
|
-
`Failed to parse NDJSON line: ${err instanceof Error ? err.message : String(err)}`,
|
|
1906
|
-
{ kind: "request", cause: err }
|
|
1907
|
-
);
|
|
1908
|
-
}
|
|
1909
|
-
if (!parsed || typeof parsed !== "object") {
|
|
1910
|
-
throw new TransportError(
|
|
1911
|
-
`NDJSON record is not an object: ${JSON.stringify(parsed)}`,
|
|
1912
|
-
{ kind: "request" }
|
|
1913
|
-
);
|
|
864
|
+
if (!parsed || typeof parsed !== "object") {
|
|
865
|
+
throw new TransportError(
|
|
866
|
+
`NDJSON record is not an object: ${JSON.stringify(parsed)}`,
|
|
867
|
+
{ kind: "request" }
|
|
868
|
+
);
|
|
1914
869
|
}
|
|
1915
870
|
if (!isRecord(parsed)) {
|
|
1916
871
|
throw new TransportError(
|
|
@@ -3550,10 +2505,10 @@ var RunsClient = class {
|
|
|
3550
2505
|
const metrics = mergeMetrics(this.metrics, options.metrics);
|
|
3551
2506
|
const trace = mergeTrace(this.trace, options.trace);
|
|
3552
2507
|
const authHeaders = await this.auth.authForResponses();
|
|
3553
|
-
const
|
|
2508
|
+
const path = runByIdPath(runId);
|
|
3554
2509
|
const headers = { ...options.headers || {} };
|
|
3555
2510
|
this.applyCustomerHeader(headers, options.customerId);
|
|
3556
|
-
const out = await this.http.json(
|
|
2511
|
+
const out = await this.http.json(path, {
|
|
3557
2512
|
method: "GET",
|
|
3558
2513
|
headers,
|
|
3559
2514
|
signal: options.signal,
|
|
@@ -3564,7 +2519,7 @@ var RunsClient = class {
|
|
|
3564
2519
|
retry: options.retry,
|
|
3565
2520
|
metrics,
|
|
3566
2521
|
trace,
|
|
3567
|
-
context: { method: "GET", path
|
|
2522
|
+
context: { method: "GET", path }
|
|
3568
2523
|
});
|
|
3569
2524
|
return {
|
|
3570
2525
|
...out,
|
|
@@ -3588,10 +2543,10 @@ var RunsClient = class {
|
|
|
3588
2543
|
if (options.wait === false) {
|
|
3589
2544
|
params.set("wait", "0");
|
|
3590
2545
|
}
|
|
3591
|
-
const
|
|
2546
|
+
const path = params.toString() ? `${basePath}?${params}` : basePath;
|
|
3592
2547
|
const headers = { ...options.headers || {} };
|
|
3593
2548
|
this.applyCustomerHeader(headers, options.customerId);
|
|
3594
|
-
const resp = await this.http.request(
|
|
2549
|
+
const resp = await this.http.request(path, {
|
|
3595
2550
|
method: "GET",
|
|
3596
2551
|
headers,
|
|
3597
2552
|
signal: options.signal,
|
|
@@ -3642,10 +2597,10 @@ var RunsClient = class {
|
|
|
3642
2597
|
const metrics = mergeMetrics(this.metrics, options.metrics);
|
|
3643
2598
|
const trace = mergeTrace(this.trace, options.trace);
|
|
3644
2599
|
const authHeaders = await this.auth.authForResponses();
|
|
3645
|
-
const
|
|
2600
|
+
const path = runToolResultsPath(runId);
|
|
3646
2601
|
const headers = { ...options.headers || {} };
|
|
3647
2602
|
this.applyCustomerHeader(headers, options.customerId);
|
|
3648
|
-
const out = await this.http.json(
|
|
2603
|
+
const out = await this.http.json(path, {
|
|
3649
2604
|
method: "POST",
|
|
3650
2605
|
headers,
|
|
3651
2606
|
body: req,
|
|
@@ -3657,7 +2612,7 @@ var RunsClient = class {
|
|
|
3657
2612
|
retry: options.retry,
|
|
3658
2613
|
metrics,
|
|
3659
2614
|
trace,
|
|
3660
|
-
context: { method: "POST", path
|
|
2615
|
+
context: { method: "POST", path }
|
|
3661
2616
|
});
|
|
3662
2617
|
return out;
|
|
3663
2618
|
}
|
|
@@ -3665,10 +2620,10 @@ var RunsClient = class {
|
|
|
3665
2620
|
const metrics = mergeMetrics(this.metrics, options.metrics);
|
|
3666
2621
|
const trace = mergeTrace(this.trace, options.trace);
|
|
3667
2622
|
const authHeaders = await this.auth.authForResponses();
|
|
3668
|
-
const
|
|
2623
|
+
const path = runPendingToolsPath(runId);
|
|
3669
2624
|
const headers = { ...options.headers || {} };
|
|
3670
2625
|
this.applyCustomerHeader(headers, options.customerId);
|
|
3671
|
-
const out = await this.http.json(
|
|
2626
|
+
const out = await this.http.json(path, {
|
|
3672
2627
|
method: "GET",
|
|
3673
2628
|
headers,
|
|
3674
2629
|
signal: options.signal,
|
|
@@ -3679,7 +2634,7 @@ var RunsClient = class {
|
|
|
3679
2634
|
retry: options.retry,
|
|
3680
2635
|
metrics,
|
|
3681
2636
|
trace,
|
|
3682
|
-
context: { method: "GET", path
|
|
2637
|
+
context: { method: "GET", path }
|
|
3683
2638
|
});
|
|
3684
2639
|
return {
|
|
3685
2640
|
...out,
|
|
@@ -4182,8 +3137,8 @@ var ModelsClient = class {
|
|
|
4182
3137
|
if (params.capability) {
|
|
4183
3138
|
qs.set("capability", params.capability);
|
|
4184
3139
|
}
|
|
4185
|
-
const
|
|
4186
|
-
const resp = await this.http.json(
|
|
3140
|
+
const path = qs.toString() ? `/models?${qs.toString()}` : "/models";
|
|
3141
|
+
const resp = await this.http.json(path, { method: "GET" });
|
|
4187
3142
|
return resp.models;
|
|
4188
3143
|
}
|
|
4189
3144
|
};
|
|
@@ -5650,7 +4605,7 @@ var HTTPClient = class {
|
|
|
5650
4605
|
this.metrics = cfg.metrics;
|
|
5651
4606
|
this.trace = cfg.trace;
|
|
5652
4607
|
}
|
|
5653
|
-
async request(
|
|
4608
|
+
async request(path, options = {}) {
|
|
5654
4609
|
const fetchFn = this.fetchImpl ?? globalThis.fetch;
|
|
5655
4610
|
if (!fetchFn) {
|
|
5656
4611
|
throw new ConfigError(
|
|
@@ -5658,12 +4613,12 @@ var HTTPClient = class {
|
|
|
5658
4613
|
);
|
|
5659
4614
|
}
|
|
5660
4615
|
const method = options.method || "GET";
|
|
5661
|
-
const url = buildUrl(this.baseUrl,
|
|
4616
|
+
const url = buildUrl(this.baseUrl, path);
|
|
5662
4617
|
const metrics = mergeMetrics(this.metrics, options.metrics);
|
|
5663
4618
|
const trace = mergeTrace(this.trace, options.trace);
|
|
5664
4619
|
const context = {
|
|
5665
4620
|
method,
|
|
5666
|
-
path
|
|
4621
|
+
path,
|
|
5667
4622
|
...options.context || {}
|
|
5668
4623
|
};
|
|
5669
4624
|
trace?.requestStart?.(context);
|
|
@@ -5804,8 +4759,8 @@ var HTTPClient = class {
|
|
|
5804
4759
|
retries: buildRetryMetadata(attempts, lastStatus)
|
|
5805
4760
|
});
|
|
5806
4761
|
}
|
|
5807
|
-
async json(
|
|
5808
|
-
const response = await this.request(
|
|
4762
|
+
async json(path, options = {}) {
|
|
4763
|
+
const response = await this.request(path, {
|
|
5809
4764
|
...options,
|
|
5810
4765
|
raw: true,
|
|
5811
4766
|
accept: options.accept || "application/json"
|
|
@@ -5826,14 +4781,14 @@ var HTTPClient = class {
|
|
|
5826
4781
|
}
|
|
5827
4782
|
}
|
|
5828
4783
|
};
|
|
5829
|
-
function buildUrl(baseUrl,
|
|
5830
|
-
if (/^https?:\/\//i.test(
|
|
5831
|
-
return
|
|
4784
|
+
function buildUrl(baseUrl, path) {
|
|
4785
|
+
if (/^https?:\/\//i.test(path)) {
|
|
4786
|
+
return path;
|
|
5832
4787
|
}
|
|
5833
|
-
if (!
|
|
5834
|
-
|
|
4788
|
+
if (!path.startsWith("/")) {
|
|
4789
|
+
path = `/${path}`;
|
|
5835
4790
|
}
|
|
5836
|
-
return `${baseUrl}${
|
|
4791
|
+
return `${baseUrl}${path}`;
|
|
5837
4792
|
}
|
|
5838
4793
|
function normalizeBaseUrl(value) {
|
|
5839
4794
|
const trimmed = value.trim();
|
|
@@ -5876,7 +4831,7 @@ function backoff(attempt, cfg) {
|
|
|
5876
4831
|
const jitter = 0.5 + Math.random();
|
|
5877
4832
|
const delay = Math.min(cfg.maxBackoffMs, capped * jitter);
|
|
5878
4833
|
if (delay <= 0) return Promise.resolve();
|
|
5879
|
-
return new Promise((
|
|
4834
|
+
return new Promise((resolve) => setTimeout(resolve, delay));
|
|
5880
4835
|
}
|
|
5881
4836
|
function mergeSignals(...signals) {
|
|
5882
4837
|
const active = signals.filter(Boolean);
|
|
@@ -6322,13 +5277,13 @@ async function sleep(ms, signal) {
|
|
|
6322
5277
|
return;
|
|
6323
5278
|
}
|
|
6324
5279
|
if (!signal) {
|
|
6325
|
-
await new Promise((
|
|
5280
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
6326
5281
|
return;
|
|
6327
5282
|
}
|
|
6328
5283
|
if (signal.aborted) {
|
|
6329
5284
|
throw new TransportError("oauth device flow aborted", { kind: "request" });
|
|
6330
5285
|
}
|
|
6331
|
-
await new Promise((
|
|
5286
|
+
await new Promise((resolve, reject) => {
|
|
6332
5287
|
const onAbort = () => {
|
|
6333
5288
|
signal.removeEventListener("abort", onAbort);
|
|
6334
5289
|
reject(new TransportError("oauth device flow aborted", { kind: "request" }));
|
|
@@ -6336,15 +5291,15 @@ async function sleep(ms, signal) {
|
|
|
6336
5291
|
signal.addEventListener("abort", onAbort);
|
|
6337
5292
|
setTimeout(() => {
|
|
6338
5293
|
signal.removeEventListener("abort", onAbort);
|
|
6339
|
-
|
|
5294
|
+
resolve();
|
|
6340
5295
|
}, ms);
|
|
6341
5296
|
});
|
|
6342
5297
|
}
|
|
6343
5298
|
|
|
6344
5299
|
// src/json_path.ts
|
|
6345
5300
|
var LLMOutputPath = class {
|
|
6346
|
-
constructor(
|
|
6347
|
-
this.path =
|
|
5301
|
+
constructor(path = "/output") {
|
|
5302
|
+
this.path = path;
|
|
6348
5303
|
}
|
|
6349
5304
|
/** Select an output by index */
|
|
6350
5305
|
index(i) {
|
|
@@ -6356,8 +5311,8 @@ var LLMOutputPath = class {
|
|
|
6356
5311
|
}
|
|
6357
5312
|
};
|
|
6358
5313
|
var LLMOutputContentPath = class {
|
|
6359
|
-
constructor(
|
|
6360
|
-
this.path =
|
|
5314
|
+
constructor(path) {
|
|
5315
|
+
this.path = path;
|
|
6361
5316
|
}
|
|
6362
5317
|
/** Select a content item by index */
|
|
6363
5318
|
content(i) {
|
|
@@ -6365,8 +5320,8 @@ var LLMOutputContentPath = class {
|
|
|
6365
5320
|
}
|
|
6366
5321
|
};
|
|
6367
5322
|
var LLMOutputContentItemPath = class {
|
|
6368
|
-
constructor(
|
|
6369
|
-
this.path =
|
|
5323
|
+
constructor(path) {
|
|
5324
|
+
this.path = path;
|
|
6370
5325
|
}
|
|
6371
5326
|
/** Get the text field pointer */
|
|
6372
5327
|
text() {
|
|
@@ -6382,8 +5337,8 @@ var LLMOutputContentItemPath = class {
|
|
|
6382
5337
|
}
|
|
6383
5338
|
};
|
|
6384
5339
|
var LLMInputPath = class {
|
|
6385
|
-
constructor(
|
|
6386
|
-
this.path =
|
|
5340
|
+
constructor(path = "/input") {
|
|
5341
|
+
this.path = path;
|
|
6387
5342
|
}
|
|
6388
5343
|
/**
|
|
6389
5344
|
* Select a message by index.
|
|
@@ -6402,8 +5357,8 @@ var LLMInputPath = class {
|
|
|
6402
5357
|
}
|
|
6403
5358
|
};
|
|
6404
5359
|
var LLMInputMessagePath = class {
|
|
6405
|
-
constructor(
|
|
6406
|
-
this.path =
|
|
5360
|
+
constructor(path) {
|
|
5361
|
+
this.path = path;
|
|
6407
5362
|
}
|
|
6408
5363
|
/** Select a content item by index */
|
|
6409
5364
|
content(i) {
|
|
@@ -6415,8 +5370,8 @@ var LLMInputMessagePath = class {
|
|
|
6415
5370
|
}
|
|
6416
5371
|
};
|
|
6417
5372
|
var LLMInputContentItemPath = class {
|
|
6418
|
-
constructor(
|
|
6419
|
-
this.path =
|
|
5373
|
+
constructor(path) {
|
|
5374
|
+
this.path = path;
|
|
6420
5375
|
}
|
|
6421
5376
|
/** Get the text field pointer */
|
|
6422
5377
|
text() {
|
|
@@ -6442,8 +5397,8 @@ var LLMInputSystemText = LLMInput().systemMessage().text();
|
|
|
6442
5397
|
var LLMInputUserText = LLMInput().userMessage().text();
|
|
6443
5398
|
var LLMInputFirstMessageText = LLMInput().message(0).text();
|
|
6444
5399
|
var JoinOutputPath = class {
|
|
6445
|
-
constructor(
|
|
6446
|
-
this.path =
|
|
5400
|
+
constructor(path) {
|
|
5401
|
+
this.path = path;
|
|
6447
5402
|
}
|
|
6448
5403
|
/** Access the output array of the node */
|
|
6449
5404
|
output() {
|
|
@@ -8490,173 +7445,16 @@ var ParallelBuilder = class _ParallelBuilder {
|
|
|
8490
7445
|
bindings: [
|
|
8491
7446
|
{
|
|
8492
7447
|
from: joinId,
|
|
8493
|
-
// Empty pointer = full join output
|
|
8494
|
-
to: LLM_USER_MESSAGE_TEXT_INTERNAL,
|
|
8495
|
-
encoding: "json_string"
|
|
8496
|
-
}
|
|
8497
|
-
]
|
|
8498
|
-
}
|
|
8499
|
-
};
|
|
8500
|
-
nodes.push(aggInput);
|
|
8501
|
-
edges.push({ from: joinId, to: this.state.aggregate.id });
|
|
8502
|
-
}
|
|
8503
|
-
return {
|
|
8504
|
-
kind: WorkflowKinds.WorkflowV0,
|
|
8505
|
-
name: this.state.name,
|
|
8506
|
-
...this.state.execution ? { execution: this.state.execution } : {},
|
|
8507
|
-
nodes,
|
|
8508
|
-
...edges.length > 0 ? { edges: sortEdges(edges) } : {},
|
|
8509
|
-
outputs: sortOutputs(this.state.outputs)
|
|
8510
|
-
};
|
|
8511
|
-
}
|
|
8512
|
-
};
|
|
8513
|
-
function Parallel(name, steps) {
|
|
8514
|
-
return ParallelBuilder.create(name, steps);
|
|
8515
|
-
}
|
|
8516
|
-
function MapItem(id, request) {
|
|
8517
|
-
const config = {
|
|
8518
|
-
id,
|
|
8519
|
-
request: wireRequest2(request),
|
|
8520
|
-
stream: false
|
|
8521
|
-
};
|
|
8522
|
-
return {
|
|
8523
|
-
...config,
|
|
8524
|
-
withStream() {
|
|
8525
|
-
return { ...config, stream: true };
|
|
8526
|
-
}
|
|
8527
|
-
};
|
|
8528
|
-
}
|
|
8529
|
-
var MapReduceBuilder = class _MapReduceBuilder {
|
|
8530
|
-
constructor(state) {
|
|
8531
|
-
this.state = state;
|
|
8532
|
-
}
|
|
8533
|
-
static create(name, items) {
|
|
8534
|
-
return new _MapReduceBuilder({ name, items, outputs: [] });
|
|
8535
|
-
}
|
|
8536
|
-
with(patch) {
|
|
8537
|
-
return new _MapReduceBuilder({ ...this.state, ...patch });
|
|
8538
|
-
}
|
|
8539
|
-
/**
|
|
8540
|
-
* Adds a mapper item to the workflow.
|
|
8541
|
-
* Each item becomes a separate LLM node that runs in parallel.
|
|
8542
|
-
*/
|
|
8543
|
-
item(id, request) {
|
|
8544
|
-
return this.with({
|
|
8545
|
-
items: [...this.state.items, { id, request: wireRequest2(request), stream: false }]
|
|
8546
|
-
});
|
|
8547
|
-
}
|
|
8548
|
-
/**
|
|
8549
|
-
* Adds a mapper item with streaming enabled.
|
|
8550
|
-
*/
|
|
8551
|
-
itemWithStream(id, request) {
|
|
8552
|
-
return this.with({
|
|
8553
|
-
items: [...this.state.items, { id, request: wireRequest2(request), stream: true }]
|
|
8554
|
-
});
|
|
8555
|
-
}
|
|
8556
|
-
/**
|
|
8557
|
-
* Sets the workflow execution configuration.
|
|
8558
|
-
*/
|
|
8559
|
-
execution(exec) {
|
|
8560
|
-
return this.with({ execution: exec });
|
|
8561
|
-
}
|
|
8562
|
-
/**
|
|
8563
|
-
* Adds a reducer node that receives all mapper outputs.
|
|
8564
|
-
* The reducer receives a JSON object mapping each mapper ID to its text output.
|
|
8565
|
-
* The join node ID is automatically generated as "<id>_join".
|
|
8566
|
-
*/
|
|
8567
|
-
reduce(id, request) {
|
|
8568
|
-
return this.with({
|
|
8569
|
-
reducer: {
|
|
8570
|
-
id,
|
|
8571
|
-
request: wireRequest2(request),
|
|
8572
|
-
stream: false
|
|
8573
|
-
}
|
|
8574
|
-
});
|
|
8575
|
-
}
|
|
8576
|
-
/**
|
|
8577
|
-
* Like reduce() but enables streaming on the reducer node.
|
|
8578
|
-
*/
|
|
8579
|
-
reduceWithStream(id, request) {
|
|
8580
|
-
return this.with({
|
|
8581
|
-
reducer: {
|
|
8582
|
-
id,
|
|
8583
|
-
request: wireRequest2(request),
|
|
8584
|
-
stream: true
|
|
8585
|
-
}
|
|
8586
|
-
});
|
|
8587
|
-
}
|
|
8588
|
-
/**
|
|
8589
|
-
* Adds an output reference from a specific node.
|
|
8590
|
-
* Typically used to output from the reducer node.
|
|
8591
|
-
*/
|
|
8592
|
-
output(name, from) {
|
|
8593
|
-
return this.with({
|
|
8594
|
-
outputs: [
|
|
8595
|
-
...this.state.outputs,
|
|
8596
|
-
{
|
|
8597
|
-
name,
|
|
8598
|
-
from,
|
|
8599
|
-
pointer: LLM_TEXT_OUTPUT_INTERNAL
|
|
8600
|
-
}
|
|
8601
|
-
]
|
|
8602
|
-
});
|
|
8603
|
-
}
|
|
8604
|
-
/**
|
|
8605
|
-
* Builds and returns the compiled workflow spec.
|
|
8606
|
-
* @throws Error if no items are provided or no reducer is configured
|
|
8607
|
-
*/
|
|
8608
|
-
build() {
|
|
8609
|
-
if (this.state.items.length === 0) {
|
|
8610
|
-
throw new Error("map-reduce requires at least one item");
|
|
8611
|
-
}
|
|
8612
|
-
if (!this.state.reducer) {
|
|
8613
|
-
throw new Error("map-reduce requires a reducer (call reduce)");
|
|
8614
|
-
}
|
|
8615
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
8616
|
-
for (const item of this.state.items) {
|
|
8617
|
-
if (!item.id) {
|
|
8618
|
-
throw new Error("item ID cannot be empty");
|
|
8619
|
-
}
|
|
8620
|
-
if (seenIds.has(item.id)) {
|
|
8621
|
-
throw new Error(`duplicate item ID: "${item.id}"`);
|
|
8622
|
-
}
|
|
8623
|
-
seenIds.add(item.id);
|
|
8624
|
-
}
|
|
8625
|
-
const nodes = [];
|
|
8626
|
-
const edges = [];
|
|
8627
|
-
const joinId = `${this.state.reducer.id}_join`;
|
|
8628
|
-
for (const item of this.state.items) {
|
|
8629
|
-
const mapperId = `map_${item.id}`;
|
|
8630
|
-
const input = {
|
|
8631
|
-
id: mapperId,
|
|
8632
|
-
type: WorkflowNodeTypes.LLMResponses,
|
|
8633
|
-
input: {
|
|
8634
|
-
request: item.request,
|
|
8635
|
-
...item.stream ? { stream: true } : {}
|
|
7448
|
+
// Empty pointer = full join output
|
|
7449
|
+
to: LLM_USER_MESSAGE_TEXT_INTERNAL,
|
|
7450
|
+
encoding: "json_string"
|
|
7451
|
+
}
|
|
7452
|
+
]
|
|
8636
7453
|
}
|
|
8637
7454
|
};
|
|
8638
|
-
nodes.push(
|
|
8639
|
-
edges.push({ from:
|
|
7455
|
+
nodes.push(aggInput);
|
|
7456
|
+
edges.push({ from: joinId, to: this.state.aggregate.id });
|
|
8640
7457
|
}
|
|
8641
|
-
nodes.push({ id: joinId, type: WorkflowNodeTypes.JoinAll });
|
|
8642
|
-
const reducerInput = {
|
|
8643
|
-
id: this.state.reducer.id,
|
|
8644
|
-
type: WorkflowNodeTypes.LLMResponses,
|
|
8645
|
-
input: {
|
|
8646
|
-
request: this.state.reducer.request,
|
|
8647
|
-
...this.state.reducer.stream ? { stream: true } : {},
|
|
8648
|
-
bindings: [
|
|
8649
|
-
{
|
|
8650
|
-
from: joinId,
|
|
8651
|
-
// Empty pointer = full join output
|
|
8652
|
-
to: LLM_USER_MESSAGE_TEXT_INTERNAL,
|
|
8653
|
-
encoding: "json_string"
|
|
8654
|
-
}
|
|
8655
|
-
]
|
|
8656
|
-
}
|
|
8657
|
-
};
|
|
8658
|
-
nodes.push(reducerInput);
|
|
8659
|
-
edges.push({ from: joinId, to: this.state.reducer.id });
|
|
8660
7458
|
return {
|
|
8661
7459
|
kind: WorkflowKinds.WorkflowV0,
|
|
8662
7460
|
name: this.state.name,
|
|
@@ -8667,672 +7465,231 @@ var MapReduceBuilder = class _MapReduceBuilder {
|
|
|
8667
7465
|
};
|
|
8668
7466
|
}
|
|
8669
7467
|
};
|
|
8670
|
-
function
|
|
8671
|
-
return
|
|
8672
|
-
}
|
|
8673
|
-
|
|
8674
|
-
// src/testing.ts
|
|
8675
|
-
function buildNDJSONResponse(lines, headers = {}, status = 200) {
|
|
8676
|
-
const encoder = new TextEncoder();
|
|
8677
|
-
const stream = new ReadableStream({
|
|
8678
|
-
start(controller) {
|
|
8679
|
-
for (const line of lines) {
|
|
8680
|
-
controller.enqueue(encoder.encode(`${line}
|
|
8681
|
-
`));
|
|
8682
|
-
}
|
|
8683
|
-
controller.close();
|
|
8684
|
-
}
|
|
8685
|
-
});
|
|
8686
|
-
return new Response(stream, {
|
|
8687
|
-
status,
|
|
8688
|
-
headers: {
|
|
8689
|
-
"Content-Type": "application/x-ndjson",
|
|
8690
|
-
...headers
|
|
8691
|
-
}
|
|
8692
|
-
});
|
|
8693
|
-
}
|
|
8694
|
-
function buildDelayedNDJSONResponse(steps, headers = {}, status = 200) {
|
|
8695
|
-
const encoder = new TextEncoder();
|
|
8696
|
-
const stream = new ReadableStream({
|
|
8697
|
-
start(controller) {
|
|
8698
|
-
let idx = 0;
|
|
8699
|
-
const pushNext = () => {
|
|
8700
|
-
if (idx >= steps.length) {
|
|
8701
|
-
controller.close();
|
|
8702
|
-
return;
|
|
8703
|
-
}
|
|
8704
|
-
const step = steps[idx++];
|
|
8705
|
-
setTimeout(() => {
|
|
8706
|
-
controller.enqueue(encoder.encode(`${step.line}
|
|
8707
|
-
`));
|
|
8708
|
-
pushNext();
|
|
8709
|
-
}, Math.max(0, step.delayMs));
|
|
8710
|
-
};
|
|
8711
|
-
pushNext();
|
|
8712
|
-
}
|
|
8713
|
-
});
|
|
8714
|
-
return new Response(stream, {
|
|
8715
|
-
status,
|
|
8716
|
-
headers: {
|
|
8717
|
-
"Content-Type": "application/x-ndjson",
|
|
8718
|
-
...headers
|
|
8719
|
-
}
|
|
8720
|
-
});
|
|
7468
|
+
function Parallel(name, steps) {
|
|
7469
|
+
return ParallelBuilder.create(name, steps);
|
|
8721
7470
|
}
|
|
8722
|
-
function
|
|
8723
|
-
const
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
|
|
8730
|
-
|
|
8731
|
-
|
|
8732
|
-
if (typeof responder === "function") {
|
|
8733
|
-
return responder(call, calls.length - 1);
|
|
7471
|
+
function MapItem(id, request) {
|
|
7472
|
+
const config = {
|
|
7473
|
+
id,
|
|
7474
|
+
request: wireRequest2(request),
|
|
7475
|
+
stream: false
|
|
7476
|
+
};
|
|
7477
|
+
return {
|
|
7478
|
+
...config,
|
|
7479
|
+
withStream() {
|
|
7480
|
+
return { ...config, stream: true };
|
|
8734
7481
|
}
|
|
8735
|
-
return responder;
|
|
8736
7482
|
};
|
|
8737
|
-
return { fetch: fetchImpl, calls };
|
|
8738
7483
|
}
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
import * as path from "path";
|
|
8743
|
-
import { spawn } from "child_process";
|
|
8744
|
-
var ToolNames = {
|
|
8745
|
-
FS_READ_FILE: "fs.read_file",
|
|
8746
|
-
FS_LIST_FILES: "fs.list_files",
|
|
8747
|
-
FS_SEARCH: "fs.search"
|
|
8748
|
-
};
|
|
8749
|
-
var FSDefaults = {
|
|
8750
|
-
MAX_READ_BYTES: 64e3,
|
|
8751
|
-
HARD_MAX_READ_BYTES: 1e6,
|
|
8752
|
-
MAX_LIST_ENTRIES: 2e3,
|
|
8753
|
-
HARD_MAX_LIST_ENTRIES: 2e4,
|
|
8754
|
-
MAX_SEARCH_MATCHES: 100,
|
|
8755
|
-
HARD_MAX_SEARCH_MATCHES: 2e3,
|
|
8756
|
-
SEARCH_TIMEOUT_MS: 5e3,
|
|
8757
|
-
MAX_SEARCH_BYTES_PER_FILE: 1e6
|
|
8758
|
-
};
|
|
8759
|
-
var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
8760
|
-
".git",
|
|
8761
|
-
"node_modules",
|
|
8762
|
-
"vendor",
|
|
8763
|
-
"dist",
|
|
8764
|
-
"build",
|
|
8765
|
-
".next",
|
|
8766
|
-
"target",
|
|
8767
|
-
".idea",
|
|
8768
|
-
".vscode",
|
|
8769
|
-
"__pycache__",
|
|
8770
|
-
".pytest_cache",
|
|
8771
|
-
"coverage"
|
|
8772
|
-
]);
|
|
8773
|
-
var LocalFSToolPack = class {
|
|
8774
|
-
constructor(options) {
|
|
8775
|
-
this.rgPath = null;
|
|
8776
|
-
this.rgChecked = false;
|
|
8777
|
-
const root = options.root?.trim();
|
|
8778
|
-
if (!root) {
|
|
8779
|
-
throw new Error("LocalFSToolPack: root directory required");
|
|
8780
|
-
}
|
|
8781
|
-
this.rootAbs = path.resolve(root);
|
|
8782
|
-
this.cfg = {
|
|
8783
|
-
ignoreDirs: options.ignoreDirs ?? new Set(DEFAULT_IGNORE_DIRS),
|
|
8784
|
-
maxReadBytes: options.maxReadBytes ?? FSDefaults.MAX_READ_BYTES,
|
|
8785
|
-
hardMaxReadBytes: options.hardMaxReadBytes ?? FSDefaults.HARD_MAX_READ_BYTES,
|
|
8786
|
-
maxListEntries: options.maxListEntries ?? FSDefaults.MAX_LIST_ENTRIES,
|
|
8787
|
-
hardMaxListEntries: options.hardMaxListEntries ?? FSDefaults.HARD_MAX_LIST_ENTRIES,
|
|
8788
|
-
maxSearchMatches: options.maxSearchMatches ?? FSDefaults.MAX_SEARCH_MATCHES,
|
|
8789
|
-
hardMaxSearchMatches: options.hardMaxSearchMatches ?? FSDefaults.HARD_MAX_SEARCH_MATCHES,
|
|
8790
|
-
searchTimeoutMs: options.searchTimeoutMs ?? FSDefaults.SEARCH_TIMEOUT_MS,
|
|
8791
|
-
maxSearchBytesPerFile: options.maxSearchBytesPerFile ?? FSDefaults.MAX_SEARCH_BYTES_PER_FILE
|
|
8792
|
-
};
|
|
7484
|
+
var MapReduceBuilder = class _MapReduceBuilder {
|
|
7485
|
+
constructor(state) {
|
|
7486
|
+
this.state = state;
|
|
8793
7487
|
}
|
|
8794
|
-
|
|
8795
|
-
|
|
8796
|
-
|
|
8797
|
-
|
|
8798
|
-
|
|
8799
|
-
return [
|
|
8800
|
-
{
|
|
8801
|
-
type: "function",
|
|
8802
|
-
function: {
|
|
8803
|
-
name: ToolNames.FS_READ_FILE,
|
|
8804
|
-
description: "Read the contents of a file. Returns the file contents as UTF-8 text.",
|
|
8805
|
-
parameters: {
|
|
8806
|
-
type: "object",
|
|
8807
|
-
properties: {
|
|
8808
|
-
path: {
|
|
8809
|
-
type: "string",
|
|
8810
|
-
description: "Workspace-relative path to the file (e.g., 'src/index.ts')"
|
|
8811
|
-
},
|
|
8812
|
-
max_bytes: {
|
|
8813
|
-
type: "integer",
|
|
8814
|
-
description: `Maximum bytes to read. Default: ${this.cfg.maxReadBytes}, max: ${this.cfg.hardMaxReadBytes}`
|
|
8815
|
-
}
|
|
8816
|
-
},
|
|
8817
|
-
required: ["path"]
|
|
8818
|
-
}
|
|
8819
|
-
}
|
|
8820
|
-
},
|
|
8821
|
-
{
|
|
8822
|
-
type: "function",
|
|
8823
|
-
function: {
|
|
8824
|
-
name: ToolNames.FS_LIST_FILES,
|
|
8825
|
-
description: "List files recursively in a directory. Returns newline-separated workspace-relative paths.",
|
|
8826
|
-
parameters: {
|
|
8827
|
-
type: "object",
|
|
8828
|
-
properties: {
|
|
8829
|
-
path: {
|
|
8830
|
-
type: "string",
|
|
8831
|
-
description: "Workspace-relative directory path. Default: '.' (workspace root)"
|
|
8832
|
-
},
|
|
8833
|
-
max_entries: {
|
|
8834
|
-
type: "integer",
|
|
8835
|
-
description: `Maximum files to list. Default: ${this.cfg.maxListEntries}, max: ${this.cfg.hardMaxListEntries}`
|
|
8836
|
-
}
|
|
8837
|
-
}
|
|
8838
|
-
}
|
|
8839
|
-
}
|
|
8840
|
-
},
|
|
8841
|
-
{
|
|
8842
|
-
type: "function",
|
|
8843
|
-
function: {
|
|
8844
|
-
name: ToolNames.FS_SEARCH,
|
|
8845
|
-
description: "Search for text matching a regex pattern. Returns matches as 'path:line:content' format.",
|
|
8846
|
-
parameters: {
|
|
8847
|
-
type: "object",
|
|
8848
|
-
properties: {
|
|
8849
|
-
query: {
|
|
8850
|
-
type: "string",
|
|
8851
|
-
description: "Regex pattern to search for"
|
|
8852
|
-
},
|
|
8853
|
-
path: {
|
|
8854
|
-
type: "string",
|
|
8855
|
-
description: "Workspace-relative directory to search. Default: '.' (workspace root)"
|
|
8856
|
-
},
|
|
8857
|
-
max_matches: {
|
|
8858
|
-
type: "integer",
|
|
8859
|
-
description: `Maximum matches to return. Default: ${this.cfg.maxSearchMatches}, max: ${this.cfg.hardMaxSearchMatches}`
|
|
8860
|
-
}
|
|
8861
|
-
},
|
|
8862
|
-
required: ["query"]
|
|
8863
|
-
}
|
|
8864
|
-
}
|
|
8865
|
-
}
|
|
8866
|
-
];
|
|
7488
|
+
static create(name, items) {
|
|
7489
|
+
return new _MapReduceBuilder({ name, items, outputs: [] });
|
|
7490
|
+
}
|
|
7491
|
+
with(patch) {
|
|
7492
|
+
return new _MapReduceBuilder({ ...this.state, ...patch });
|
|
8867
7493
|
}
|
|
8868
7494
|
/**
|
|
8869
|
-
*
|
|
8870
|
-
*
|
|
8871
|
-
* @returns The registry for chaining
|
|
7495
|
+
* Adds a mapper item to the workflow.
|
|
7496
|
+
* Each item becomes a separate LLM node that runs in parallel.
|
|
8872
7497
|
*/
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
return registry;
|
|
7498
|
+
item(id, request) {
|
|
7499
|
+
return this.with({
|
|
7500
|
+
items: [...this.state.items, { id, request: wireRequest2(request), stream: false }]
|
|
7501
|
+
});
|
|
8878
7502
|
}
|
|
8879
7503
|
/**
|
|
8880
|
-
*
|
|
7504
|
+
* Adds a mapper item with streaming enabled.
|
|
8881
7505
|
*/
|
|
8882
|
-
|
|
8883
|
-
return this.
|
|
8884
|
-
|
|
8885
|
-
// ========================================================================
|
|
8886
|
-
// Tool Handlers
|
|
8887
|
-
// ========================================================================
|
|
8888
|
-
async readFile(_args, call) {
|
|
8889
|
-
const args = this.parseArgs(call, ["path"]);
|
|
8890
|
-
const func = call.function;
|
|
8891
|
-
const relPath = this.requireString(args, "path", call);
|
|
8892
|
-
const requestedMax = this.optionalPositiveInt(args, "max_bytes", call);
|
|
8893
|
-
let maxBytes = this.cfg.maxReadBytes;
|
|
8894
|
-
if (requestedMax !== void 0) {
|
|
8895
|
-
if (requestedMax > this.cfg.hardMaxReadBytes) {
|
|
8896
|
-
throw new ToolArgumentError({
|
|
8897
|
-
message: `max_bytes exceeds hard cap (${this.cfg.hardMaxReadBytes})`,
|
|
8898
|
-
toolCallId: call.id,
|
|
8899
|
-
toolName: func.name,
|
|
8900
|
-
rawArguments: func.arguments
|
|
8901
|
-
});
|
|
8902
|
-
}
|
|
8903
|
-
maxBytes = requestedMax;
|
|
8904
|
-
}
|
|
8905
|
-
const absPath = await this.resolveAndValidatePath(relPath, call);
|
|
8906
|
-
const stat = await fs.stat(absPath);
|
|
8907
|
-
if (stat.isDirectory()) {
|
|
8908
|
-
throw new Error(`fs.read_file: path is a directory: ${relPath}`);
|
|
8909
|
-
}
|
|
8910
|
-
if (stat.size > maxBytes) {
|
|
8911
|
-
throw new Error(`fs.read_file: file exceeds max_bytes (${maxBytes})`);
|
|
8912
|
-
}
|
|
8913
|
-
const data = await fs.readFile(absPath);
|
|
8914
|
-
if (!this.isValidUtf8(data)) {
|
|
8915
|
-
throw new Error(`fs.read_file: file is not valid UTF-8: ${relPath}`);
|
|
8916
|
-
}
|
|
8917
|
-
return data.toString("utf-8");
|
|
8918
|
-
}
|
|
8919
|
-
async listFiles(_args, call) {
|
|
8920
|
-
const args = this.parseArgs(call, []);
|
|
8921
|
-
const func = call.function;
|
|
8922
|
-
const startPath = this.optionalString(args, "path", call)?.trim() || ".";
|
|
8923
|
-
let maxEntries = this.cfg.maxListEntries;
|
|
8924
|
-
const requestedMax = this.optionalPositiveInt(args, "max_entries", call);
|
|
8925
|
-
if (requestedMax !== void 0) {
|
|
8926
|
-
if (requestedMax > this.cfg.hardMaxListEntries) {
|
|
8927
|
-
throw new ToolArgumentError({
|
|
8928
|
-
message: `max_entries exceeds hard cap (${this.cfg.hardMaxListEntries})`,
|
|
8929
|
-
toolCallId: call.id,
|
|
8930
|
-
toolName: func.name,
|
|
8931
|
-
rawArguments: func.arguments
|
|
8932
|
-
});
|
|
8933
|
-
}
|
|
8934
|
-
maxEntries = requestedMax;
|
|
8935
|
-
}
|
|
8936
|
-
const absPath = await this.resolveAndValidatePath(startPath, call);
|
|
8937
|
-
let rootReal;
|
|
8938
|
-
try {
|
|
8939
|
-
rootReal = await fs.realpath(this.rootAbs);
|
|
8940
|
-
} catch {
|
|
8941
|
-
rootReal = this.rootAbs;
|
|
8942
|
-
}
|
|
8943
|
-
const stat = await fs.stat(absPath);
|
|
8944
|
-
if (!stat.isDirectory()) {
|
|
8945
|
-
throw new Error(`fs.list_files: path is not a directory: ${startPath}`);
|
|
8946
|
-
}
|
|
8947
|
-
const files = [];
|
|
8948
|
-
await this.walkDir(absPath, async (filePath, dirent) => {
|
|
8949
|
-
if (files.length >= maxEntries) {
|
|
8950
|
-
return false;
|
|
8951
|
-
}
|
|
8952
|
-
if (dirent.isDirectory()) {
|
|
8953
|
-
if (this.cfg.ignoreDirs.has(dirent.name)) {
|
|
8954
|
-
return false;
|
|
8955
|
-
}
|
|
8956
|
-
return true;
|
|
8957
|
-
}
|
|
8958
|
-
if (dirent.isFile()) {
|
|
8959
|
-
const relPath = path.relative(rootReal, filePath);
|
|
8960
|
-
files.push(relPath.split(path.sep).join("/"));
|
|
8961
|
-
}
|
|
8962
|
-
return true;
|
|
7506
|
+
itemWithStream(id, request) {
|
|
7507
|
+
return this.with({
|
|
7508
|
+
items: [...this.state.items, { id, request: wireRequest2(request), stream: true }]
|
|
8963
7509
|
});
|
|
8964
|
-
return files.join("\n");
|
|
8965
|
-
}
|
|
8966
|
-
async search(_args, call) {
|
|
8967
|
-
const args = this.parseArgs(call, ["query"]);
|
|
8968
|
-
const func = call.function;
|
|
8969
|
-
const query = this.requireString(args, "query", call);
|
|
8970
|
-
const startPath = this.optionalString(args, "path", call)?.trim() || ".";
|
|
8971
|
-
let maxMatches = this.cfg.maxSearchMatches;
|
|
8972
|
-
const requestedMax = this.optionalPositiveInt(args, "max_matches", call);
|
|
8973
|
-
if (requestedMax !== void 0) {
|
|
8974
|
-
if (requestedMax > this.cfg.hardMaxSearchMatches) {
|
|
8975
|
-
throw new ToolArgumentError({
|
|
8976
|
-
message: `max_matches exceeds hard cap (${this.cfg.hardMaxSearchMatches})`,
|
|
8977
|
-
toolCallId: call.id,
|
|
8978
|
-
toolName: func.name,
|
|
8979
|
-
rawArguments: func.arguments
|
|
8980
|
-
});
|
|
8981
|
-
}
|
|
8982
|
-
maxMatches = requestedMax;
|
|
8983
|
-
}
|
|
8984
|
-
const absPath = await this.resolveAndValidatePath(startPath, call);
|
|
8985
|
-
const rgPath = await this.detectRipgrep();
|
|
8986
|
-
if (rgPath) {
|
|
8987
|
-
return this.searchWithRipgrep(
|
|
8988
|
-
rgPath,
|
|
8989
|
-
query,
|
|
8990
|
-
absPath,
|
|
8991
|
-
maxMatches
|
|
8992
|
-
);
|
|
8993
|
-
}
|
|
8994
|
-
return this.searchWithJS(query, absPath, maxMatches, call);
|
|
8995
7510
|
}
|
|
8996
|
-
// ========================================================================
|
|
8997
|
-
// Path Safety
|
|
8998
|
-
// ========================================================================
|
|
8999
7511
|
/**
|
|
9000
|
-
*
|
|
9001
|
-
* @throws {ToolArgumentError} if path is invalid
|
|
9002
|
-
* @throws {PathEscapeError} if resolved path escapes root
|
|
7512
|
+
* Sets the workflow execution configuration.
|
|
9003
7513
|
*/
|
|
9004
|
-
|
|
9005
|
-
|
|
9006
|
-
const cleanRel = relPath.trim();
|
|
9007
|
-
if (!cleanRel) {
|
|
9008
|
-
throw new ToolArgumentError({
|
|
9009
|
-
message: "path cannot be empty",
|
|
9010
|
-
toolCallId: call.id,
|
|
9011
|
-
toolName: func.name,
|
|
9012
|
-
rawArguments: func.arguments
|
|
9013
|
-
});
|
|
9014
|
-
}
|
|
9015
|
-
if (path.isAbsolute(cleanRel)) {
|
|
9016
|
-
throw new ToolArgumentError({
|
|
9017
|
-
message: "path must be workspace-relative (not absolute)",
|
|
9018
|
-
toolCallId: call.id,
|
|
9019
|
-
toolName: func.name,
|
|
9020
|
-
rawArguments: func.arguments
|
|
9021
|
-
});
|
|
9022
|
-
}
|
|
9023
|
-
const normalized = path.normalize(cleanRel);
|
|
9024
|
-
if (normalized.startsWith("..") || normalized.startsWith(`.${path.sep}..`)) {
|
|
9025
|
-
throw new ToolArgumentError({
|
|
9026
|
-
message: "path must not escape the workspace root",
|
|
9027
|
-
toolCallId: call.id,
|
|
9028
|
-
toolName: func.name,
|
|
9029
|
-
rawArguments: func.arguments
|
|
9030
|
-
});
|
|
9031
|
-
}
|
|
9032
|
-
const target = path.join(this.rootAbs, normalized);
|
|
9033
|
-
let rootReal;
|
|
9034
|
-
try {
|
|
9035
|
-
rootReal = await fs.realpath(this.rootAbs);
|
|
9036
|
-
} catch {
|
|
9037
|
-
rootReal = this.rootAbs;
|
|
9038
|
-
}
|
|
9039
|
-
let resolved;
|
|
9040
|
-
try {
|
|
9041
|
-
resolved = await fs.realpath(target);
|
|
9042
|
-
} catch (err) {
|
|
9043
|
-
resolved = path.join(rootReal, normalized);
|
|
9044
|
-
}
|
|
9045
|
-
const relFromRoot = path.relative(rootReal, resolved);
|
|
9046
|
-
if (relFromRoot.startsWith("..") || relFromRoot.startsWith(`.${path.sep}..`) || path.isAbsolute(relFromRoot)) {
|
|
9047
|
-
throw new PathEscapeError({
|
|
9048
|
-
requestedPath: relPath,
|
|
9049
|
-
resolvedPath: resolved
|
|
9050
|
-
});
|
|
9051
|
-
}
|
|
9052
|
-
return resolved;
|
|
7514
|
+
execution(exec) {
|
|
7515
|
+
return this.with({ execution: exec });
|
|
9053
7516
|
}
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9062
|
-
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9066
|
-
resolve2(null);
|
|
9067
|
-
});
|
|
9068
|
-
proc.on("close", (code) => {
|
|
9069
|
-
if (code === 0) {
|
|
9070
|
-
this.rgPath = "rg";
|
|
9071
|
-
resolve2("rg");
|
|
9072
|
-
} else {
|
|
9073
|
-
this.rgPath = null;
|
|
9074
|
-
resolve2(null);
|
|
9075
|
-
}
|
|
9076
|
-
});
|
|
7517
|
+
/**
|
|
7518
|
+
* Adds a reducer node that receives all mapper outputs.
|
|
7519
|
+
* The reducer receives a JSON object mapping each mapper ID to its text output.
|
|
7520
|
+
* The join node ID is automatically generated as "<id>_join".
|
|
7521
|
+
*/
|
|
7522
|
+
reduce(id, request) {
|
|
7523
|
+
return this.with({
|
|
7524
|
+
reducer: {
|
|
7525
|
+
id,
|
|
7526
|
+
request: wireRequest2(request),
|
|
7527
|
+
stream: false
|
|
7528
|
+
}
|
|
9077
7529
|
});
|
|
9078
7530
|
}
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
7531
|
+
/**
|
|
7532
|
+
* Like reduce() but enables streaming on the reducer node.
|
|
7533
|
+
*/
|
|
7534
|
+
reduceWithStream(id, request) {
|
|
7535
|
+
return this.with({
|
|
7536
|
+
reducer: {
|
|
7537
|
+
id,
|
|
7538
|
+
request: wireRequest2(request),
|
|
7539
|
+
stream: true
|
|
9084
7540
|
}
|
|
9085
|
-
|
|
9086
|
-
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
|
|
9099
|
-
killed = true;
|
|
9100
|
-
proc.kill();
|
|
9101
|
-
break;
|
|
9102
|
-
}
|
|
9103
|
-
}
|
|
9104
|
-
});
|
|
9105
|
-
proc.stderr.on("data", (chunk) => {
|
|
9106
|
-
stderr += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
|
|
9107
|
-
});
|
|
9108
|
-
proc.on("error", (err) => {
|
|
9109
|
-
reject(new Error(`fs.search: ripgrep error: ${err.message}`));
|
|
9110
|
-
});
|
|
9111
|
-
proc.on("close", (code) => {
|
|
9112
|
-
if (killed) {
|
|
9113
|
-
resolve2(lines.join("\n"));
|
|
9114
|
-
return;
|
|
9115
|
-
}
|
|
9116
|
-
if (code === 0 || code === 1) {
|
|
9117
|
-
resolve2(lines.join("\n"));
|
|
9118
|
-
} else if (code === 2 && stderr.toLowerCase().includes("regex")) {
|
|
9119
|
-
reject(
|
|
9120
|
-
new ToolArgumentError({
|
|
9121
|
-
message: `invalid query regex: ${stderr.trim()}`,
|
|
9122
|
-
toolCallId: "",
|
|
9123
|
-
toolName: ToolNames.FS_SEARCH,
|
|
9124
|
-
rawArguments: ""
|
|
9125
|
-
})
|
|
9126
|
-
);
|
|
9127
|
-
} else if (stderr) {
|
|
9128
|
-
reject(new Error(`fs.search: ripgrep failed: ${stderr.trim()}`));
|
|
9129
|
-
} else {
|
|
9130
|
-
resolve2(lines.join("\n"));
|
|
7541
|
+
});
|
|
7542
|
+
}
|
|
7543
|
+
/**
|
|
7544
|
+
* Adds an output reference from a specific node.
|
|
7545
|
+
* Typically used to output from the reducer node.
|
|
7546
|
+
*/
|
|
7547
|
+
output(name, from) {
|
|
7548
|
+
return this.with({
|
|
7549
|
+
outputs: [
|
|
7550
|
+
...this.state.outputs,
|
|
7551
|
+
{
|
|
7552
|
+
name,
|
|
7553
|
+
from,
|
|
7554
|
+
pointer: LLM_TEXT_OUTPUT_INTERNAL
|
|
9131
7555
|
}
|
|
9132
|
-
|
|
7556
|
+
]
|
|
9133
7557
|
});
|
|
9134
7558
|
}
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
|
|
9139
|
-
|
|
9140
|
-
|
|
9141
|
-
|
|
9142
|
-
const rest = trimmed.slice(colonIdx + 1);
|
|
9143
|
-
if (path.isAbsolute(filePath)) {
|
|
9144
|
-
const rel = path.relative(this.rootAbs, filePath);
|
|
9145
|
-
if (!rel.startsWith("..")) {
|
|
9146
|
-
return rel.split(path.sep).join("/") + ":" + rest;
|
|
9147
|
-
}
|
|
7559
|
+
/**
|
|
7560
|
+
* Builds and returns the compiled workflow spec.
|
|
7561
|
+
* @throws Error if no items are provided or no reducer is configured
|
|
7562
|
+
*/
|
|
7563
|
+
build() {
|
|
7564
|
+
if (this.state.items.length === 0) {
|
|
7565
|
+
throw new Error("map-reduce requires at least one item");
|
|
9148
7566
|
}
|
|
9149
|
-
|
|
9150
|
-
|
|
9151
|
-
// ========================================================================
|
|
9152
|
-
// JavaScript Fallback Search
|
|
9153
|
-
// ========================================================================
|
|
9154
|
-
async searchWithJS(query, dirAbs, maxMatches, call) {
|
|
9155
|
-
const func = call.function;
|
|
9156
|
-
let regex;
|
|
9157
|
-
try {
|
|
9158
|
-
regex = new RegExp(query);
|
|
9159
|
-
} catch (err) {
|
|
9160
|
-
throw new ToolArgumentError({
|
|
9161
|
-
message: `invalid query regex: ${err.message}`,
|
|
9162
|
-
toolCallId: call.id,
|
|
9163
|
-
toolName: func.name,
|
|
9164
|
-
rawArguments: func.arguments
|
|
9165
|
-
});
|
|
7567
|
+
if (!this.state.reducer) {
|
|
7568
|
+
throw new Error("map-reduce requires a reducer (call reduce)");
|
|
9166
7569
|
}
|
|
9167
|
-
const
|
|
9168
|
-
const
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
return false;
|
|
9172
|
-
}
|
|
9173
|
-
if (matches.length >= maxMatches) {
|
|
9174
|
-
return false;
|
|
9175
|
-
}
|
|
9176
|
-
if (dirent.isDirectory()) {
|
|
9177
|
-
if (this.cfg.ignoreDirs.has(dirent.name)) {
|
|
9178
|
-
return false;
|
|
9179
|
-
}
|
|
9180
|
-
return true;
|
|
7570
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
7571
|
+
for (const item of this.state.items) {
|
|
7572
|
+
if (!item.id) {
|
|
7573
|
+
throw new Error("item ID cannot be empty");
|
|
9181
7574
|
}
|
|
9182
|
-
if (
|
|
9183
|
-
|
|
7575
|
+
if (seenIds.has(item.id)) {
|
|
7576
|
+
throw new Error(`duplicate item ID: "${item.id}"`);
|
|
9184
7577
|
}
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
|
|
9188
|
-
|
|
7578
|
+
seenIds.add(item.id);
|
|
7579
|
+
}
|
|
7580
|
+
const nodes = [];
|
|
7581
|
+
const edges = [];
|
|
7582
|
+
const joinId = `${this.state.reducer.id}_join`;
|
|
7583
|
+
for (const item of this.state.items) {
|
|
7584
|
+
const mapperId = `map_${item.id}`;
|
|
7585
|
+
const input = {
|
|
7586
|
+
id: mapperId,
|
|
7587
|
+
type: WorkflowNodeTypes.LLMResponses,
|
|
7588
|
+
input: {
|
|
7589
|
+
request: item.request,
|
|
7590
|
+
...item.stream ? { stream: true } : {}
|
|
9189
7591
|
}
|
|
9190
|
-
}
|
|
9191
|
-
|
|
9192
|
-
}
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
7592
|
+
};
|
|
7593
|
+
nodes.push(input);
|
|
7594
|
+
edges.push({ from: mapperId, to: joinId });
|
|
7595
|
+
}
|
|
7596
|
+
nodes.push({ id: joinId, type: WorkflowNodeTypes.JoinAll });
|
|
7597
|
+
const reducerInput = {
|
|
7598
|
+
id: this.state.reducer.id,
|
|
7599
|
+
type: WorkflowNodeTypes.LLMResponses,
|
|
7600
|
+
input: {
|
|
7601
|
+
request: this.state.reducer.request,
|
|
7602
|
+
...this.state.reducer.stream ? { stream: true } : {},
|
|
7603
|
+
bindings: [
|
|
7604
|
+
{
|
|
7605
|
+
from: joinId,
|
|
7606
|
+
// Empty pointer = full join output
|
|
7607
|
+
to: LLM_USER_MESSAGE_TEXT_INTERNAL,
|
|
7608
|
+
encoding: "json_string"
|
|
9201
7609
|
}
|
|
9202
|
-
|
|
9203
|
-
} catch {
|
|
7610
|
+
]
|
|
9204
7611
|
}
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
7612
|
+
};
|
|
7613
|
+
nodes.push(reducerInput);
|
|
7614
|
+
edges.push({ from: joinId, to: this.state.reducer.id });
|
|
7615
|
+
return {
|
|
7616
|
+
kind: WorkflowKinds.WorkflowV0,
|
|
7617
|
+
name: this.state.name,
|
|
7618
|
+
...this.state.execution ? { execution: this.state.execution } : {},
|
|
7619
|
+
nodes,
|
|
7620
|
+
...edges.length > 0 ? { edges: sortEdges(edges) } : {},
|
|
7621
|
+
outputs: sortOutputs(this.state.outputs)
|
|
7622
|
+
};
|
|
9208
7623
|
}
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
const rawArgs = func.arguments || "{}";
|
|
9223
|
-
let parsed;
|
|
9224
|
-
try {
|
|
9225
|
-
parsed = JSON.parse(rawArgs);
|
|
9226
|
-
} catch (err) {
|
|
9227
|
-
throw new ToolArgumentError({
|
|
9228
|
-
message: `invalid JSON arguments: ${err.message}`,
|
|
9229
|
-
toolCallId: call.id,
|
|
9230
|
-
toolName: func.name,
|
|
9231
|
-
rawArguments: rawArgs
|
|
9232
|
-
});
|
|
9233
|
-
}
|
|
9234
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
9235
|
-
throw new ToolArgumentError({
|
|
9236
|
-
message: "arguments must be an object",
|
|
9237
|
-
toolCallId: call.id,
|
|
9238
|
-
toolName: func.name,
|
|
9239
|
-
rawArguments: rawArgs
|
|
9240
|
-
});
|
|
9241
|
-
}
|
|
9242
|
-
const args = parsed;
|
|
9243
|
-
for (const key of required) {
|
|
9244
|
-
const value = args[key];
|
|
9245
|
-
if (value === void 0 || value === null || value === "") {
|
|
9246
|
-
throw new ToolArgumentError({
|
|
9247
|
-
message: `${key} is required`,
|
|
9248
|
-
toolCallId: call.id,
|
|
9249
|
-
toolName: func.name,
|
|
9250
|
-
rawArguments: rawArgs
|
|
9251
|
-
});
|
|
7624
|
+
};
|
|
7625
|
+
function MapReduce(name, items = []) {
|
|
7626
|
+
return MapReduceBuilder.create(name, items);
|
|
7627
|
+
}
|
|
7628
|
+
|
|
7629
|
+
// src/testing.ts
|
|
7630
|
+
function buildNDJSONResponse(lines, headers = {}, status = 200) {
|
|
7631
|
+
const encoder = new TextEncoder();
|
|
7632
|
+
const stream = new ReadableStream({
|
|
7633
|
+
start(controller) {
|
|
7634
|
+
for (const line of lines) {
|
|
7635
|
+
controller.enqueue(encoder.encode(`${line}
|
|
7636
|
+
`));
|
|
9252
7637
|
}
|
|
7638
|
+
controller.close();
|
|
9253
7639
|
}
|
|
9254
|
-
|
|
9255
|
-
|
|
9256
|
-
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
toolCallId: call.id,
|
|
9261
|
-
toolName: func?.name ?? "",
|
|
9262
|
-
rawArguments: func?.arguments ?? ""
|
|
9263
|
-
});
|
|
9264
|
-
}
|
|
9265
|
-
requireString(args, key, call) {
|
|
9266
|
-
const value = args[key];
|
|
9267
|
-
if (typeof value !== "string") {
|
|
9268
|
-
this.toolArgumentError(call, `${key} must be a string`);
|
|
9269
|
-
}
|
|
9270
|
-
if (value.trim() === "") {
|
|
9271
|
-
this.toolArgumentError(call, `${key} is required`);
|
|
9272
|
-
}
|
|
9273
|
-
return value;
|
|
9274
|
-
}
|
|
9275
|
-
optionalString(args, key, call) {
|
|
9276
|
-
const value = args[key];
|
|
9277
|
-
if (value === void 0 || value === null) {
|
|
9278
|
-
return void 0;
|
|
9279
|
-
}
|
|
9280
|
-
if (typeof value !== "string") {
|
|
9281
|
-
this.toolArgumentError(call, `${key} must be a string`);
|
|
9282
|
-
}
|
|
9283
|
-
const trimmed = value.trim();
|
|
9284
|
-
if (trimmed === "") {
|
|
9285
|
-
return void 0;
|
|
9286
|
-
}
|
|
9287
|
-
return value;
|
|
9288
|
-
}
|
|
9289
|
-
optionalPositiveInt(args, key, call) {
|
|
9290
|
-
const value = args[key];
|
|
9291
|
-
if (value === void 0 || value === null) {
|
|
9292
|
-
return void 0;
|
|
7640
|
+
});
|
|
7641
|
+
return new Response(stream, {
|
|
7642
|
+
status,
|
|
7643
|
+
headers: {
|
|
7644
|
+
"Content-Type": "application/x-ndjson",
|
|
7645
|
+
...headers
|
|
9293
7646
|
}
|
|
9294
|
-
|
|
9295
|
-
|
|
7647
|
+
});
|
|
7648
|
+
}
|
|
7649
|
+
function buildDelayedNDJSONResponse(steps, headers = {}, status = 200) {
|
|
7650
|
+
const encoder = new TextEncoder();
|
|
7651
|
+
const stream = new ReadableStream({
|
|
7652
|
+
start(controller) {
|
|
7653
|
+
let idx = 0;
|
|
7654
|
+
const pushNext = () => {
|
|
7655
|
+
if (idx >= steps.length) {
|
|
7656
|
+
controller.close();
|
|
7657
|
+
return;
|
|
7658
|
+
}
|
|
7659
|
+
const step = steps[idx++];
|
|
7660
|
+
setTimeout(() => {
|
|
7661
|
+
controller.enqueue(encoder.encode(`${step.line}
|
|
7662
|
+
`));
|
|
7663
|
+
pushNext();
|
|
7664
|
+
}, Math.max(0, step.delayMs));
|
|
7665
|
+
};
|
|
7666
|
+
pushNext();
|
|
9296
7667
|
}
|
|
9297
|
-
|
|
9298
|
-
|
|
7668
|
+
});
|
|
7669
|
+
return new Response(stream, {
|
|
7670
|
+
status,
|
|
7671
|
+
headers: {
|
|
7672
|
+
"Content-Type": "application/x-ndjson",
|
|
7673
|
+
...headers
|
|
9299
7674
|
}
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
7675
|
+
});
|
|
7676
|
+
}
|
|
7677
|
+
function createMockFetchQueue(responses) {
|
|
7678
|
+
const calls = [];
|
|
7679
|
+
const queue = [...responses];
|
|
7680
|
+
const fetchImpl = async (url, init) => {
|
|
7681
|
+
const call = { url: String(url), init };
|
|
7682
|
+
calls.push(call);
|
|
7683
|
+
const responder = queue.shift();
|
|
7684
|
+
if (!responder) {
|
|
7685
|
+
throw new Error("mock fetch queue exhausted");
|
|
9308
7686
|
}
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
* Recursively walks a directory, calling visitor for each entry.
|
|
9312
|
-
* Visitor returns true to continue, false to skip (for dirs) or stop.
|
|
9313
|
-
*/
|
|
9314
|
-
async walkDir(dir, visitor) {
|
|
9315
|
-
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
9316
|
-
for (const entry of entries) {
|
|
9317
|
-
const fullPath = path.join(dir, entry.name);
|
|
9318
|
-
const shouldContinue = await visitor(fullPath, entry);
|
|
9319
|
-
if (!shouldContinue) {
|
|
9320
|
-
if (entry.isDirectory()) {
|
|
9321
|
-
continue;
|
|
9322
|
-
}
|
|
9323
|
-
return;
|
|
9324
|
-
}
|
|
9325
|
-
if (entry.isDirectory()) {
|
|
9326
|
-
await this.walkDir(fullPath, visitor);
|
|
9327
|
-
}
|
|
7687
|
+
if (typeof responder === "function") {
|
|
7688
|
+
return responder(call, calls.length - 1);
|
|
9328
7689
|
}
|
|
9329
|
-
|
|
9330
|
-
};
|
|
9331
|
-
|
|
9332
|
-
return new LocalFSToolPack(options);
|
|
9333
|
-
}
|
|
9334
|
-
function createLocalFSTools(options) {
|
|
9335
|
-
return createLocalFSToolPack(options).toRegistry();
|
|
7690
|
+
return responder;
|
|
7691
|
+
};
|
|
7692
|
+
return { fetch: fetchImpl, calls };
|
|
9336
7693
|
}
|
|
9337
7694
|
|
|
9338
7695
|
// src/tools_browser.ts
|
|
@@ -10087,23 +8444,23 @@ __export(workflow_exports, {
|
|
|
10087
8444
|
});
|
|
10088
8445
|
|
|
10089
8446
|
// src/workflow/helpers_v1.ts
|
|
10090
|
-
function whenOutputEquals(
|
|
10091
|
-
return { source: "node_output", op: "equals", path
|
|
8447
|
+
function whenOutputEquals(path, value) {
|
|
8448
|
+
return { source: "node_output", op: "equals", path, value };
|
|
10092
8449
|
}
|
|
10093
|
-
function whenOutputMatches(
|
|
10094
|
-
return { source: "node_output", op: "matches", path
|
|
8450
|
+
function whenOutputMatches(path, pattern) {
|
|
8451
|
+
return { source: "node_output", op: "matches", path, value: pattern };
|
|
10095
8452
|
}
|
|
10096
|
-
function whenOutputExists(
|
|
10097
|
-
return { source: "node_output", op: "exists", path
|
|
8453
|
+
function whenOutputExists(path) {
|
|
8454
|
+
return { source: "node_output", op: "exists", path };
|
|
10098
8455
|
}
|
|
10099
|
-
function whenStatusEquals(
|
|
10100
|
-
return { source: "node_status", op: "equals", path
|
|
8456
|
+
function whenStatusEquals(path, value) {
|
|
8457
|
+
return { source: "node_status", op: "equals", path, value };
|
|
10101
8458
|
}
|
|
10102
|
-
function whenStatusMatches(
|
|
10103
|
-
return { source: "node_status", op: "matches", path
|
|
8459
|
+
function whenStatusMatches(path, pattern) {
|
|
8460
|
+
return { source: "node_status", op: "matches", path, value: pattern };
|
|
10104
8461
|
}
|
|
10105
|
-
function whenStatusExists(
|
|
10106
|
-
return { source: "node_status", op: "exists", path
|
|
8462
|
+
function whenStatusExists(path) {
|
|
8463
|
+
return { source: "node_status", op: "exists", path };
|
|
10107
8464
|
}
|
|
10108
8465
|
function bindToPlaceholder(from, placeholder, opts) {
|
|
10109
8466
|
return {
|
|
@@ -10407,11 +8764,8 @@ export {
|
|
|
10407
8764
|
DEFAULT_BASE_URL,
|
|
10408
8765
|
DEFAULT_CLIENT_HEADER,
|
|
10409
8766
|
DEFAULT_CONNECT_TIMEOUT_MS,
|
|
10410
|
-
DEFAULT_IGNORE_DIRS,
|
|
10411
8767
|
DEFAULT_REQUEST_TIMEOUT_MS,
|
|
10412
8768
|
ErrorCodes,
|
|
10413
|
-
FSDefaults,
|
|
10414
|
-
ToolNames as FSToolNames,
|
|
10415
8769
|
FrontendTokenProvider,
|
|
10416
8770
|
ImagesClient,
|
|
10417
8771
|
InputItemTypes,
|
|
@@ -10433,7 +8787,6 @@ export {
|
|
|
10433
8787
|
LLMStep,
|
|
10434
8788
|
LLM_TEXT_OUTPUT,
|
|
10435
8789
|
LLM_USER_MESSAGE_TEXT,
|
|
10436
|
-
LocalFSToolPack,
|
|
10437
8790
|
LocalSession,
|
|
10438
8791
|
MapFanoutInputError,
|
|
10439
8792
|
MapItem,
|
|
@@ -10474,7 +8827,7 @@ export {
|
|
|
10474
8827
|
TransformJSONNodeBuilder,
|
|
10475
8828
|
TransportError,
|
|
10476
8829
|
WORKFLOWS_COMPILE_PATH,
|
|
10477
|
-
|
|
8830
|
+
WebToolIntents,
|
|
10478
8831
|
Workflow,
|
|
10479
8832
|
WorkflowBuilderV0,
|
|
10480
8833
|
WorkflowBuilderV1,
|
|
@@ -10497,8 +8850,6 @@ export {
|
|
|
10497
8850
|
createFunctionCall,
|
|
10498
8851
|
createFunctionTool,
|
|
10499
8852
|
createFunctionToolFromSchema,
|
|
10500
|
-
createLocalFSToolPack,
|
|
10501
|
-
createLocalFSTools,
|
|
10502
8853
|
createLocalSession,
|
|
10503
8854
|
createMemorySessionStore,
|
|
10504
8855
|
createMockFetchQueue,
|