@modelrelay/sdk 1.14.0 → 1.27.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/README.md +40 -4
- package/dist/chunk-BL7GWXRZ.js +1196 -0
- package/dist/index.cjs +2343 -867
- package/dist/index.d.cts +2777 -1594
- package/dist/index.d.ts +2777 -1594
- package/dist/index.js +3686 -3279
- 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.cjs
CHANGED
|
@@ -33,6 +33,7 @@ __export(index_exports, {
|
|
|
33
33
|
APIError: () => APIError,
|
|
34
34
|
AuthClient: () => AuthClient,
|
|
35
35
|
BillingProviders: () => BillingProviders,
|
|
36
|
+
BindingTargetError: () => BindingTargetError,
|
|
36
37
|
BrowserDefaults: () => BrowserDefaults,
|
|
37
38
|
BrowserToolNames: () => BrowserToolNames,
|
|
38
39
|
BrowserToolPack: () => BrowserToolPack,
|
|
@@ -47,20 +48,31 @@ __export(index_exports, {
|
|
|
47
48
|
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
48
49
|
DEFAULT_CLIENT_HEADER: () => DEFAULT_CLIENT_HEADER,
|
|
49
50
|
DEFAULT_CONNECT_TIMEOUT_MS: () => DEFAULT_CONNECT_TIMEOUT_MS,
|
|
50
|
-
DEFAULT_IGNORE_DIRS: () => DEFAULT_IGNORE_DIRS,
|
|
51
51
|
DEFAULT_REQUEST_TIMEOUT_MS: () => DEFAULT_REQUEST_TIMEOUT_MS,
|
|
52
52
|
ErrorCodes: () => ErrorCodes,
|
|
53
|
-
FSDefaults: () => FSDefaults,
|
|
54
|
-
FSToolNames: () => ToolNames,
|
|
55
53
|
FrontendTokenProvider: () => FrontendTokenProvider,
|
|
56
54
|
ImagesClient: () => ImagesClient,
|
|
57
55
|
InputItemTypes: () => InputItemTypes,
|
|
56
|
+
JoinOutput: () => JoinOutput,
|
|
57
|
+
JoinOutputPath: () => JoinOutputPath,
|
|
58
|
+
LLMInput: () => LLMInput,
|
|
59
|
+
LLMInputContentItemPath: () => LLMInputContentItemPath,
|
|
60
|
+
LLMInputFirstMessageText: () => LLMInputFirstMessageText,
|
|
61
|
+
LLMInputMessagePath: () => LLMInputMessagePath,
|
|
62
|
+
LLMInputPath: () => LLMInputPath,
|
|
63
|
+
LLMInputSystemText: () => LLMInputSystemText,
|
|
64
|
+
LLMInputUserText: () => LLMInputUserText,
|
|
58
65
|
LLMNodeBuilder: () => LLMNodeBuilder,
|
|
66
|
+
LLMOutput: () => LLMOutput,
|
|
67
|
+
LLMOutputContentItemPath: () => LLMOutputContentItemPath,
|
|
68
|
+
LLMOutputContentPath: () => LLMOutputContentPath,
|
|
69
|
+
LLMOutputPath: () => LLMOutputPath,
|
|
70
|
+
LLMOutputText: () => LLMOutputText,
|
|
59
71
|
LLMStep: () => LLMStep,
|
|
60
72
|
LLM_TEXT_OUTPUT: () => LLM_TEXT_OUTPUT,
|
|
61
73
|
LLM_USER_MESSAGE_TEXT: () => LLM_USER_MESSAGE_TEXT,
|
|
62
|
-
LocalFSToolPack: () => LocalFSToolPack,
|
|
63
74
|
LocalSession: () => LocalSession,
|
|
75
|
+
MapFanoutInputError: () => MapFanoutInputError,
|
|
64
76
|
MapItem: () => MapItem,
|
|
65
77
|
MapReduce: () => MapReduce,
|
|
66
78
|
MapReduceBuilder: () => MapReduceBuilder,
|
|
@@ -99,9 +111,10 @@ __export(index_exports, {
|
|
|
99
111
|
TransformJSONNodeBuilder: () => TransformJSONNodeBuilder,
|
|
100
112
|
TransportError: () => TransportError,
|
|
101
113
|
WORKFLOWS_COMPILE_PATH: () => WORKFLOWS_COMPILE_PATH,
|
|
102
|
-
|
|
114
|
+
WebToolIntents: () => WebToolIntents,
|
|
103
115
|
Workflow: () => Workflow,
|
|
104
116
|
WorkflowBuilderV0: () => WorkflowBuilderV0,
|
|
117
|
+
WorkflowBuilderV1: () => WorkflowBuilderV1,
|
|
105
118
|
WorkflowKinds: () => WorkflowKinds,
|
|
106
119
|
WorkflowNodeTypes: () => WorkflowNodeTypes,
|
|
107
120
|
WorkflowValidationError: () => WorkflowValidationError,
|
|
@@ -111,6 +124,8 @@ __export(index_exports, {
|
|
|
111
124
|
asSessionId: () => asSessionId,
|
|
112
125
|
asTierCode: () => asTierCode,
|
|
113
126
|
assistantMessageWithToolCalls: () => assistantMessageWithToolCalls,
|
|
127
|
+
buildDelayedNDJSONResponse: () => buildDelayedNDJSONResponse,
|
|
128
|
+
buildNDJSONResponse: () => buildNDJSONResponse,
|
|
114
129
|
createAccessTokenAuth: () => createAccessTokenAuth,
|
|
115
130
|
createApiKeyAuth: () => createApiKeyAuth,
|
|
116
131
|
createAssistantMessage: () => createAssistantMessage,
|
|
@@ -119,10 +134,9 @@ __export(index_exports, {
|
|
|
119
134
|
createFunctionCall: () => createFunctionCall,
|
|
120
135
|
createFunctionTool: () => createFunctionTool,
|
|
121
136
|
createFunctionToolFromSchema: () => createFunctionToolFromSchema,
|
|
122
|
-
createLocalFSToolPack: () => createLocalFSToolPack,
|
|
123
|
-
createLocalFSTools: () => createLocalFSTools,
|
|
124
137
|
createLocalSession: () => createLocalSession,
|
|
125
138
|
createMemorySessionStore: () => createMemorySessionStore,
|
|
139
|
+
createMockFetchQueue: () => createMockFetchQueue,
|
|
126
140
|
createRetryMessages: () => createRetryMessages,
|
|
127
141
|
createSystemMessage: () => createSystemMessage,
|
|
128
142
|
createToolCall: () => createToolCall,
|
|
@@ -164,6 +178,7 @@ __export(index_exports, {
|
|
|
164
178
|
parseToolArgs: () => parseToolArgs,
|
|
165
179
|
parseToolArgsRaw: () => parseToolArgsRaw,
|
|
166
180
|
pollOAuthDeviceToken: () => pollOAuthDeviceToken,
|
|
181
|
+
pollUntil: () => pollUntil,
|
|
167
182
|
respondToToolCall: () => respondToToolCall,
|
|
168
183
|
runOAuthDeviceFlowForIDToken: () => runOAuthDeviceFlowForIDToken,
|
|
169
184
|
startOAuthDeviceAuthorization: () => startOAuthDeviceAuthorization,
|
|
@@ -173,13 +188,18 @@ __export(index_exports, {
|
|
|
173
188
|
toolChoiceRequired: () => toolChoiceRequired,
|
|
174
189
|
toolResultMessage: () => toolResultMessage,
|
|
175
190
|
transformJSONMerge: () => transformJSONMerge,
|
|
191
|
+
transformJSONMergeV1: () => transformJSONMergeV1,
|
|
176
192
|
transformJSONObject: () => transformJSONObject,
|
|
193
|
+
transformJSONObjectV1: () => transformJSONObjectV1,
|
|
177
194
|
transformJSONValue: () => transformJSONValue,
|
|
195
|
+
transformJSONValueV1: () => transformJSONValueV1,
|
|
178
196
|
tryParseToolArgs: () => tryParseToolArgs,
|
|
179
197
|
validateWithZod: () => validateWithZod,
|
|
180
198
|
workflow: () => workflow_exports,
|
|
181
199
|
workflowV0: () => workflowV0,
|
|
182
200
|
workflowV0Schema: () => workflow_v0_schema_default,
|
|
201
|
+
workflowV1: () => workflowV1,
|
|
202
|
+
workflowV1Schema: () => workflow_v1_schema_default,
|
|
183
203
|
zodToJsonSchema: () => zodToJsonSchema
|
|
184
204
|
});
|
|
185
205
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -248,11 +268,11 @@ var StreamProtocolError = class extends TransportError {
|
|
|
248
268
|
this.status = opts.status;
|
|
249
269
|
}
|
|
250
270
|
};
|
|
251
|
-
var StreamTimeoutError = class extends
|
|
271
|
+
var StreamTimeoutError = class extends ModelRelayError {
|
|
252
272
|
constructor(streamKind, timeoutMs) {
|
|
253
273
|
const label = streamKind === "ttft" ? "TTFT" : streamKind === "idle" ? "idle" : "total";
|
|
254
|
-
super(`stream ${label} timeout after ${timeoutMs}ms`, {
|
|
255
|
-
this.
|
|
274
|
+
super(`stream ${label} timeout after ${timeoutMs}ms`, { category: "transport", status: 408 });
|
|
275
|
+
this.kind = streamKind;
|
|
256
276
|
this.timeoutMs = timeoutMs;
|
|
257
277
|
}
|
|
258
278
|
};
|
|
@@ -407,10 +427,10 @@ async function parseErrorResponse(response, retries) {
|
|
|
407
427
|
if (!raw || typeof raw !== "object") continue;
|
|
408
428
|
const obj = raw;
|
|
409
429
|
const code = typeof obj.code === "string" ? obj.code : "";
|
|
410
|
-
const
|
|
430
|
+
const path = typeof obj.path === "string" ? obj.path : "";
|
|
411
431
|
const message = typeof obj.message === "string" ? obj.message : "";
|
|
412
|
-
if (!code || !
|
|
413
|
-
normalized.push({ code, path
|
|
432
|
+
if (!code || !path || !message) continue;
|
|
433
|
+
normalized.push({ code, path, message });
|
|
414
434
|
}
|
|
415
435
|
if (normalized.length > 0) {
|
|
416
436
|
return new WorkflowValidationError({
|
|
@@ -760,8 +780,8 @@ var AuthClient = class {
|
|
|
760
780
|
params.set("provider", request.provider);
|
|
761
781
|
}
|
|
762
782
|
const queryString = params.toString();
|
|
763
|
-
const
|
|
764
|
-
const apiResp = await this.http.json(
|
|
783
|
+
const path = queryString ? `/auth/device/start?${queryString}` : "/auth/device/start";
|
|
784
|
+
const apiResp = await this.http.json(path, {
|
|
765
785
|
method: "POST",
|
|
766
786
|
apiKey: this.apiKey
|
|
767
787
|
});
|
|
@@ -884,7 +904,7 @@ function isTokenReusable(token) {
|
|
|
884
904
|
// package.json
|
|
885
905
|
var package_default = {
|
|
886
906
|
name: "@modelrelay/sdk",
|
|
887
|
-
version: "1.
|
|
907
|
+
version: "1.27.0",
|
|
888
908
|
description: "TypeScript SDK for the ModelRelay API",
|
|
889
909
|
type: "module",
|
|
890
910
|
main: "dist/index.cjs",
|
|
@@ -895,6 +915,11 @@ var package_default = {
|
|
|
895
915
|
types: "./dist/index.d.ts",
|
|
896
916
|
import: "./dist/index.js",
|
|
897
917
|
require: "./dist/index.cjs"
|
|
918
|
+
},
|
|
919
|
+
"./node": {
|
|
920
|
+
types: "./dist/node.d.ts",
|
|
921
|
+
import: "./dist/node.js",
|
|
922
|
+
require: "./dist/node.cjs"
|
|
898
923
|
}
|
|
899
924
|
},
|
|
900
925
|
publishConfig: {
|
|
@@ -904,8 +929,8 @@ var package_default = {
|
|
|
904
929
|
"dist"
|
|
905
930
|
],
|
|
906
931
|
scripts: {
|
|
907
|
-
build: "tsup src/index.ts --format esm,cjs --dts --external playwright",
|
|
908
|
-
dev: "tsup src/index.ts --format esm,cjs --dts --watch",
|
|
932
|
+
build: "tsup src/index.ts src/node.ts --format esm,cjs --dts --external playwright",
|
|
933
|
+
dev: "tsup src/index.ts src/node.ts --format esm,cjs --dts --watch",
|
|
909
934
|
lint: "tsc --noEmit --project tsconfig.lint.json",
|
|
910
935
|
test: "vitest run",
|
|
911
936
|
"generate:types": "openapi-typescript ../../api/openapi/api.json -o src/generated/api.ts"
|
|
@@ -1013,11 +1038,10 @@ var ToolTypes = {
|
|
|
1013
1038
|
XSearch: "x_search",
|
|
1014
1039
|
CodeExecution: "code_execution"
|
|
1015
1040
|
};
|
|
1016
|
-
var
|
|
1041
|
+
var WebToolIntents = {
|
|
1017
1042
|
Auto: "auto",
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
SearchAndFetch: "search_and_fetch"
|
|
1043
|
+
SearchWeb: "search_web",
|
|
1044
|
+
FetchURL: "fetch_url"
|
|
1021
1045
|
};
|
|
1022
1046
|
var ToolChoiceTypes = {
|
|
1023
1047
|
Auto: "auto",
|
|
@@ -1358,7 +1382,7 @@ function createWebTool(options) {
|
|
|
1358
1382
|
return {
|
|
1359
1383
|
type: ToolTypes.Web,
|
|
1360
1384
|
web: options ? {
|
|
1361
|
-
|
|
1385
|
+
intent: options.intent,
|
|
1362
1386
|
allowedDomains: options.allowedDomains,
|
|
1363
1387
|
excludedDomains: options.excludedDomains,
|
|
1364
1388
|
maxUses: options.maxUses
|
|
@@ -1502,8 +1526,8 @@ function parseToolArgs(call, schema) {
|
|
|
1502
1526
|
const zodErr = err;
|
|
1503
1527
|
if (zodErr.errors && Array.isArray(zodErr.errors)) {
|
|
1504
1528
|
const issues = zodErr.errors.map((e) => {
|
|
1505
|
-
const
|
|
1506
|
-
return `${
|
|
1529
|
+
const path = e.path.length > 0 ? `${e.path.join(".")}: ` : "";
|
|
1530
|
+
return `${path}${e.message}`;
|
|
1507
1531
|
}).join("; ");
|
|
1508
1532
|
message = issues;
|
|
1509
1533
|
} else {
|
|
@@ -2069,7 +2093,7 @@ function extractAssistantText(output) {
|
|
|
2069
2093
|
const text = parts.filter((p) => p.type === "text").map((p) => p.type === "text" ? p.text : "").join("");
|
|
2070
2094
|
if (!text.trim()) {
|
|
2071
2095
|
throw new TransportError("response contained no assistant text output", {
|
|
2072
|
-
kind: "
|
|
2096
|
+
kind: "empty_response"
|
|
2073
2097
|
});
|
|
2074
2098
|
}
|
|
2075
2099
|
return text;
|
|
@@ -2763,6 +2787,101 @@ var ResponsesClient = class {
|
|
|
2763
2787
|
const resp = await this.create(req, options);
|
|
2764
2788
|
return extractAssistantText(resp.output);
|
|
2765
2789
|
}
|
|
2790
|
+
/**
|
|
2791
|
+
* Generate a typed object from a Zod schema with a single function call.
|
|
2792
|
+
*
|
|
2793
|
+
* This is the most ergonomic way to get structured output - all configuration
|
|
2794
|
+
* is passed in a single object argument, matching the Vercel AI SDK pattern.
|
|
2795
|
+
*
|
|
2796
|
+
* @example
|
|
2797
|
+
* ```typescript
|
|
2798
|
+
* import { z } from 'zod';
|
|
2799
|
+
*
|
|
2800
|
+
* const review = await client.responses.object({
|
|
2801
|
+
* model: 'claude-sonnet-4-20250514',
|
|
2802
|
+
* schema: z.object({
|
|
2803
|
+
* vulnerabilities: z.array(z.string()),
|
|
2804
|
+
* riskLevel: z.enum(['low', 'medium', 'high']),
|
|
2805
|
+
* }),
|
|
2806
|
+
* system: 'You are a security expert.',
|
|
2807
|
+
* prompt: `Review this code:\n${code}`,
|
|
2808
|
+
* });
|
|
2809
|
+
*
|
|
2810
|
+
* console.log(review.riskLevel); // 'low' | 'medium' | 'high'
|
|
2811
|
+
* ```
|
|
2812
|
+
*
|
|
2813
|
+
* @example Parallel execution with Promise.all
|
|
2814
|
+
* ```typescript
|
|
2815
|
+
* const [security, performance] = await Promise.all([
|
|
2816
|
+
* client.responses.object({
|
|
2817
|
+
* model,
|
|
2818
|
+
* schema: SecuritySchema,
|
|
2819
|
+
* system: 'Security expert...',
|
|
2820
|
+
* prompt: code,
|
|
2821
|
+
* }),
|
|
2822
|
+
* client.responses.object({
|
|
2823
|
+
* model,
|
|
2824
|
+
* schema: PerformanceSchema,
|
|
2825
|
+
* system: 'Performance expert...',
|
|
2826
|
+
* prompt: code,
|
|
2827
|
+
* }),
|
|
2828
|
+
* ]);
|
|
2829
|
+
* ```
|
|
2830
|
+
*/
|
|
2831
|
+
async object(args) {
|
|
2832
|
+
let builder = this.new().model(args.model);
|
|
2833
|
+
if (args.system) {
|
|
2834
|
+
builder = builder.system(args.system);
|
|
2835
|
+
}
|
|
2836
|
+
builder = builder.user(args.prompt);
|
|
2837
|
+
if (args.customerId) {
|
|
2838
|
+
builder = builder.customerId(args.customerId);
|
|
2839
|
+
}
|
|
2840
|
+
const request = builder.build();
|
|
2841
|
+
const result = await this.structured(args.schema, request, {
|
|
2842
|
+
maxRetries: args.maxRetries,
|
|
2843
|
+
retryHandler: args.retryHandler,
|
|
2844
|
+
schemaName: args.schemaName,
|
|
2845
|
+
...args.options
|
|
2846
|
+
});
|
|
2847
|
+
return result.value;
|
|
2848
|
+
}
|
|
2849
|
+
/**
|
|
2850
|
+
* Generate a typed object with full result metadata.
|
|
2851
|
+
*
|
|
2852
|
+
* Like `object()` but returns the full `StructuredResult<T>` including
|
|
2853
|
+
* attempt count and request ID.
|
|
2854
|
+
*
|
|
2855
|
+
* @example
|
|
2856
|
+
* ```typescript
|
|
2857
|
+
* const result = await client.responses.objectWithMetadata({
|
|
2858
|
+
* model: 'claude-sonnet-4-20250514',
|
|
2859
|
+
* schema: ReviewSchema,
|
|
2860
|
+
* prompt: 'Review this code...',
|
|
2861
|
+
* });
|
|
2862
|
+
*
|
|
2863
|
+
* console.log(result.value); // The parsed object
|
|
2864
|
+
* console.log(result.attempts); // Number of attempts (1 = first try succeeded)
|
|
2865
|
+
* console.log(result.requestId); // Server request ID
|
|
2866
|
+
* ```
|
|
2867
|
+
*/
|
|
2868
|
+
async objectWithMetadata(args) {
|
|
2869
|
+
let builder = this.new().model(args.model);
|
|
2870
|
+
if (args.system) {
|
|
2871
|
+
builder = builder.system(args.system);
|
|
2872
|
+
}
|
|
2873
|
+
builder = builder.user(args.prompt);
|
|
2874
|
+
if (args.customerId) {
|
|
2875
|
+
builder = builder.customerId(args.customerId);
|
|
2876
|
+
}
|
|
2877
|
+
const request = builder.build();
|
|
2878
|
+
return this.structured(args.schema, request, {
|
|
2879
|
+
maxRetries: args.maxRetries,
|
|
2880
|
+
retryHandler: args.retryHandler,
|
|
2881
|
+
schemaName: args.schemaName,
|
|
2882
|
+
...args.options
|
|
2883
|
+
});
|
|
2884
|
+
}
|
|
2766
2885
|
async textForCustomer(customerIdOrArgs, system, user, options = {}) {
|
|
2767
2886
|
const args = typeof customerIdOrArgs === "string" ? { customerId: customerIdOrArgs, system, user, options } : customerIdOrArgs;
|
|
2768
2887
|
if (args.system === void 0 || args.user === void 0) {
|
|
@@ -3203,13 +3322,23 @@ function parseOutputName(raw) {
|
|
|
3203
3322
|
|
|
3204
3323
|
// src/runs_types.ts
|
|
3205
3324
|
var WorkflowKinds = {
|
|
3206
|
-
WorkflowV0: "workflow.v0"
|
|
3325
|
+
WorkflowV0: "workflow.v0",
|
|
3326
|
+
WorkflowV1: "workflow.v1"
|
|
3207
3327
|
};
|
|
3208
3328
|
var WorkflowNodeTypes = {
|
|
3209
3329
|
LLMResponses: "llm.responses",
|
|
3210
3330
|
JoinAll: "join.all",
|
|
3211
3331
|
TransformJSON: "transform.json"
|
|
3212
3332
|
};
|
|
3333
|
+
var WorkflowNodeTypesV1 = {
|
|
3334
|
+
LLMResponses: "llm.responses",
|
|
3335
|
+
RouteSwitch: "route.switch",
|
|
3336
|
+
JoinAll: "join.all",
|
|
3337
|
+
JoinAny: "join.any",
|
|
3338
|
+
JoinCollect: "join.collect",
|
|
3339
|
+
TransformJSON: "transform.json",
|
|
3340
|
+
MapFanout: "map.fanout"
|
|
3341
|
+
};
|
|
3213
3342
|
var nodeErrorSchema = import_zod.default.object({
|
|
3214
3343
|
code: import_zod.default.string().optional(),
|
|
3215
3344
|
message: import_zod.default.string().min(1)
|
|
@@ -3567,6 +3696,9 @@ var RunsClient = class {
|
|
|
3567
3696
|
const headers = { ...options.headers || {} };
|
|
3568
3697
|
this.applyCustomerHeader(headers, options.customerId);
|
|
3569
3698
|
const payload = { spec };
|
|
3699
|
+
if (options.sessionId?.trim()) {
|
|
3700
|
+
payload.session_id = options.sessionId.trim();
|
|
3701
|
+
}
|
|
3570
3702
|
if (options.idempotencyKey?.trim()) {
|
|
3571
3703
|
payload.options = { idempotency_key: options.idempotencyKey.trim() };
|
|
3572
3704
|
}
|
|
@@ -3622,10 +3754,10 @@ var RunsClient = class {
|
|
|
3622
3754
|
const metrics = mergeMetrics(this.metrics, options.metrics);
|
|
3623
3755
|
const trace = mergeTrace(this.trace, options.trace);
|
|
3624
3756
|
const authHeaders = await this.auth.authForResponses();
|
|
3625
|
-
const
|
|
3757
|
+
const path = runByIdPath(runId);
|
|
3626
3758
|
const headers = { ...options.headers || {} };
|
|
3627
3759
|
this.applyCustomerHeader(headers, options.customerId);
|
|
3628
|
-
const out = await this.http.json(
|
|
3760
|
+
const out = await this.http.json(path, {
|
|
3629
3761
|
method: "GET",
|
|
3630
3762
|
headers,
|
|
3631
3763
|
signal: options.signal,
|
|
@@ -3636,7 +3768,7 @@ var RunsClient = class {
|
|
|
3636
3768
|
retry: options.retry,
|
|
3637
3769
|
metrics,
|
|
3638
3770
|
trace,
|
|
3639
|
-
context: { method: "GET", path
|
|
3771
|
+
context: { method: "GET", path }
|
|
3640
3772
|
});
|
|
3641
3773
|
return {
|
|
3642
3774
|
...out,
|
|
@@ -3660,10 +3792,10 @@ var RunsClient = class {
|
|
|
3660
3792
|
if (options.wait === false) {
|
|
3661
3793
|
params.set("wait", "0");
|
|
3662
3794
|
}
|
|
3663
|
-
const
|
|
3795
|
+
const path = params.toString() ? `${basePath}?${params}` : basePath;
|
|
3664
3796
|
const headers = { ...options.headers || {} };
|
|
3665
3797
|
this.applyCustomerHeader(headers, options.customerId);
|
|
3666
|
-
const resp = await this.http.request(
|
|
3798
|
+
const resp = await this.http.request(path, {
|
|
3667
3799
|
method: "GET",
|
|
3668
3800
|
headers,
|
|
3669
3801
|
signal: options.signal,
|
|
@@ -3714,10 +3846,10 @@ var RunsClient = class {
|
|
|
3714
3846
|
const metrics = mergeMetrics(this.metrics, options.metrics);
|
|
3715
3847
|
const trace = mergeTrace(this.trace, options.trace);
|
|
3716
3848
|
const authHeaders = await this.auth.authForResponses();
|
|
3717
|
-
const
|
|
3849
|
+
const path = runToolResultsPath(runId);
|
|
3718
3850
|
const headers = { ...options.headers || {} };
|
|
3719
3851
|
this.applyCustomerHeader(headers, options.customerId);
|
|
3720
|
-
const out = await this.http.json(
|
|
3852
|
+
const out = await this.http.json(path, {
|
|
3721
3853
|
method: "POST",
|
|
3722
3854
|
headers,
|
|
3723
3855
|
body: req,
|
|
@@ -3729,7 +3861,7 @@ var RunsClient = class {
|
|
|
3729
3861
|
retry: options.retry,
|
|
3730
3862
|
metrics,
|
|
3731
3863
|
trace,
|
|
3732
|
-
context: { method: "POST", path
|
|
3864
|
+
context: { method: "POST", path }
|
|
3733
3865
|
});
|
|
3734
3866
|
return out;
|
|
3735
3867
|
}
|
|
@@ -3737,10 +3869,10 @@ var RunsClient = class {
|
|
|
3737
3869
|
const metrics = mergeMetrics(this.metrics, options.metrics);
|
|
3738
3870
|
const trace = mergeTrace(this.trace, options.trace);
|
|
3739
3871
|
const authHeaders = await this.auth.authForResponses();
|
|
3740
|
-
const
|
|
3872
|
+
const path = runPendingToolsPath(runId);
|
|
3741
3873
|
const headers = { ...options.headers || {} };
|
|
3742
3874
|
this.applyCustomerHeader(headers, options.customerId);
|
|
3743
|
-
const out = await this.http.json(
|
|
3875
|
+
const out = await this.http.json(path, {
|
|
3744
3876
|
method: "GET",
|
|
3745
3877
|
headers,
|
|
3746
3878
|
signal: options.signal,
|
|
@@ -3751,7 +3883,7 @@ var RunsClient = class {
|
|
|
3751
3883
|
retry: options.retry,
|
|
3752
3884
|
metrics,
|
|
3753
3885
|
trace,
|
|
3754
|
-
context: { method: "GET", path
|
|
3886
|
+
context: { method: "GET", path }
|
|
3755
3887
|
});
|
|
3756
3888
|
return {
|
|
3757
3889
|
...out,
|
|
@@ -3835,6 +3967,65 @@ var WorkflowsClient = class {
|
|
|
3835
3967
|
throw err;
|
|
3836
3968
|
}
|
|
3837
3969
|
}
|
|
3970
|
+
async compileV1(spec, options = {}) {
|
|
3971
|
+
const metrics = mergeMetrics(this.metrics, options.metrics);
|
|
3972
|
+
const trace = mergeTrace(this.trace, options.trace);
|
|
3973
|
+
const authHeaders = await this.auth.authForResponses();
|
|
3974
|
+
const headers = { ...options.headers || {} };
|
|
3975
|
+
const customerId = options.customerId?.trim();
|
|
3976
|
+
if (customerId) {
|
|
3977
|
+
headers[CUSTOMER_ID_HEADER] = customerId;
|
|
3978
|
+
}
|
|
3979
|
+
try {
|
|
3980
|
+
const out = await this.http.json(
|
|
3981
|
+
WORKFLOWS_COMPILE_PATH,
|
|
3982
|
+
{
|
|
3983
|
+
method: "POST",
|
|
3984
|
+
headers,
|
|
3985
|
+
body: spec,
|
|
3986
|
+
signal: options.signal,
|
|
3987
|
+
apiKey: authHeaders.apiKey,
|
|
3988
|
+
accessToken: authHeaders.accessToken,
|
|
3989
|
+
timeoutMs: options.timeoutMs,
|
|
3990
|
+
connectTimeoutMs: options.connectTimeoutMs,
|
|
3991
|
+
retry: options.retry,
|
|
3992
|
+
metrics,
|
|
3993
|
+
trace,
|
|
3994
|
+
context: { method: "POST", path: WORKFLOWS_COMPILE_PATH }
|
|
3995
|
+
}
|
|
3996
|
+
);
|
|
3997
|
+
return {
|
|
3998
|
+
ok: true,
|
|
3999
|
+
plan_json: out.plan_json,
|
|
4000
|
+
plan_hash: parsePlanHash(out.plan_hash)
|
|
4001
|
+
};
|
|
4002
|
+
} catch (err) {
|
|
4003
|
+
if (err instanceof WorkflowValidationError) {
|
|
4004
|
+
return { ok: false, error_type: "validation_error", issues: err.issues };
|
|
4005
|
+
}
|
|
4006
|
+
if (err instanceof APIError) {
|
|
4007
|
+
return {
|
|
4008
|
+
ok: false,
|
|
4009
|
+
error_type: "internal_error",
|
|
4010
|
+
status: err.status ?? 0,
|
|
4011
|
+
message: err.message,
|
|
4012
|
+
code: err.code,
|
|
4013
|
+
requestId: err.requestId
|
|
4014
|
+
};
|
|
4015
|
+
}
|
|
4016
|
+
if (err instanceof ModelRelayError && err.category === "api") {
|
|
4017
|
+
return {
|
|
4018
|
+
ok: false,
|
|
4019
|
+
error_type: "internal_error",
|
|
4020
|
+
status: err.status ?? 0,
|
|
4021
|
+
message: err.message,
|
|
4022
|
+
code: err.code,
|
|
4023
|
+
requestId: err.requestId
|
|
4024
|
+
};
|
|
4025
|
+
}
|
|
4026
|
+
throw err;
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
3838
4029
|
};
|
|
3839
4030
|
|
|
3840
4031
|
// src/customers.ts
|
|
@@ -4195,8 +4386,8 @@ var ModelsClient = class {
|
|
|
4195
4386
|
if (params.capability) {
|
|
4196
4387
|
qs.set("capability", params.capability);
|
|
4197
4388
|
}
|
|
4198
|
-
const
|
|
4199
|
-
const resp = await this.http.json(
|
|
4389
|
+
const path = qs.toString() ? `/models?${qs.toString()}` : "/models";
|
|
4390
|
+
const resp = await this.http.json(path, { method: "GET" });
|
|
4200
4391
|
return resp.models;
|
|
4201
4392
|
}
|
|
4202
4393
|
};
|
|
@@ -4230,8 +4421,287 @@ var ImagesClient = class {
|
|
|
4230
4421
|
accessToken: auth.accessToken
|
|
4231
4422
|
});
|
|
4232
4423
|
}
|
|
4424
|
+
/**
|
|
4425
|
+
* Get information about a specific image.
|
|
4426
|
+
*
|
|
4427
|
+
* Returns the image's pinned status, expiration time, and URL.
|
|
4428
|
+
*
|
|
4429
|
+
* @param imageId - The image ID to retrieve
|
|
4430
|
+
* @returns Image details including pinned status and URL
|
|
4431
|
+
* @throws {Error} If imageId is empty
|
|
4432
|
+
*/
|
|
4433
|
+
async get(imageId) {
|
|
4434
|
+
if (!imageId?.trim()) {
|
|
4435
|
+
throw new Error("imageId is required");
|
|
4436
|
+
}
|
|
4437
|
+
const auth = await this.auth.authForResponses();
|
|
4438
|
+
return await this.http.json(`/images/${imageId}`, {
|
|
4439
|
+
method: "GET",
|
|
4440
|
+
apiKey: auth.apiKey,
|
|
4441
|
+
accessToken: auth.accessToken
|
|
4442
|
+
});
|
|
4443
|
+
}
|
|
4444
|
+
/**
|
|
4445
|
+
* Pin an image to prevent it from expiring.
|
|
4446
|
+
*
|
|
4447
|
+
* Pinned images remain accessible permanently (subject to tier limits).
|
|
4448
|
+
*
|
|
4449
|
+
* @param imageId - The image ID to pin
|
|
4450
|
+
* @returns Updated image state including permanent URL
|
|
4451
|
+
* @throws {Error} If imageId is empty
|
|
4452
|
+
*/
|
|
4453
|
+
async pin(imageId) {
|
|
4454
|
+
if (!imageId?.trim()) {
|
|
4455
|
+
throw new Error("imageId is required");
|
|
4456
|
+
}
|
|
4457
|
+
const auth = await this.auth.authForResponses();
|
|
4458
|
+
return await this.http.json(`/images/${imageId}/pin`, {
|
|
4459
|
+
method: "POST",
|
|
4460
|
+
apiKey: auth.apiKey,
|
|
4461
|
+
accessToken: auth.accessToken
|
|
4462
|
+
});
|
|
4463
|
+
}
|
|
4464
|
+
/**
|
|
4465
|
+
* Unpin an image, allowing it to expire.
|
|
4466
|
+
*
|
|
4467
|
+
* The image will expire after the default ephemeral period (7 days).
|
|
4468
|
+
*
|
|
4469
|
+
* @param imageId - The image ID to unpin
|
|
4470
|
+
* @returns Updated image state including new expiration time
|
|
4471
|
+
* @throws {Error} If imageId is empty
|
|
4472
|
+
*/
|
|
4473
|
+
async unpin(imageId) {
|
|
4474
|
+
if (!imageId?.trim()) {
|
|
4475
|
+
throw new Error("imageId is required");
|
|
4476
|
+
}
|
|
4477
|
+
const auth = await this.auth.authForResponses();
|
|
4478
|
+
return await this.http.json(`/images/${imageId}/pin`, {
|
|
4479
|
+
method: "DELETE",
|
|
4480
|
+
apiKey: auth.apiKey,
|
|
4481
|
+
accessToken: auth.accessToken
|
|
4482
|
+
});
|
|
4483
|
+
}
|
|
4233
4484
|
};
|
|
4234
4485
|
|
|
4486
|
+
// src/sessions/context_management.ts
|
|
4487
|
+
var DEFAULT_CONTEXT_BUFFER_TOKENS = 256;
|
|
4488
|
+
var CONTEXT_BUFFER_RATIO = 0.02;
|
|
4489
|
+
var MESSAGE_OVERHEAD_TOKENS = 6;
|
|
4490
|
+
var TOOL_CALL_OVERHEAD_TOKENS = 4;
|
|
4491
|
+
var CHARS_PER_TOKEN = 4;
|
|
4492
|
+
var IMAGE_TOKENS_LOW_DETAIL = 85;
|
|
4493
|
+
var IMAGE_TOKENS_HIGH_DETAIL = 1e3;
|
|
4494
|
+
var modelContextCache = /* @__PURE__ */ new WeakMap();
|
|
4495
|
+
function createModelContextResolver(client) {
|
|
4496
|
+
return async (modelId) => {
|
|
4497
|
+
const entry = getModelContextCacheEntry(client);
|
|
4498
|
+
const key = String(modelId);
|
|
4499
|
+
const cached = entry.byId.get(key);
|
|
4500
|
+
if (cached !== void 0) {
|
|
4501
|
+
return cached;
|
|
4502
|
+
}
|
|
4503
|
+
await populateModelContextCache(client, entry);
|
|
4504
|
+
const resolved = entry.byId.get(key);
|
|
4505
|
+
if (resolved === void 0) {
|
|
4506
|
+
throw new ConfigError(
|
|
4507
|
+
`Unknown model "${key}"; ensure the model exists in the ModelRelay catalog`
|
|
4508
|
+
);
|
|
4509
|
+
}
|
|
4510
|
+
return resolved;
|
|
4511
|
+
};
|
|
4512
|
+
}
|
|
4513
|
+
async function buildSessionInputWithContext(messages, options, defaultModel, resolveModelContext) {
|
|
4514
|
+
const strategy = options.contextManagement ?? "none";
|
|
4515
|
+
if (strategy === "none") {
|
|
4516
|
+
return messagesToInput(messages);
|
|
4517
|
+
}
|
|
4518
|
+
if (strategy === "summarize") {
|
|
4519
|
+
throw new ConfigError("contextManagement 'summarize' is not implemented yet");
|
|
4520
|
+
}
|
|
4521
|
+
if (strategy !== "truncate") {
|
|
4522
|
+
throw new ConfigError(`Unknown contextManagement strategy: ${strategy}`);
|
|
4523
|
+
}
|
|
4524
|
+
const modelId = options.model ?? defaultModel;
|
|
4525
|
+
if (!modelId) {
|
|
4526
|
+
throw new ConfigError(
|
|
4527
|
+
"model is required for context management; set options.model or a session defaultModel"
|
|
4528
|
+
);
|
|
4529
|
+
}
|
|
4530
|
+
const budget = await resolveHistoryBudget(
|
|
4531
|
+
modelId,
|
|
4532
|
+
options,
|
|
4533
|
+
resolveModelContext
|
|
4534
|
+
);
|
|
4535
|
+
const truncated = truncateMessagesByTokens(
|
|
4536
|
+
messages,
|
|
4537
|
+
budget.maxHistoryTokens
|
|
4538
|
+
);
|
|
4539
|
+
if (options.onContextTruncate && truncated.length < messages.length) {
|
|
4540
|
+
const info = {
|
|
4541
|
+
model: modelId,
|
|
4542
|
+
originalMessages: messages.length,
|
|
4543
|
+
keptMessages: truncated.length,
|
|
4544
|
+
maxHistoryTokens: budget.maxHistoryTokens,
|
|
4545
|
+
reservedOutputTokens: budget.reservedOutputTokens
|
|
4546
|
+
};
|
|
4547
|
+
options.onContextTruncate(info);
|
|
4548
|
+
}
|
|
4549
|
+
return messagesToInput(truncated);
|
|
4550
|
+
}
|
|
4551
|
+
function messagesToInput(messages) {
|
|
4552
|
+
return messages.map((m) => ({
|
|
4553
|
+
type: m.type,
|
|
4554
|
+
role: m.role,
|
|
4555
|
+
content: m.content,
|
|
4556
|
+
toolCalls: m.toolCalls,
|
|
4557
|
+
toolCallId: m.toolCallId
|
|
4558
|
+
}));
|
|
4559
|
+
}
|
|
4560
|
+
function truncateMessagesByTokens(messages, maxHistoryTokens) {
|
|
4561
|
+
const maxTokens = normalizePositiveInt(maxHistoryTokens, "maxHistoryTokens");
|
|
4562
|
+
if (messages.length === 0) return [];
|
|
4563
|
+
const tokensByIndex = messages.map((msg) => estimateTokensForMessage(msg));
|
|
4564
|
+
const systemIndices = messages.map((msg, idx) => msg.role === "system" ? idx : -1).filter((idx) => idx >= 0);
|
|
4565
|
+
let selectedSystem = [...systemIndices];
|
|
4566
|
+
let systemTokens = sumTokens(tokensByIndex, selectedSystem);
|
|
4567
|
+
while (systemTokens > maxTokens && selectedSystem.length > 1) {
|
|
4568
|
+
selectedSystem.shift();
|
|
4569
|
+
systemTokens = sumTokens(tokensByIndex, selectedSystem);
|
|
4570
|
+
}
|
|
4571
|
+
if (systemTokens > maxTokens) {
|
|
4572
|
+
throw new ConfigError(
|
|
4573
|
+
"maxHistoryTokens is too small to fit the latest system message"
|
|
4574
|
+
);
|
|
4575
|
+
}
|
|
4576
|
+
const selected = new Set(selectedSystem);
|
|
4577
|
+
let remaining = maxTokens - systemTokens;
|
|
4578
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
4579
|
+
if (selected.has(i)) continue;
|
|
4580
|
+
const tokens = tokensByIndex[i];
|
|
4581
|
+
if (tokens <= remaining) {
|
|
4582
|
+
selected.add(i);
|
|
4583
|
+
remaining -= tokens;
|
|
4584
|
+
}
|
|
4585
|
+
}
|
|
4586
|
+
const result = messages.filter((_, idx) => selected.has(idx));
|
|
4587
|
+
if (result.length === 0) {
|
|
4588
|
+
throw new ConfigError("No messages fit within maxHistoryTokens");
|
|
4589
|
+
}
|
|
4590
|
+
return result;
|
|
4591
|
+
}
|
|
4592
|
+
function estimateTokens(text) {
|
|
4593
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
4594
|
+
}
|
|
4595
|
+
function isImagePart(part) {
|
|
4596
|
+
if (typeof part !== "object" || part === null) return false;
|
|
4597
|
+
const p = part;
|
|
4598
|
+
return p.type === "image" || p.type === "image_url";
|
|
4599
|
+
}
|
|
4600
|
+
function estimateImageTokens(part) {
|
|
4601
|
+
const detail = part.detail ?? "auto";
|
|
4602
|
+
if (detail === "low") return IMAGE_TOKENS_LOW_DETAIL;
|
|
4603
|
+
return IMAGE_TOKENS_HIGH_DETAIL;
|
|
4604
|
+
}
|
|
4605
|
+
function estimateTokensForMessage(message) {
|
|
4606
|
+
const segments = [message.role];
|
|
4607
|
+
let imageTokens = 0;
|
|
4608
|
+
for (const part of message.content || []) {
|
|
4609
|
+
if (part.type === "text" && part.text) {
|
|
4610
|
+
segments.push(part.text);
|
|
4611
|
+
} else if (isImagePart(part)) {
|
|
4612
|
+
imageTokens += estimateImageTokens(part);
|
|
4613
|
+
}
|
|
4614
|
+
}
|
|
4615
|
+
if (message.toolCalls) {
|
|
4616
|
+
for (const call of message.toolCalls) {
|
|
4617
|
+
if (call.function?.name) segments.push(call.function.name);
|
|
4618
|
+
if (call.function?.arguments) segments.push(call.function.arguments);
|
|
4619
|
+
}
|
|
4620
|
+
}
|
|
4621
|
+
if (message.toolCallId) {
|
|
4622
|
+
segments.push(message.toolCallId);
|
|
4623
|
+
}
|
|
4624
|
+
const textTokens = estimateTokens(segments.join("\n"));
|
|
4625
|
+
const toolOverhead = message.toolCalls ? message.toolCalls.length * TOOL_CALL_OVERHEAD_TOKENS : 0;
|
|
4626
|
+
return textTokens + MESSAGE_OVERHEAD_TOKENS + toolOverhead + imageTokens;
|
|
4627
|
+
}
|
|
4628
|
+
function normalizePositiveInt(value, label) {
|
|
4629
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
4630
|
+
throw new ConfigError(`${label} must be a positive number`);
|
|
4631
|
+
}
|
|
4632
|
+
return Math.floor(value);
|
|
4633
|
+
}
|
|
4634
|
+
function sumTokens(tokensByIndex, indices) {
|
|
4635
|
+
return indices.reduce((sum, idx) => sum + tokensByIndex[idx], 0);
|
|
4636
|
+
}
|
|
4637
|
+
async function resolveHistoryBudget(modelId, options, resolveModelContext) {
|
|
4638
|
+
const reservedOutputTokens = options.reserveOutputTokens === void 0 ? void 0 : normalizeNonNegativeInt(
|
|
4639
|
+
options.reserveOutputTokens,
|
|
4640
|
+
"reserveOutputTokens"
|
|
4641
|
+
);
|
|
4642
|
+
if (options.maxHistoryTokens !== void 0) {
|
|
4643
|
+
return {
|
|
4644
|
+
maxHistoryTokens: normalizePositiveInt(
|
|
4645
|
+
options.maxHistoryTokens,
|
|
4646
|
+
"maxHistoryTokens"
|
|
4647
|
+
),
|
|
4648
|
+
reservedOutputTokens
|
|
4649
|
+
};
|
|
4650
|
+
}
|
|
4651
|
+
const model = await resolveModelContext(modelId);
|
|
4652
|
+
if (!model) {
|
|
4653
|
+
throw new ConfigError(
|
|
4654
|
+
`Unknown model "${modelId}"; ensure the model exists in the ModelRelay catalog`
|
|
4655
|
+
);
|
|
4656
|
+
}
|
|
4657
|
+
const contextWindow = normalizePositiveInt(model.contextWindow, "context_window");
|
|
4658
|
+
const modelOutputTokens = model.maxOutputTokens === void 0 ? 0 : normalizeNonNegativeInt(model.maxOutputTokens, "max_output_tokens");
|
|
4659
|
+
const effectiveReserve = reservedOutputTokens ?? modelOutputTokens;
|
|
4660
|
+
const buffer = Math.max(
|
|
4661
|
+
DEFAULT_CONTEXT_BUFFER_TOKENS,
|
|
4662
|
+
Math.ceil(contextWindow * CONTEXT_BUFFER_RATIO)
|
|
4663
|
+
);
|
|
4664
|
+
const maxHistoryTokens = contextWindow - effectiveReserve - buffer;
|
|
4665
|
+
if (maxHistoryTokens <= 0) {
|
|
4666
|
+
throw new ConfigError(
|
|
4667
|
+
"model context window is too small after reserving output tokens; set maxHistoryTokens explicitly"
|
|
4668
|
+
);
|
|
4669
|
+
}
|
|
4670
|
+
return {
|
|
4671
|
+
maxHistoryTokens,
|
|
4672
|
+
reservedOutputTokens: effectiveReserve
|
|
4673
|
+
};
|
|
4674
|
+
}
|
|
4675
|
+
function normalizeNonNegativeInt(value, label) {
|
|
4676
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
4677
|
+
throw new ConfigError(`${label} must be a non-negative number`);
|
|
4678
|
+
}
|
|
4679
|
+
return Math.floor(value);
|
|
4680
|
+
}
|
|
4681
|
+
function getModelContextCacheEntry(client) {
|
|
4682
|
+
const existing = modelContextCache.get(client);
|
|
4683
|
+
if (existing) return existing;
|
|
4684
|
+
const entry = { byId: /* @__PURE__ */ new Map() };
|
|
4685
|
+
modelContextCache.set(client, entry);
|
|
4686
|
+
return entry;
|
|
4687
|
+
}
|
|
4688
|
+
async function populateModelContextCache(client, entry) {
|
|
4689
|
+
if (!entry.listPromise) {
|
|
4690
|
+
entry.listPromise = (async () => {
|
|
4691
|
+
const models = await client.models.list();
|
|
4692
|
+
for (const model of models) {
|
|
4693
|
+
entry.byId.set(String(model.model_id), {
|
|
4694
|
+
contextWindow: model.context_window,
|
|
4695
|
+
maxOutputTokens: model.max_output_tokens
|
|
4696
|
+
});
|
|
4697
|
+
}
|
|
4698
|
+
})().finally(() => {
|
|
4699
|
+
entry.listPromise = void 0;
|
|
4700
|
+
});
|
|
4701
|
+
}
|
|
4702
|
+
await entry.listPromise;
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4235
4705
|
// src/sessions/types.ts
|
|
4236
4706
|
function asSessionId(value) {
|
|
4237
4707
|
return value;
|
|
@@ -4296,6 +4766,7 @@ var LocalSession = class _LocalSession {
|
|
|
4296
4766
|
this.defaultProvider = options.defaultProvider;
|
|
4297
4767
|
this.defaultTools = options.defaultTools;
|
|
4298
4768
|
this.metadata = options.metadata || {};
|
|
4769
|
+
this.resolveModelContext = createModelContextResolver(client);
|
|
4299
4770
|
if (existingState) {
|
|
4300
4771
|
this.id = existingState.id;
|
|
4301
4772
|
this.messages = existingState.messages.map((m) => ({
|
|
@@ -4362,7 +4833,7 @@ var LocalSession = class _LocalSession {
|
|
|
4362
4833
|
this.currentNodeId = void 0;
|
|
4363
4834
|
this.currentWaiting = void 0;
|
|
4364
4835
|
try {
|
|
4365
|
-
const input = this.buildInput();
|
|
4836
|
+
const input = await this.buildInput(options);
|
|
4366
4837
|
const tools = mergeTools(this.defaultTools, options.tools);
|
|
4367
4838
|
const spec = {
|
|
4368
4839
|
kind: "workflow.v0",
|
|
@@ -4424,6 +4895,68 @@ var LocalSession = class _LocalSession {
|
|
|
4424
4895
|
await this.persist();
|
|
4425
4896
|
await this.store.close();
|
|
4426
4897
|
}
|
|
4898
|
+
/**
|
|
4899
|
+
* Sync this local session's messages to a remote session.
|
|
4900
|
+
*
|
|
4901
|
+
* This uploads all local messages to the remote session, enabling
|
|
4902
|
+
* cross-device access and server-side backup. Messages are synced
|
|
4903
|
+
* in order and the remote session's history will contain all local
|
|
4904
|
+
* messages after sync completes.
|
|
4905
|
+
*
|
|
4906
|
+
* @param remoteSession - The remote session to sync to
|
|
4907
|
+
* @param options - Optional sync configuration
|
|
4908
|
+
* @returns Sync result with message count
|
|
4909
|
+
*
|
|
4910
|
+
* @example
|
|
4911
|
+
* ```typescript
|
|
4912
|
+
* // Create local session and work offline
|
|
4913
|
+
* const local = LocalSession.create(client, { ... });
|
|
4914
|
+
* await local.run("Implement the feature");
|
|
4915
|
+
*
|
|
4916
|
+
* // Later, sync to remote for backup/sharing
|
|
4917
|
+
* const remote = await RemoteSession.create(client);
|
|
4918
|
+
* const result = await local.syncTo(remote, {
|
|
4919
|
+
* onProgress: (synced, total) => console.log(`${synced}/${total}`),
|
|
4920
|
+
* });
|
|
4921
|
+
* ```
|
|
4922
|
+
*/
|
|
4923
|
+
async syncTo(remoteSession, options = {}) {
|
|
4924
|
+
const { onProgress, signal } = options;
|
|
4925
|
+
const total = this.messages.length;
|
|
4926
|
+
if (total === 0) {
|
|
4927
|
+
return {
|
|
4928
|
+
messagesSynced: 0,
|
|
4929
|
+
remoteSessionId: remoteSession.id
|
|
4930
|
+
};
|
|
4931
|
+
}
|
|
4932
|
+
if (remoteSession.history.length > 0) {
|
|
4933
|
+
throw new ConfigError(
|
|
4934
|
+
`Cannot sync to non-empty remote session (has ${remoteSession.history.length} messages). syncTo() is for initial migration only. Create a new remote session or use bidirectional sync.`
|
|
4935
|
+
);
|
|
4936
|
+
}
|
|
4937
|
+
const http = this.client.http;
|
|
4938
|
+
let synced = 0;
|
|
4939
|
+
for (const message of this.messages) {
|
|
4940
|
+
if (signal?.aborted) {
|
|
4941
|
+
throw new Error("Sync aborted");
|
|
4942
|
+
}
|
|
4943
|
+
await http.request(`/sessions/${remoteSession.id}/messages`, {
|
|
4944
|
+
method: "POST",
|
|
4945
|
+
body: {
|
|
4946
|
+
role: message.role,
|
|
4947
|
+
content: message.content,
|
|
4948
|
+
run_id: message.runId ? String(message.runId) : void 0
|
|
4949
|
+
}
|
|
4950
|
+
});
|
|
4951
|
+
synced++;
|
|
4952
|
+
onProgress?.(synced, total);
|
|
4953
|
+
}
|
|
4954
|
+
await remoteSession.refresh();
|
|
4955
|
+
return {
|
|
4956
|
+
messagesSynced: synced,
|
|
4957
|
+
remoteSessionId: remoteSession.id
|
|
4958
|
+
};
|
|
4959
|
+
}
|
|
4427
4960
|
// ============================================================================
|
|
4428
4961
|
// Private Methods
|
|
4429
4962
|
// ============================================================================
|
|
@@ -4438,14 +4971,13 @@ var LocalSession = class _LocalSession {
|
|
|
4438
4971
|
this.updatedAt = /* @__PURE__ */ new Date();
|
|
4439
4972
|
return message;
|
|
4440
4973
|
}
|
|
4441
|
-
buildInput() {
|
|
4442
|
-
return
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
}));
|
|
4974
|
+
async buildInput(options) {
|
|
4975
|
+
return buildSessionInputWithContext(
|
|
4976
|
+
this.messages,
|
|
4977
|
+
options,
|
|
4978
|
+
this.defaultModel,
|
|
4979
|
+
this.resolveModelContext
|
|
4980
|
+
);
|
|
4449
4981
|
}
|
|
4450
4982
|
async processRunEvents(signal) {
|
|
4451
4983
|
if (!this.currentRunId) {
|
|
@@ -4670,6 +5202,7 @@ var RemoteSession = class _RemoteSession {
|
|
|
4670
5202
|
this.defaultModel = options.defaultModel;
|
|
4671
5203
|
this.defaultProvider = options.defaultProvider;
|
|
4672
5204
|
this.defaultTools = options.defaultTools;
|
|
5205
|
+
this.resolveModelContext = createModelContextResolver(client);
|
|
4673
5206
|
if ("messages" in sessionData && sessionData.messages) {
|
|
4674
5207
|
this.messages = sessionData.messages.map((m) => ({
|
|
4675
5208
|
type: "message",
|
|
@@ -4780,7 +5313,7 @@ var RemoteSession = class _RemoteSession {
|
|
|
4780
5313
|
});
|
|
4781
5314
|
this.resetRunState();
|
|
4782
5315
|
try {
|
|
4783
|
-
const input = this.buildInput();
|
|
5316
|
+
const input = await this.buildInput(options);
|
|
4784
5317
|
const tools = mergeTools2(this.defaultTools, options.tools);
|
|
4785
5318
|
const spec = {
|
|
4786
5319
|
kind: "workflow.v0",
|
|
@@ -4803,7 +5336,8 @@ var RemoteSession = class _RemoteSession {
|
|
|
4803
5336
|
outputs: [{ name: "result", from: "main" }]
|
|
4804
5337
|
};
|
|
4805
5338
|
const run = await this.client.runs.create(spec, {
|
|
4806
|
-
customerId: options.customerId || this.endUserId
|
|
5339
|
+
customerId: options.customerId || this.endUserId,
|
|
5340
|
+
sessionId: String(this.id)
|
|
4807
5341
|
});
|
|
4808
5342
|
this.currentRunId = run.run_id;
|
|
4809
5343
|
return await this.processRunEvents(options.signal);
|
|
@@ -4888,14 +5422,13 @@ var RemoteSession = class _RemoteSession {
|
|
|
4888
5422
|
this.updatedAt = /* @__PURE__ */ new Date();
|
|
4889
5423
|
return message;
|
|
4890
5424
|
}
|
|
4891
|
-
buildInput() {
|
|
4892
|
-
return
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
}));
|
|
5425
|
+
async buildInput(options) {
|
|
5426
|
+
return buildSessionInputWithContext(
|
|
5427
|
+
this.messages,
|
|
5428
|
+
options,
|
|
5429
|
+
this.defaultModel,
|
|
5430
|
+
this.resolveModelContext
|
|
5431
|
+
);
|
|
4899
5432
|
}
|
|
4900
5433
|
resetRunState() {
|
|
4901
5434
|
this.currentRunId = void 0;
|
|
@@ -4972,10 +5505,7 @@ var RemoteSession = class _RemoteSession {
|
|
|
4972
5505
|
break;
|
|
4973
5506
|
case "run_completed": {
|
|
4974
5507
|
const runState2 = await this.client.runs.get(this.currentRunId);
|
|
4975
|
-
|
|
4976
|
-
if (runState2.outputs && Array.isArray(runState2.outputs)) {
|
|
4977
|
-
output2 = runState2.outputs.filter((o) => o.type === "text").map((o) => o.text || "").join("");
|
|
4978
|
-
}
|
|
5508
|
+
const output2 = this.extractOutputText(runState2.outputs);
|
|
4979
5509
|
if (output2) {
|
|
4980
5510
|
this.addMessage(
|
|
4981
5511
|
{
|
|
@@ -4983,7 +5513,8 @@ var RemoteSession = class _RemoteSession {
|
|
|
4983
5513
|
role: "assistant",
|
|
4984
5514
|
content: [{ type: "text", text: output2 }]
|
|
4985
5515
|
},
|
|
4986
|
-
this.currentRunId
|
|
5516
|
+
this.currentRunId,
|
|
5517
|
+
false
|
|
4987
5518
|
);
|
|
4988
5519
|
}
|
|
4989
5520
|
await this.flushPendingMessages();
|
|
@@ -5013,10 +5544,7 @@ var RemoteSession = class _RemoteSession {
|
|
|
5013
5544
|
}
|
|
5014
5545
|
}
|
|
5015
5546
|
const runState = await this.client.runs.get(this.currentRunId);
|
|
5016
|
-
|
|
5017
|
-
if (runState.outputs && Array.isArray(runState.outputs)) {
|
|
5018
|
-
output = runState.outputs.filter((o) => o.type === "text").map((o) => o.text || "").join("");
|
|
5019
|
-
}
|
|
5547
|
+
const output = this.extractOutputText(runState.outputs);
|
|
5020
5548
|
if (output) {
|
|
5021
5549
|
this.addMessage(
|
|
5022
5550
|
{
|
|
@@ -5024,7 +5552,8 @@ var RemoteSession = class _RemoteSession {
|
|
|
5024
5552
|
role: "assistant",
|
|
5025
5553
|
content: [{ type: "text", text: output }]
|
|
5026
5554
|
},
|
|
5027
|
-
this.currentRunId
|
|
5555
|
+
this.currentRunId,
|
|
5556
|
+
false
|
|
5028
5557
|
);
|
|
5029
5558
|
}
|
|
5030
5559
|
await this.flushPendingMessages();
|
|
@@ -5111,6 +5640,45 @@ var RemoteSession = class _RemoteSession {
|
|
|
5111
5640
|
runId: data.run_id ? parseRunId(data.run_id) : void 0
|
|
5112
5641
|
};
|
|
5113
5642
|
}
|
|
5643
|
+
extractOutputText(outputs) {
|
|
5644
|
+
if (!outputs) return void 0;
|
|
5645
|
+
for (const value of Object.values(outputs)) {
|
|
5646
|
+
const text = this.extractTextFromOutputValue(value);
|
|
5647
|
+
if (text) return text;
|
|
5648
|
+
}
|
|
5649
|
+
return void 0;
|
|
5650
|
+
}
|
|
5651
|
+
extractTextFromOutputValue(value) {
|
|
5652
|
+
if (!value || typeof value !== "object") return void 0;
|
|
5653
|
+
if ("output" in value && Array.isArray(value.output)) {
|
|
5654
|
+
return this.extractTextFromOutputItems(value.output);
|
|
5655
|
+
}
|
|
5656
|
+
if (Array.isArray(value)) {
|
|
5657
|
+
const arr = value;
|
|
5658
|
+
if (arr.length === 0 || typeof arr[0] !== "object") return void 0;
|
|
5659
|
+
if ("content" in arr[0]) {
|
|
5660
|
+
return this.extractTextFromOutputItems(arr);
|
|
5661
|
+
}
|
|
5662
|
+
if ("type" in arr[0] && "text" in arr[0]) {
|
|
5663
|
+
return this.extractTextFromContentParts(arr);
|
|
5664
|
+
}
|
|
5665
|
+
}
|
|
5666
|
+
return void 0;
|
|
5667
|
+
}
|
|
5668
|
+
extractTextFromOutputItems(items) {
|
|
5669
|
+
const texts = [];
|
|
5670
|
+
for (const item of items) {
|
|
5671
|
+
if (item.type !== "message" || item.role !== "assistant") continue;
|
|
5672
|
+
texts.push(this.extractTextFromContentParts(item.content) || "");
|
|
5673
|
+
}
|
|
5674
|
+
const combined = texts.join("");
|
|
5675
|
+
return combined.trim() ? combined : void 0;
|
|
5676
|
+
}
|
|
5677
|
+
extractTextFromContentParts(parts) {
|
|
5678
|
+
if (!parts || parts.length === 0) return void 0;
|
|
5679
|
+
const text = parts.filter((p) => p.type === "text").map((p) => p.text || "").join("");
|
|
5680
|
+
return text.trim() ? text : void 0;
|
|
5681
|
+
}
|
|
5114
5682
|
};
|
|
5115
5683
|
function getHTTPClient(client) {
|
|
5116
5684
|
return client.http;
|
|
@@ -5286,7 +5854,7 @@ var HTTPClient = class {
|
|
|
5286
5854
|
this.metrics = cfg.metrics;
|
|
5287
5855
|
this.trace = cfg.trace;
|
|
5288
5856
|
}
|
|
5289
|
-
async request(
|
|
5857
|
+
async request(path, options = {}) {
|
|
5290
5858
|
const fetchFn = this.fetchImpl ?? globalThis.fetch;
|
|
5291
5859
|
if (!fetchFn) {
|
|
5292
5860
|
throw new ConfigError(
|
|
@@ -5294,12 +5862,12 @@ var HTTPClient = class {
|
|
|
5294
5862
|
);
|
|
5295
5863
|
}
|
|
5296
5864
|
const method = options.method || "GET";
|
|
5297
|
-
const url = buildUrl(this.baseUrl,
|
|
5865
|
+
const url = buildUrl(this.baseUrl, path);
|
|
5298
5866
|
const metrics = mergeMetrics(this.metrics, options.metrics);
|
|
5299
5867
|
const trace = mergeTrace(this.trace, options.trace);
|
|
5300
5868
|
const context = {
|
|
5301
5869
|
method,
|
|
5302
|
-
path
|
|
5870
|
+
path,
|
|
5303
5871
|
...options.context || {}
|
|
5304
5872
|
};
|
|
5305
5873
|
trace?.requestStart?.(context);
|
|
@@ -5440,8 +6008,8 @@ var HTTPClient = class {
|
|
|
5440
6008
|
retries: buildRetryMetadata(attempts, lastStatus)
|
|
5441
6009
|
});
|
|
5442
6010
|
}
|
|
5443
|
-
async json(
|
|
5444
|
-
const response = await this.request(
|
|
6011
|
+
async json(path, options = {}) {
|
|
6012
|
+
const response = await this.request(path, {
|
|
5445
6013
|
...options,
|
|
5446
6014
|
raw: true,
|
|
5447
6015
|
accept: options.accept || "application/json"
|
|
@@ -5462,14 +6030,14 @@ var HTTPClient = class {
|
|
|
5462
6030
|
}
|
|
5463
6031
|
}
|
|
5464
6032
|
};
|
|
5465
|
-
function buildUrl(baseUrl,
|
|
5466
|
-
if (/^https?:\/\//i.test(
|
|
5467
|
-
return
|
|
6033
|
+
function buildUrl(baseUrl, path) {
|
|
6034
|
+
if (/^https?:\/\//i.test(path)) {
|
|
6035
|
+
return path;
|
|
5468
6036
|
}
|
|
5469
|
-
if (!
|
|
5470
|
-
|
|
6037
|
+
if (!path.startsWith("/")) {
|
|
6038
|
+
path = `/${path}`;
|
|
5471
6039
|
}
|
|
5472
|
-
return `${baseUrl}${
|
|
6040
|
+
return `${baseUrl}${path}`;
|
|
5473
6041
|
}
|
|
5474
6042
|
function normalizeBaseUrl(value) {
|
|
5475
6043
|
const trimmed = value.trim();
|
|
@@ -5512,7 +6080,7 @@ function backoff(attempt, cfg) {
|
|
|
5512
6080
|
const jitter = 0.5 + Math.random();
|
|
5513
6081
|
const delay = Math.min(cfg.maxBackoffMs, capped * jitter);
|
|
5514
6082
|
if (delay <= 0) return Promise.resolve();
|
|
5515
|
-
return new Promise((
|
|
6083
|
+
return new Promise((resolve) => setTimeout(resolve, delay));
|
|
5516
6084
|
}
|
|
5517
6085
|
function mergeSignals(...signals) {
|
|
5518
6086
|
const active = signals.filter(Boolean);
|
|
@@ -5768,6 +6336,23 @@ var OIDCExchangeTokenProvider = class {
|
|
|
5768
6336
|
};
|
|
5769
6337
|
|
|
5770
6338
|
// src/device_flow.ts
|
|
6339
|
+
async function pollUntil(opts) {
|
|
6340
|
+
let intervalMs = Math.max(1, opts.intervalMs);
|
|
6341
|
+
let attempt = 0;
|
|
6342
|
+
while (true) {
|
|
6343
|
+
if (opts.deadline && Date.now() >= opts.deadline.getTime()) {
|
|
6344
|
+
throw opts.onTimeout?.() ?? new TransportError("polling timed out", { kind: "timeout" });
|
|
6345
|
+
}
|
|
6346
|
+
const result = await opts.poll(attempt);
|
|
6347
|
+
if (result.done) {
|
|
6348
|
+
return result.value;
|
|
6349
|
+
}
|
|
6350
|
+
const delay = Math.max(1, result.retryAfterMs ?? intervalMs);
|
|
6351
|
+
intervalMs = delay;
|
|
6352
|
+
await sleep(delay, opts.signal);
|
|
6353
|
+
attempt += 1;
|
|
6354
|
+
}
|
|
6355
|
+
}
|
|
5771
6356
|
async function startOAuthDeviceAuthorization(req) {
|
|
5772
6357
|
const deviceAuthorizationEndpoint = req.deviceAuthorizationEndpoint?.trim();
|
|
5773
6358
|
if (!deviceAuthorizationEndpoint) {
|
|
@@ -5825,58 +6410,59 @@ async function pollOAuthDeviceToken(req) {
|
|
|
5825
6410
|
}
|
|
5826
6411
|
const deadline = req.deadline ?? new Date(Date.now() + 10 * 60 * 1e3);
|
|
5827
6412
|
let intervalMs = Math.max(1, req.intervalSeconds ?? 5) * 1e3;
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
if (err) {
|
|
5843
|
-
switch (err) {
|
|
5844
|
-
case "authorization_pending":
|
|
5845
|
-
await sleep(intervalMs, req.signal);
|
|
5846
|
-
continue;
|
|
5847
|
-
case "slow_down":
|
|
5848
|
-
intervalMs += 5e3;
|
|
5849
|
-
await sleep(intervalMs, req.signal);
|
|
5850
|
-
continue;
|
|
5851
|
-
case "expired_token":
|
|
5852
|
-
case "access_denied":
|
|
5853
|
-
case "invalid_grant":
|
|
5854
|
-
throw new TransportError(`oauth device flow failed: ${err}`, {
|
|
5855
|
-
kind: "request",
|
|
5856
|
-
cause: payload
|
|
5857
|
-
});
|
|
5858
|
-
default:
|
|
5859
|
-
throw new TransportError(`oauth device flow error: ${err}`, {
|
|
5860
|
-
kind: "request",
|
|
5861
|
-
cause: payload
|
|
5862
|
-
});
|
|
5863
|
-
}
|
|
5864
|
-
}
|
|
5865
|
-
const accessToken = String(payload.access_token || "").trim() || void 0;
|
|
5866
|
-
const idToken = String(payload.id_token || "").trim() || void 0;
|
|
5867
|
-
const refreshToken = String(payload.refresh_token || "").trim() || void 0;
|
|
5868
|
-
const tokenType = String(payload.token_type || "").trim() || void 0;
|
|
5869
|
-
const scope = String(payload.scope || "").trim() || void 0;
|
|
5870
|
-
const expiresIn = payload.expires_in !== void 0 ? Number(payload.expires_in) : void 0;
|
|
5871
|
-
const expiresAt = typeof expiresIn === "number" && Number.isFinite(expiresIn) && expiresIn > 0 ? new Date(Date.now() + expiresIn * 1e3) : void 0;
|
|
5872
|
-
if (!accessToken && !idToken) {
|
|
5873
|
-
throw new TransportError("oauth device flow returned an invalid token response", {
|
|
5874
|
-
kind: "request",
|
|
5875
|
-
cause: payload
|
|
6413
|
+
return pollUntil({
|
|
6414
|
+
intervalMs,
|
|
6415
|
+
deadline,
|
|
6416
|
+
signal: req.signal,
|
|
6417
|
+
onTimeout: () => new TransportError("oauth device flow timed out", { kind: "timeout" }),
|
|
6418
|
+
poll: async () => {
|
|
6419
|
+
const form = new URLSearchParams();
|
|
6420
|
+
form.set("grant_type", "urn:ietf:params:oauth:grant-type:device_code");
|
|
6421
|
+
form.set("device_code", deviceCode);
|
|
6422
|
+
form.set("client_id", clientId);
|
|
6423
|
+
const payload = await postOAuthForm(tokenEndpoint, form, {
|
|
6424
|
+
fetch: req.fetch,
|
|
6425
|
+
signal: req.signal,
|
|
6426
|
+
allowErrorPayload: true
|
|
5876
6427
|
});
|
|
6428
|
+
const err = String(payload.error || "").trim();
|
|
6429
|
+
if (err) {
|
|
6430
|
+
switch (err) {
|
|
6431
|
+
case "authorization_pending":
|
|
6432
|
+
return { done: false };
|
|
6433
|
+
case "slow_down":
|
|
6434
|
+
intervalMs += 5e3;
|
|
6435
|
+
return { done: false, retryAfterMs: intervalMs };
|
|
6436
|
+
case "expired_token":
|
|
6437
|
+
case "access_denied":
|
|
6438
|
+
case "invalid_grant":
|
|
6439
|
+
throw new TransportError(`oauth device flow failed: ${err}`, {
|
|
6440
|
+
kind: "request",
|
|
6441
|
+
cause: payload
|
|
6442
|
+
});
|
|
6443
|
+
default:
|
|
6444
|
+
throw new TransportError(`oauth device flow error: ${err}`, {
|
|
6445
|
+
kind: "request",
|
|
6446
|
+
cause: payload
|
|
6447
|
+
});
|
|
6448
|
+
}
|
|
6449
|
+
}
|
|
6450
|
+
const accessToken = String(payload.access_token || "").trim() || void 0;
|
|
6451
|
+
const idToken = String(payload.id_token || "").trim() || void 0;
|
|
6452
|
+
const refreshToken = String(payload.refresh_token || "").trim() || void 0;
|
|
6453
|
+
const tokenType = String(payload.token_type || "").trim() || void 0;
|
|
6454
|
+
const scope = String(payload.scope || "").trim() || void 0;
|
|
6455
|
+
const expiresIn = payload.expires_in !== void 0 ? Number(payload.expires_in) : void 0;
|
|
6456
|
+
const expiresAt = typeof expiresIn === "number" && Number.isFinite(expiresIn) && expiresIn > 0 ? new Date(Date.now() + expiresIn * 1e3) : void 0;
|
|
6457
|
+
if (!accessToken && !idToken) {
|
|
6458
|
+
throw new TransportError("oauth device flow returned an invalid token response", {
|
|
6459
|
+
kind: "request",
|
|
6460
|
+
cause: payload
|
|
6461
|
+
});
|
|
6462
|
+
}
|
|
6463
|
+
return { done: true, value: { accessToken, idToken, refreshToken, tokenType, scope, expiresAt } };
|
|
5877
6464
|
}
|
|
5878
|
-
|
|
5879
|
-
}
|
|
6465
|
+
});
|
|
5880
6466
|
}
|
|
5881
6467
|
async function runOAuthDeviceFlowForIDToken(cfg) {
|
|
5882
6468
|
const auth = await startOAuthDeviceAuthorization({
|
|
@@ -5940,13 +6526,13 @@ async function sleep(ms, signal) {
|
|
|
5940
6526
|
return;
|
|
5941
6527
|
}
|
|
5942
6528
|
if (!signal) {
|
|
5943
|
-
await new Promise((
|
|
6529
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
5944
6530
|
return;
|
|
5945
6531
|
}
|
|
5946
6532
|
if (signal.aborted) {
|
|
5947
6533
|
throw new TransportError("oauth device flow aborted", { kind: "request" });
|
|
5948
6534
|
}
|
|
5949
|
-
await new Promise((
|
|
6535
|
+
await new Promise((resolve, reject) => {
|
|
5950
6536
|
const onAbort = () => {
|
|
5951
6537
|
signal.removeEventListener("abort", onAbort);
|
|
5952
6538
|
reject(new TransportError("oauth device flow aborted", { kind: "request" }));
|
|
@@ -5954,27 +6540,154 @@ async function sleep(ms, signal) {
|
|
|
5954
6540
|
signal.addEventListener("abort", onAbort);
|
|
5955
6541
|
setTimeout(() => {
|
|
5956
6542
|
signal.removeEventListener("abort", onAbort);
|
|
5957
|
-
|
|
6543
|
+
resolve();
|
|
5958
6544
|
}, ms);
|
|
5959
6545
|
});
|
|
5960
6546
|
}
|
|
5961
6547
|
|
|
5962
|
-
// src/
|
|
5963
|
-
var
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
}
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
6548
|
+
// src/json_path.ts
|
|
6549
|
+
var LLMOutputPath = class {
|
|
6550
|
+
constructor(path = "/output") {
|
|
6551
|
+
this.path = path;
|
|
6552
|
+
}
|
|
6553
|
+
/** Select an output by index */
|
|
6554
|
+
index(i) {
|
|
6555
|
+
return new LLMOutputContentPath(`${this.path}/${i}`);
|
|
6556
|
+
}
|
|
6557
|
+
/** Shorthand for index(0).content(i) */
|
|
6558
|
+
content(i) {
|
|
6559
|
+
return this.index(0).content(i);
|
|
6560
|
+
}
|
|
6561
|
+
};
|
|
6562
|
+
var LLMOutputContentPath = class {
|
|
6563
|
+
constructor(path) {
|
|
6564
|
+
this.path = path;
|
|
6565
|
+
}
|
|
6566
|
+
/** Select a content item by index */
|
|
6567
|
+
content(i) {
|
|
6568
|
+
return new LLMOutputContentItemPath(`${this.path}/content/${i}`);
|
|
6569
|
+
}
|
|
6570
|
+
};
|
|
6571
|
+
var LLMOutputContentItemPath = class {
|
|
6572
|
+
constructor(path) {
|
|
6573
|
+
this.path = path;
|
|
6574
|
+
}
|
|
6575
|
+
/** Get the text field pointer */
|
|
6576
|
+
text() {
|
|
6577
|
+
return `${this.path}/text`;
|
|
6578
|
+
}
|
|
6579
|
+
/** Get the type field pointer */
|
|
6580
|
+
type() {
|
|
6581
|
+
return `${this.path}/type`;
|
|
6582
|
+
}
|
|
6583
|
+
/** Get the path as a string */
|
|
6584
|
+
toString() {
|
|
6585
|
+
return this.path;
|
|
6586
|
+
}
|
|
6587
|
+
};
|
|
6588
|
+
var LLMInputPath = class {
|
|
6589
|
+
constructor(path = "/input") {
|
|
6590
|
+
this.path = path;
|
|
6591
|
+
}
|
|
6592
|
+
/**
|
|
6593
|
+
* Select a message by index.
|
|
6594
|
+
* Index 0 is typically the system message, index 1 is the first user message.
|
|
6595
|
+
*/
|
|
6596
|
+
message(i) {
|
|
6597
|
+
return new LLMInputMessagePath(`${this.path}/${i}`);
|
|
6598
|
+
}
|
|
6599
|
+
/** Shorthand for message(0) - the first message slot */
|
|
6600
|
+
systemMessage() {
|
|
6601
|
+
return this.message(0);
|
|
6602
|
+
}
|
|
6603
|
+
/** Shorthand for message(1) - typically the user message after system */
|
|
6604
|
+
userMessage() {
|
|
6605
|
+
return this.message(1);
|
|
6606
|
+
}
|
|
6607
|
+
};
|
|
6608
|
+
var LLMInputMessagePath = class {
|
|
6609
|
+
constructor(path) {
|
|
6610
|
+
this.path = path;
|
|
6611
|
+
}
|
|
6612
|
+
/** Select a content item by index */
|
|
6613
|
+
content(i) {
|
|
6614
|
+
return new LLMInputContentItemPath(`${this.path}/content/${i}`);
|
|
6615
|
+
}
|
|
6616
|
+
/** Shorthand for content(0).text() */
|
|
6617
|
+
text() {
|
|
6618
|
+
return this.content(0).text();
|
|
6619
|
+
}
|
|
6620
|
+
};
|
|
6621
|
+
var LLMInputContentItemPath = class {
|
|
6622
|
+
constructor(path) {
|
|
6623
|
+
this.path = path;
|
|
6624
|
+
}
|
|
6625
|
+
/** Get the text field pointer */
|
|
6626
|
+
text() {
|
|
6627
|
+
return `${this.path}/text`;
|
|
6628
|
+
}
|
|
6629
|
+
/** Get the type field pointer */
|
|
6630
|
+
type() {
|
|
6631
|
+
return `${this.path}/type`;
|
|
6632
|
+
}
|
|
6633
|
+
/** Get the path as a string */
|
|
6634
|
+
toString() {
|
|
6635
|
+
return this.path;
|
|
6636
|
+
}
|
|
6637
|
+
};
|
|
6638
|
+
function LLMOutput() {
|
|
6639
|
+
return new LLMOutputPath();
|
|
6640
|
+
}
|
|
6641
|
+
function LLMInput() {
|
|
6642
|
+
return new LLMInputPath();
|
|
6643
|
+
}
|
|
6644
|
+
var LLMOutputText = LLMOutput().content(0).text();
|
|
6645
|
+
var LLMInputSystemText = LLMInput().systemMessage().text();
|
|
6646
|
+
var LLMInputUserText = LLMInput().userMessage().text();
|
|
6647
|
+
var LLMInputFirstMessageText = LLMInput().message(0).text();
|
|
6648
|
+
var JoinOutputPath = class {
|
|
6649
|
+
constructor(path) {
|
|
6650
|
+
this.path = path;
|
|
6651
|
+
}
|
|
6652
|
+
/** Access the output array of the node */
|
|
6653
|
+
output() {
|
|
6654
|
+
return new LLMOutputPath(`${this.path}/output`);
|
|
6655
|
+
}
|
|
6656
|
+
/**
|
|
6657
|
+
* Shorthand for accessing the first text content from the node.
|
|
6658
|
+
* Equivalent to: JoinOutput(nodeId).output().content(0).text()
|
|
6659
|
+
*/
|
|
6660
|
+
text() {
|
|
6661
|
+
return this.output().content(0).text();
|
|
6662
|
+
}
|
|
6663
|
+
/** Get the path as a string */
|
|
6664
|
+
toString() {
|
|
6665
|
+
return this.path;
|
|
6666
|
+
}
|
|
6667
|
+
};
|
|
6668
|
+
function JoinOutput(nodeId) {
|
|
6669
|
+
return new JoinOutputPath(`/${nodeId}`);
|
|
6670
|
+
}
|
|
6671
|
+
|
|
6672
|
+
// src/workflow_builder.ts
|
|
6673
|
+
var LLM_TEXT_OUTPUT = LLMOutputText;
|
|
6674
|
+
var LLM_USER_MESSAGE_TEXT = LLMInputUserText;
|
|
6675
|
+
function transformJSONValue(from, pointer) {
|
|
6676
|
+
return pointer ? { from, pointer } : { from };
|
|
6677
|
+
}
|
|
6678
|
+
function transformJSONObject(object) {
|
|
6679
|
+
return { object };
|
|
6680
|
+
}
|
|
6681
|
+
function transformJSONMerge(merge) {
|
|
6682
|
+
return { merge: merge.slice() };
|
|
6683
|
+
}
|
|
6684
|
+
var transformJSONValueV1 = transformJSONValue;
|
|
6685
|
+
var transformJSONObjectV1 = transformJSONObject;
|
|
6686
|
+
var transformJSONMergeV1 = transformJSONMerge;
|
|
6687
|
+
function wireRequest(req) {
|
|
6688
|
+
const raw = req;
|
|
6689
|
+
if (raw && typeof raw === "object") {
|
|
6690
|
+
if ("input" in raw) {
|
|
5978
6691
|
return req;
|
|
5979
6692
|
}
|
|
5980
6693
|
if ("body" in raw) {
|
|
@@ -5983,6 +6696,98 @@ function wireRequest(req) {
|
|
|
5983
6696
|
}
|
|
5984
6697
|
return asInternal(req).body;
|
|
5985
6698
|
}
|
|
6699
|
+
var INPUT_POINTER_PATTERN = /^\/input\/(\d+)(?:\/content\/(\d+))?/;
|
|
6700
|
+
var BindingTargetError = class extends Error {
|
|
6701
|
+
constructor(nodeId, bindingIndex, pointer, message) {
|
|
6702
|
+
super(`node "${nodeId}" binding ${bindingIndex}: ${message}`);
|
|
6703
|
+
this.name = "BindingTargetError";
|
|
6704
|
+
this.nodeId = nodeId;
|
|
6705
|
+
this.bindingIndex = bindingIndex;
|
|
6706
|
+
this.pointer = pointer;
|
|
6707
|
+
}
|
|
6708
|
+
};
|
|
6709
|
+
var MapFanoutInputError = class extends Error {
|
|
6710
|
+
constructor(nodeId, message) {
|
|
6711
|
+
super(`node "${nodeId}": ${message}`);
|
|
6712
|
+
this.name = "MapFanoutInputError";
|
|
6713
|
+
this.nodeId = nodeId;
|
|
6714
|
+
}
|
|
6715
|
+
};
|
|
6716
|
+
function validateBindingTargets(nodeId, input, bindings) {
|
|
6717
|
+
for (let i = 0; i < bindings.length; i++) {
|
|
6718
|
+
const binding = bindings[i];
|
|
6719
|
+
if (!binding.to) continue;
|
|
6720
|
+
const error = validateInputPointer(binding.to, input);
|
|
6721
|
+
if (error) {
|
|
6722
|
+
throw new BindingTargetError(nodeId, i, binding.to, error);
|
|
6723
|
+
}
|
|
6724
|
+
}
|
|
6725
|
+
}
|
|
6726
|
+
function validateInputPointer(pointer, input) {
|
|
6727
|
+
if (!pointer.startsWith("/input/")) {
|
|
6728
|
+
return void 0;
|
|
6729
|
+
}
|
|
6730
|
+
const match = pointer.match(INPUT_POINTER_PATTERN);
|
|
6731
|
+
if (!match) {
|
|
6732
|
+
return void 0;
|
|
6733
|
+
}
|
|
6734
|
+
const msgIndex = parseInt(match[1], 10);
|
|
6735
|
+
if (msgIndex >= input.length) {
|
|
6736
|
+
return `targets ${pointer} but request only has ${input.length} messages (indices 0-${input.length - 1}); add placeholder messages or adjust binding target`;
|
|
6737
|
+
}
|
|
6738
|
+
if (match[2] !== void 0) {
|
|
6739
|
+
const contentIndex = parseInt(match[2], 10);
|
|
6740
|
+
const msg = input[msgIndex];
|
|
6741
|
+
if (contentIndex >= msg.content.length) {
|
|
6742
|
+
return `targets ${pointer} but message ${msgIndex} only has ${msg.content.length} content blocks (indices 0-${msg.content.length - 1})`;
|
|
6743
|
+
}
|
|
6744
|
+
}
|
|
6745
|
+
return void 0;
|
|
6746
|
+
}
|
|
6747
|
+
function validateMapFanoutInput(nodeId, input) {
|
|
6748
|
+
const subnode = input.subnode;
|
|
6749
|
+
if ((subnode.type === WorkflowNodeTypesV1.LLMResponses || subnode.type === WorkflowNodeTypesV1.RouteSwitch) && subnode.input.bindings && subnode.input.bindings.length > 0) {
|
|
6750
|
+
throw new MapFanoutInputError(nodeId, "map.fanout subnode bindings are not allowed");
|
|
6751
|
+
}
|
|
6752
|
+
if (subnode.type !== WorkflowNodeTypesV1.TransformJSON) {
|
|
6753
|
+
return;
|
|
6754
|
+
}
|
|
6755
|
+
if (input.item_bindings && input.item_bindings.length > 0) {
|
|
6756
|
+
throw new MapFanoutInputError(
|
|
6757
|
+
nodeId,
|
|
6758
|
+
"map.fanout transform.json subnode cannot use item_bindings"
|
|
6759
|
+
);
|
|
6760
|
+
}
|
|
6761
|
+
const hasObject = !!subnode.input.object && Object.keys(subnode.input.object).length > 0;
|
|
6762
|
+
const hasMerge = !!subnode.input.merge && subnode.input.merge.length > 0;
|
|
6763
|
+
if (hasObject === hasMerge) {
|
|
6764
|
+
throw new MapFanoutInputError(
|
|
6765
|
+
nodeId,
|
|
6766
|
+
"map.fanout transform.json must provide exactly one of object or merge"
|
|
6767
|
+
);
|
|
6768
|
+
}
|
|
6769
|
+
if (hasObject) {
|
|
6770
|
+
for (const [key, value] of Object.entries(subnode.input.object ?? {})) {
|
|
6771
|
+
if (!key.trim()) continue;
|
|
6772
|
+
if (String(value.from) !== "item") {
|
|
6773
|
+
throw new MapFanoutInputError(
|
|
6774
|
+
nodeId,
|
|
6775
|
+
`map.fanout transform.json object.${key}.from must be "item"`
|
|
6776
|
+
);
|
|
6777
|
+
}
|
|
6778
|
+
}
|
|
6779
|
+
}
|
|
6780
|
+
if (hasMerge) {
|
|
6781
|
+
for (const [index, value] of (subnode.input.merge ?? []).entries()) {
|
|
6782
|
+
if (String(value.from) !== "item") {
|
|
6783
|
+
throw new MapFanoutInputError(
|
|
6784
|
+
nodeId,
|
|
6785
|
+
`map.fanout transform.json merge[${index}].from must be "item"`
|
|
6786
|
+
);
|
|
6787
|
+
}
|
|
6788
|
+
}
|
|
6789
|
+
}
|
|
6790
|
+
}
|
|
5986
6791
|
var WorkflowBuilderV0 = class _WorkflowBuilderV0 {
|
|
5987
6792
|
constructor(state = { nodes: [], edges: [], outputs: [] }) {
|
|
5988
6793
|
this.state = state;
|
|
@@ -6006,8 +6811,12 @@ var WorkflowBuilderV0 = class _WorkflowBuilderV0 {
|
|
|
6006
6811
|
return this.with({ nodes: [...this.state.nodes, node] });
|
|
6007
6812
|
}
|
|
6008
6813
|
llmResponses(id, request, options = {}) {
|
|
6814
|
+
const wiredRequest = wireRequest(request);
|
|
6815
|
+
if (options.bindings) {
|
|
6816
|
+
validateBindingTargets(id, wiredRequest.input, options.bindings);
|
|
6817
|
+
}
|
|
6009
6818
|
const input = {
|
|
6010
|
-
request:
|
|
6819
|
+
request: wiredRequest,
|
|
6011
6820
|
...options.stream === void 0 ? {} : { stream: options.stream },
|
|
6012
6821
|
...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
|
|
6013
6822
|
...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
|
|
@@ -6076,6 +6885,141 @@ var WorkflowBuilderV0 = class _WorkflowBuilderV0 {
|
|
|
6076
6885
|
function workflowV0() {
|
|
6077
6886
|
return WorkflowBuilderV0.new();
|
|
6078
6887
|
}
|
|
6888
|
+
var WorkflowBuilderV1 = class _WorkflowBuilderV1 {
|
|
6889
|
+
constructor(state = { nodes: [], edges: [], outputs: [] }) {
|
|
6890
|
+
this.state = state;
|
|
6891
|
+
}
|
|
6892
|
+
static new() {
|
|
6893
|
+
return new _WorkflowBuilderV1();
|
|
6894
|
+
}
|
|
6895
|
+
with(patch) {
|
|
6896
|
+
return new _WorkflowBuilderV1({
|
|
6897
|
+
...this.state,
|
|
6898
|
+
...patch
|
|
6899
|
+
});
|
|
6900
|
+
}
|
|
6901
|
+
name(name) {
|
|
6902
|
+
return this.with({ name: name.trim() || void 0 });
|
|
6903
|
+
}
|
|
6904
|
+
execution(execution) {
|
|
6905
|
+
return this.with({ execution });
|
|
6906
|
+
}
|
|
6907
|
+
node(node) {
|
|
6908
|
+
return this.with({ nodes: [...this.state.nodes, node] });
|
|
6909
|
+
}
|
|
6910
|
+
llmResponses(id, request, options = {}) {
|
|
6911
|
+
const wiredRequest = wireRequest(request);
|
|
6912
|
+
if (options.bindings) {
|
|
6913
|
+
validateBindingTargets(id, wiredRequest.input, options.bindings);
|
|
6914
|
+
}
|
|
6915
|
+
const input = {
|
|
6916
|
+
request: wiredRequest,
|
|
6917
|
+
...options.stream === void 0 ? {} : { stream: options.stream },
|
|
6918
|
+
...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
|
|
6919
|
+
...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
|
|
6920
|
+
...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
|
|
6921
|
+
};
|
|
6922
|
+
return this.node({
|
|
6923
|
+
id,
|
|
6924
|
+
type: WorkflowNodeTypesV1.LLMResponses,
|
|
6925
|
+
input
|
|
6926
|
+
});
|
|
6927
|
+
}
|
|
6928
|
+
routeSwitch(id, request, options = {}) {
|
|
6929
|
+
const wiredRequest = wireRequest(request);
|
|
6930
|
+
if (options.bindings) {
|
|
6931
|
+
validateBindingTargets(id, wiredRequest.input, options.bindings);
|
|
6932
|
+
}
|
|
6933
|
+
const input = {
|
|
6934
|
+
request: wiredRequest,
|
|
6935
|
+
...options.stream === void 0 ? {} : { stream: options.stream },
|
|
6936
|
+
...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
|
|
6937
|
+
...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
|
|
6938
|
+
...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
|
|
6939
|
+
};
|
|
6940
|
+
return this.node({
|
|
6941
|
+
id,
|
|
6942
|
+
type: WorkflowNodeTypesV1.RouteSwitch,
|
|
6943
|
+
input
|
|
6944
|
+
});
|
|
6945
|
+
}
|
|
6946
|
+
joinAll(id) {
|
|
6947
|
+
return this.node({ id, type: WorkflowNodeTypesV1.JoinAll });
|
|
6948
|
+
}
|
|
6949
|
+
joinAny(id, input) {
|
|
6950
|
+
return this.node({
|
|
6951
|
+
id,
|
|
6952
|
+
type: WorkflowNodeTypesV1.JoinAny,
|
|
6953
|
+
...input ? { input } : {}
|
|
6954
|
+
});
|
|
6955
|
+
}
|
|
6956
|
+
joinCollect(id, input) {
|
|
6957
|
+
return this.node({ id, type: WorkflowNodeTypesV1.JoinCollect, input });
|
|
6958
|
+
}
|
|
6959
|
+
transformJSON(id, input) {
|
|
6960
|
+
return this.node({ id, type: WorkflowNodeTypesV1.TransformJSON, input });
|
|
6961
|
+
}
|
|
6962
|
+
mapFanout(id, input) {
|
|
6963
|
+
validateMapFanoutInput(id, input);
|
|
6964
|
+
return this.node({ id, type: WorkflowNodeTypesV1.MapFanout, input });
|
|
6965
|
+
}
|
|
6966
|
+
edge(from, to, when) {
|
|
6967
|
+
return this.with({
|
|
6968
|
+
edges: [...this.state.edges, { from, to, ...when ? { when } : {} }]
|
|
6969
|
+
});
|
|
6970
|
+
}
|
|
6971
|
+
output(name, from, pointer) {
|
|
6972
|
+
return this.with({
|
|
6973
|
+
outputs: [
|
|
6974
|
+
...this.state.outputs,
|
|
6975
|
+
{ name, from, ...pointer ? { pointer } : {} }
|
|
6976
|
+
]
|
|
6977
|
+
});
|
|
6978
|
+
}
|
|
6979
|
+
build() {
|
|
6980
|
+
const edges = this.state.edges.slice().sort((a, b) => {
|
|
6981
|
+
const af = String(a.from);
|
|
6982
|
+
const bf = String(b.from);
|
|
6983
|
+
if (af < bf) return -1;
|
|
6984
|
+
if (af > bf) return 1;
|
|
6985
|
+
const at = String(a.to);
|
|
6986
|
+
const bt = String(b.to);
|
|
6987
|
+
if (at < bt) return -1;
|
|
6988
|
+
if (at > bt) return 1;
|
|
6989
|
+
const aw = a.when ? JSON.stringify(a.when) : "";
|
|
6990
|
+
const bw = b.when ? JSON.stringify(b.when) : "";
|
|
6991
|
+
if (aw < bw) return -1;
|
|
6992
|
+
if (aw > bw) return 1;
|
|
6993
|
+
return 0;
|
|
6994
|
+
});
|
|
6995
|
+
const outputs = this.state.outputs.slice().sort((a, b) => {
|
|
6996
|
+
const an = String(a.name);
|
|
6997
|
+
const bn = String(b.name);
|
|
6998
|
+
if (an < bn) return -1;
|
|
6999
|
+
if (an > bn) return 1;
|
|
7000
|
+
const af = String(a.from);
|
|
7001
|
+
const bf = String(b.from);
|
|
7002
|
+
if (af < bf) return -1;
|
|
7003
|
+
if (af > bf) return 1;
|
|
7004
|
+
const ap = a.pointer ?? "";
|
|
7005
|
+
const bp = b.pointer ?? "";
|
|
7006
|
+
if (ap < bp) return -1;
|
|
7007
|
+
if (ap > bp) return 1;
|
|
7008
|
+
return 0;
|
|
7009
|
+
});
|
|
7010
|
+
return {
|
|
7011
|
+
kind: WorkflowKinds.WorkflowV1,
|
|
7012
|
+
...this.state.name ? { name: this.state.name } : {},
|
|
7013
|
+
...this.state.execution ? { execution: this.state.execution } : {},
|
|
7014
|
+
nodes: this.state.nodes.slice(),
|
|
7015
|
+
...edges.length ? { edges } : {},
|
|
7016
|
+
outputs
|
|
7017
|
+
};
|
|
7018
|
+
}
|
|
7019
|
+
};
|
|
7020
|
+
function workflowV1() {
|
|
7021
|
+
return WorkflowBuilderV1.new();
|
|
7022
|
+
}
|
|
6079
7023
|
var Workflow = class _Workflow {
|
|
6080
7024
|
constructor(name) {
|
|
6081
7025
|
this._nodes = [];
|
|
@@ -6208,6 +7152,9 @@ var Workflow = class _Workflow {
|
|
|
6208
7152
|
const pending = this._pendingNode;
|
|
6209
7153
|
if (!pending) return;
|
|
6210
7154
|
this._pendingNode = null;
|
|
7155
|
+
if (pending.bindings.length > 0) {
|
|
7156
|
+
validateBindingTargets(pending.id, pending.request.input, pending.bindings);
|
|
7157
|
+
}
|
|
6211
7158
|
const input = {
|
|
6212
7159
|
id: pending.id,
|
|
6213
7160
|
type: WorkflowNodeTypes.LLMResponses,
|
|
@@ -6271,6 +7218,31 @@ var LLMNodeBuilder = class {
|
|
|
6271
7218
|
}
|
|
6272
7219
|
return this;
|
|
6273
7220
|
}
|
|
7221
|
+
/**
|
|
7222
|
+
* Add a binding that replaces a {{placeholder}} in the prompt text.
|
|
7223
|
+
* This is useful when the prompt contains placeholder markers like {{tier_data}}.
|
|
7224
|
+
* The edge from the source node is automatically inferred.
|
|
7225
|
+
*/
|
|
7226
|
+
bindToPlaceholder(from, fromPointer, placeholder) {
|
|
7227
|
+
const pending = this.workflow._getPendingNode();
|
|
7228
|
+
if (pending) {
|
|
7229
|
+
pending.bindings.push({
|
|
7230
|
+
from,
|
|
7231
|
+
...fromPointer ? { pointer: fromPointer } : {},
|
|
7232
|
+
to_placeholder: placeholder,
|
|
7233
|
+
encoding: "json_string"
|
|
7234
|
+
});
|
|
7235
|
+
}
|
|
7236
|
+
return this;
|
|
7237
|
+
}
|
|
7238
|
+
/**
|
|
7239
|
+
* Add a binding from an LLM node's text output to a placeholder.
|
|
7240
|
+
* This is the most common placeholder binding: LLM text → {{placeholder}}.
|
|
7241
|
+
* The edge from the source node is automatically inferred.
|
|
7242
|
+
*/
|
|
7243
|
+
bindTextToPlaceholder(from, placeholder) {
|
|
7244
|
+
return this.bindToPlaceholder(from, LLM_TEXT_OUTPUT, placeholder);
|
|
7245
|
+
}
|
|
6274
7246
|
/**
|
|
6275
7247
|
* Set the tool execution mode (server or client).
|
|
6276
7248
|
*/
|
|
@@ -6412,6 +7384,18 @@ var workflow_v0_schema_default = {
|
|
|
6412
7384
|
},
|
|
6413
7385
|
llmResponsesBinding: {
|
|
6414
7386
|
additionalProperties: false,
|
|
7387
|
+
oneOf: [
|
|
7388
|
+
{
|
|
7389
|
+
required: [
|
|
7390
|
+
"to"
|
|
7391
|
+
]
|
|
7392
|
+
},
|
|
7393
|
+
{
|
|
7394
|
+
required: [
|
|
7395
|
+
"to_placeholder"
|
|
7396
|
+
]
|
|
7397
|
+
}
|
|
7398
|
+
],
|
|
6415
7399
|
properties: {
|
|
6416
7400
|
encoding: {
|
|
6417
7401
|
enum: [
|
|
@@ -6431,11 +7415,14 @@ var workflow_v0_schema_default = {
|
|
|
6431
7415
|
to: {
|
|
6432
7416
|
pattern: "^/.*$",
|
|
6433
7417
|
type: "string"
|
|
7418
|
+
},
|
|
7419
|
+
to_placeholder: {
|
|
7420
|
+
minLength: 1,
|
|
7421
|
+
type: "string"
|
|
6434
7422
|
}
|
|
6435
7423
|
},
|
|
6436
7424
|
required: [
|
|
6437
|
-
"from"
|
|
6438
|
-
"to"
|
|
7425
|
+
"from"
|
|
6439
7426
|
],
|
|
6440
7427
|
type: "object"
|
|
6441
7428
|
},
|
|
@@ -6702,41 +7689,808 @@ var workflow_v0_schema_default = {
|
|
|
6702
7689
|
type: "object"
|
|
6703
7690
|
};
|
|
6704
7691
|
|
|
6705
|
-
// src/
|
|
6706
|
-
var
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
}
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
7692
|
+
// src/workflow_v1.schema.json
|
|
7693
|
+
var workflow_v1_schema_default = {
|
|
7694
|
+
$id: "https://modelrelay.ai/schemas/workflow_v1.schema.json",
|
|
7695
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
7696
|
+
additionalProperties: false,
|
|
7697
|
+
definitions: {
|
|
7698
|
+
condition: {
|
|
7699
|
+
additionalProperties: false,
|
|
7700
|
+
properties: {
|
|
7701
|
+
op: {
|
|
7702
|
+
enum: [
|
|
7703
|
+
"equals",
|
|
7704
|
+
"matches",
|
|
7705
|
+
"exists"
|
|
7706
|
+
],
|
|
7707
|
+
type: "string"
|
|
7708
|
+
},
|
|
7709
|
+
path: {
|
|
7710
|
+
pattern: "^\\$.*$",
|
|
7711
|
+
type: "string"
|
|
7712
|
+
},
|
|
7713
|
+
source: {
|
|
7714
|
+
enum: [
|
|
7715
|
+
"node_output",
|
|
7716
|
+
"node_status"
|
|
7717
|
+
],
|
|
7718
|
+
type: "string"
|
|
7719
|
+
},
|
|
7720
|
+
value: {}
|
|
7721
|
+
},
|
|
7722
|
+
required: [
|
|
7723
|
+
"source",
|
|
7724
|
+
"op"
|
|
7725
|
+
],
|
|
7726
|
+
type: "object"
|
|
7727
|
+
},
|
|
7728
|
+
edge: {
|
|
7729
|
+
additionalProperties: false,
|
|
7730
|
+
properties: {
|
|
7731
|
+
from: {
|
|
7732
|
+
minLength: 1,
|
|
7733
|
+
type: "string"
|
|
7734
|
+
},
|
|
7735
|
+
to: {
|
|
7736
|
+
minLength: 1,
|
|
7737
|
+
type: "string"
|
|
7738
|
+
},
|
|
7739
|
+
when: {
|
|
7740
|
+
$ref: "#/definitions/condition"
|
|
7741
|
+
}
|
|
7742
|
+
},
|
|
7743
|
+
required: [
|
|
7744
|
+
"from",
|
|
7745
|
+
"to"
|
|
7746
|
+
],
|
|
7747
|
+
type: "object"
|
|
7748
|
+
},
|
|
7749
|
+
fragmentBindInput: {
|
|
7750
|
+
additionalProperties: false,
|
|
7751
|
+
oneOf: [
|
|
7752
|
+
{
|
|
7753
|
+
required: [
|
|
7754
|
+
"from_node"
|
|
7755
|
+
]
|
|
7756
|
+
},
|
|
7757
|
+
{
|
|
7758
|
+
required: [
|
|
7759
|
+
"from_input"
|
|
7760
|
+
]
|
|
7761
|
+
}
|
|
7762
|
+
],
|
|
7763
|
+
properties: {
|
|
7764
|
+
from_input: {
|
|
7765
|
+
minLength: 1,
|
|
7766
|
+
type: "string"
|
|
7767
|
+
},
|
|
7768
|
+
from_node: {
|
|
7769
|
+
minLength: 1,
|
|
7770
|
+
type: "string"
|
|
7771
|
+
},
|
|
7772
|
+
pointer: {
|
|
7773
|
+
pattern: "^(/.*)?$",
|
|
7774
|
+
type: "string"
|
|
7775
|
+
}
|
|
7776
|
+
},
|
|
7777
|
+
type: "object"
|
|
7778
|
+
},
|
|
7779
|
+
fragmentDef: {
|
|
7780
|
+
additionalProperties: false,
|
|
7781
|
+
properties: {
|
|
7782
|
+
edges: {
|
|
7783
|
+
items: {
|
|
7784
|
+
$ref: "#/definitions/edge"
|
|
7785
|
+
},
|
|
7786
|
+
type: "array"
|
|
7787
|
+
},
|
|
7788
|
+
inputs: {
|
|
7789
|
+
items: {
|
|
7790
|
+
$ref: "#/definitions/fragmentInput"
|
|
7791
|
+
},
|
|
7792
|
+
type: "array"
|
|
7793
|
+
},
|
|
7794
|
+
nodes: {
|
|
7795
|
+
items: {
|
|
7796
|
+
$ref: "#/definitions/node"
|
|
7797
|
+
},
|
|
7798
|
+
minItems: 1,
|
|
7799
|
+
type: "array"
|
|
7800
|
+
},
|
|
7801
|
+
outputs: {
|
|
7802
|
+
items: {
|
|
7803
|
+
$ref: "#/definitions/fragmentOutput"
|
|
7804
|
+
},
|
|
7805
|
+
minItems: 1,
|
|
7806
|
+
type: "array"
|
|
7807
|
+
}
|
|
7808
|
+
},
|
|
7809
|
+
required: [
|
|
7810
|
+
"outputs",
|
|
7811
|
+
"nodes"
|
|
7812
|
+
],
|
|
7813
|
+
type: "object"
|
|
7814
|
+
},
|
|
7815
|
+
fragmentInput: {
|
|
7816
|
+
additionalProperties: false,
|
|
7817
|
+
properties: {
|
|
7818
|
+
name: {
|
|
7819
|
+
minLength: 1,
|
|
7820
|
+
type: "string"
|
|
7821
|
+
},
|
|
7822
|
+
type: {
|
|
7823
|
+
type: "string"
|
|
7824
|
+
}
|
|
7825
|
+
},
|
|
7826
|
+
required: [
|
|
7827
|
+
"name"
|
|
7828
|
+
],
|
|
7829
|
+
type: "object"
|
|
7830
|
+
},
|
|
7831
|
+
fragmentOutput: {
|
|
7832
|
+
additionalProperties: false,
|
|
7833
|
+
properties: {
|
|
7834
|
+
from_node: {
|
|
7835
|
+
minLength: 1,
|
|
7836
|
+
type: "string"
|
|
7837
|
+
},
|
|
7838
|
+
name: {
|
|
7839
|
+
minLength: 1,
|
|
7840
|
+
type: "string"
|
|
7841
|
+
},
|
|
7842
|
+
pointer: {
|
|
7843
|
+
pattern: "^(/.*)?$",
|
|
7844
|
+
type: "string"
|
|
7845
|
+
}
|
|
7846
|
+
},
|
|
7847
|
+
required: [
|
|
7848
|
+
"name",
|
|
7849
|
+
"from_node"
|
|
7850
|
+
],
|
|
7851
|
+
type: "object"
|
|
7852
|
+
},
|
|
7853
|
+
llmResponsesBinding: {
|
|
7854
|
+
additionalProperties: false,
|
|
7855
|
+
oneOf: [
|
|
7856
|
+
{
|
|
7857
|
+
required: [
|
|
7858
|
+
"to"
|
|
7859
|
+
]
|
|
7860
|
+
},
|
|
7861
|
+
{
|
|
7862
|
+
required: [
|
|
7863
|
+
"to_placeholder"
|
|
7864
|
+
]
|
|
7865
|
+
}
|
|
7866
|
+
],
|
|
7867
|
+
properties: {
|
|
7868
|
+
encoding: {
|
|
7869
|
+
enum: [
|
|
7870
|
+
"json",
|
|
7871
|
+
"json_string"
|
|
7872
|
+
],
|
|
7873
|
+
type: "string"
|
|
7874
|
+
},
|
|
7875
|
+
from: {
|
|
7876
|
+
minLength: 1,
|
|
7877
|
+
type: "string"
|
|
7878
|
+
},
|
|
7879
|
+
pointer: {
|
|
7880
|
+
pattern: "^(/.*)?$",
|
|
7881
|
+
type: "string"
|
|
7882
|
+
},
|
|
7883
|
+
to: {
|
|
7884
|
+
pattern: "^/.*$",
|
|
7885
|
+
type: "string"
|
|
7886
|
+
},
|
|
7887
|
+
to_placeholder: {
|
|
7888
|
+
minLength: 1,
|
|
7889
|
+
type: "string"
|
|
7890
|
+
}
|
|
7891
|
+
},
|
|
7892
|
+
required: [
|
|
7893
|
+
"from"
|
|
7894
|
+
],
|
|
7895
|
+
type: "object"
|
|
7896
|
+
},
|
|
7897
|
+
mapFanoutItemBinding: {
|
|
7898
|
+
additionalProperties: false,
|
|
7899
|
+
oneOf: [
|
|
7900
|
+
{
|
|
7901
|
+
required: [
|
|
7902
|
+
"to"
|
|
7903
|
+
]
|
|
7904
|
+
},
|
|
7905
|
+
{
|
|
7906
|
+
required: [
|
|
7907
|
+
"to_placeholder"
|
|
7908
|
+
]
|
|
7909
|
+
}
|
|
7910
|
+
],
|
|
7911
|
+
properties: {
|
|
7912
|
+
encoding: {
|
|
7913
|
+
enum: [
|
|
7914
|
+
"json",
|
|
7915
|
+
"json_string"
|
|
7916
|
+
],
|
|
7917
|
+
type: "string"
|
|
7918
|
+
},
|
|
7919
|
+
path: {
|
|
7920
|
+
pattern: "^(/.*)?$",
|
|
7921
|
+
type: "string"
|
|
7922
|
+
},
|
|
7923
|
+
to: {
|
|
7924
|
+
pattern: "^/.*$",
|
|
7925
|
+
type: "string"
|
|
7926
|
+
},
|
|
7927
|
+
to_placeholder: {
|
|
7928
|
+
minLength: 1,
|
|
7929
|
+
type: "string"
|
|
7930
|
+
}
|
|
7931
|
+
},
|
|
7932
|
+
type: "object"
|
|
7933
|
+
},
|
|
7934
|
+
node: {
|
|
7935
|
+
additionalProperties: false,
|
|
7936
|
+
oneOf: [
|
|
7937
|
+
{
|
|
7938
|
+
allOf: [
|
|
7939
|
+
{
|
|
7940
|
+
properties: {
|
|
7941
|
+
input: {
|
|
7942
|
+
properties: {
|
|
7943
|
+
bindings: {
|
|
7944
|
+
items: {
|
|
7945
|
+
$ref: "#/definitions/llmResponsesBinding"
|
|
7946
|
+
},
|
|
7947
|
+
type: "array"
|
|
7948
|
+
},
|
|
7949
|
+
request: {
|
|
7950
|
+
type: "object"
|
|
7951
|
+
},
|
|
7952
|
+
stream: {
|
|
7953
|
+
type: "boolean"
|
|
7954
|
+
},
|
|
7955
|
+
tool_execution: {
|
|
7956
|
+
additionalProperties: false,
|
|
7957
|
+
properties: {
|
|
7958
|
+
mode: {
|
|
7959
|
+
default: "server",
|
|
7960
|
+
enum: [
|
|
7961
|
+
"server",
|
|
7962
|
+
"client"
|
|
7963
|
+
],
|
|
7964
|
+
type: "string"
|
|
7965
|
+
}
|
|
7966
|
+
},
|
|
7967
|
+
required: [
|
|
7968
|
+
"mode"
|
|
7969
|
+
],
|
|
7970
|
+
type: "object"
|
|
7971
|
+
},
|
|
7972
|
+
tool_limits: {
|
|
7973
|
+
additionalProperties: false,
|
|
7974
|
+
properties: {
|
|
7975
|
+
max_llm_calls: {
|
|
7976
|
+
default: 8,
|
|
7977
|
+
maximum: 64,
|
|
7978
|
+
minimum: 1,
|
|
7979
|
+
type: "integer"
|
|
7980
|
+
},
|
|
7981
|
+
max_tool_calls_per_step: {
|
|
7982
|
+
default: 16,
|
|
7983
|
+
maximum: 64,
|
|
7984
|
+
minimum: 1,
|
|
7985
|
+
type: "integer"
|
|
7986
|
+
},
|
|
7987
|
+
wait_ttl_ms: {
|
|
7988
|
+
default: 9e5,
|
|
7989
|
+
maximum: 864e5,
|
|
7990
|
+
minimum: 1,
|
|
7991
|
+
type: "integer"
|
|
7992
|
+
}
|
|
7993
|
+
},
|
|
7994
|
+
type: "object"
|
|
7995
|
+
}
|
|
7996
|
+
},
|
|
7997
|
+
required: [
|
|
7998
|
+
"request"
|
|
7999
|
+
],
|
|
8000
|
+
type: "object"
|
|
8001
|
+
}
|
|
8002
|
+
}
|
|
8003
|
+
}
|
|
8004
|
+
],
|
|
8005
|
+
properties: {
|
|
8006
|
+
type: {
|
|
8007
|
+
const: "llm.responses"
|
|
8008
|
+
}
|
|
8009
|
+
},
|
|
8010
|
+
required: [
|
|
8011
|
+
"input"
|
|
8012
|
+
]
|
|
8013
|
+
},
|
|
8014
|
+
{
|
|
8015
|
+
allOf: [
|
|
8016
|
+
{
|
|
8017
|
+
properties: {
|
|
8018
|
+
input: {
|
|
8019
|
+
properties: {
|
|
8020
|
+
bindings: {
|
|
8021
|
+
items: {
|
|
8022
|
+
$ref: "#/definitions/llmResponsesBinding"
|
|
8023
|
+
},
|
|
8024
|
+
type: "array"
|
|
8025
|
+
},
|
|
8026
|
+
request: {
|
|
8027
|
+
type: "object"
|
|
8028
|
+
},
|
|
8029
|
+
stream: {
|
|
8030
|
+
type: "boolean"
|
|
8031
|
+
},
|
|
8032
|
+
tool_execution: {
|
|
8033
|
+
additionalProperties: false,
|
|
8034
|
+
properties: {
|
|
8035
|
+
mode: {
|
|
8036
|
+
default: "server",
|
|
8037
|
+
enum: [
|
|
8038
|
+
"server",
|
|
8039
|
+
"client"
|
|
8040
|
+
],
|
|
8041
|
+
type: "string"
|
|
8042
|
+
}
|
|
8043
|
+
},
|
|
8044
|
+
required: [
|
|
8045
|
+
"mode"
|
|
8046
|
+
],
|
|
8047
|
+
type: "object"
|
|
8048
|
+
},
|
|
8049
|
+
tool_limits: {
|
|
8050
|
+
additionalProperties: false,
|
|
8051
|
+
properties: {
|
|
8052
|
+
max_llm_calls: {
|
|
8053
|
+
default: 8,
|
|
8054
|
+
maximum: 64,
|
|
8055
|
+
minimum: 1,
|
|
8056
|
+
type: "integer"
|
|
8057
|
+
},
|
|
8058
|
+
max_tool_calls_per_step: {
|
|
8059
|
+
default: 16,
|
|
8060
|
+
maximum: 64,
|
|
8061
|
+
minimum: 1,
|
|
8062
|
+
type: "integer"
|
|
8063
|
+
},
|
|
8064
|
+
wait_ttl_ms: {
|
|
8065
|
+
default: 9e5,
|
|
8066
|
+
maximum: 864e5,
|
|
8067
|
+
minimum: 1,
|
|
8068
|
+
type: "integer"
|
|
8069
|
+
}
|
|
8070
|
+
},
|
|
8071
|
+
type: "object"
|
|
8072
|
+
}
|
|
8073
|
+
},
|
|
8074
|
+
required: [
|
|
8075
|
+
"request"
|
|
8076
|
+
],
|
|
8077
|
+
type: "object"
|
|
8078
|
+
}
|
|
8079
|
+
}
|
|
8080
|
+
}
|
|
8081
|
+
],
|
|
8082
|
+
properties: {
|
|
8083
|
+
type: {
|
|
8084
|
+
const: "route.switch"
|
|
8085
|
+
}
|
|
8086
|
+
},
|
|
8087
|
+
required: [
|
|
8088
|
+
"input"
|
|
8089
|
+
]
|
|
8090
|
+
},
|
|
8091
|
+
{
|
|
8092
|
+
properties: {
|
|
8093
|
+
type: {
|
|
8094
|
+
const: "join.all"
|
|
8095
|
+
}
|
|
8096
|
+
}
|
|
8097
|
+
},
|
|
8098
|
+
{
|
|
8099
|
+
allOf: [
|
|
8100
|
+
{
|
|
8101
|
+
properties: {
|
|
8102
|
+
input: {
|
|
8103
|
+
additionalProperties: false,
|
|
8104
|
+
properties: {
|
|
8105
|
+
predicate: {
|
|
8106
|
+
$ref: "#/definitions/condition"
|
|
8107
|
+
}
|
|
8108
|
+
},
|
|
8109
|
+
type: "object"
|
|
8110
|
+
}
|
|
8111
|
+
}
|
|
8112
|
+
}
|
|
8113
|
+
],
|
|
8114
|
+
properties: {
|
|
8115
|
+
type: {
|
|
8116
|
+
const: "join.any"
|
|
8117
|
+
}
|
|
8118
|
+
}
|
|
8119
|
+
},
|
|
8120
|
+
{
|
|
8121
|
+
allOf: [
|
|
8122
|
+
{
|
|
8123
|
+
properties: {
|
|
8124
|
+
input: {
|
|
8125
|
+
additionalProperties: false,
|
|
8126
|
+
properties: {
|
|
8127
|
+
limit: {
|
|
8128
|
+
minimum: 1,
|
|
8129
|
+
type: "integer"
|
|
8130
|
+
},
|
|
8131
|
+
predicate: {
|
|
8132
|
+
$ref: "#/definitions/condition"
|
|
8133
|
+
},
|
|
8134
|
+
timeout_ms: {
|
|
8135
|
+
minimum: 1,
|
|
8136
|
+
type: "integer"
|
|
8137
|
+
}
|
|
8138
|
+
},
|
|
8139
|
+
type: "object"
|
|
8140
|
+
}
|
|
8141
|
+
}
|
|
8142
|
+
}
|
|
8143
|
+
],
|
|
8144
|
+
properties: {
|
|
8145
|
+
type: {
|
|
8146
|
+
const: "join.collect"
|
|
8147
|
+
}
|
|
8148
|
+
},
|
|
8149
|
+
required: [
|
|
8150
|
+
"input"
|
|
8151
|
+
]
|
|
8152
|
+
},
|
|
8153
|
+
{
|
|
8154
|
+
allOf: [
|
|
8155
|
+
{
|
|
8156
|
+
properties: {
|
|
8157
|
+
input: {
|
|
8158
|
+
additionalProperties: false,
|
|
8159
|
+
oneOf: [
|
|
8160
|
+
{
|
|
8161
|
+
not: {
|
|
8162
|
+
required: [
|
|
8163
|
+
"merge"
|
|
8164
|
+
]
|
|
8165
|
+
},
|
|
8166
|
+
required: [
|
|
8167
|
+
"object"
|
|
8168
|
+
]
|
|
8169
|
+
},
|
|
8170
|
+
{
|
|
8171
|
+
not: {
|
|
8172
|
+
required: [
|
|
8173
|
+
"object"
|
|
8174
|
+
]
|
|
8175
|
+
},
|
|
8176
|
+
required: [
|
|
8177
|
+
"merge"
|
|
8178
|
+
]
|
|
8179
|
+
}
|
|
8180
|
+
],
|
|
8181
|
+
properties: {
|
|
8182
|
+
merge: {
|
|
8183
|
+
items: {
|
|
8184
|
+
$ref: "#/definitions/transformValue"
|
|
8185
|
+
},
|
|
8186
|
+
minItems: 1,
|
|
8187
|
+
type: "array"
|
|
8188
|
+
},
|
|
8189
|
+
object: {
|
|
8190
|
+
additionalProperties: {
|
|
8191
|
+
$ref: "#/definitions/transformValue"
|
|
8192
|
+
},
|
|
8193
|
+
minProperties: 1,
|
|
8194
|
+
type: "object"
|
|
8195
|
+
}
|
|
8196
|
+
},
|
|
8197
|
+
type: "object"
|
|
8198
|
+
}
|
|
8199
|
+
}
|
|
8200
|
+
}
|
|
8201
|
+
],
|
|
8202
|
+
properties: {
|
|
8203
|
+
type: {
|
|
8204
|
+
const: "transform.json"
|
|
8205
|
+
}
|
|
8206
|
+
},
|
|
8207
|
+
required: [
|
|
8208
|
+
"input"
|
|
8209
|
+
]
|
|
8210
|
+
},
|
|
8211
|
+
{
|
|
8212
|
+
allOf: [
|
|
8213
|
+
{
|
|
8214
|
+
properties: {
|
|
8215
|
+
input: {
|
|
8216
|
+
additionalProperties: false,
|
|
8217
|
+
properties: {
|
|
8218
|
+
item_bindings: {
|
|
8219
|
+
items: {
|
|
8220
|
+
$ref: "#/definitions/mapFanoutItemBinding"
|
|
8221
|
+
},
|
|
8222
|
+
type: "array"
|
|
8223
|
+
},
|
|
8224
|
+
items: {
|
|
8225
|
+
additionalProperties: false,
|
|
8226
|
+
properties: {
|
|
8227
|
+
from: {
|
|
8228
|
+
minLength: 1,
|
|
8229
|
+
type: "string"
|
|
8230
|
+
},
|
|
8231
|
+
path: {
|
|
8232
|
+
pattern: "^(/.*)?$",
|
|
8233
|
+
type: "string"
|
|
8234
|
+
},
|
|
8235
|
+
pointer: {
|
|
8236
|
+
pattern: "^(/.*)?$",
|
|
8237
|
+
type: "string"
|
|
8238
|
+
}
|
|
8239
|
+
},
|
|
8240
|
+
required: [
|
|
8241
|
+
"from"
|
|
8242
|
+
],
|
|
8243
|
+
type: "object"
|
|
8244
|
+
},
|
|
8245
|
+
max_parallelism: {
|
|
8246
|
+
minimum: 1,
|
|
8247
|
+
type: "integer"
|
|
8248
|
+
},
|
|
8249
|
+
subnode: {
|
|
8250
|
+
additionalProperties: false,
|
|
8251
|
+
properties: {
|
|
8252
|
+
id: {
|
|
8253
|
+
minLength: 1,
|
|
8254
|
+
type: "string"
|
|
8255
|
+
},
|
|
8256
|
+
input: {},
|
|
8257
|
+
type: {
|
|
8258
|
+
enum: [
|
|
8259
|
+
"llm.responses",
|
|
8260
|
+
"route.switch",
|
|
8261
|
+
"transform.json"
|
|
8262
|
+
],
|
|
8263
|
+
type: "string"
|
|
8264
|
+
}
|
|
8265
|
+
},
|
|
8266
|
+
required: [
|
|
8267
|
+
"id",
|
|
8268
|
+
"type"
|
|
8269
|
+
],
|
|
8270
|
+
type: "object"
|
|
8271
|
+
}
|
|
8272
|
+
},
|
|
8273
|
+
required: [
|
|
8274
|
+
"items",
|
|
8275
|
+
"subnode"
|
|
8276
|
+
],
|
|
8277
|
+
type: "object"
|
|
8278
|
+
}
|
|
8279
|
+
}
|
|
8280
|
+
}
|
|
8281
|
+
],
|
|
8282
|
+
properties: {
|
|
8283
|
+
type: {
|
|
8284
|
+
const: "map.fanout"
|
|
8285
|
+
}
|
|
8286
|
+
},
|
|
8287
|
+
required: [
|
|
8288
|
+
"input"
|
|
8289
|
+
]
|
|
8290
|
+
},
|
|
8291
|
+
{
|
|
8292
|
+
allOf: [
|
|
8293
|
+
{
|
|
8294
|
+
properties: {
|
|
8295
|
+
input: {
|
|
8296
|
+
additionalProperties: false,
|
|
8297
|
+
properties: {
|
|
8298
|
+
bind_inputs: {
|
|
8299
|
+
additionalProperties: {
|
|
8300
|
+
$ref: "#/definitions/fragmentBindInput"
|
|
8301
|
+
},
|
|
8302
|
+
type: "object"
|
|
8303
|
+
},
|
|
8304
|
+
ref: {
|
|
8305
|
+
minLength: 1,
|
|
8306
|
+
type: "string"
|
|
8307
|
+
}
|
|
8308
|
+
},
|
|
8309
|
+
required: [
|
|
8310
|
+
"ref"
|
|
8311
|
+
],
|
|
8312
|
+
type: "object"
|
|
8313
|
+
}
|
|
8314
|
+
}
|
|
8315
|
+
}
|
|
8316
|
+
],
|
|
8317
|
+
properties: {
|
|
8318
|
+
type: {
|
|
8319
|
+
const: "fragment"
|
|
8320
|
+
}
|
|
8321
|
+
},
|
|
8322
|
+
required: [
|
|
8323
|
+
"input"
|
|
8324
|
+
]
|
|
8325
|
+
}
|
|
8326
|
+
],
|
|
8327
|
+
properties: {
|
|
8328
|
+
id: {
|
|
8329
|
+
minLength: 1,
|
|
8330
|
+
type: "string"
|
|
8331
|
+
},
|
|
8332
|
+
input: {},
|
|
8333
|
+
type: {
|
|
8334
|
+
enum: [
|
|
8335
|
+
"llm.responses",
|
|
8336
|
+
"route.switch",
|
|
8337
|
+
"join.all",
|
|
8338
|
+
"join.any",
|
|
8339
|
+
"join.collect",
|
|
8340
|
+
"transform.json",
|
|
8341
|
+
"map.fanout",
|
|
8342
|
+
"fragment"
|
|
8343
|
+
],
|
|
8344
|
+
type: "string"
|
|
8345
|
+
}
|
|
8346
|
+
},
|
|
8347
|
+
required: [
|
|
8348
|
+
"id",
|
|
8349
|
+
"type"
|
|
8350
|
+
],
|
|
8351
|
+
type: "object"
|
|
8352
|
+
},
|
|
8353
|
+
output: {
|
|
8354
|
+
additionalProperties: false,
|
|
8355
|
+
properties: {
|
|
8356
|
+
from: {
|
|
8357
|
+
minLength: 1,
|
|
8358
|
+
type: "string"
|
|
8359
|
+
},
|
|
8360
|
+
name: {
|
|
8361
|
+
minLength: 1,
|
|
8362
|
+
type: "string"
|
|
8363
|
+
},
|
|
8364
|
+
output: {
|
|
8365
|
+
minLength: 1,
|
|
8366
|
+
type: "string"
|
|
8367
|
+
},
|
|
8368
|
+
pointer: {
|
|
8369
|
+
pattern: "^(/.*)?$",
|
|
8370
|
+
type: "string"
|
|
8371
|
+
}
|
|
8372
|
+
},
|
|
8373
|
+
required: [
|
|
8374
|
+
"name",
|
|
8375
|
+
"from"
|
|
8376
|
+
],
|
|
8377
|
+
type: "object"
|
|
8378
|
+
},
|
|
8379
|
+
transformValue: {
|
|
8380
|
+
additionalProperties: false,
|
|
8381
|
+
properties: {
|
|
8382
|
+
from: {
|
|
8383
|
+
minLength: 1,
|
|
8384
|
+
type: "string"
|
|
8385
|
+
},
|
|
8386
|
+
pointer: {
|
|
8387
|
+
pattern: "^(/.*)?$",
|
|
8388
|
+
type: "string"
|
|
8389
|
+
}
|
|
8390
|
+
},
|
|
8391
|
+
required: [
|
|
8392
|
+
"from"
|
|
8393
|
+
],
|
|
8394
|
+
type: "object"
|
|
8395
|
+
}
|
|
8396
|
+
},
|
|
8397
|
+
properties: {
|
|
8398
|
+
edges: {
|
|
8399
|
+
items: {
|
|
8400
|
+
$ref: "#/definitions/edge"
|
|
8401
|
+
},
|
|
8402
|
+
type: "array"
|
|
8403
|
+
},
|
|
8404
|
+
execution: {
|
|
8405
|
+
additionalProperties: false,
|
|
8406
|
+
properties: {
|
|
8407
|
+
max_parallelism: {
|
|
8408
|
+
minimum: 1,
|
|
8409
|
+
type: "integer"
|
|
8410
|
+
},
|
|
8411
|
+
node_timeout_ms: {
|
|
8412
|
+
minimum: 1,
|
|
8413
|
+
type: "integer"
|
|
8414
|
+
},
|
|
8415
|
+
run_timeout_ms: {
|
|
8416
|
+
minimum: 1,
|
|
8417
|
+
type: "integer"
|
|
8418
|
+
}
|
|
8419
|
+
},
|
|
8420
|
+
type: "object"
|
|
8421
|
+
},
|
|
8422
|
+
fragments: {
|
|
8423
|
+
additionalProperties: {
|
|
8424
|
+
$ref: "#/definitions/fragmentDef"
|
|
8425
|
+
},
|
|
8426
|
+
type: "object"
|
|
8427
|
+
},
|
|
8428
|
+
kind: {
|
|
8429
|
+
const: "workflow.v1",
|
|
8430
|
+
type: "string"
|
|
8431
|
+
},
|
|
8432
|
+
name: {
|
|
8433
|
+
type: "string"
|
|
8434
|
+
},
|
|
8435
|
+
nodes: {
|
|
8436
|
+
items: {
|
|
8437
|
+
$ref: "#/definitions/node"
|
|
8438
|
+
},
|
|
8439
|
+
minItems: 1,
|
|
8440
|
+
type: "array"
|
|
8441
|
+
},
|
|
8442
|
+
outputs: {
|
|
8443
|
+
items: {
|
|
8444
|
+
$ref: "#/definitions/output"
|
|
8445
|
+
},
|
|
8446
|
+
minItems: 1,
|
|
8447
|
+
type: "array"
|
|
8448
|
+
}
|
|
8449
|
+
},
|
|
8450
|
+
required: [
|
|
8451
|
+
"kind",
|
|
8452
|
+
"nodes",
|
|
8453
|
+
"outputs"
|
|
8454
|
+
],
|
|
8455
|
+
title: "ModelRelay workflow.v1",
|
|
8456
|
+
type: "object"
|
|
8457
|
+
};
|
|
8458
|
+
|
|
8459
|
+
// src/workflow_patterns.ts
|
|
8460
|
+
var LLM_TEXT_OUTPUT_INTERNAL = "/output/0/content/0/text";
|
|
8461
|
+
var LLM_USER_MESSAGE_TEXT_INTERNAL = "/input/1/content/0/text";
|
|
8462
|
+
function wireRequest2(req) {
|
|
8463
|
+
const raw = req;
|
|
8464
|
+
if (raw && typeof raw === "object") {
|
|
8465
|
+
if ("input" in raw) {
|
|
8466
|
+
return req;
|
|
8467
|
+
}
|
|
8468
|
+
if ("body" in raw) {
|
|
8469
|
+
return raw.body ?? {};
|
|
8470
|
+
}
|
|
8471
|
+
}
|
|
8472
|
+
return asInternal(req).body;
|
|
8473
|
+
}
|
|
8474
|
+
function sortEdges(edges) {
|
|
8475
|
+
return edges.slice().sort((a, b) => {
|
|
8476
|
+
const af = String(a.from);
|
|
8477
|
+
const bf = String(b.from);
|
|
8478
|
+
if (af < bf) return -1;
|
|
8479
|
+
if (af > bf) return 1;
|
|
8480
|
+
const at = String(a.to);
|
|
8481
|
+
const bt = String(b.to);
|
|
8482
|
+
if (at < bt) return -1;
|
|
8483
|
+
if (at > bt) return 1;
|
|
8484
|
+
return 0;
|
|
8485
|
+
});
|
|
8486
|
+
}
|
|
8487
|
+
function sortOutputs(outputs) {
|
|
8488
|
+
return outputs.slice().sort((a, b) => {
|
|
8489
|
+
const an = String(a.name);
|
|
8490
|
+
const bn = String(b.name);
|
|
8491
|
+
if (an < bn) return -1;
|
|
8492
|
+
if (an > bn) return 1;
|
|
8493
|
+
const af = String(a.from);
|
|
6740
8494
|
const bf = String(b.from);
|
|
6741
8495
|
if (af < bf) return -1;
|
|
6742
8496
|
if (af > bf) return 1;
|
|
@@ -7042,681 +8796,149 @@ var MapReduceBuilder = class _MapReduceBuilder {
|
|
|
7042
8796
|
output(name, from) {
|
|
7043
8797
|
return this.with({
|
|
7044
8798
|
outputs: [
|
|
7045
|
-
...this.state.outputs,
|
|
7046
|
-
{
|
|
7047
|
-
name,
|
|
7048
|
-
from,
|
|
7049
|
-
pointer: LLM_TEXT_OUTPUT_INTERNAL
|
|
7050
|
-
}
|
|
7051
|
-
]
|
|
7052
|
-
});
|
|
7053
|
-
}
|
|
7054
|
-
/**
|
|
7055
|
-
* Builds and returns the compiled workflow spec.
|
|
7056
|
-
* @throws Error if no items are provided or no reducer is configured
|
|
7057
|
-
*/
|
|
7058
|
-
build() {
|
|
7059
|
-
if (this.state.items.length === 0) {
|
|
7060
|
-
throw new Error("map-reduce requires at least one item");
|
|
7061
|
-
}
|
|
7062
|
-
if (!this.state.reducer) {
|
|
7063
|
-
throw new Error("map-reduce requires a reducer (call reduce)");
|
|
7064
|
-
}
|
|
7065
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
7066
|
-
for (const item of this.state.items) {
|
|
7067
|
-
if (!item.id) {
|
|
7068
|
-
throw new Error("item ID cannot be empty");
|
|
7069
|
-
}
|
|
7070
|
-
if (seenIds.has(item.id)) {
|
|
7071
|
-
throw new Error(`duplicate item ID: "${item.id}"`);
|
|
7072
|
-
}
|
|
7073
|
-
seenIds.add(item.id);
|
|
7074
|
-
}
|
|
7075
|
-
const nodes = [];
|
|
7076
|
-
const edges = [];
|
|
7077
|
-
const joinId = `${this.state.reducer.id}_join`;
|
|
7078
|
-
for (const item of this.state.items) {
|
|
7079
|
-
const mapperId = `map_${item.id}`;
|
|
7080
|
-
const input = {
|
|
7081
|
-
id: mapperId,
|
|
7082
|
-
type: WorkflowNodeTypes.LLMResponses,
|
|
7083
|
-
input: {
|
|
7084
|
-
request: item.request,
|
|
7085
|
-
...item.stream ? { stream: true } : {}
|
|
7086
|
-
}
|
|
7087
|
-
};
|
|
7088
|
-
nodes.push(input);
|
|
7089
|
-
edges.push({ from: mapperId, to: joinId });
|
|
7090
|
-
}
|
|
7091
|
-
nodes.push({ id: joinId, type: WorkflowNodeTypes.JoinAll });
|
|
7092
|
-
const reducerInput = {
|
|
7093
|
-
id: this.state.reducer.id,
|
|
7094
|
-
type: WorkflowNodeTypes.LLMResponses,
|
|
7095
|
-
input: {
|
|
7096
|
-
request: this.state.reducer.request,
|
|
7097
|
-
...this.state.reducer.stream ? { stream: true } : {},
|
|
7098
|
-
bindings: [
|
|
7099
|
-
{
|
|
7100
|
-
from: joinId,
|
|
7101
|
-
// Empty pointer = full join output
|
|
7102
|
-
to: LLM_USER_MESSAGE_TEXT_INTERNAL,
|
|
7103
|
-
encoding: "json_string"
|
|
7104
|
-
}
|
|
7105
|
-
]
|
|
7106
|
-
}
|
|
7107
|
-
};
|
|
7108
|
-
nodes.push(reducerInput);
|
|
7109
|
-
edges.push({ from: joinId, to: this.state.reducer.id });
|
|
7110
|
-
return {
|
|
7111
|
-
kind: WorkflowKinds.WorkflowV0,
|
|
7112
|
-
name: this.state.name,
|
|
7113
|
-
...this.state.execution ? { execution: this.state.execution } : {},
|
|
7114
|
-
nodes,
|
|
7115
|
-
...edges.length > 0 ? { edges: sortEdges(edges) } : {},
|
|
7116
|
-
outputs: sortOutputs(this.state.outputs)
|
|
7117
|
-
};
|
|
7118
|
-
}
|
|
7119
|
-
};
|
|
7120
|
-
function MapReduce(name, items = []) {
|
|
7121
|
-
return MapReduceBuilder.create(name, items);
|
|
7122
|
-
}
|
|
7123
|
-
|
|
7124
|
-
// src/tools_local_fs.ts
|
|
7125
|
-
var import_fs = require("fs");
|
|
7126
|
-
var path = __toESM(require("path"), 1);
|
|
7127
|
-
var import_child_process = require("child_process");
|
|
7128
|
-
var ToolNames = {
|
|
7129
|
-
FS_READ_FILE: "fs.read_file",
|
|
7130
|
-
FS_LIST_FILES: "fs.list_files",
|
|
7131
|
-
FS_SEARCH: "fs.search"
|
|
7132
|
-
};
|
|
7133
|
-
var FSDefaults = {
|
|
7134
|
-
MAX_READ_BYTES: 64e3,
|
|
7135
|
-
HARD_MAX_READ_BYTES: 1e6,
|
|
7136
|
-
MAX_LIST_ENTRIES: 2e3,
|
|
7137
|
-
HARD_MAX_LIST_ENTRIES: 2e4,
|
|
7138
|
-
MAX_SEARCH_MATCHES: 100,
|
|
7139
|
-
HARD_MAX_SEARCH_MATCHES: 2e3,
|
|
7140
|
-
SEARCH_TIMEOUT_MS: 5e3,
|
|
7141
|
-
MAX_SEARCH_BYTES_PER_FILE: 1e6
|
|
7142
|
-
};
|
|
7143
|
-
var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
7144
|
-
".git",
|
|
7145
|
-
"node_modules",
|
|
7146
|
-
"vendor",
|
|
7147
|
-
"dist",
|
|
7148
|
-
"build",
|
|
7149
|
-
".next",
|
|
7150
|
-
"target",
|
|
7151
|
-
".idea",
|
|
7152
|
-
".vscode",
|
|
7153
|
-
"__pycache__",
|
|
7154
|
-
".pytest_cache",
|
|
7155
|
-
"coverage"
|
|
7156
|
-
]);
|
|
7157
|
-
var LocalFSToolPack = class {
|
|
7158
|
-
constructor(options) {
|
|
7159
|
-
this.rgPath = null;
|
|
7160
|
-
this.rgChecked = false;
|
|
7161
|
-
const root = options.root?.trim();
|
|
7162
|
-
if (!root) {
|
|
7163
|
-
throw new Error("LocalFSToolPack: root directory required");
|
|
7164
|
-
}
|
|
7165
|
-
this.rootAbs = path.resolve(root);
|
|
7166
|
-
this.cfg = {
|
|
7167
|
-
ignoreDirs: options.ignoreDirs ?? new Set(DEFAULT_IGNORE_DIRS),
|
|
7168
|
-
maxReadBytes: options.maxReadBytes ?? FSDefaults.MAX_READ_BYTES,
|
|
7169
|
-
hardMaxReadBytes: options.hardMaxReadBytes ?? FSDefaults.HARD_MAX_READ_BYTES,
|
|
7170
|
-
maxListEntries: options.maxListEntries ?? FSDefaults.MAX_LIST_ENTRIES,
|
|
7171
|
-
hardMaxListEntries: options.hardMaxListEntries ?? FSDefaults.HARD_MAX_LIST_ENTRIES,
|
|
7172
|
-
maxSearchMatches: options.maxSearchMatches ?? FSDefaults.MAX_SEARCH_MATCHES,
|
|
7173
|
-
hardMaxSearchMatches: options.hardMaxSearchMatches ?? FSDefaults.HARD_MAX_SEARCH_MATCHES,
|
|
7174
|
-
searchTimeoutMs: options.searchTimeoutMs ?? FSDefaults.SEARCH_TIMEOUT_MS,
|
|
7175
|
-
maxSearchBytesPerFile: options.maxSearchBytesPerFile ?? FSDefaults.MAX_SEARCH_BYTES_PER_FILE
|
|
7176
|
-
};
|
|
7177
|
-
}
|
|
7178
|
-
/**
|
|
7179
|
-
* Returns the tool definitions for LLM requests.
|
|
7180
|
-
* Use these when constructing the tools array for /responses requests.
|
|
7181
|
-
*/
|
|
7182
|
-
getToolDefinitions() {
|
|
7183
|
-
return [
|
|
7184
|
-
{
|
|
7185
|
-
type: "function",
|
|
7186
|
-
function: {
|
|
7187
|
-
name: ToolNames.FS_READ_FILE,
|
|
7188
|
-
description: "Read the contents of a file. Returns the file contents as UTF-8 text.",
|
|
7189
|
-
parameters: {
|
|
7190
|
-
type: "object",
|
|
7191
|
-
properties: {
|
|
7192
|
-
path: {
|
|
7193
|
-
type: "string",
|
|
7194
|
-
description: "Workspace-relative path to the file (e.g., 'src/index.ts')"
|
|
7195
|
-
},
|
|
7196
|
-
max_bytes: {
|
|
7197
|
-
type: "integer",
|
|
7198
|
-
description: `Maximum bytes to read. Default: ${this.cfg.maxReadBytes}, max: ${this.cfg.hardMaxReadBytes}`
|
|
7199
|
-
}
|
|
7200
|
-
},
|
|
7201
|
-
required: ["path"]
|
|
7202
|
-
}
|
|
7203
|
-
}
|
|
7204
|
-
},
|
|
7205
|
-
{
|
|
7206
|
-
type: "function",
|
|
7207
|
-
function: {
|
|
7208
|
-
name: ToolNames.FS_LIST_FILES,
|
|
7209
|
-
description: "List files recursively in a directory. Returns newline-separated workspace-relative paths.",
|
|
7210
|
-
parameters: {
|
|
7211
|
-
type: "object",
|
|
7212
|
-
properties: {
|
|
7213
|
-
path: {
|
|
7214
|
-
type: "string",
|
|
7215
|
-
description: "Workspace-relative directory path. Default: '.' (workspace root)"
|
|
7216
|
-
},
|
|
7217
|
-
max_entries: {
|
|
7218
|
-
type: "integer",
|
|
7219
|
-
description: `Maximum files to list. Default: ${this.cfg.maxListEntries}, max: ${this.cfg.hardMaxListEntries}`
|
|
7220
|
-
}
|
|
7221
|
-
}
|
|
7222
|
-
}
|
|
7223
|
-
}
|
|
7224
|
-
},
|
|
7225
|
-
{
|
|
7226
|
-
type: "function",
|
|
7227
|
-
function: {
|
|
7228
|
-
name: ToolNames.FS_SEARCH,
|
|
7229
|
-
description: "Search for text matching a regex pattern. Returns matches as 'path:line:content' format.",
|
|
7230
|
-
parameters: {
|
|
7231
|
-
type: "object",
|
|
7232
|
-
properties: {
|
|
7233
|
-
query: {
|
|
7234
|
-
type: "string",
|
|
7235
|
-
description: "Regex pattern to search for"
|
|
7236
|
-
},
|
|
7237
|
-
path: {
|
|
7238
|
-
type: "string",
|
|
7239
|
-
description: "Workspace-relative directory to search. Default: '.' (workspace root)"
|
|
7240
|
-
},
|
|
7241
|
-
max_matches: {
|
|
7242
|
-
type: "integer",
|
|
7243
|
-
description: `Maximum matches to return. Default: ${this.cfg.maxSearchMatches}, max: ${this.cfg.hardMaxSearchMatches}`
|
|
7244
|
-
}
|
|
7245
|
-
},
|
|
7246
|
-
required: ["query"]
|
|
7247
|
-
}
|
|
7248
|
-
}
|
|
7249
|
-
}
|
|
7250
|
-
];
|
|
7251
|
-
}
|
|
7252
|
-
/**
|
|
7253
|
-
* Registers handlers into an existing ToolRegistry.
|
|
7254
|
-
* @param registry - The registry to register into
|
|
7255
|
-
* @returns The registry for chaining
|
|
7256
|
-
*/
|
|
7257
|
-
registerInto(registry) {
|
|
7258
|
-
registry.register(ToolNames.FS_READ_FILE, this.readFile.bind(this));
|
|
7259
|
-
registry.register(ToolNames.FS_LIST_FILES, this.listFiles.bind(this));
|
|
7260
|
-
registry.register(ToolNames.FS_SEARCH, this.search.bind(this));
|
|
7261
|
-
return registry;
|
|
7262
|
-
}
|
|
7263
|
-
/**
|
|
7264
|
-
* Creates a new ToolRegistry with fs.* tools pre-registered.
|
|
7265
|
-
*/
|
|
7266
|
-
toRegistry() {
|
|
7267
|
-
return this.registerInto(new ToolRegistry());
|
|
7268
|
-
}
|
|
7269
|
-
// ========================================================================
|
|
7270
|
-
// Tool Handlers
|
|
7271
|
-
// ========================================================================
|
|
7272
|
-
async readFile(_args, call) {
|
|
7273
|
-
const args = this.parseArgs(call, ["path"]);
|
|
7274
|
-
const func = call.function;
|
|
7275
|
-
const relPath = this.requireString(args, "path", call);
|
|
7276
|
-
const requestedMax = this.optionalPositiveInt(args, "max_bytes", call);
|
|
7277
|
-
let maxBytes = this.cfg.maxReadBytes;
|
|
7278
|
-
if (requestedMax !== void 0) {
|
|
7279
|
-
if (requestedMax > this.cfg.hardMaxReadBytes) {
|
|
7280
|
-
throw new ToolArgumentError({
|
|
7281
|
-
message: `max_bytes exceeds hard cap (${this.cfg.hardMaxReadBytes})`,
|
|
7282
|
-
toolCallId: call.id,
|
|
7283
|
-
toolName: func.name,
|
|
7284
|
-
rawArguments: func.arguments
|
|
7285
|
-
});
|
|
7286
|
-
}
|
|
7287
|
-
maxBytes = requestedMax;
|
|
7288
|
-
}
|
|
7289
|
-
const absPath = await this.resolveAndValidatePath(relPath, call);
|
|
7290
|
-
const stat = await import_fs.promises.stat(absPath);
|
|
7291
|
-
if (stat.isDirectory()) {
|
|
7292
|
-
throw new Error(`fs.read_file: path is a directory: ${relPath}`);
|
|
7293
|
-
}
|
|
7294
|
-
if (stat.size > maxBytes) {
|
|
7295
|
-
throw new Error(`fs.read_file: file exceeds max_bytes (${maxBytes})`);
|
|
7296
|
-
}
|
|
7297
|
-
const data = await import_fs.promises.readFile(absPath);
|
|
7298
|
-
if (!this.isValidUtf8(data)) {
|
|
7299
|
-
throw new Error(`fs.read_file: file is not valid UTF-8: ${relPath}`);
|
|
7300
|
-
}
|
|
7301
|
-
return data.toString("utf-8");
|
|
7302
|
-
}
|
|
7303
|
-
async listFiles(_args, call) {
|
|
7304
|
-
const args = this.parseArgs(call, []);
|
|
7305
|
-
const func = call.function;
|
|
7306
|
-
const startPath = this.optionalString(args, "path", call)?.trim() || ".";
|
|
7307
|
-
let maxEntries = this.cfg.maxListEntries;
|
|
7308
|
-
const requestedMax = this.optionalPositiveInt(args, "max_entries", call);
|
|
7309
|
-
if (requestedMax !== void 0) {
|
|
7310
|
-
if (requestedMax > this.cfg.hardMaxListEntries) {
|
|
7311
|
-
throw new ToolArgumentError({
|
|
7312
|
-
message: `max_entries exceeds hard cap (${this.cfg.hardMaxListEntries})`,
|
|
7313
|
-
toolCallId: call.id,
|
|
7314
|
-
toolName: func.name,
|
|
7315
|
-
rawArguments: func.arguments
|
|
7316
|
-
});
|
|
7317
|
-
}
|
|
7318
|
-
maxEntries = requestedMax;
|
|
7319
|
-
}
|
|
7320
|
-
const absPath = await this.resolveAndValidatePath(startPath, call);
|
|
7321
|
-
let rootReal;
|
|
7322
|
-
try {
|
|
7323
|
-
rootReal = await import_fs.promises.realpath(this.rootAbs);
|
|
7324
|
-
} catch {
|
|
7325
|
-
rootReal = this.rootAbs;
|
|
7326
|
-
}
|
|
7327
|
-
const stat = await import_fs.promises.stat(absPath);
|
|
7328
|
-
if (!stat.isDirectory()) {
|
|
7329
|
-
throw new Error(`fs.list_files: path is not a directory: ${startPath}`);
|
|
7330
|
-
}
|
|
7331
|
-
const files = [];
|
|
7332
|
-
await this.walkDir(absPath, async (filePath, dirent) => {
|
|
7333
|
-
if (files.length >= maxEntries) {
|
|
7334
|
-
return false;
|
|
7335
|
-
}
|
|
7336
|
-
if (dirent.isDirectory()) {
|
|
7337
|
-
if (this.cfg.ignoreDirs.has(dirent.name)) {
|
|
7338
|
-
return false;
|
|
7339
|
-
}
|
|
7340
|
-
return true;
|
|
7341
|
-
}
|
|
7342
|
-
if (dirent.isFile()) {
|
|
7343
|
-
const relPath = path.relative(rootReal, filePath);
|
|
7344
|
-
files.push(relPath.split(path.sep).join("/"));
|
|
7345
|
-
}
|
|
7346
|
-
return true;
|
|
7347
|
-
});
|
|
7348
|
-
return files.join("\n");
|
|
7349
|
-
}
|
|
7350
|
-
async search(_args, call) {
|
|
7351
|
-
const args = this.parseArgs(call, ["query"]);
|
|
7352
|
-
const func = call.function;
|
|
7353
|
-
const query = this.requireString(args, "query", call);
|
|
7354
|
-
const startPath = this.optionalString(args, "path", call)?.trim() || ".";
|
|
7355
|
-
let maxMatches = this.cfg.maxSearchMatches;
|
|
7356
|
-
const requestedMax = this.optionalPositiveInt(args, "max_matches", call);
|
|
7357
|
-
if (requestedMax !== void 0) {
|
|
7358
|
-
if (requestedMax > this.cfg.hardMaxSearchMatches) {
|
|
7359
|
-
throw new ToolArgumentError({
|
|
7360
|
-
message: `max_matches exceeds hard cap (${this.cfg.hardMaxSearchMatches})`,
|
|
7361
|
-
toolCallId: call.id,
|
|
7362
|
-
toolName: func.name,
|
|
7363
|
-
rawArguments: func.arguments
|
|
7364
|
-
});
|
|
7365
|
-
}
|
|
7366
|
-
maxMatches = requestedMax;
|
|
7367
|
-
}
|
|
7368
|
-
const absPath = await this.resolveAndValidatePath(startPath, call);
|
|
7369
|
-
const rgPath = await this.detectRipgrep();
|
|
7370
|
-
if (rgPath) {
|
|
7371
|
-
return this.searchWithRipgrep(
|
|
7372
|
-
rgPath,
|
|
7373
|
-
query,
|
|
7374
|
-
absPath,
|
|
7375
|
-
maxMatches
|
|
7376
|
-
);
|
|
7377
|
-
}
|
|
7378
|
-
return this.searchWithJS(query, absPath, maxMatches, call);
|
|
7379
|
-
}
|
|
7380
|
-
// ========================================================================
|
|
7381
|
-
// Path Safety
|
|
7382
|
-
// ========================================================================
|
|
7383
|
-
/**
|
|
7384
|
-
* Resolves a workspace-relative path and validates it stays within the sandbox.
|
|
7385
|
-
* @throws {ToolArgumentError} if path is invalid
|
|
7386
|
-
* @throws {PathEscapeError} if resolved path escapes root
|
|
7387
|
-
*/
|
|
7388
|
-
async resolveAndValidatePath(relPath, call) {
|
|
7389
|
-
const func = call.function;
|
|
7390
|
-
const cleanRel = relPath.trim();
|
|
7391
|
-
if (!cleanRel) {
|
|
7392
|
-
throw new ToolArgumentError({
|
|
7393
|
-
message: "path cannot be empty",
|
|
7394
|
-
toolCallId: call.id,
|
|
7395
|
-
toolName: func.name,
|
|
7396
|
-
rawArguments: func.arguments
|
|
7397
|
-
});
|
|
7398
|
-
}
|
|
7399
|
-
if (path.isAbsolute(cleanRel)) {
|
|
7400
|
-
throw new ToolArgumentError({
|
|
7401
|
-
message: "path must be workspace-relative (not absolute)",
|
|
7402
|
-
toolCallId: call.id,
|
|
7403
|
-
toolName: func.name,
|
|
7404
|
-
rawArguments: func.arguments
|
|
7405
|
-
});
|
|
7406
|
-
}
|
|
7407
|
-
const normalized = path.normalize(cleanRel);
|
|
7408
|
-
if (normalized.startsWith("..") || normalized.startsWith(`.${path.sep}..`)) {
|
|
7409
|
-
throw new ToolArgumentError({
|
|
7410
|
-
message: "path must not escape the workspace root",
|
|
7411
|
-
toolCallId: call.id,
|
|
7412
|
-
toolName: func.name,
|
|
7413
|
-
rawArguments: func.arguments
|
|
7414
|
-
});
|
|
7415
|
-
}
|
|
7416
|
-
const target = path.join(this.rootAbs, normalized);
|
|
7417
|
-
let rootReal;
|
|
7418
|
-
try {
|
|
7419
|
-
rootReal = await import_fs.promises.realpath(this.rootAbs);
|
|
7420
|
-
} catch {
|
|
7421
|
-
rootReal = this.rootAbs;
|
|
7422
|
-
}
|
|
7423
|
-
let resolved;
|
|
7424
|
-
try {
|
|
7425
|
-
resolved = await import_fs.promises.realpath(target);
|
|
7426
|
-
} catch (err) {
|
|
7427
|
-
resolved = path.join(rootReal, normalized);
|
|
7428
|
-
}
|
|
7429
|
-
const relFromRoot = path.relative(rootReal, resolved);
|
|
7430
|
-
if (relFromRoot.startsWith("..") || relFromRoot.startsWith(`.${path.sep}..`) || path.isAbsolute(relFromRoot)) {
|
|
7431
|
-
throw new PathEscapeError({
|
|
7432
|
-
requestedPath: relPath,
|
|
7433
|
-
resolvedPath: resolved
|
|
7434
|
-
});
|
|
7435
|
-
}
|
|
7436
|
-
return resolved;
|
|
7437
|
-
}
|
|
7438
|
-
// ========================================================================
|
|
7439
|
-
// Ripgrep Search
|
|
7440
|
-
// ========================================================================
|
|
7441
|
-
async detectRipgrep() {
|
|
7442
|
-
if (this.rgChecked) {
|
|
7443
|
-
return this.rgPath;
|
|
7444
|
-
}
|
|
7445
|
-
this.rgChecked = true;
|
|
7446
|
-
return new Promise((resolve2) => {
|
|
7447
|
-
const proc = (0, import_child_process.spawn)("rg", ["--version"], { stdio: "ignore" });
|
|
7448
|
-
proc.on("error", () => {
|
|
7449
|
-
this.rgPath = null;
|
|
7450
|
-
resolve2(null);
|
|
7451
|
-
});
|
|
7452
|
-
proc.on("close", (code) => {
|
|
7453
|
-
if (code === 0) {
|
|
7454
|
-
this.rgPath = "rg";
|
|
7455
|
-
resolve2("rg");
|
|
7456
|
-
} else {
|
|
7457
|
-
this.rgPath = null;
|
|
7458
|
-
resolve2(null);
|
|
7459
|
-
}
|
|
7460
|
-
});
|
|
7461
|
-
});
|
|
7462
|
-
}
|
|
7463
|
-
async searchWithRipgrep(rgPath, query, dirAbs, maxMatches) {
|
|
7464
|
-
return new Promise((resolve2, reject) => {
|
|
7465
|
-
const args = ["--line-number", "--no-heading", "--color=never"];
|
|
7466
|
-
for (const name of this.cfg.ignoreDirs) {
|
|
7467
|
-
args.push("--glob", `!**/${name}/**`);
|
|
7468
|
-
}
|
|
7469
|
-
args.push(query, dirAbs);
|
|
7470
|
-
const proc = (0, import_child_process.spawn)(rgPath, args, {
|
|
7471
|
-
timeout: this.cfg.searchTimeoutMs
|
|
7472
|
-
});
|
|
7473
|
-
const lines = [];
|
|
7474
|
-
let stderr = "";
|
|
7475
|
-
let killed = false;
|
|
7476
|
-
proc.stdout.on("data", (chunk) => {
|
|
7477
|
-
if (killed) return;
|
|
7478
|
-
const text = typeof chunk === "string" ? chunk : chunk.toString("utf-8");
|
|
7479
|
-
const newLines = text.split("\n").filter((l) => l.trim());
|
|
7480
|
-
for (const line of newLines) {
|
|
7481
|
-
lines.push(this.normalizeRipgrepLine(line));
|
|
7482
|
-
if (lines.length >= maxMatches) {
|
|
7483
|
-
killed = true;
|
|
7484
|
-
proc.kill();
|
|
7485
|
-
break;
|
|
7486
|
-
}
|
|
7487
|
-
}
|
|
7488
|
-
});
|
|
7489
|
-
proc.stderr.on("data", (chunk) => {
|
|
7490
|
-
stderr += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
|
|
7491
|
-
});
|
|
7492
|
-
proc.on("error", (err) => {
|
|
7493
|
-
reject(new Error(`fs.search: ripgrep error: ${err.message}`));
|
|
7494
|
-
});
|
|
7495
|
-
proc.on("close", (code) => {
|
|
7496
|
-
if (killed) {
|
|
7497
|
-
resolve2(lines.join("\n"));
|
|
7498
|
-
return;
|
|
7499
|
-
}
|
|
7500
|
-
if (code === 0 || code === 1) {
|
|
7501
|
-
resolve2(lines.join("\n"));
|
|
7502
|
-
} else if (code === 2 && stderr.toLowerCase().includes("regex")) {
|
|
7503
|
-
reject(
|
|
7504
|
-
new ToolArgumentError({
|
|
7505
|
-
message: `invalid query regex: ${stderr.trim()}`,
|
|
7506
|
-
toolCallId: "",
|
|
7507
|
-
toolName: ToolNames.FS_SEARCH,
|
|
7508
|
-
rawArguments: ""
|
|
7509
|
-
})
|
|
7510
|
-
);
|
|
7511
|
-
} else if (stderr) {
|
|
7512
|
-
reject(new Error(`fs.search: ripgrep failed: ${stderr.trim()}`));
|
|
7513
|
-
} else {
|
|
7514
|
-
resolve2(lines.join("\n"));
|
|
8799
|
+
...this.state.outputs,
|
|
8800
|
+
{
|
|
8801
|
+
name,
|
|
8802
|
+
from,
|
|
8803
|
+
pointer: LLM_TEXT_OUTPUT_INTERNAL
|
|
7515
8804
|
}
|
|
7516
|
-
|
|
8805
|
+
]
|
|
7517
8806
|
});
|
|
7518
8807
|
}
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
const rest = trimmed.slice(colonIdx + 1);
|
|
7527
|
-
if (path.isAbsolute(filePath)) {
|
|
7528
|
-
const rel = path.relative(this.rootAbs, filePath);
|
|
7529
|
-
if (!rel.startsWith("..")) {
|
|
7530
|
-
return rel.split(path.sep).join("/") + ":" + rest;
|
|
7531
|
-
}
|
|
8808
|
+
/**
|
|
8809
|
+
* Builds and returns the compiled workflow spec.
|
|
8810
|
+
* @throws Error if no items are provided or no reducer is configured
|
|
8811
|
+
*/
|
|
8812
|
+
build() {
|
|
8813
|
+
if (this.state.items.length === 0) {
|
|
8814
|
+
throw new Error("map-reduce requires at least one item");
|
|
7532
8815
|
}
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
// ========================================================================
|
|
7536
|
-
// JavaScript Fallback Search
|
|
7537
|
-
// ========================================================================
|
|
7538
|
-
async searchWithJS(query, dirAbs, maxMatches, call) {
|
|
7539
|
-
const func = call.function;
|
|
7540
|
-
let regex;
|
|
7541
|
-
try {
|
|
7542
|
-
regex = new RegExp(query);
|
|
7543
|
-
} catch (err) {
|
|
7544
|
-
throw new ToolArgumentError({
|
|
7545
|
-
message: `invalid query regex: ${err.message}`,
|
|
7546
|
-
toolCallId: call.id,
|
|
7547
|
-
toolName: func.name,
|
|
7548
|
-
rawArguments: func.arguments
|
|
7549
|
-
});
|
|
8816
|
+
if (!this.state.reducer) {
|
|
8817
|
+
throw new Error("map-reduce requires a reducer (call reduce)");
|
|
7550
8818
|
}
|
|
7551
|
-
const
|
|
7552
|
-
const
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
return false;
|
|
7556
|
-
}
|
|
7557
|
-
if (matches.length >= maxMatches) {
|
|
7558
|
-
return false;
|
|
7559
|
-
}
|
|
7560
|
-
if (dirent.isDirectory()) {
|
|
7561
|
-
if (this.cfg.ignoreDirs.has(dirent.name)) {
|
|
7562
|
-
return false;
|
|
7563
|
-
}
|
|
7564
|
-
return true;
|
|
8819
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
8820
|
+
for (const item of this.state.items) {
|
|
8821
|
+
if (!item.id) {
|
|
8822
|
+
throw new Error("item ID cannot be empty");
|
|
7565
8823
|
}
|
|
7566
|
-
if (
|
|
7567
|
-
|
|
8824
|
+
if (seenIds.has(item.id)) {
|
|
8825
|
+
throw new Error(`duplicate item ID: "${item.id}"`);
|
|
7568
8826
|
}
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
8827
|
+
seenIds.add(item.id);
|
|
8828
|
+
}
|
|
8829
|
+
const nodes = [];
|
|
8830
|
+
const edges = [];
|
|
8831
|
+
const joinId = `${this.state.reducer.id}_join`;
|
|
8832
|
+
for (const item of this.state.items) {
|
|
8833
|
+
const mapperId = `map_${item.id}`;
|
|
8834
|
+
const input = {
|
|
8835
|
+
id: mapperId,
|
|
8836
|
+
type: WorkflowNodeTypes.LLMResponses,
|
|
8837
|
+
input: {
|
|
8838
|
+
request: item.request,
|
|
8839
|
+
...item.stream ? { stream: true } : {}
|
|
7573
8840
|
}
|
|
7574
|
-
}
|
|
7575
|
-
|
|
7576
|
-
}
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
8841
|
+
};
|
|
8842
|
+
nodes.push(input);
|
|
8843
|
+
edges.push({ from: mapperId, to: joinId });
|
|
8844
|
+
}
|
|
8845
|
+
nodes.push({ id: joinId, type: WorkflowNodeTypes.JoinAll });
|
|
8846
|
+
const reducerInput = {
|
|
8847
|
+
id: this.state.reducer.id,
|
|
8848
|
+
type: WorkflowNodeTypes.LLMResponses,
|
|
8849
|
+
input: {
|
|
8850
|
+
request: this.state.reducer.request,
|
|
8851
|
+
...this.state.reducer.stream ? { stream: true } : {},
|
|
8852
|
+
bindings: [
|
|
8853
|
+
{
|
|
8854
|
+
from: joinId,
|
|
8855
|
+
// Empty pointer = full join output
|
|
8856
|
+
to: LLM_USER_MESSAGE_TEXT_INTERNAL,
|
|
8857
|
+
encoding: "json_string"
|
|
7585
8858
|
}
|
|
7586
|
-
|
|
7587
|
-
} catch {
|
|
8859
|
+
]
|
|
7588
8860
|
}
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
8861
|
+
};
|
|
8862
|
+
nodes.push(reducerInput);
|
|
8863
|
+
edges.push({ from: joinId, to: this.state.reducer.id });
|
|
8864
|
+
return {
|
|
8865
|
+
kind: WorkflowKinds.WorkflowV0,
|
|
8866
|
+
name: this.state.name,
|
|
8867
|
+
...this.state.execution ? { execution: this.state.execution } : {},
|
|
8868
|
+
nodes,
|
|
8869
|
+
...edges.length > 0 ? { edges: sortEdges(edges) } : {},
|
|
8870
|
+
outputs: sortOutputs(this.state.outputs)
|
|
8871
|
+
};
|
|
7592
8872
|
}
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
const rawArgs = func.arguments || "{}";
|
|
7607
|
-
let parsed;
|
|
7608
|
-
try {
|
|
7609
|
-
parsed = JSON.parse(rawArgs);
|
|
7610
|
-
} catch (err) {
|
|
7611
|
-
throw new ToolArgumentError({
|
|
7612
|
-
message: `invalid JSON arguments: ${err.message}`,
|
|
7613
|
-
toolCallId: call.id,
|
|
7614
|
-
toolName: func.name,
|
|
7615
|
-
rawArguments: rawArgs
|
|
7616
|
-
});
|
|
7617
|
-
}
|
|
7618
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
7619
|
-
throw new ToolArgumentError({
|
|
7620
|
-
message: "arguments must be an object",
|
|
7621
|
-
toolCallId: call.id,
|
|
7622
|
-
toolName: func.name,
|
|
7623
|
-
rawArguments: rawArgs
|
|
7624
|
-
});
|
|
7625
|
-
}
|
|
7626
|
-
const args = parsed;
|
|
7627
|
-
for (const key of required) {
|
|
7628
|
-
const value = args[key];
|
|
7629
|
-
if (value === void 0 || value === null || value === "") {
|
|
7630
|
-
throw new ToolArgumentError({
|
|
7631
|
-
message: `${key} is required`,
|
|
7632
|
-
toolCallId: call.id,
|
|
7633
|
-
toolName: func.name,
|
|
7634
|
-
rawArguments: rawArgs
|
|
7635
|
-
});
|
|
8873
|
+
};
|
|
8874
|
+
function MapReduce(name, items = []) {
|
|
8875
|
+
return MapReduceBuilder.create(name, items);
|
|
8876
|
+
}
|
|
8877
|
+
|
|
8878
|
+
// src/testing.ts
|
|
8879
|
+
function buildNDJSONResponse(lines, headers = {}, status = 200) {
|
|
8880
|
+
const encoder = new TextEncoder();
|
|
8881
|
+
const stream = new ReadableStream({
|
|
8882
|
+
start(controller) {
|
|
8883
|
+
for (const line of lines) {
|
|
8884
|
+
controller.enqueue(encoder.encode(`${line}
|
|
8885
|
+
`));
|
|
7636
8886
|
}
|
|
8887
|
+
controller.close();
|
|
7637
8888
|
}
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
toolCallId: call.id,
|
|
7645
|
-
toolName: func?.name ?? "",
|
|
7646
|
-
rawArguments: func?.arguments ?? ""
|
|
7647
|
-
});
|
|
7648
|
-
}
|
|
7649
|
-
requireString(args, key, call) {
|
|
7650
|
-
const value = args[key];
|
|
7651
|
-
if (typeof value !== "string") {
|
|
7652
|
-
this.toolArgumentError(call, `${key} must be a string`);
|
|
7653
|
-
}
|
|
7654
|
-
if (value.trim() === "") {
|
|
7655
|
-
this.toolArgumentError(call, `${key} is required`);
|
|
7656
|
-
}
|
|
7657
|
-
return value;
|
|
7658
|
-
}
|
|
7659
|
-
optionalString(args, key, call) {
|
|
7660
|
-
const value = args[key];
|
|
7661
|
-
if (value === void 0 || value === null) {
|
|
7662
|
-
return void 0;
|
|
7663
|
-
}
|
|
7664
|
-
if (typeof value !== "string") {
|
|
7665
|
-
this.toolArgumentError(call, `${key} must be a string`);
|
|
7666
|
-
}
|
|
7667
|
-
const trimmed = value.trim();
|
|
7668
|
-
if (trimmed === "") {
|
|
7669
|
-
return void 0;
|
|
7670
|
-
}
|
|
7671
|
-
return value;
|
|
7672
|
-
}
|
|
7673
|
-
optionalPositiveInt(args, key, call) {
|
|
7674
|
-
const value = args[key];
|
|
7675
|
-
if (value === void 0 || value === null) {
|
|
7676
|
-
return void 0;
|
|
8889
|
+
});
|
|
8890
|
+
return new Response(stream, {
|
|
8891
|
+
status,
|
|
8892
|
+
headers: {
|
|
8893
|
+
"Content-Type": "application/x-ndjson",
|
|
8894
|
+
...headers
|
|
7677
8895
|
}
|
|
7678
|
-
|
|
7679
|
-
|
|
8896
|
+
});
|
|
8897
|
+
}
|
|
8898
|
+
function buildDelayedNDJSONResponse(steps, headers = {}, status = 200) {
|
|
8899
|
+
const encoder = new TextEncoder();
|
|
8900
|
+
const stream = new ReadableStream({
|
|
8901
|
+
start(controller) {
|
|
8902
|
+
let idx = 0;
|
|
8903
|
+
const pushNext = () => {
|
|
8904
|
+
if (idx >= steps.length) {
|
|
8905
|
+
controller.close();
|
|
8906
|
+
return;
|
|
8907
|
+
}
|
|
8908
|
+
const step = steps[idx++];
|
|
8909
|
+
setTimeout(() => {
|
|
8910
|
+
controller.enqueue(encoder.encode(`${step.line}
|
|
8911
|
+
`));
|
|
8912
|
+
pushNext();
|
|
8913
|
+
}, Math.max(0, step.delayMs));
|
|
8914
|
+
};
|
|
8915
|
+
pushNext();
|
|
7680
8916
|
}
|
|
7681
|
-
|
|
7682
|
-
|
|
8917
|
+
});
|
|
8918
|
+
return new Response(stream, {
|
|
8919
|
+
status,
|
|
8920
|
+
headers: {
|
|
8921
|
+
"Content-Type": "application/x-ndjson",
|
|
8922
|
+
...headers
|
|
7683
8923
|
}
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
|
|
7691
|
-
|
|
8924
|
+
});
|
|
8925
|
+
}
|
|
8926
|
+
function createMockFetchQueue(responses) {
|
|
8927
|
+
const calls = [];
|
|
8928
|
+
const queue = [...responses];
|
|
8929
|
+
const fetchImpl = async (url, init) => {
|
|
8930
|
+
const call = { url: String(url), init };
|
|
8931
|
+
calls.push(call);
|
|
8932
|
+
const responder = queue.shift();
|
|
8933
|
+
if (!responder) {
|
|
8934
|
+
throw new Error("mock fetch queue exhausted");
|
|
7692
8935
|
}
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
* Recursively walks a directory, calling visitor for each entry.
|
|
7696
|
-
* Visitor returns true to continue, false to skip (for dirs) or stop.
|
|
7697
|
-
*/
|
|
7698
|
-
async walkDir(dir, visitor) {
|
|
7699
|
-
const entries = await import_fs.promises.readdir(dir, { withFileTypes: true });
|
|
7700
|
-
for (const entry of entries) {
|
|
7701
|
-
const fullPath = path.join(dir, entry.name);
|
|
7702
|
-
const shouldContinue = await visitor(fullPath, entry);
|
|
7703
|
-
if (!shouldContinue) {
|
|
7704
|
-
if (entry.isDirectory()) {
|
|
7705
|
-
continue;
|
|
7706
|
-
}
|
|
7707
|
-
return;
|
|
7708
|
-
}
|
|
7709
|
-
if (entry.isDirectory()) {
|
|
7710
|
-
await this.walkDir(fullPath, visitor);
|
|
7711
|
-
}
|
|
8936
|
+
if (typeof responder === "function") {
|
|
8937
|
+
return responder(call, calls.length - 1);
|
|
7712
8938
|
}
|
|
7713
|
-
|
|
7714
|
-
};
|
|
7715
|
-
|
|
7716
|
-
return new LocalFSToolPack(options);
|
|
7717
|
-
}
|
|
7718
|
-
function createLocalFSTools(options) {
|
|
7719
|
-
return createLocalFSToolPack(options).toRegistry();
|
|
8939
|
+
return responder;
|
|
8940
|
+
};
|
|
8941
|
+
return { fetch: fetchImpl, calls };
|
|
7720
8942
|
}
|
|
7721
8943
|
|
|
7722
8944
|
// src/tools_browser.ts
|
|
@@ -8444,23 +9666,259 @@ var generated_exports = {};
|
|
|
8444
9666
|
// src/workflow/index.ts
|
|
8445
9667
|
var workflow_exports = {};
|
|
8446
9668
|
__export(workflow_exports, {
|
|
9669
|
+
BindingBuilder: () => BindingBuilder,
|
|
8447
9670
|
BindingEncodings: () => BindingEncodings,
|
|
9671
|
+
FanoutReduceV1: () => FanoutReduceV1,
|
|
8448
9672
|
KindV0: () => KindV0,
|
|
8449
|
-
|
|
8450
|
-
|
|
9673
|
+
KindV1: () => KindV1,
|
|
9674
|
+
LLM_TEXT_OUTPUT: () => LLM_TEXT_OUTPUT,
|
|
9675
|
+
LLM_USER_MESSAGE_TEXT: () => LLM_USER_MESSAGE_TEXT,
|
|
8451
9676
|
NodeTypes: () => NodeTypes,
|
|
9677
|
+
NodeTypesV1: () => NodeTypesV1,
|
|
9678
|
+
RouterV1: () => RouterV1,
|
|
8452
9679
|
ToolExecutionModes: () => ToolExecutionModes,
|
|
9680
|
+
bindFrom: () => bindFrom,
|
|
9681
|
+
bindToPlaceholder: () => bindToPlaceholder,
|
|
9682
|
+
bindToPointer: () => bindToPointer,
|
|
8453
9683
|
parseNodeId: () => parseNodeId,
|
|
8454
9684
|
parseOutputName: () => parseOutputName,
|
|
8455
9685
|
parsePlanHash: () => parsePlanHash,
|
|
8456
|
-
parseRunId: () => parseRunId
|
|
9686
|
+
parseRunId: () => parseRunId,
|
|
9687
|
+
whenOutputEquals: () => whenOutputEquals,
|
|
9688
|
+
whenOutputExists: () => whenOutputExists,
|
|
9689
|
+
whenOutputMatches: () => whenOutputMatches,
|
|
9690
|
+
whenStatusEquals: () => whenStatusEquals,
|
|
9691
|
+
whenStatusExists: () => whenStatusExists,
|
|
9692
|
+
whenStatusMatches: () => whenStatusMatches
|
|
8457
9693
|
});
|
|
9694
|
+
|
|
9695
|
+
// src/workflow/helpers_v1.ts
|
|
9696
|
+
function whenOutputEquals(path, value) {
|
|
9697
|
+
return { source: "node_output", op: "equals", path, value };
|
|
9698
|
+
}
|
|
9699
|
+
function whenOutputMatches(path, pattern) {
|
|
9700
|
+
return { source: "node_output", op: "matches", path, value: pattern };
|
|
9701
|
+
}
|
|
9702
|
+
function whenOutputExists(path) {
|
|
9703
|
+
return { source: "node_output", op: "exists", path };
|
|
9704
|
+
}
|
|
9705
|
+
function whenStatusEquals(path, value) {
|
|
9706
|
+
return { source: "node_status", op: "equals", path, value };
|
|
9707
|
+
}
|
|
9708
|
+
function whenStatusMatches(path, pattern) {
|
|
9709
|
+
return { source: "node_status", op: "matches", path, value: pattern };
|
|
9710
|
+
}
|
|
9711
|
+
function whenStatusExists(path) {
|
|
9712
|
+
return { source: "node_status", op: "exists", path };
|
|
9713
|
+
}
|
|
9714
|
+
function bindToPlaceholder(from, placeholder, opts) {
|
|
9715
|
+
return {
|
|
9716
|
+
from,
|
|
9717
|
+
...opts?.pointer ? { pointer: opts.pointer } : {},
|
|
9718
|
+
to_placeholder: placeholder,
|
|
9719
|
+
encoding: opts?.encoding ?? "json_string"
|
|
9720
|
+
};
|
|
9721
|
+
}
|
|
9722
|
+
function bindToPointer(from, to, opts) {
|
|
9723
|
+
return {
|
|
9724
|
+
from,
|
|
9725
|
+
...opts?.pointer ? { pointer: opts.pointer } : {},
|
|
9726
|
+
to,
|
|
9727
|
+
encoding: opts?.encoding ?? "json_string"
|
|
9728
|
+
};
|
|
9729
|
+
}
|
|
9730
|
+
function bindFrom(from) {
|
|
9731
|
+
return new BindingBuilder(from);
|
|
9732
|
+
}
|
|
9733
|
+
var BindingBuilder = class {
|
|
9734
|
+
constructor(from) {
|
|
9735
|
+
this._encoding = "json_string";
|
|
9736
|
+
this._from = from;
|
|
9737
|
+
}
|
|
9738
|
+
/**
|
|
9739
|
+
* Set the source pointer to extract from the node's output.
|
|
9740
|
+
*/
|
|
9741
|
+
pointer(ptr) {
|
|
9742
|
+
this._pointer = ptr;
|
|
9743
|
+
return this;
|
|
9744
|
+
}
|
|
9745
|
+
/**
|
|
9746
|
+
* Set the destination JSON pointer in the request.
|
|
9747
|
+
*/
|
|
9748
|
+
to(ptr) {
|
|
9749
|
+
this._to = ptr;
|
|
9750
|
+
this._toPlaceholder = void 0;
|
|
9751
|
+
return this;
|
|
9752
|
+
}
|
|
9753
|
+
/**
|
|
9754
|
+
* Set the destination placeholder name.
|
|
9755
|
+
*/
|
|
9756
|
+
toPlaceholder(name) {
|
|
9757
|
+
this._toPlaceholder = name;
|
|
9758
|
+
this._to = void 0;
|
|
9759
|
+
return this;
|
|
9760
|
+
}
|
|
9761
|
+
/**
|
|
9762
|
+
* Set the encoding for the binding value.
|
|
9763
|
+
*/
|
|
9764
|
+
encoding(enc) {
|
|
9765
|
+
this._encoding = enc;
|
|
9766
|
+
return this;
|
|
9767
|
+
}
|
|
9768
|
+
/**
|
|
9769
|
+
* Build the binding object.
|
|
9770
|
+
*/
|
|
9771
|
+
build() {
|
|
9772
|
+
const binding = {
|
|
9773
|
+
from: this._from,
|
|
9774
|
+
encoding: this._encoding
|
|
9775
|
+
};
|
|
9776
|
+
if (this._pointer) binding.pointer = this._pointer;
|
|
9777
|
+
if (this._to) binding.to = this._to;
|
|
9778
|
+
if (this._toPlaceholder) binding.to_placeholder = this._toPlaceholder;
|
|
9779
|
+
return binding;
|
|
9780
|
+
}
|
|
9781
|
+
};
|
|
9782
|
+
|
|
9783
|
+
// src/workflow/patterns_v1.ts
|
|
9784
|
+
function wireRequest3(req) {
|
|
9785
|
+
const raw = req;
|
|
9786
|
+
if (raw && typeof raw === "object") {
|
|
9787
|
+
if ("input" in raw) {
|
|
9788
|
+
return req;
|
|
9789
|
+
}
|
|
9790
|
+
if ("body" in raw) {
|
|
9791
|
+
return raw.body ?? {};
|
|
9792
|
+
}
|
|
9793
|
+
}
|
|
9794
|
+
return asInternal(req).body;
|
|
9795
|
+
}
|
|
9796
|
+
var RouterV1 = class {
|
|
9797
|
+
constructor(config) {
|
|
9798
|
+
this.config = config;
|
|
9799
|
+
}
|
|
9800
|
+
/**
|
|
9801
|
+
* Build the workflow specification.
|
|
9802
|
+
*/
|
|
9803
|
+
build() {
|
|
9804
|
+
const {
|
|
9805
|
+
name,
|
|
9806
|
+
classifier,
|
|
9807
|
+
classifierId = "router",
|
|
9808
|
+
routePath = "$.route",
|
|
9809
|
+
routes,
|
|
9810
|
+
aggregator,
|
|
9811
|
+
outputName = "final"
|
|
9812
|
+
} = this.config;
|
|
9813
|
+
let builder = new WorkflowBuilderV1();
|
|
9814
|
+
if (name) {
|
|
9815
|
+
builder = builder.name(name);
|
|
9816
|
+
}
|
|
9817
|
+
builder = builder.routeSwitch(classifierId, classifier);
|
|
9818
|
+
const joinId = "__router_join";
|
|
9819
|
+
builder = builder.joinAny(joinId);
|
|
9820
|
+
for (let i = 0; i < routes.length; i++) {
|
|
9821
|
+
const route = routes[i];
|
|
9822
|
+
const handlerId = route.id ?? `handler_${i}`;
|
|
9823
|
+
builder = builder.llmResponses(handlerId, route.handler, {
|
|
9824
|
+
bindings: route.bindings
|
|
9825
|
+
});
|
|
9826
|
+
builder = builder.edge(classifierId, handlerId, whenOutputEquals(routePath, route.value));
|
|
9827
|
+
builder = builder.edge(handlerId, joinId);
|
|
9828
|
+
}
|
|
9829
|
+
if (aggregator) {
|
|
9830
|
+
const aggId = aggregator.id ?? "aggregate";
|
|
9831
|
+
const placeholder = aggregator.placeholder ?? "route_output";
|
|
9832
|
+
builder = builder.llmResponses(aggId, aggregator.request, {
|
|
9833
|
+
bindings: [bindToPlaceholder(joinId, placeholder)]
|
|
9834
|
+
});
|
|
9835
|
+
builder = builder.edge(joinId, aggId);
|
|
9836
|
+
builder = builder.output(outputName, aggId);
|
|
9837
|
+
} else {
|
|
9838
|
+
builder = builder.output(outputName, joinId);
|
|
9839
|
+
}
|
|
9840
|
+
return builder.build();
|
|
9841
|
+
}
|
|
9842
|
+
};
|
|
9843
|
+
var FanoutReduceV1 = class {
|
|
9844
|
+
constructor(config) {
|
|
9845
|
+
this.config = config;
|
|
9846
|
+
}
|
|
9847
|
+
/**
|
|
9848
|
+
* Build the workflow specification.
|
|
9849
|
+
*/
|
|
9850
|
+
build() {
|
|
9851
|
+
const {
|
|
9852
|
+
name,
|
|
9853
|
+
generator,
|
|
9854
|
+
generatorId = "generator",
|
|
9855
|
+
itemsPath = "/items",
|
|
9856
|
+
mapper,
|
|
9857
|
+
mapperPlaceholder = "item",
|
|
9858
|
+
maxParallelism = 4,
|
|
9859
|
+
reducer,
|
|
9860
|
+
reducerId = "reducer",
|
|
9861
|
+
reducerBinding,
|
|
9862
|
+
outputName = "final"
|
|
9863
|
+
} = this.config;
|
|
9864
|
+
let builder = new WorkflowBuilderV1();
|
|
9865
|
+
if (name) {
|
|
9866
|
+
builder = builder.name(name);
|
|
9867
|
+
}
|
|
9868
|
+
builder = builder.llmResponses(generatorId, generator);
|
|
9869
|
+
const fanoutId = "__fanout";
|
|
9870
|
+
const itemBindings = [
|
|
9871
|
+
{
|
|
9872
|
+
path: "$",
|
|
9873
|
+
to_placeholder: mapperPlaceholder,
|
|
9874
|
+
encoding: "json_string"
|
|
9875
|
+
}
|
|
9876
|
+
];
|
|
9877
|
+
const mapperRequest = wireRequest3(mapper);
|
|
9878
|
+
builder = builder.mapFanout(fanoutId, {
|
|
9879
|
+
items: { from: generatorId, path: itemsPath },
|
|
9880
|
+
item_bindings: itemBindings,
|
|
9881
|
+
subnode: {
|
|
9882
|
+
id: "__mapper",
|
|
9883
|
+
type: "llm.responses",
|
|
9884
|
+
input: { request: mapperRequest }
|
|
9885
|
+
},
|
|
9886
|
+
max_parallelism: maxParallelism
|
|
9887
|
+
});
|
|
9888
|
+
builder = builder.edge(generatorId, fanoutId);
|
|
9889
|
+
const pointer = reducerBinding?.pointer ?? "/results";
|
|
9890
|
+
const binding = reducerBinding?.placeholder ? bindToPlaceholder(fanoutId, reducerBinding.placeholder, { pointer }) : {
|
|
9891
|
+
from: fanoutId,
|
|
9892
|
+
pointer,
|
|
9893
|
+
to: reducerBinding?.to ?? "/input/0/content/0/text",
|
|
9894
|
+
encoding: "json_string"
|
|
9895
|
+
};
|
|
9896
|
+
builder = builder.llmResponses(reducerId, reducer, {
|
|
9897
|
+
bindings: [binding]
|
|
9898
|
+
});
|
|
9899
|
+
builder = builder.edge(fanoutId, reducerId);
|
|
9900
|
+
builder = builder.output(outputName, reducerId);
|
|
9901
|
+
return builder.build();
|
|
9902
|
+
}
|
|
9903
|
+
};
|
|
9904
|
+
|
|
9905
|
+
// src/workflow/index.ts
|
|
8458
9906
|
var KindV0 = WorkflowKinds.WorkflowV0;
|
|
9907
|
+
var KindV1 = WorkflowKinds.WorkflowV1;
|
|
8459
9908
|
var NodeTypes = {
|
|
8460
9909
|
LLMResponses: WorkflowNodeTypes.LLMResponses,
|
|
8461
9910
|
JoinAll: WorkflowNodeTypes.JoinAll,
|
|
8462
9911
|
TransformJSON: WorkflowNodeTypes.TransformJSON
|
|
8463
9912
|
};
|
|
9913
|
+
var NodeTypesV1 = {
|
|
9914
|
+
LLMResponses: WorkflowNodeTypesV1.LLMResponses,
|
|
9915
|
+
RouteSwitch: WorkflowNodeTypesV1.RouteSwitch,
|
|
9916
|
+
JoinAll: WorkflowNodeTypesV1.JoinAll,
|
|
9917
|
+
JoinAny: WorkflowNodeTypesV1.JoinAny,
|
|
9918
|
+
JoinCollect: WorkflowNodeTypesV1.JoinCollect,
|
|
9919
|
+
TransformJSON: WorkflowNodeTypesV1.TransformJSON,
|
|
9920
|
+
MapFanout: WorkflowNodeTypesV1.MapFanout
|
|
9921
|
+
};
|
|
8464
9922
|
var BindingEncodings = {
|
|
8465
9923
|
JSON: "json",
|
|
8466
9924
|
JSONString: "json_string"
|
|
@@ -8469,8 +9927,6 @@ var ToolExecutionModes = {
|
|
|
8469
9927
|
Server: "server",
|
|
8470
9928
|
Client: "client"
|
|
8471
9929
|
};
|
|
8472
|
-
var LLM_TEXT_OUTPUT2 = "/output/0/content/0/text";
|
|
8473
|
-
var LLM_USER_MESSAGE_TEXT2 = "/request/input/1/content/0/text";
|
|
8474
9930
|
|
|
8475
9931
|
// src/index.ts
|
|
8476
9932
|
var ModelRelay = class _ModelRelay {
|
|
@@ -8492,7 +9948,7 @@ var ModelRelay = class _ModelRelay {
|
|
|
8492
9948
|
const accessToken = "token" in cfg ? cfg.token : void 0;
|
|
8493
9949
|
const tokenProvider = "tokenProvider" in cfg ? cfg.tokenProvider : void 0;
|
|
8494
9950
|
this.baseUrl = resolveBaseUrl(cfg.baseUrl);
|
|
8495
|
-
|
|
9951
|
+
this.http = new HTTPClient({
|
|
8496
9952
|
baseUrl: this.baseUrl,
|
|
8497
9953
|
apiKey,
|
|
8498
9954
|
accessToken,
|
|
@@ -8505,30 +9961,30 @@ var ModelRelay = class _ModelRelay {
|
|
|
8505
9961
|
metrics: cfg.metrics,
|
|
8506
9962
|
trace: cfg.trace
|
|
8507
9963
|
});
|
|
8508
|
-
const auth = new AuthClient(http, {
|
|
9964
|
+
const auth = new AuthClient(this.http, {
|
|
8509
9965
|
apiKey,
|
|
8510
9966
|
accessToken,
|
|
8511
9967
|
customer: cfg.customer,
|
|
8512
9968
|
tokenProvider
|
|
8513
9969
|
});
|
|
8514
9970
|
this.auth = auth;
|
|
8515
|
-
this.responses = new ResponsesClient(http, auth, {
|
|
9971
|
+
this.responses = new ResponsesClient(this.http, auth, {
|
|
8516
9972
|
metrics: cfg.metrics,
|
|
8517
9973
|
trace: cfg.trace
|
|
8518
9974
|
});
|
|
8519
|
-
this.runs = new RunsClient(http, auth, {
|
|
9975
|
+
this.runs = new RunsClient(this.http, auth, {
|
|
8520
9976
|
metrics: cfg.metrics,
|
|
8521
9977
|
trace: cfg.trace
|
|
8522
9978
|
});
|
|
8523
|
-
this.workflows = new WorkflowsClient(http, auth, {
|
|
9979
|
+
this.workflows = new WorkflowsClient(this.http, auth, {
|
|
8524
9980
|
metrics: cfg.metrics,
|
|
8525
9981
|
trace: cfg.trace
|
|
8526
9982
|
});
|
|
8527
|
-
this.images = new ImagesClient(http, auth);
|
|
8528
|
-
this.customers = new CustomersClient(http, { apiKey, accessToken, tokenProvider });
|
|
8529
|
-
this.tiers = new TiersClient(http, { apiKey });
|
|
8530
|
-
this.models = new ModelsClient(http);
|
|
8531
|
-
this.sessions = new SessionsClient(this, http, auth);
|
|
9983
|
+
this.images = new ImagesClient(this.http, auth);
|
|
9984
|
+
this.customers = new CustomersClient(this.http, { apiKey, accessToken, tokenProvider });
|
|
9985
|
+
this.tiers = new TiersClient(this.http, { apiKey });
|
|
9986
|
+
this.models = new ModelsClient(this.http);
|
|
9987
|
+
this.sessions = new SessionsClient(this, this.http, auth);
|
|
8532
9988
|
}
|
|
8533
9989
|
forCustomer(customerId) {
|
|
8534
9990
|
return new CustomerScopedModelRelay(this.responses, customerId, this.baseUrl);
|
|
@@ -8543,6 +9999,7 @@ function resolveBaseUrl(override) {
|
|
|
8543
9999
|
APIError,
|
|
8544
10000
|
AuthClient,
|
|
8545
10001
|
BillingProviders,
|
|
10002
|
+
BindingTargetError,
|
|
8546
10003
|
BrowserDefaults,
|
|
8547
10004
|
BrowserToolNames,
|
|
8548
10005
|
BrowserToolPack,
|
|
@@ -8557,20 +10014,31 @@ function resolveBaseUrl(override) {
|
|
|
8557
10014
|
DEFAULT_BASE_URL,
|
|
8558
10015
|
DEFAULT_CLIENT_HEADER,
|
|
8559
10016
|
DEFAULT_CONNECT_TIMEOUT_MS,
|
|
8560
|
-
DEFAULT_IGNORE_DIRS,
|
|
8561
10017
|
DEFAULT_REQUEST_TIMEOUT_MS,
|
|
8562
10018
|
ErrorCodes,
|
|
8563
|
-
FSDefaults,
|
|
8564
|
-
FSToolNames,
|
|
8565
10019
|
FrontendTokenProvider,
|
|
8566
10020
|
ImagesClient,
|
|
8567
10021
|
InputItemTypes,
|
|
10022
|
+
JoinOutput,
|
|
10023
|
+
JoinOutputPath,
|
|
10024
|
+
LLMInput,
|
|
10025
|
+
LLMInputContentItemPath,
|
|
10026
|
+
LLMInputFirstMessageText,
|
|
10027
|
+
LLMInputMessagePath,
|
|
10028
|
+
LLMInputPath,
|
|
10029
|
+
LLMInputSystemText,
|
|
10030
|
+
LLMInputUserText,
|
|
8568
10031
|
LLMNodeBuilder,
|
|
10032
|
+
LLMOutput,
|
|
10033
|
+
LLMOutputContentItemPath,
|
|
10034
|
+
LLMOutputContentPath,
|
|
10035
|
+
LLMOutputPath,
|
|
10036
|
+
LLMOutputText,
|
|
8569
10037
|
LLMStep,
|
|
8570
10038
|
LLM_TEXT_OUTPUT,
|
|
8571
10039
|
LLM_USER_MESSAGE_TEXT,
|
|
8572
|
-
LocalFSToolPack,
|
|
8573
10040
|
LocalSession,
|
|
10041
|
+
MapFanoutInputError,
|
|
8574
10042
|
MapItem,
|
|
8575
10043
|
MapReduce,
|
|
8576
10044
|
MapReduceBuilder,
|
|
@@ -8609,9 +10077,10 @@ function resolveBaseUrl(override) {
|
|
|
8609
10077
|
TransformJSONNodeBuilder,
|
|
8610
10078
|
TransportError,
|
|
8611
10079
|
WORKFLOWS_COMPILE_PATH,
|
|
8612
|
-
|
|
10080
|
+
WebToolIntents,
|
|
8613
10081
|
Workflow,
|
|
8614
10082
|
WorkflowBuilderV0,
|
|
10083
|
+
WorkflowBuilderV1,
|
|
8615
10084
|
WorkflowKinds,
|
|
8616
10085
|
WorkflowNodeTypes,
|
|
8617
10086
|
WorkflowValidationError,
|
|
@@ -8621,6 +10090,8 @@ function resolveBaseUrl(override) {
|
|
|
8621
10090
|
asSessionId,
|
|
8622
10091
|
asTierCode,
|
|
8623
10092
|
assistantMessageWithToolCalls,
|
|
10093
|
+
buildDelayedNDJSONResponse,
|
|
10094
|
+
buildNDJSONResponse,
|
|
8624
10095
|
createAccessTokenAuth,
|
|
8625
10096
|
createApiKeyAuth,
|
|
8626
10097
|
createAssistantMessage,
|
|
@@ -8629,10 +10100,9 @@ function resolveBaseUrl(override) {
|
|
|
8629
10100
|
createFunctionCall,
|
|
8630
10101
|
createFunctionTool,
|
|
8631
10102
|
createFunctionToolFromSchema,
|
|
8632
|
-
createLocalFSToolPack,
|
|
8633
|
-
createLocalFSTools,
|
|
8634
10103
|
createLocalSession,
|
|
8635
10104
|
createMemorySessionStore,
|
|
10105
|
+
createMockFetchQueue,
|
|
8636
10106
|
createRetryMessages,
|
|
8637
10107
|
createSystemMessage,
|
|
8638
10108
|
createToolCall,
|
|
@@ -8674,6 +10144,7 @@ function resolveBaseUrl(override) {
|
|
|
8674
10144
|
parseToolArgs,
|
|
8675
10145
|
parseToolArgsRaw,
|
|
8676
10146
|
pollOAuthDeviceToken,
|
|
10147
|
+
pollUntil,
|
|
8677
10148
|
respondToToolCall,
|
|
8678
10149
|
runOAuthDeviceFlowForIDToken,
|
|
8679
10150
|
startOAuthDeviceAuthorization,
|
|
@@ -8683,12 +10154,17 @@ function resolveBaseUrl(override) {
|
|
|
8683
10154
|
toolChoiceRequired,
|
|
8684
10155
|
toolResultMessage,
|
|
8685
10156
|
transformJSONMerge,
|
|
10157
|
+
transformJSONMergeV1,
|
|
8686
10158
|
transformJSONObject,
|
|
10159
|
+
transformJSONObjectV1,
|
|
8687
10160
|
transformJSONValue,
|
|
10161
|
+
transformJSONValueV1,
|
|
8688
10162
|
tryParseToolArgs,
|
|
8689
10163
|
validateWithZod,
|
|
8690
10164
|
workflow,
|
|
8691
10165
|
workflowV0,
|
|
8692
10166
|
workflowV0Schema,
|
|
10167
|
+
workflowV1,
|
|
10168
|
+
workflowV1Schema,
|
|
8693
10169
|
zodToJsonSchema
|
|
8694
10170
|
});
|