@modelrelay/sdk 1.42.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -48,11 +48,6 @@ import {
48
48
  getRetryableErrors,
49
49
  hasRetryableErrors,
50
50
  hasToolCalls,
51
- isAutoProvisionDisabled,
52
- isAutoProvisionMisconfigured,
53
- isEmailRequired,
54
- isIdentityRequired,
55
- isProvisioningError,
56
51
  mergeMetrics,
57
52
  mergeTrace,
58
53
  modelToString,
@@ -69,39 +64,27 @@ import {
69
64
  toolResultMessage,
70
65
  tryParseToolArgs,
71
66
  zodToJsonSchema
72
- } from "./chunk-PLZWDUOP.js";
67
+ } from "./chunk-AZD5EKLV.js";
73
68
  import {
74
69
  __export
75
70
  } from "./chunk-MLKGABMK.js";
76
71
 
77
72
  // src/api_keys.ts
78
- var PUBLISHABLE_PREFIX = "mr_pk_";
79
73
  var SECRET_PREFIX = "mr_sk_";
80
74
  function keyKindHint(raw) {
81
75
  const value = raw?.trim?.() ? raw.trim() : "";
82
- if (value.startsWith(PUBLISHABLE_PREFIX)) return "publishable";
83
76
  if (value.startsWith(SECRET_PREFIX)) return "secret";
84
77
  return "unknown";
85
78
  }
86
79
  function parseApiKey(raw) {
87
80
  const value = raw?.trim?.() ? raw.trim() : "";
88
- if (value.startsWith(PUBLISHABLE_PREFIX) && value.length > PUBLISHABLE_PREFIX.length) {
89
- return value;
90
- }
91
81
  if (value.startsWith(SECRET_PREFIX) && value.length > SECRET_PREFIX.length) {
92
82
  return value;
93
83
  }
94
- throw new ConfigError("Invalid API key format (expected mr_pk_* or mr_sk_*)", {
84
+ throw new ConfigError("Invalid API key format (expected mr_sk_*)", {
95
85
  keyKind: keyKindHint(raw)
96
86
  });
97
87
  }
98
- function parsePublishableKey(raw) {
99
- const key = parseApiKey(raw);
100
- if (!isPublishableKey(key)) {
101
- throw new ConfigError("Publishable key required (expected mr_pk_*)", { keyKind: keyKindHint(raw) });
102
- }
103
- return key;
104
- }
105
88
  function parseSecretKey(raw) {
106
89
  const key = parseApiKey(raw);
107
90
  if (!isSecretKey(key)) {
@@ -109,9 +92,6 @@ function parseSecretKey(raw) {
109
92
  }
110
93
  return key;
111
94
  }
112
- function isPublishableKey(key) {
113
- return key.startsWith(PUBLISHABLE_PREFIX);
114
- }
115
95
  function isSecretKey(key) {
116
96
  return key.startsWith(SECRET_PREFIX);
117
97
  }
@@ -125,102 +105,15 @@ function createAccessTokenAuth(accessToken) {
125
105
  }
126
106
  var AuthClient = class {
127
107
  constructor(http, cfg) {
128
- this.cachedFrontend = /* @__PURE__ */ new Map();
129
108
  this.http = http;
130
109
  this.apiKey = cfg.apiKey ? parseApiKey(cfg.apiKey) : void 0;
131
- this.apiKeyIsPublishable = this.apiKey ? isPublishableKey(this.apiKey) : false;
132
110
  this.accessToken = cfg.accessToken;
133
- this.customer = cfg.customer;
134
111
  this.tokenProvider = cfg.tokenProvider;
135
112
  }
136
- /**
137
- * Exchange a publishable key for a short-lived frontend token for an existing customer.
138
- * Tokens are cached until they are close to expiry.
139
- *
140
- * Use this method when the customer already exists in the system.
141
- * For auto-provisioning new customers, use frontendTokenAutoProvision instead.
142
- */
143
- async frontendToken(request) {
144
- if (!request.publishableKey?.trim()) {
145
- throw new ConfigError("publishableKey is required");
146
- }
147
- if (!request.identityProvider?.trim()) {
148
- throw new ConfigError("identityProvider is required");
149
- }
150
- if (!request.identitySubject?.trim()) {
151
- throw new ConfigError("identitySubject is required");
152
- }
153
- return this.sendFrontendTokenRequest(request);
154
- }
155
- /**
156
- * Exchange a publishable key for a frontend token, creating the customer if needed.
157
- * The customer will be auto-provisioned on the project's free tier.
158
- * Tokens are cached until they are close to expiry.
159
- *
160
- * Use this method when the customer may not exist and should be created automatically.
161
- * The email is required for auto-provisioning.
162
- */
163
- async frontendTokenAutoProvision(request) {
164
- if (!request.publishableKey?.trim()) {
165
- throw new ConfigError("publishableKey is required");
166
- }
167
- if (!request.identityProvider?.trim()) {
168
- throw new ConfigError("identityProvider is required");
169
- }
170
- if (!request.identitySubject?.trim()) {
171
- throw new ConfigError("identitySubject is required");
172
- }
173
- if (!request.email?.trim()) {
174
- throw new ConfigError("email is required for auto-provisioning");
175
- }
176
- return this.sendFrontendTokenRequest(request);
177
- }
178
- /**
179
- * Internal method to send frontend token requests.
180
- */
181
- async sendFrontendTokenRequest(request) {
182
- const { publishableKey, identityProvider, identitySubject, deviceId, ttlSeconds } = request;
183
- const email = "email" in request ? request.email : void 0;
184
- const cacheKey = `${publishableKey}:${identityProvider}:${identitySubject}:${deviceId || ""}`;
185
- const cached = this.cachedFrontend.get(cacheKey);
186
- if (cached && isTokenReusable(cached)) {
187
- return cached;
188
- }
189
- const payload = {
190
- publishable_key: publishableKey,
191
- identity_provider: identityProvider,
192
- identity_subject: identitySubject
193
- };
194
- if (deviceId) {
195
- payload.device_id = deviceId;
196
- }
197
- if (typeof ttlSeconds === "number" && ttlSeconds > 0) {
198
- payload.ttl_seconds = ttlSeconds;
199
- }
200
- if (email) {
201
- payload.email = email;
202
- }
203
- const response = await this.http.json(
204
- "/auth/frontend-token",
205
- {
206
- method: "POST",
207
- body: payload
208
- }
209
- );
210
- const token = normalizeFrontendToken(response, {
211
- publishableKey,
212
- deviceId,
213
- identityProvider,
214
- identitySubject
215
- });
216
- this.cachedFrontend.set(cacheKey, token);
217
- return token;
218
- }
219
113
  /**
220
114
  * Determine the correct auth headers for /responses.
221
- * Publishable keys are automatically exchanged for frontend tokens.
222
115
  */
223
- async authForResponses(overrides) {
116
+ async authForResponses() {
224
117
  if (this.accessToken) {
225
118
  return createAccessTokenAuth(this.accessToken);
226
119
  }
@@ -234,32 +127,6 @@ var AuthClient = class {
234
127
  if (!this.apiKey) {
235
128
  throw new ConfigError("API key or token is required");
236
129
  }
237
- if (this.apiKeyIsPublishable) {
238
- const publishableKey = this.apiKey;
239
- const identityProvider = overrides?.provider || this.customer?.provider;
240
- const identitySubject = overrides?.subject || this.customer?.subject;
241
- const deviceId = overrides?.deviceId || this.customer?.deviceId;
242
- const ttlSeconds = overrides?.ttlSeconds ?? this.customer?.ttlSeconds;
243
- const email = overrides?.email || this.customer?.email;
244
- if (!identityProvider || !identitySubject) {
245
- throw new ConfigError("identity provider + subject are required to mint a frontend token");
246
- }
247
- const token = email ? await this.frontendTokenAutoProvision({
248
- publishableKey,
249
- identityProvider,
250
- identitySubject,
251
- email,
252
- deviceId,
253
- ttlSeconds
254
- }) : await this.frontendToken({
255
- publishableKey,
256
- identityProvider,
257
- identitySubject,
258
- deviceId,
259
- ttlSeconds
260
- });
261
- return createAccessTokenAuth(token.token);
262
- }
263
130
  return createApiKeyAuth(this.apiKey);
264
131
  }
265
132
  /**
@@ -274,7 +141,7 @@ var AuthClient = class {
274
141
  if (request.ttlSeconds !== void 0 && request.ttlSeconds < 0) {
275
142
  throw new ConfigError("ttlSeconds must be non-negative when provided");
276
143
  }
277
- if (!this.apiKey || this.apiKeyIsPublishable) {
144
+ if (!this.apiKey) {
278
145
  throw new ConfigError("Secret API key is required to mint customer tokens");
279
146
  }
280
147
  const payload = {};
@@ -299,44 +166,54 @@ var AuthClient = class {
299
166
  tokenType: apiResp.token_type,
300
167
  projectId: apiResp.project_id,
301
168
  customerId: apiResp.customer_id,
169
+ billingProfileId: apiResp.billing_profile_id,
302
170
  customerExternalId: apiResp.customer_external_id,
303
171
  tierCode: apiResp.tier_code ? asTierCode(apiResp.tier_code) : void 0
304
172
  };
305
173
  }
306
174
  /**
307
- * Verify an OIDC id_token and exchange it for a customer bearer token.
175
+ * Get or create a customer and mint a bearer token.
176
+ *
177
+ * This is a convenience method that:
178
+ * 1. Upserts the customer (creates if not exists)
179
+ * 2. Mints a customer-scoped bearer token
180
+ *
181
+ * Use this when you want to ensure the customer exists before minting a token,
182
+ * without needing to handle 404 errors from customerToken().
183
+ *
184
+ * Requires a secret key.
308
185
  */
309
- async oidcExchange(request) {
310
- const idToken = request.idToken?.trim();
311
- if (!idToken) {
312
- throw new ConfigError("idToken is required");
186
+ async getOrCreateCustomerToken(request) {
187
+ const externalId = request.externalId?.trim();
188
+ const email = request.email?.trim();
189
+ if (!externalId) {
190
+ throw new ConfigError("externalId is required");
191
+ }
192
+ if (!email) {
193
+ throw new ConfigError("email is required");
313
194
  }
314
195
  if (!this.apiKey) {
315
- throw new ConfigError("API key is required for OIDC exchange");
196
+ throw new ConfigError("Secret API key is required to get or create customer tokens");
316
197
  }
317
- const payload = { id_token: idToken };
318
- const projectId = request.projectId?.trim();
319
- if (projectId) {
320
- payload.project_id = projectId;
198
+ const upsertPayload = {
199
+ external_id: externalId,
200
+ email
201
+ };
202
+ if (request.metadata) {
203
+ upsertPayload.metadata = request.metadata;
321
204
  }
322
- const apiResp = await this.http.json("/auth/oidc/exchange", {
323
- method: "POST",
324
- body: payload,
205
+ await this.http.json("/customers", {
206
+ method: "PUT",
207
+ body: upsertPayload,
325
208
  apiKey: this.apiKey
326
209
  });
327
- return {
328
- token: apiResp.token,
329
- expiresAt: new Date(apiResp.expires_at),
330
- expiresIn: apiResp.expires_in,
331
- tokenType: apiResp.token_type,
332
- projectId: apiResp.project_id,
333
- customerId: apiResp.customer_id,
334
- customerExternalId: apiResp.customer_external_id,
335
- tierCode: apiResp.tier_code ? asTierCode(apiResp.tier_code) : void 0
336
- };
210
+ return this.customerToken({
211
+ customerExternalId: externalId,
212
+ ttlSeconds: request.ttlSeconds
213
+ });
337
214
  }
338
215
  /**
339
- * Billing calls accept either bearer tokens or API keys (including publishable keys).
216
+ * Billing calls accept either bearer tokens or API keys.
340
217
  */
341
218
  authForBilling() {
342
219
  if (this.accessToken) {
@@ -347,207 +224,7 @@ var AuthClient = class {
347
224
  }
348
225
  return createApiKeyAuth(this.apiKey);
349
226
  }
350
- /**
351
- * Start a device authorization flow (RFC 8628).
352
- *
353
- * @param request - Optional request options
354
- * @param request.provider - Set to "github" to use GitHub's native device flow
355
- *
356
- * @example Wrapped flow (default)
357
- * ```typescript
358
- * const auth = await client.auth.deviceStart();
359
- * console.log(`Go to ${auth.verificationUri} and enter code: ${auth.userCode}`);
360
- * ```
361
- *
362
- * @example Native GitHub flow
363
- * ```typescript
364
- * const auth = await client.auth.deviceStart({ provider: "github" });
365
- * // verificationUri will be "https://github.com/login/device"
366
- * console.log(`Go to ${auth.verificationUri} and enter code: ${auth.userCode}`);
367
- * ```
368
- */
369
- async deviceStart(request) {
370
- if (!this.apiKey) {
371
- throw new ConfigError("API key is required to start device flow");
372
- }
373
- const params = new URLSearchParams();
374
- if (request?.provider) {
375
- params.set("provider", request.provider);
376
- }
377
- const queryString = params.toString();
378
- const path = queryString ? `/auth/device/start?${queryString}` : "/auth/device/start";
379
- const apiResp = await this.http.json(path, {
380
- method: "POST",
381
- apiKey: this.apiKey
382
- });
383
- return {
384
- deviceCode: apiResp.device_code,
385
- userCode: apiResp.user_code,
386
- verificationUri: apiResp.verification_uri,
387
- verificationUriComplete: apiResp.verification_uri_complete,
388
- expiresAt: new Date(Date.now() + apiResp.expires_in * 1e3),
389
- interval: apiResp.interval
390
- };
391
- }
392
- /**
393
- * Poll the device token endpoint for authorization completion.
394
- *
395
- * Returns a discriminated union:
396
- * - `{ status: "approved", token }` - User authorized, token available
397
- * - `{ status: "pending", pending }` - User hasn't authorized yet, keep polling
398
- * - `{ status: "error", error }` - Authorization failed (expired, denied, etc.)
399
- *
400
- * @param deviceCode - The device code from deviceStart()
401
- *
402
- * @example
403
- * ```typescript
404
- * const auth = await client.auth.deviceStart({ provider: "github" });
405
- * console.log(`Go to ${auth.verificationUri} and enter: ${auth.userCode}`);
406
- *
407
- * let interval = auth.interval;
408
- * while (true) {
409
- * await sleep(interval * 1000);
410
- * const result = await client.auth.deviceToken(auth.deviceCode);
411
- *
412
- * if (result.status === "approved") {
413
- * console.log("Token:", result.token.token);
414
- * break;
415
- * } else if (result.status === "pending") {
416
- * if (result.pending.interval) interval = result.pending.interval;
417
- * continue;
418
- * } else {
419
- * throw new Error(`Authorization failed: ${result.error}`);
420
- * }
421
- * }
422
- * ```
423
- */
424
- async deviceToken(deviceCode) {
425
- if (!this.apiKey) {
426
- throw new ConfigError("API key is required to poll device token");
427
- }
428
- if (!deviceCode?.trim()) {
429
- throw new ConfigError("deviceCode is required");
430
- }
431
- try {
432
- const apiResp = await this.http.json("/auth/device/token", {
433
- method: "POST",
434
- body: { device_code: deviceCode },
435
- apiKey: this.apiKey
436
- });
437
- return {
438
- status: "approved",
439
- token: {
440
- token: apiResp.token,
441
- expiresAt: new Date(apiResp.expires_at),
442
- expiresIn: apiResp.expires_in,
443
- tokenType: "Bearer",
444
- projectId: apiResp.project_id,
445
- customerId: apiResp.customer_id,
446
- customerExternalId: apiResp.customer_external_id,
447
- tierCode: apiResp.tier_code ? asTierCode(apiResp.tier_code) : void 0
448
- }
449
- };
450
- } catch (err) {
451
- if (err instanceof APIError && err.status === 400) {
452
- const data = err.data;
453
- const errorCode = data?.error || err.code || "unknown";
454
- if (errorCode === "authorization_pending" || errorCode === "slow_down") {
455
- return {
456
- status: "pending",
457
- pending: {
458
- error: errorCode,
459
- errorDescription: data?.error_description,
460
- interval: data?.interval
461
- }
462
- };
463
- }
464
- return {
465
- status: "error",
466
- error: errorCode,
467
- errorDescription: data?.error_description || err.message
468
- };
469
- }
470
- throw err;
471
- }
472
- }
473
- /**
474
- * Start an OAuth flow for customer authentication.
475
- *
476
- * This initiates the OAuth redirect flow where users authenticate with
477
- * GitHub or Google and are redirected back to your application with a
478
- * customer token.
479
- *
480
- * @param request - OAuth start parameters
481
- * @param request.projectId - The project ID to authenticate against
482
- * @param request.provider - OAuth provider: "github" or "google"
483
- * @param request.redirectUri - Where to redirect after OAuth. Must be in project's whitelist.
484
- * @returns Promise with the redirect URL
485
- *
486
- * @example
487
- * ```typescript
488
- * const { redirectUrl } = await client.auth.oauthStart({
489
- * projectId: "your-project-id",
490
- * provider: "github",
491
- * redirectUri: "https://your-app.com/auth/callback",
492
- * });
493
- *
494
- * // Redirect user to the OAuth provider
495
- * window.location.href = redirectUrl;
496
- *
497
- * // After OAuth, your callback receives a POST with:
498
- * // token, token_type, expires_at, expires_in, project_id, customer_id, customer_external_id, tier_code
499
- * ```
500
- */
501
- async oauthStart(request) {
502
- if (!request.projectId?.trim()) {
503
- throw new ConfigError("projectId is required");
504
- }
505
- if (!request.provider?.trim()) {
506
- throw new ConfigError("provider is required");
507
- }
508
- if (!request.redirectUri?.trim()) {
509
- throw new ConfigError("redirectUri is required");
510
- }
511
- const apiResp = await this.http.json(
512
- "/auth/customer/oauth/start",
513
- {
514
- method: "POST",
515
- body: {
516
- project_id: request.projectId,
517
- provider: request.provider,
518
- redirect_uri: request.redirectUri
519
- }
520
- }
521
- );
522
- return {
523
- redirectUrl: apiResp.redirect_url
524
- };
525
- }
526
227
  };
527
- function normalizeFrontendToken(payload, meta) {
528
- return {
529
- token: payload.token,
530
- expiresAt: new Date(payload.expires_at),
531
- expiresIn: payload.expires_in,
532
- tokenType: payload.token_type,
533
- keyId: payload.key_id,
534
- sessionId: payload.session_id,
535
- projectId: payload.project_id,
536
- customerId: payload.customer_id,
537
- customerExternalId: payload.customer_external_id,
538
- tierCode: payload.tier_code,
539
- publishableKey: meta.publishableKey,
540
- deviceId: meta.deviceId,
541
- identityProvider: meta.identityProvider,
542
- identitySubject: meta.identitySubject
543
- };
544
- }
545
- function isTokenReusable(token) {
546
- if (!token.token) {
547
- return false;
548
- }
549
- return token.expiresAt.getTime() - Date.now() > 6e4;
550
- }
551
228
 
552
229
  // src/structured.ts
553
230
  var StructuredDecodeError = class extends Error {
@@ -1604,7 +1281,7 @@ var ResponsesClient = class {
1604
1281
  * import { z } from 'zod';
1605
1282
  *
1606
1283
  * const review = await client.responses.object({
1607
- * model: 'claude-sonnet-4-20250514',
1284
+ * model: 'claude-sonnet-4-5',
1608
1285
  * schema: z.object({
1609
1286
  * vulnerabilities: z.array(z.string()),
1610
1287
  * riskLevel: z.enum(['low', 'medium', 'high']),
@@ -1661,7 +1338,7 @@ var ResponsesClient = class {
1661
1338
  * @example
1662
1339
  * ```typescript
1663
1340
  * const result = await client.responses.objectWithMetadata({
1664
- * model: 'claude-sonnet-4-20250514',
1341
+ * model: 'claude-sonnet-4-5',
1665
1342
  * schema: ReviewSchema,
1666
1343
  * prompt: 'Review this code...',
1667
1344
  * });
@@ -2070,7 +1747,6 @@ var ResponsesClient = class {
2070
1747
 
2071
1748
  // src/runs_request.ts
2072
1749
  var RUNS_PATH = "/runs";
2073
- var WORKFLOW_V0_SCHEMA_PATH = "/schemas/workflow_v0.schema.json";
2074
1750
  var RUN_EVENT_V0_SCHEMA_PATH = "/schemas/run_event_v0.schema.json";
2075
1751
  function runByIdPath(runId) {
2076
1752
  return `${RUNS_PATH}/${encodeURIComponent(runId)}`;
@@ -2128,14 +1804,8 @@ function parseOutputName(raw) {
2128
1804
 
2129
1805
  // src/runs_types.ts
2130
1806
  var WorkflowKinds = {
2131
- WorkflowV0: "workflow.v0",
2132
1807
  WorkflowV1: "workflow.v1"
2133
1808
  };
2134
- var WorkflowNodeTypes = {
2135
- LLMResponses: "llm.responses",
2136
- JoinAll: "join.all",
2137
- TransformJSON: "transform.json"
2138
- };
2139
1809
  var WorkflowNodeTypesV1 = {
2140
1810
  LLMResponses: "llm.responses",
2141
1811
  RouteSwitch: "route.switch",
@@ -2524,22 +2194,6 @@ var RunsClient = class {
2524
2194
  });
2525
2195
  return { ...out, run_id: parseRunId(out.run_id), plan_hash: parsePlanHash(out.plan_hash) };
2526
2196
  }
2527
- async schemaV0(options = {}) {
2528
- const metrics = mergeMetrics(this.metrics, options.metrics);
2529
- const trace = mergeTrace(this.trace, options.trace);
2530
- return this.http.json(WORKFLOW_V0_SCHEMA_PATH, {
2531
- method: "GET",
2532
- headers: options.headers,
2533
- signal: options.signal,
2534
- timeoutMs: options.timeoutMs,
2535
- connectTimeoutMs: options.connectTimeoutMs,
2536
- retry: options.retry,
2537
- metrics,
2538
- trace,
2539
- context: { method: "GET", path: WORKFLOW_V0_SCHEMA_PATH },
2540
- accept: "application/schema+json"
2541
- });
2542
- }
2543
2197
  async runEventSchemaV0(options = {}) {
2544
2198
  const metrics = mergeMetrics(this.metrics, options.metrics);
2545
2199
  const trace = mergeTrace(this.trace, options.trace);
@@ -2714,65 +2368,6 @@ var WorkflowsClient = class {
2714
2368
  this.metrics = cfg.metrics;
2715
2369
  this.trace = cfg.trace;
2716
2370
  }
2717
- async compileV0(spec, options = {}) {
2718
- const metrics = mergeMetrics(this.metrics, options.metrics);
2719
- const trace = mergeTrace(this.trace, options.trace);
2720
- const authHeaders = await this.auth.authForResponses();
2721
- const headers = { ...options.headers || {} };
2722
- const customerId = options.customerId?.trim();
2723
- if (customerId) {
2724
- headers[CUSTOMER_ID_HEADER] = customerId;
2725
- }
2726
- try {
2727
- const out = await this.http.json(
2728
- WORKFLOWS_COMPILE_PATH,
2729
- {
2730
- method: "POST",
2731
- headers,
2732
- body: spec,
2733
- signal: options.signal,
2734
- apiKey: authHeaders.apiKey,
2735
- accessToken: authHeaders.accessToken,
2736
- timeoutMs: options.timeoutMs,
2737
- connectTimeoutMs: options.connectTimeoutMs,
2738
- retry: options.retry,
2739
- metrics,
2740
- trace,
2741
- context: { method: "POST", path: WORKFLOWS_COMPILE_PATH }
2742
- }
2743
- );
2744
- return {
2745
- ok: true,
2746
- plan_json: out.plan_json,
2747
- plan_hash: parsePlanHash(out.plan_hash)
2748
- };
2749
- } catch (err) {
2750
- if (err instanceof WorkflowValidationError) {
2751
- return { ok: false, error_type: "validation_error", issues: err.issues };
2752
- }
2753
- if (err instanceof APIError) {
2754
- return {
2755
- ok: false,
2756
- error_type: "internal_error",
2757
- status: err.status ?? 0,
2758
- message: err.message,
2759
- code: err.code,
2760
- requestId: err.requestId
2761
- };
2762
- }
2763
- if (err instanceof ModelRelayError && err.category === "api") {
2764
- return {
2765
- ok: false,
2766
- error_type: "internal_error",
2767
- status: err.status ?? 0,
2768
- message: err.message,
2769
- code: err.code,
2770
- requestId: err.requestId
2771
- };
2772
- }
2773
- throw err;
2774
- }
2775
- }
2776
2371
  async compileV1(spec, options = {}) {
2777
2372
  const metrics = mergeMetrics(this.metrics, options.metrics);
2778
2373
  const trace = mergeTrace(this.trace, options.trace);
@@ -3278,7 +2873,7 @@ var LocalSession = class _LocalSession {
3278
2873
  const input = await this.buildInput(options);
3279
2874
  const tools = mergeTools(this.defaultTools, options.tools);
3280
2875
  const spec = {
3281
- kind: "workflow.v0",
2876
+ kind: "workflow.v1",
3282
2877
  name: `session-${this.id}-turn-${this.nextSeq}`,
3283
2878
  nodes: [
3284
2879
  {
@@ -3591,21 +3186,34 @@ function mergeTools(defaults, overrides) {
3591
3186
  }
3592
3187
  return Array.from(merged.values());
3593
3188
  }
3189
+ function isOutputMessage(item) {
3190
+ return typeof item === "object" && item !== null && "type" in item && typeof item.type === "string";
3191
+ }
3192
+ function isContentPiece(c) {
3193
+ return typeof c === "object" && c !== null && "type" in c && typeof c.type === "string";
3194
+ }
3195
+ function hasOutputArray(obj) {
3196
+ return "output" in obj && Array.isArray(obj.output);
3197
+ }
3198
+ function hasContentArray(obj) {
3199
+ return "content" in obj && Array.isArray(obj.content);
3200
+ }
3594
3201
  function extractTextOutput(outputs) {
3595
3202
  const result = outputs.result;
3596
3203
  if (typeof result === "string") return result;
3597
3204
  if (result && typeof result === "object") {
3598
- const resp = result;
3599
- if (Array.isArray(resp.output)) {
3600
- const textParts = resp.output.filter((item) => item?.type === "message" && item?.role === "assistant").flatMap(
3601
- (item) => (item.content || []).filter((c) => c?.type === "text").map((c) => c.text)
3602
- );
3205
+ if (hasOutputArray(result)) {
3206
+ const textParts = result.output.filter(
3207
+ (item) => isOutputMessage(item) && item.type === "message" && item.role === "assistant"
3208
+ ).flatMap(
3209
+ (item) => (item.content || []).filter((c) => isContentPiece(c) && c.type === "text").map((c) => c.text ?? "")
3210
+ ).filter((text) => text.length > 0);
3603
3211
  if (textParts.length > 0) {
3604
3212
  return textParts.join("\n");
3605
3213
  }
3606
3214
  }
3607
- if (Array.isArray(resp.content)) {
3608
- const textParts = resp.content.filter((c) => c?.type === "text").map((c) => c.text);
3215
+ if (hasContentArray(result)) {
3216
+ const textParts = result.content.filter((c) => isContentPiece(c) && c.type === "text").map((c) => c.text ?? "").filter((text) => text.length > 0);
3609
3217
  if (textParts.length > 0) {
3610
3218
  return textParts.join("\n");
3611
3219
  }
@@ -3637,7 +3245,7 @@ var RemoteSession = class _RemoteSession {
3637
3245
  this.http = http;
3638
3246
  this.id = asSessionId(sessionData.id);
3639
3247
  this.metadata = sessionData.metadata;
3640
- this.endUserId = sessionData.end_user_id || options.endUserId;
3248
+ this.customerId = sessionData.customer_id || options.customerId;
3641
3249
  this.createdAt = new Date(sessionData.created_at);
3642
3250
  this.updatedAt = new Date(sessionData.updated_at);
3643
3251
  this.toolRegistry = options.toolRegistry;
@@ -3669,7 +3277,7 @@ var RemoteSession = class _RemoteSession {
3669
3277
  const response = await http.request("/sessions", {
3670
3278
  method: "POST",
3671
3279
  body: {
3672
- end_user_id: options.endUserId,
3280
+ customer_id: options.customerId,
3673
3281
  metadata: options.metadata || {}
3674
3282
  }
3675
3283
  });
@@ -3705,7 +3313,7 @@ var RemoteSession = class _RemoteSession {
3705
3313
  const params = new URLSearchParams();
3706
3314
  if (options.limit) params.set("limit", String(options.limit));
3707
3315
  if (options.offset) params.set("offset", String(options.offset));
3708
- if (options.endUserId) params.set("end_user_id", options.endUserId);
3316
+ if (options.customerId) params.set("customer_id", options.customerId);
3709
3317
  const response = await http.request(
3710
3318
  `/sessions${params.toString() ? `?${params.toString()}` : ""}`,
3711
3319
  { method: "GET" }
@@ -3758,7 +3366,7 @@ var RemoteSession = class _RemoteSession {
3758
3366
  const input = await this.buildInput(options);
3759
3367
  const tools = mergeTools2(this.defaultTools, options.tools);
3760
3368
  const spec = {
3761
- kind: "workflow.v0",
3369
+ kind: "workflow.v1",
3762
3370
  name: `session-${this.id}-turn-${this.nextSeq}`,
3763
3371
  nodes: [
3764
3372
  {
@@ -3778,7 +3386,7 @@ var RemoteSession = class _RemoteSession {
3778
3386
  outputs: [{ name: "result", from: "main" }]
3779
3387
  };
3780
3388
  const run = await this.client.runs.create(spec, {
3781
- customerId: options.customerId || this.endUserId,
3389
+ customerId: options.customerId || this.customerId,
3782
3390
  sessionId: String(this.id)
3783
3391
  });
3784
3392
  this.currentRunId = run.run_id;
@@ -4240,7 +3848,7 @@ var SessionsClient = class {
4240
3848
  /**
4241
3849
  * List remote sessions.
4242
3850
  *
4243
- * @param options - List options (limit, cursor, endUserId)
3851
+ * @param options - List options (limit, cursor, customerId)
4244
3852
  * @returns Paginated list of session summaries
4245
3853
  *
4246
3854
  * @example
@@ -4255,13 +3863,13 @@ var SessionsClient = class {
4255
3863
  return RemoteSession.list(this.modelRelay, {
4256
3864
  limit: options.limit,
4257
3865
  offset: options.cursor ? parseInt(options.cursor, 10) : void 0,
4258
- endUserId: options.endUserId
3866
+ customerId: options.customerId
4259
3867
  });
4260
3868
  }
4261
3869
  /**
4262
3870
  * Delete a remote session.
4263
3871
  *
4264
- * Requires a secret key (not publishable key).
3872
+ * Requires a secret key.
4265
3873
  *
4266
3874
  * @param sessionId - ID of the session to delete
4267
3875
  *
@@ -4287,11 +3895,12 @@ var TiersClient = class {
4287
3895
  this.http = http;
4288
3896
  this.apiKey = cfg.apiKey ? parseApiKey(cfg.apiKey) : void 0;
4289
3897
  this.hasSecretKey = this.apiKey ? isSecretKey(this.apiKey) : false;
3898
+ this.hasAccessToken = !!cfg.accessToken?.trim();
4290
3899
  }
4291
- ensureApiKey() {
4292
- if (!this.apiKey) {
3900
+ ensureAuth() {
3901
+ if (!this.apiKey && !this.hasAccessToken) {
4293
3902
  throw new ConfigError(
4294
- "API key (mr_pk_* or mr_sk_*) required for tier operations"
3903
+ "API key (mr_sk_*) or bearer token required for tier operations"
4295
3904
  );
4296
3905
  }
4297
3906
  }
@@ -4306,7 +3915,7 @@ var TiersClient = class {
4306
3915
  * List all tiers in the project.
4307
3916
  */
4308
3917
  async list() {
4309
- this.ensureApiKey();
3918
+ this.ensureAuth();
4310
3919
  const response = await this.http.json("/tiers", {
4311
3920
  method: "GET",
4312
3921
  apiKey: this.apiKey
@@ -4317,7 +3926,7 @@ var TiersClient = class {
4317
3926
  * Get a tier by ID.
4318
3927
  */
4319
3928
  async get(tierId) {
4320
- this.ensureApiKey();
3929
+ this.ensureAuth();
4321
3930
  if (!tierId?.trim()) {
4322
3931
  throw new ConfigError("tierId is required");
4323
3932
  }
@@ -4332,8 +3941,8 @@ var TiersClient = class {
4332
3941
  *
4333
3942
  * This enables users to subscribe before authenticating. Stripe collects
4334
3943
  * the customer's email during checkout. After checkout completes, a
4335
- * customer record is created with the email from Stripe. The customer
4336
- * can later be linked to an identity via POST /customers/claim.
3944
+ * customer record is created with the email from Stripe. Your backend
3945
+ * can map it to your app user and mint customer tokens as needed.
4337
3946
  *
4338
3947
  * Requires a secret key (mr_sk_*).
4339
3948
  *
@@ -4776,47 +4385,6 @@ function isReusable(token) {
4776
4385
  }
4777
4386
  return token.expiresAt.getTime() - Date.now() > 6e4;
4778
4387
  }
4779
- var FrontendTokenProvider = class {
4780
- constructor(cfg) {
4781
- const publishableKey = parsePublishableKey(cfg.publishableKey);
4782
- const http = new HTTPClient({
4783
- baseUrl: cfg.baseUrl || DEFAULT_BASE_URL,
4784
- fetchImpl: cfg.fetch,
4785
- clientHeader: cfg.clientHeader || DEFAULT_CLIENT_HEADER,
4786
- apiKey: publishableKey
4787
- });
4788
- this.publishableKey = publishableKey;
4789
- this.customer = cfg.customer;
4790
- this.auth = new AuthClient(http, { apiKey: publishableKey, customer: cfg.customer });
4791
- }
4792
- async getToken() {
4793
- if (!this.customer?.provider || !this.customer?.subject) {
4794
- throw new ConfigError("customer.provider and customer.subject are required");
4795
- }
4796
- const reqBase = {
4797
- publishableKey: this.publishableKey,
4798
- identityProvider: this.customer.provider,
4799
- identitySubject: this.customer.subject,
4800
- deviceId: this.customer.deviceId,
4801
- ttlSeconds: this.customer.ttlSeconds
4802
- };
4803
- let token;
4804
- if (this.customer.email) {
4805
- const req = {
4806
- ...reqBase,
4807
- email: this.customer.email
4808
- };
4809
- token = await this.auth.frontendTokenAutoProvision(req);
4810
- } else {
4811
- const req = reqBase;
4812
- token = await this.auth.frontendToken(req);
4813
- }
4814
- if (!token.token) {
4815
- throw new ConfigError("frontend token exchange returned an empty token");
4816
- }
4817
- return token.token;
4818
- }
4819
- };
4820
4388
  var CustomerTokenProvider = class {
4821
4389
  constructor(cfg) {
4822
4390
  const key = parseSecretKey(cfg.secretKey);
@@ -4838,247 +4406,11 @@ var CustomerTokenProvider = class {
4838
4406
  return token.token;
4839
4407
  }
4840
4408
  };
4841
- var OIDCExchangeTokenProvider = class {
4842
- constructor(cfg) {
4843
- const apiKey = parseApiKey(cfg.apiKey);
4844
- const http = new HTTPClient({
4845
- baseUrl: cfg.baseUrl || DEFAULT_BASE_URL,
4846
- fetchImpl: cfg.fetch,
4847
- clientHeader: cfg.clientHeader || DEFAULT_CLIENT_HEADER,
4848
- apiKey
4849
- });
4850
- this.auth = new AuthClient(http, { apiKey });
4851
- this.idTokenProvider = cfg.idTokenProvider;
4852
- this.request = { idToken: "", projectId: cfg.projectId };
4853
- }
4854
- async getToken() {
4855
- if (this.cached && isReusable(this.cached)) {
4856
- return this.cached.token;
4857
- }
4858
- const idToken = (await this.idTokenProvider())?.trim();
4859
- if (!idToken) {
4860
- throw new ConfigError("idTokenProvider returned an empty id_token");
4861
- }
4862
- const token = await this.auth.oidcExchange({ ...this.request, idToken });
4863
- this.cached = token;
4864
- return token.token;
4865
- }
4866
- };
4867
4409
 
4868
- // src/device_flow.ts
4869
- async function pollUntil(opts) {
4870
- let intervalMs = Math.max(1, opts.intervalMs);
4871
- let attempt = 0;
4872
- while (true) {
4873
- if (opts.deadline && Date.now() >= opts.deadline.getTime()) {
4874
- throw opts.onTimeout?.() ?? new TransportError("polling timed out", { kind: "timeout" });
4875
- }
4876
- const result = await opts.poll(attempt);
4877
- if (result.done) {
4878
- return result.value;
4879
- }
4880
- const delay = Math.max(1, result.retryAfterMs ?? intervalMs);
4881
- intervalMs = delay;
4882
- await sleep(delay, opts.signal);
4883
- attempt += 1;
4884
- }
4885
- }
4886
- async function startOAuthDeviceAuthorization(req) {
4887
- const deviceAuthorizationEndpoint = req.deviceAuthorizationEndpoint?.trim();
4888
- if (!deviceAuthorizationEndpoint) {
4889
- throw new ConfigError("deviceAuthorizationEndpoint is required");
4890
- }
4891
- const clientId = req.clientId?.trim();
4892
- if (!clientId) {
4893
- throw new ConfigError("clientId is required");
4894
- }
4895
- const form = new URLSearchParams();
4896
- form.set("client_id", clientId);
4897
- if (req.scope?.trim()) {
4898
- form.set("scope", req.scope.trim());
4899
- }
4900
- if (req.audience?.trim()) {
4901
- form.set("audience", req.audience.trim());
4902
- }
4903
- const payload = await postOAuthForm(deviceAuthorizationEndpoint, form, {
4904
- fetch: req.fetch,
4905
- signal: req.signal
4906
- });
4907
- const deviceCode = String(payload.device_code || "").trim();
4908
- const userCode = String(payload.user_code || "").trim();
4909
- const verificationUri = String(payload.verification_uri || payload.verification_uri_complete || "").trim();
4910
- const verificationUriComplete = String(payload.verification_uri_complete || "").trim() || void 0;
4911
- const expiresIn = Number(payload.expires_in || 0);
4912
- const intervalSeconds = Math.max(1, Number(payload.interval || 5));
4913
- if (!deviceCode || !userCode || !verificationUri || !expiresIn) {
4914
- throw new TransportError("oauth device authorization returned an invalid response", {
4915
- kind: "request",
4916
- cause: payload
4917
- });
4918
- }
4919
- return {
4920
- deviceCode,
4921
- userCode,
4922
- verificationUri,
4923
- verificationUriComplete,
4924
- expiresAt: new Date(Date.now() + expiresIn * 1e3),
4925
- intervalSeconds
4926
- };
4927
- }
4928
- async function pollOAuthDeviceToken(req) {
4929
- const tokenEndpoint = req.tokenEndpoint?.trim();
4930
- if (!tokenEndpoint) {
4931
- throw new ConfigError("tokenEndpoint is required");
4932
- }
4933
- const clientId = req.clientId?.trim();
4934
- if (!clientId) {
4935
- throw new ConfigError("clientId is required");
4936
- }
4937
- const deviceCode = req.deviceCode?.trim();
4938
- if (!deviceCode) {
4939
- throw new ConfigError("deviceCode is required");
4940
- }
4941
- const deadline = req.deadline ?? new Date(Date.now() + 10 * 60 * 1e3);
4942
- let intervalMs = Math.max(1, req.intervalSeconds ?? 5) * 1e3;
4943
- return pollUntil({
4944
- intervalMs,
4945
- deadline,
4946
- signal: req.signal,
4947
- onTimeout: () => new TransportError("oauth device flow timed out", { kind: "timeout" }),
4948
- poll: async () => {
4949
- const form = new URLSearchParams();
4950
- form.set("grant_type", "urn:ietf:params:oauth:grant-type:device_code");
4951
- form.set("device_code", deviceCode);
4952
- form.set("client_id", clientId);
4953
- const payload = await postOAuthForm(tokenEndpoint, form, {
4954
- fetch: req.fetch,
4955
- signal: req.signal,
4956
- allowErrorPayload: true
4957
- });
4958
- const err = String(payload.error || "").trim();
4959
- if (err) {
4960
- switch (err) {
4961
- case "authorization_pending":
4962
- return { done: false };
4963
- case "slow_down":
4964
- intervalMs += 5e3;
4965
- return { done: false, retryAfterMs: intervalMs };
4966
- case "expired_token":
4967
- case "access_denied":
4968
- case "invalid_grant":
4969
- throw new TransportError(`oauth device flow failed: ${err}`, {
4970
- kind: "request",
4971
- cause: payload
4972
- });
4973
- default:
4974
- throw new TransportError(`oauth device flow error: ${err}`, {
4975
- kind: "request",
4976
- cause: payload
4977
- });
4978
- }
4979
- }
4980
- const accessToken = String(payload.access_token || "").trim() || void 0;
4981
- const idToken = String(payload.id_token || "").trim() || void 0;
4982
- const refreshToken = String(payload.refresh_token || "").trim() || void 0;
4983
- const tokenType = String(payload.token_type || "").trim() || void 0;
4984
- const scope = String(payload.scope || "").trim() || void 0;
4985
- const expiresIn = payload.expires_in !== void 0 ? Number(payload.expires_in) : void 0;
4986
- const expiresAt = typeof expiresIn === "number" && Number.isFinite(expiresIn) && expiresIn > 0 ? new Date(Date.now() + expiresIn * 1e3) : void 0;
4987
- if (!accessToken && !idToken) {
4988
- throw new TransportError("oauth device flow returned an invalid token response", {
4989
- kind: "request",
4990
- cause: payload
4991
- });
4992
- }
4993
- return { done: true, value: { accessToken, idToken, refreshToken, tokenType, scope, expiresAt } };
4994
- }
4995
- });
4996
- }
4997
- async function runOAuthDeviceFlowForIDToken(cfg) {
4998
- const auth = await startOAuthDeviceAuthorization({
4999
- deviceAuthorizationEndpoint: cfg.deviceAuthorizationEndpoint,
5000
- clientId: cfg.clientId,
5001
- scope: cfg.scope,
5002
- audience: cfg.audience,
5003
- fetch: cfg.fetch,
5004
- signal: cfg.signal
5005
- });
5006
- await cfg.onUserCode(auth);
5007
- const token = await pollOAuthDeviceToken({
5008
- tokenEndpoint: cfg.tokenEndpoint,
5009
- clientId: cfg.clientId,
5010
- deviceCode: auth.deviceCode,
5011
- intervalSeconds: auth.intervalSeconds,
5012
- deadline: auth.expiresAt,
5013
- fetch: cfg.fetch,
5014
- signal: cfg.signal
5015
- });
5016
- if (!token.idToken) {
5017
- throw new TransportError("oauth device flow did not return an id_token", {
5018
- kind: "request",
5019
- cause: token
5020
- });
5021
- }
5022
- return token.idToken;
5023
- }
5024
- async function postOAuthForm(url, form, opts) {
5025
- const fetchFn = opts.fetch ?? globalThis.fetch;
5026
- if (!fetchFn) {
5027
- throw new ConfigError("fetch is not available; provide a fetch implementation");
5028
- }
5029
- let resp;
5030
- try {
5031
- resp = await fetchFn(url, {
5032
- method: "POST",
5033
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
5034
- body: form.toString(),
5035
- signal: opts.signal
5036
- });
5037
- } catch (cause) {
5038
- throw new TransportError("oauth request failed", { kind: "request", cause });
5039
- }
5040
- let json;
5041
- try {
5042
- json = await resp.json();
5043
- } catch (cause) {
5044
- throw new TransportError("oauth response was not valid JSON", { kind: "request", cause });
5045
- }
5046
- if (!resp.ok && !opts.allowErrorPayload) {
5047
- throw new TransportError(`oauth request failed (${resp.status})`, {
5048
- kind: "request",
5049
- cause: json
5050
- });
5051
- }
5052
- return json || {};
5053
- }
5054
- async function sleep(ms, signal) {
5055
- if (!ms || ms <= 0) {
5056
- return;
5057
- }
5058
- if (!signal) {
5059
- await new Promise((resolve) => setTimeout(resolve, ms));
5060
- return;
5061
- }
5062
- if (signal.aborted) {
5063
- throw new TransportError("oauth device flow aborted", { kind: "request" });
5064
- }
5065
- await new Promise((resolve, reject) => {
5066
- const onAbort = () => {
5067
- signal.removeEventListener("abort", onAbort);
5068
- reject(new TransportError("oauth device flow aborted", { kind: "request" }));
5069
- };
5070
- signal.addEventListener("abort", onAbort);
5071
- setTimeout(() => {
5072
- signal.removeEventListener("abort", onAbort);
5073
- resolve();
5074
- }, ms);
5075
- });
5076
- }
5077
-
5078
- // src/json_path.ts
5079
- var LLMOutputPath = class {
5080
- constructor(path = "/output") {
5081
- this.path = path;
4410
+ // src/json_path.ts
4411
+ var LLMOutputPath = class {
4412
+ constructor(path = "/output") {
4413
+ this.path = path;
5082
4414
  }
5083
4415
  /** Select an output by index */
5084
4416
  index(i) {
@@ -5211,9 +4543,6 @@ function transformJSONObject(object) {
5211
4543
  function transformJSONMerge(merge) {
5212
4544
  return { merge: merge.slice() };
5213
4545
  }
5214
- var transformJSONValueV1 = transformJSONValue;
5215
- var transformJSONObjectV1 = transformJSONObject;
5216
- var transformJSONMergeV1 = transformJSONMerge;
5217
4546
  function wireRequest(req) {
5218
4547
  const raw = req;
5219
4548
  if (raw && typeof raw === "object") {
@@ -5263,2146 +4592,195 @@ function validateInputPointer(pointer, input) {
5263
4592
  }
5264
4593
  const msgIndex = parseInt(match[1], 10);
5265
4594
  if (msgIndex >= input.length) {
5266
- return `targets ${pointer} but request only has ${input.length} messages (indices 0-${input.length - 1}); add placeholder messages or adjust binding target`;
5267
- }
5268
- if (match[2] !== void 0) {
5269
- const contentIndex = parseInt(match[2], 10);
5270
- const msg = input[msgIndex];
5271
- if (contentIndex >= msg.content.length) {
5272
- return `targets ${pointer} but message ${msgIndex} only has ${msg.content.length} content blocks (indices 0-${msg.content.length - 1})`;
5273
- }
5274
- }
5275
- return void 0;
5276
- }
5277
- function validateMapFanoutInput(nodeId, input) {
5278
- const subnode = input.subnode;
5279
- if ((subnode.type === WorkflowNodeTypesV1.LLMResponses || subnode.type === WorkflowNodeTypesV1.RouteSwitch) && subnode.input.bindings && subnode.input.bindings.length > 0) {
5280
- throw new MapFanoutInputError(nodeId, "map.fanout subnode bindings are not allowed");
5281
- }
5282
- if (subnode.type !== WorkflowNodeTypesV1.TransformJSON) {
5283
- return;
5284
- }
5285
- if (input.item_bindings && input.item_bindings.length > 0) {
5286
- throw new MapFanoutInputError(
5287
- nodeId,
5288
- "map.fanout transform.json subnode cannot use item_bindings"
5289
- );
5290
- }
5291
- const hasObject = !!subnode.input.object && Object.keys(subnode.input.object).length > 0;
5292
- const hasMerge = !!subnode.input.merge && subnode.input.merge.length > 0;
5293
- if (hasObject === hasMerge) {
5294
- throw new MapFanoutInputError(
5295
- nodeId,
5296
- "map.fanout transform.json must provide exactly one of object or merge"
5297
- );
5298
- }
5299
- if (hasObject) {
5300
- for (const [key, value] of Object.entries(subnode.input.object ?? {})) {
5301
- if (!key.trim()) continue;
5302
- if (String(value.from) !== "item") {
5303
- throw new MapFanoutInputError(
5304
- nodeId,
5305
- `map.fanout transform.json object.${key}.from must be "item"`
5306
- );
5307
- }
5308
- }
5309
- }
5310
- if (hasMerge) {
5311
- for (const [index, value] of (subnode.input.merge ?? []).entries()) {
5312
- if (String(value.from) !== "item") {
5313
- throw new MapFanoutInputError(
5314
- nodeId,
5315
- `map.fanout transform.json merge[${index}].from must be "item"`
5316
- );
5317
- }
5318
- }
5319
- }
5320
- }
5321
- var WorkflowBuilderV0 = class _WorkflowBuilderV0 {
5322
- constructor(state = { nodes: [], edges: [], outputs: [] }) {
5323
- this.state = state;
5324
- }
5325
- static new() {
5326
- return new _WorkflowBuilderV0();
5327
- }
5328
- with(patch) {
5329
- return new _WorkflowBuilderV0({
5330
- ...this.state,
5331
- ...patch
5332
- });
5333
- }
5334
- name(name) {
5335
- return this.with({ name: name.trim() || void 0 });
5336
- }
5337
- execution(execution) {
5338
- return this.with({ execution });
5339
- }
5340
- node(node) {
5341
- return this.with({ nodes: [...this.state.nodes, node] });
5342
- }
5343
- llmResponses(id, request, options = {}) {
5344
- const wiredRequest = wireRequest(request);
5345
- if (options.bindings) {
5346
- validateBindingTargets(id, wiredRequest.input, options.bindings);
5347
- }
5348
- const input = {
5349
- request: wiredRequest,
5350
- ...options.stream === void 0 ? {} : { stream: options.stream },
5351
- ...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
5352
- ...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
5353
- ...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
5354
- };
5355
- return this.node({
5356
- id,
5357
- type: WorkflowNodeTypes.LLMResponses,
5358
- input
5359
- });
5360
- }
5361
- joinAll(id) {
5362
- return this.node({ id, type: WorkflowNodeTypes.JoinAll });
5363
- }
5364
- transformJSON(id, input) {
5365
- return this.node({ id, type: WorkflowNodeTypes.TransformJSON, input });
5366
- }
5367
- edge(from, to) {
5368
- return this.with({ edges: [...this.state.edges, { from, to }] });
5369
- }
5370
- output(name, from, pointer) {
5371
- return this.with({
5372
- outputs: [
5373
- ...this.state.outputs,
5374
- { name, from, ...pointer ? { pointer } : {} }
5375
- ]
5376
- });
5377
- }
5378
- build() {
5379
- const edges = this.state.edges.slice().sort((a, b) => {
5380
- const af = String(a.from);
5381
- const bf = String(b.from);
5382
- if (af < bf) return -1;
5383
- if (af > bf) return 1;
5384
- const at = String(a.to);
5385
- const bt = String(b.to);
5386
- if (at < bt) return -1;
5387
- if (at > bt) return 1;
5388
- return 0;
5389
- });
5390
- const outputs = this.state.outputs.slice().sort((a, b) => {
5391
- const an = String(a.name);
5392
- const bn = String(b.name);
5393
- if (an < bn) return -1;
5394
- if (an > bn) return 1;
5395
- const af = String(a.from);
5396
- const bf = String(b.from);
5397
- if (af < bf) return -1;
5398
- if (af > bf) return 1;
5399
- const ap = a.pointer ?? "";
5400
- const bp = b.pointer ?? "";
5401
- if (ap < bp) return -1;
5402
- if (ap > bp) return 1;
5403
- return 0;
5404
- });
5405
- return {
5406
- kind: WorkflowKinds.WorkflowV0,
5407
- ...this.state.name ? { name: this.state.name } : {},
5408
- ...this.state.execution ? { execution: this.state.execution } : {},
5409
- nodes: this.state.nodes.slice(),
5410
- ...edges.length ? { edges } : {},
5411
- outputs
5412
- };
5413
- }
5414
- };
5415
- function workflowV0() {
5416
- return WorkflowBuilderV0.new();
5417
- }
5418
- var WorkflowBuilderV1 = class _WorkflowBuilderV1 {
5419
- constructor(state = { nodes: [], edges: [], outputs: [] }) {
5420
- this.state = state;
5421
- }
5422
- static new() {
5423
- return new _WorkflowBuilderV1();
5424
- }
5425
- with(patch) {
5426
- return new _WorkflowBuilderV1({
5427
- ...this.state,
5428
- ...patch
5429
- });
5430
- }
5431
- name(name) {
5432
- return this.with({ name: name.trim() || void 0 });
5433
- }
5434
- execution(execution) {
5435
- return this.with({ execution });
5436
- }
5437
- node(node) {
5438
- return this.with({ nodes: [...this.state.nodes, node] });
5439
- }
5440
- llmResponses(id, request, options = {}) {
5441
- const wiredRequest = wireRequest(request);
5442
- if (options.bindings) {
5443
- validateBindingTargets(id, wiredRequest.input, options.bindings);
5444
- }
5445
- const input = {
5446
- request: wiredRequest,
5447
- ...options.stream === void 0 ? {} : { stream: options.stream },
5448
- ...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
5449
- ...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
5450
- ...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
5451
- };
5452
- return this.node({
5453
- id,
5454
- type: WorkflowNodeTypesV1.LLMResponses,
5455
- input
5456
- });
5457
- }
5458
- routeSwitch(id, request, options = {}) {
5459
- const wiredRequest = wireRequest(request);
5460
- if (options.bindings) {
5461
- validateBindingTargets(id, wiredRequest.input, options.bindings);
5462
- }
5463
- const input = {
5464
- request: wiredRequest,
5465
- ...options.stream === void 0 ? {} : { stream: options.stream },
5466
- ...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
5467
- ...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
5468
- ...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
5469
- };
5470
- return this.node({
5471
- id,
5472
- type: WorkflowNodeTypesV1.RouteSwitch,
5473
- input
5474
- });
5475
- }
5476
- joinAll(id) {
5477
- return this.node({ id, type: WorkflowNodeTypesV1.JoinAll });
5478
- }
5479
- joinAny(id, input) {
5480
- return this.node({
5481
- id,
5482
- type: WorkflowNodeTypesV1.JoinAny,
5483
- ...input ? { input } : {}
5484
- });
5485
- }
5486
- joinCollect(id, input) {
5487
- return this.node({ id, type: WorkflowNodeTypesV1.JoinCollect, input });
5488
- }
5489
- transformJSON(id, input) {
5490
- return this.node({ id, type: WorkflowNodeTypesV1.TransformJSON, input });
5491
- }
5492
- mapFanout(id, input) {
5493
- validateMapFanoutInput(id, input);
5494
- return this.node({ id, type: WorkflowNodeTypesV1.MapFanout, input });
5495
- }
5496
- edge(from, to, when) {
5497
- return this.with({
5498
- edges: [...this.state.edges, { from, to, ...when ? { when } : {} }]
5499
- });
5500
- }
5501
- output(name, from, pointer) {
5502
- return this.with({
5503
- outputs: [
5504
- ...this.state.outputs,
5505
- { name, from, ...pointer ? { pointer } : {} }
5506
- ]
5507
- });
5508
- }
5509
- build() {
5510
- const edges = this.state.edges.slice().sort((a, b) => {
5511
- const af = String(a.from);
5512
- const bf = String(b.from);
5513
- if (af < bf) return -1;
5514
- if (af > bf) return 1;
5515
- const at = String(a.to);
5516
- const bt = String(b.to);
5517
- if (at < bt) return -1;
5518
- if (at > bt) return 1;
5519
- const aw = a.when ? JSON.stringify(a.when) : "";
5520
- const bw = b.when ? JSON.stringify(b.when) : "";
5521
- if (aw < bw) return -1;
5522
- if (aw > bw) return 1;
5523
- return 0;
5524
- });
5525
- const outputs = this.state.outputs.slice().sort((a, b) => {
5526
- const an = String(a.name);
5527
- const bn = String(b.name);
5528
- if (an < bn) return -1;
5529
- if (an > bn) return 1;
5530
- const af = String(a.from);
5531
- const bf = String(b.from);
5532
- if (af < bf) return -1;
5533
- if (af > bf) return 1;
5534
- const ap = a.pointer ?? "";
5535
- const bp = b.pointer ?? "";
5536
- if (ap < bp) return -1;
5537
- if (ap > bp) return 1;
5538
- return 0;
5539
- });
5540
- return {
5541
- kind: WorkflowKinds.WorkflowV1,
5542
- ...this.state.name ? { name: this.state.name } : {},
5543
- ...this.state.execution ? { execution: this.state.execution } : {},
5544
- nodes: this.state.nodes.slice(),
5545
- ...edges.length ? { edges } : {},
5546
- outputs
5547
- };
5548
- }
5549
- };
5550
- function workflowV1() {
5551
- return WorkflowBuilderV1.new();
5552
- }
5553
- var Workflow = class _Workflow {
5554
- constructor(name) {
5555
- this._nodes = [];
5556
- this._edges = /* @__PURE__ */ new Set();
5557
- this._outputs = [];
5558
- this._pendingNode = null;
5559
- this._name = name?.trim() || void 0;
5560
- }
5561
- /**
5562
- * Create a new workflow builder with the given name.
5563
- */
5564
- static create(name) {
5565
- return new _Workflow(name);
5566
- }
5567
- /**
5568
- * Set the workflow execution configuration.
5569
- */
5570
- execution(exec) {
5571
- this.flushPendingNode();
5572
- this._execution = exec;
5573
- return this;
5574
- }
5575
- /**
5576
- * Add an LLM responses node and return a node builder for configuration.
5577
- */
5578
- addLLMNode(id, request) {
5579
- this.flushPendingNode();
5580
- this._pendingNode = {
5581
- id,
5582
- request: wireRequest(request),
5583
- bindings: []
5584
- };
5585
- return new LLMNodeBuilder(this);
5586
- }
5587
- /**
5588
- * Add a join.all node that waits for all incoming edges.
5589
- */
5590
- addJoinAllNode(id) {
5591
- this.flushPendingNode();
5592
- this._nodes.push({ id, type: WorkflowNodeTypes.JoinAll });
5593
- return this;
5594
- }
5595
- /**
5596
- * Add a transform.json node and return a builder for configuration.
5597
- */
5598
- addTransformJSONNode(id) {
5599
- this.flushPendingNode();
5600
- return new TransformJSONNodeBuilder(this, id);
5601
- }
5602
- /**
5603
- * Add an output reference extracting the full node output.
5604
- */
5605
- output(name, from, pointer) {
5606
- this.flushPendingNode();
5607
- this._outputs.push({ name, from, ...pointer ? { pointer } : {} });
5608
- return this;
5609
- }
5610
- /**
5611
- * Add an output reference extracting text content from an LLM response.
5612
- * This is a convenience method that uses the LLM_TEXT_OUTPUT pointer.
5613
- */
5614
- outputText(name, from) {
5615
- return this.output(name, from, LLM_TEXT_OUTPUT);
5616
- }
5617
- /**
5618
- * Explicitly add an edge between nodes.
5619
- * Note: edges are automatically inferred from bindings, so this is rarely needed.
5620
- */
5621
- edge(from, to) {
5622
- this.flushPendingNode();
5623
- this._edges.add(`${from}->${to}`);
5624
- return this;
5625
- }
5626
- /**
5627
- * Build the workflow specification.
5628
- */
5629
- build() {
5630
- this.flushPendingNode();
5631
- const edges = Array.from(this._edges).map((key) => {
5632
- const [from, to] = key.split("->");
5633
- return { from, to };
5634
- }).sort((a, b) => {
5635
- const af = String(a.from);
5636
- const bf = String(b.from);
5637
- if (af < bf) return -1;
5638
- if (af > bf) return 1;
5639
- const at = String(a.to);
5640
- const bt = String(b.to);
5641
- if (at < bt) return -1;
5642
- if (at > bt) return 1;
5643
- return 0;
5644
- });
5645
- const outputs = this._outputs.slice().sort((a, b) => {
5646
- const an = String(a.name);
5647
- const bn = String(b.name);
5648
- if (an < bn) return -1;
5649
- if (an > bn) return 1;
5650
- const af = String(a.from);
5651
- const bf = String(b.from);
5652
- if (af < bf) return -1;
5653
- if (af > bf) return 1;
5654
- const ap = a.pointer ?? "";
5655
- const bp = b.pointer ?? "";
5656
- if (ap < bp) return -1;
5657
- if (ap > bp) return 1;
5658
- return 0;
5659
- });
5660
- return {
5661
- kind: WorkflowKinds.WorkflowV0,
5662
- ...this._name ? { name: this._name } : {},
5663
- ...this._execution ? { execution: this._execution } : {},
5664
- nodes: this._nodes.slice(),
5665
- ...edges.length ? { edges } : {},
5666
- outputs
5667
- };
5668
- }
5669
- /** @internal */
5670
- _getPendingNode() {
5671
- return this._pendingNode;
5672
- }
5673
- /** @internal */
5674
- _addEdge(from, to) {
5675
- this._edges.add(`${from}->${to}`);
5676
- }
5677
- /** @internal */
5678
- _addNode(node) {
5679
- this._nodes.push(node);
5680
- }
5681
- flushPendingNode() {
5682
- const pending = this._pendingNode;
5683
- if (!pending) return;
5684
- this._pendingNode = null;
5685
- if (pending.bindings.length > 0) {
5686
- validateBindingTargets(pending.id, pending.request.input, pending.bindings);
5687
- }
5688
- const input = {
5689
- id: pending.id,
5690
- type: WorkflowNodeTypes.LLMResponses,
5691
- input: {
5692
- request: pending.request,
5693
- ...pending.stream !== void 0 ? { stream: pending.stream } : {},
5694
- ...pending.toolExecution ? { tool_execution: { mode: pending.toolExecution } } : {},
5695
- ...pending.toolLimits ? { tool_limits: pending.toolLimits } : {},
5696
- ...pending.bindings.length ? { bindings: pending.bindings } : {}
5697
- }
5698
- };
5699
- this._nodes.push(input);
5700
- for (const binding of pending.bindings) {
5701
- this._edges.add(`${binding.from}->${pending.id}`);
5702
- }
5703
- }
5704
- };
5705
- var LLMNodeBuilder = class {
5706
- constructor(workflow) {
5707
- this.workflow = workflow;
5708
- }
5709
- /**
5710
- * Enable or disable streaming for this node.
5711
- */
5712
- stream(enabled) {
5713
- const pending = this.workflow._getPendingNode();
5714
- if (pending) {
5715
- pending.stream = enabled;
5716
- }
5717
- return this;
5718
- }
5719
- /**
5720
- * Add a binding from another LLM node's text output to this node's user message.
5721
- * This is the most common binding pattern: LLM text → user message with json_string encoding.
5722
- * The edge from the source node is automatically inferred.
5723
- */
5724
- bindTextFrom(from) {
5725
- return this.bindFromTo(from, LLM_TEXT_OUTPUT, LLM_USER_MESSAGE_TEXT, "json_string");
5726
- }
5727
- /**
5728
- * Add a binding from another node's output to this node's user message text.
5729
- * Use bindTextFrom for the common case of binding LLM text output.
5730
- * The edge from the source node is automatically inferred.
5731
- */
5732
- bindFrom(from, pointer) {
5733
- return this.bindFromTo(from, pointer, LLM_USER_MESSAGE_TEXT, "json_string");
5734
- }
5735
- /**
5736
- * Add a full binding with explicit source/destination pointers and encoding.
5737
- * The edge from the source node is automatically inferred.
5738
- */
5739
- bindFromTo(from, fromPointer, toPointer, encoding) {
5740
- const pending = this.workflow._getPendingNode();
5741
- if (pending) {
5742
- pending.bindings.push({
5743
- from,
5744
- ...fromPointer ? { pointer: fromPointer } : {},
5745
- to: toPointer,
5746
- ...encoding ? { encoding } : {}
5747
- });
5748
- }
5749
- return this;
5750
- }
5751
- /**
5752
- * Add a binding that replaces a {{placeholder}} in the prompt text.
5753
- * This is useful when the prompt contains placeholder markers like {{tier_data}}.
5754
- * The edge from the source node is automatically inferred.
5755
- */
5756
- bindToPlaceholder(from, fromPointer, placeholder) {
5757
- const pending = this.workflow._getPendingNode();
5758
- if (pending) {
5759
- pending.bindings.push({
5760
- from,
5761
- ...fromPointer ? { pointer: fromPointer } : {},
5762
- to_placeholder: placeholder,
5763
- encoding: "json_string"
5764
- });
5765
- }
5766
- return this;
5767
- }
5768
- /**
5769
- * Add a binding from an LLM node's text output to a placeholder.
5770
- * This is the most common placeholder binding: LLM text → {{placeholder}}.
5771
- * The edge from the source node is automatically inferred.
5772
- */
5773
- bindTextToPlaceholder(from, placeholder) {
5774
- return this.bindToPlaceholder(from, LLM_TEXT_OUTPUT, placeholder);
5775
- }
5776
- /**
5777
- * Set the tool execution mode (server or client).
5778
- */
5779
- toolExecution(mode) {
5780
- const pending = this.workflow._getPendingNode();
5781
- if (pending) {
5782
- pending.toolExecution = mode;
5783
- }
5784
- return this;
5785
- }
5786
- /**
5787
- * Set the tool execution limits.
5788
- */
5789
- toolLimits(limits) {
5790
- const pending = this.workflow._getPendingNode();
5791
- if (pending) {
5792
- pending.toolLimits = limits;
5793
- }
5794
- return this;
5795
- }
5796
- // Workflow methods for chaining back
5797
- addLLMNode(id, request) {
5798
- return this.workflow.addLLMNode(id, request);
5799
- }
5800
- addJoinAllNode(id) {
5801
- return this.workflow.addJoinAllNode(id);
5802
- }
5803
- addTransformJSONNode(id) {
5804
- return this.workflow.addTransformJSONNode(id);
5805
- }
5806
- edge(from, to) {
5807
- return this.workflow.edge(from, to);
5808
- }
5809
- output(name, from, pointer) {
5810
- return this.workflow.output(name, from, pointer);
5811
- }
5812
- outputText(name, from) {
5813
- return this.workflow.outputText(name, from);
5814
- }
5815
- execution(exec) {
5816
- return this.workflow.execution(exec);
5817
- }
5818
- build() {
5819
- return this.workflow.build();
5820
- }
5821
- };
5822
- var TransformJSONNodeBuilder = class {
5823
- constructor(workflow, id) {
5824
- this.workflow = workflow;
5825
- this.id = id;
5826
- }
5827
- /**
5828
- * Set the object transformation with field mappings.
5829
- */
5830
- object(fields) {
5831
- this._object = fields;
5832
- return this;
5833
- }
5834
- /**
5835
- * Set the merge transformation with source references.
5836
- */
5837
- merge(items) {
5838
- this._merge = items;
5839
- return this;
5840
- }
5841
- finalize() {
5842
- const input = {};
5843
- if (this._object) input.object = this._object;
5844
- if (this._merge) input.merge = this._merge;
5845
- this.workflow._addNode({
5846
- id: this.id,
5847
- type: WorkflowNodeTypes.TransformJSON,
5848
- input
5849
- });
5850
- if (this._object) {
5851
- for (const ref of Object.values(this._object)) {
5852
- this.workflow._addEdge(ref.from, this.id);
5853
- }
5854
- }
5855
- if (this._merge) {
5856
- for (const ref of this._merge) {
5857
- this.workflow._addEdge(ref.from, this.id);
5858
- }
5859
- }
5860
- }
5861
- // Workflow methods for chaining back
5862
- addLLMNode(id, request) {
5863
- this.finalize();
5864
- return this.workflow.addLLMNode(id, request);
5865
- }
5866
- addJoinAllNode(id) {
5867
- this.finalize();
5868
- return this.workflow.addJoinAllNode(id);
5869
- }
5870
- edge(from, to) {
5871
- this.finalize();
5872
- return this.workflow.edge(from, to);
5873
- }
5874
- output(name, from, pointer) {
5875
- this.finalize();
5876
- return this.workflow.output(name, from, pointer);
5877
- }
5878
- execution(exec) {
5879
- this.finalize();
5880
- return this.workflow.execution(exec);
5881
- }
5882
- build() {
5883
- this.finalize();
5884
- return this.workflow.build();
5885
- }
5886
- };
5887
- function newWorkflow(name) {
5888
- return Workflow.create(name);
5889
- }
5890
-
5891
- // src/workflow_v0.schema.json
5892
- var workflow_v0_schema_default = {
5893
- $id: "https://modelrelay.ai/schemas/workflow_v0.schema.json",
5894
- $schema: "http://json-schema.org/draft-07/schema#",
5895
- additionalProperties: false,
5896
- definitions: {
5897
- edge: {
5898
- additionalProperties: false,
5899
- properties: {
5900
- from: {
5901
- minLength: 1,
5902
- type: "string"
5903
- },
5904
- to: {
5905
- minLength: 1,
5906
- type: "string"
5907
- }
5908
- },
5909
- required: [
5910
- "from",
5911
- "to"
5912
- ],
5913
- type: "object"
5914
- },
5915
- llmResponsesBinding: {
5916
- additionalProperties: false,
5917
- oneOf: [
5918
- {
5919
- required: [
5920
- "to"
5921
- ]
5922
- },
5923
- {
5924
- required: [
5925
- "to_placeholder"
5926
- ]
5927
- }
5928
- ],
5929
- properties: {
5930
- encoding: {
5931
- enum: [
5932
- "json",
5933
- "json_string"
5934
- ],
5935
- type: "string"
5936
- },
5937
- from: {
5938
- minLength: 1,
5939
- type: "string"
5940
- },
5941
- pointer: {
5942
- pattern: "^(/.*)?$",
5943
- type: "string"
5944
- },
5945
- to: {
5946
- pattern: "^/.*$",
5947
- type: "string"
5948
- },
5949
- to_placeholder: {
5950
- minLength: 1,
5951
- type: "string"
5952
- }
5953
- },
5954
- required: [
5955
- "from"
5956
- ],
5957
- type: "object"
5958
- },
5959
- node: {
5960
- additionalProperties: false,
5961
- oneOf: [
5962
- {
5963
- allOf: [
5964
- {
5965
- properties: {
5966
- input: {
5967
- properties: {
5968
- bindings: {
5969
- items: {
5970
- $ref: "#/definitions/llmResponsesBinding"
5971
- },
5972
- type: "array"
5973
- },
5974
- request: {
5975
- type: "object"
5976
- },
5977
- stream: {
5978
- type: "boolean"
5979
- },
5980
- tool_execution: {
5981
- additionalProperties: false,
5982
- properties: {
5983
- mode: {
5984
- default: "server",
5985
- enum: [
5986
- "server",
5987
- "client"
5988
- ],
5989
- type: "string"
5990
- }
5991
- },
5992
- required: [
5993
- "mode"
5994
- ],
5995
- type: "object"
5996
- },
5997
- tool_limits: {
5998
- additionalProperties: false,
5999
- properties: {
6000
- max_llm_calls: {
6001
- default: 8,
6002
- maximum: 64,
6003
- minimum: 1,
6004
- type: "integer"
6005
- },
6006
- max_tool_calls_per_step: {
6007
- default: 16,
6008
- maximum: 64,
6009
- minimum: 1,
6010
- type: "integer"
6011
- },
6012
- wait_ttl_ms: {
6013
- default: 9e5,
6014
- maximum: 864e5,
6015
- minimum: 1,
6016
- type: "integer"
6017
- }
6018
- },
6019
- type: "object"
6020
- }
6021
- },
6022
- required: [
6023
- "request"
6024
- ],
6025
- type: "object"
6026
- }
6027
- }
6028
- }
6029
- ],
6030
- properties: {
6031
- type: {
6032
- const: "llm.responses"
6033
- }
6034
- },
6035
- required: [
6036
- "input"
6037
- ]
6038
- },
6039
- {
6040
- properties: {
6041
- type: {
6042
- const: "join.all"
6043
- }
6044
- }
6045
- },
6046
- {
6047
- allOf: [
6048
- {
6049
- properties: {
6050
- input: {
6051
- additionalProperties: false,
6052
- oneOf: [
6053
- {
6054
- not: {
6055
- required: [
6056
- "merge"
6057
- ]
6058
- },
6059
- required: [
6060
- "object"
6061
- ]
6062
- },
6063
- {
6064
- not: {
6065
- required: [
6066
- "object"
6067
- ]
6068
- },
6069
- required: [
6070
- "merge"
6071
- ]
6072
- }
6073
- ],
6074
- properties: {
6075
- merge: {
6076
- items: {
6077
- $ref: "#/definitions/transformValue"
6078
- },
6079
- minItems: 1,
6080
- type: "array"
6081
- },
6082
- object: {
6083
- additionalProperties: {
6084
- $ref: "#/definitions/transformValue"
6085
- },
6086
- minProperties: 1,
6087
- type: "object"
6088
- }
6089
- },
6090
- type: "object"
6091
- }
6092
- }
6093
- }
6094
- ],
6095
- properties: {
6096
- type: {
6097
- const: "transform.json"
6098
- }
6099
- },
6100
- required: [
6101
- "input"
6102
- ]
6103
- }
6104
- ],
6105
- properties: {
6106
- id: {
6107
- minLength: 1,
6108
- type: "string"
6109
- },
6110
- input: {},
6111
- type: {
6112
- enum: [
6113
- "llm.responses",
6114
- "join.all",
6115
- "transform.json"
6116
- ],
6117
- type: "string"
6118
- }
6119
- },
6120
- required: [
6121
- "id",
6122
- "type"
6123
- ],
6124
- type: "object"
6125
- },
6126
- output: {
6127
- additionalProperties: false,
6128
- properties: {
6129
- from: {
6130
- minLength: 1,
6131
- type: "string"
6132
- },
6133
- name: {
6134
- minLength: 1,
6135
- type: "string"
6136
- },
6137
- pointer: {
6138
- pattern: "^(/.*)?$",
6139
- type: "string"
6140
- }
6141
- },
6142
- required: [
6143
- "name",
6144
- "from"
6145
- ],
6146
- type: "object"
6147
- },
6148
- transformValue: {
6149
- additionalProperties: false,
6150
- properties: {
6151
- from: {
6152
- minLength: 1,
6153
- type: "string"
6154
- },
6155
- pointer: {
6156
- pattern: "^(/.*)?$",
6157
- type: "string"
6158
- }
6159
- },
6160
- required: [
6161
- "from"
6162
- ],
6163
- type: "object"
6164
- }
6165
- },
6166
- properties: {
6167
- edges: {
6168
- items: {
6169
- $ref: "#/definitions/edge"
6170
- },
6171
- type: "array"
6172
- },
6173
- execution: {
6174
- additionalProperties: false,
6175
- properties: {
6176
- max_parallelism: {
6177
- minimum: 1,
6178
- type: "integer"
6179
- },
6180
- node_timeout_ms: {
6181
- minimum: 1,
6182
- type: "integer"
6183
- },
6184
- run_timeout_ms: {
6185
- minimum: 1,
6186
- type: "integer"
6187
- }
6188
- },
6189
- type: "object"
6190
- },
6191
- kind: {
6192
- const: "workflow.v0",
6193
- type: "string"
6194
- },
6195
- name: {
6196
- type: "string"
6197
- },
6198
- nodes: {
6199
- items: {
6200
- $ref: "#/definitions/node"
6201
- },
6202
- minItems: 1,
6203
- type: "array"
6204
- },
6205
- outputs: {
6206
- items: {
6207
- $ref: "#/definitions/output"
6208
- },
6209
- minItems: 1,
6210
- type: "array"
6211
- }
6212
- },
6213
- required: [
6214
- "kind",
6215
- "nodes",
6216
- "outputs"
6217
- ],
6218
- title: "ModelRelay workflow.v0",
6219
- type: "object"
6220
- };
6221
-
6222
- // src/workflow_v1.schema.json
6223
- var workflow_v1_schema_default = {
6224
- $id: "https://modelrelay.ai/schemas/workflow_v1.schema.json",
6225
- $schema: "http://json-schema.org/draft-07/schema#",
6226
- additionalProperties: false,
6227
- definitions: {
6228
- condition: {
6229
- additionalProperties: false,
6230
- properties: {
6231
- op: {
6232
- enum: [
6233
- "equals",
6234
- "matches",
6235
- "exists"
6236
- ],
6237
- type: "string"
6238
- },
6239
- path: {
6240
- pattern: "^\\$.*$",
6241
- type: "string"
6242
- },
6243
- source: {
6244
- enum: [
6245
- "node_output",
6246
- "node_status"
6247
- ],
6248
- type: "string"
6249
- },
6250
- value: {}
6251
- },
6252
- required: [
6253
- "source",
6254
- "op"
6255
- ],
6256
- type: "object"
6257
- },
6258
- edge: {
6259
- additionalProperties: false,
6260
- properties: {
6261
- from: {
6262
- minLength: 1,
6263
- type: "string"
6264
- },
6265
- to: {
6266
- minLength: 1,
6267
- type: "string"
6268
- },
6269
- when: {
6270
- $ref: "#/definitions/condition"
6271
- }
6272
- },
6273
- required: [
6274
- "from",
6275
- "to"
6276
- ],
6277
- type: "object"
6278
- },
6279
- fragmentBindInput: {
6280
- additionalProperties: false,
6281
- oneOf: [
6282
- {
6283
- required: [
6284
- "from_node"
6285
- ]
6286
- },
6287
- {
6288
- required: [
6289
- "from_input"
6290
- ]
6291
- }
6292
- ],
6293
- properties: {
6294
- from_input: {
6295
- minLength: 1,
6296
- type: "string"
6297
- },
6298
- from_node: {
6299
- minLength: 1,
6300
- type: "string"
6301
- },
6302
- pointer: {
6303
- pattern: "^(/.*)?$",
6304
- type: "string"
6305
- }
6306
- },
6307
- type: "object"
6308
- },
6309
- fragmentDef: {
6310
- additionalProperties: false,
6311
- properties: {
6312
- edges: {
6313
- items: {
6314
- $ref: "#/definitions/edge"
6315
- },
6316
- type: "array"
6317
- },
6318
- inputs: {
6319
- items: {
6320
- $ref: "#/definitions/fragmentInput"
6321
- },
6322
- type: "array"
6323
- },
6324
- nodes: {
6325
- items: {
6326
- $ref: "#/definitions/node"
6327
- },
6328
- minItems: 1,
6329
- type: "array"
6330
- },
6331
- outputs: {
6332
- items: {
6333
- $ref: "#/definitions/fragmentOutput"
6334
- },
6335
- minItems: 1,
6336
- type: "array"
6337
- }
6338
- },
6339
- required: [
6340
- "outputs",
6341
- "nodes"
6342
- ],
6343
- type: "object"
6344
- },
6345
- fragmentInput: {
6346
- additionalProperties: false,
6347
- properties: {
6348
- name: {
6349
- minLength: 1,
6350
- type: "string"
6351
- },
6352
- type: {
6353
- type: "string"
6354
- }
6355
- },
6356
- required: [
6357
- "name"
6358
- ],
6359
- type: "object"
6360
- },
6361
- fragmentOutput: {
6362
- additionalProperties: false,
6363
- properties: {
6364
- from_node: {
6365
- minLength: 1,
6366
- type: "string"
6367
- },
6368
- name: {
6369
- minLength: 1,
6370
- type: "string"
6371
- },
6372
- pointer: {
6373
- pattern: "^(/.*)?$",
6374
- type: "string"
6375
- }
6376
- },
6377
- required: [
6378
- "name",
6379
- "from_node"
6380
- ],
6381
- type: "object"
6382
- },
6383
- llmResponsesBinding: {
6384
- additionalProperties: false,
6385
- oneOf: [
6386
- {
6387
- required: [
6388
- "to"
6389
- ]
6390
- },
6391
- {
6392
- required: [
6393
- "to_placeholder"
6394
- ]
6395
- }
6396
- ],
6397
- properties: {
6398
- encoding: {
6399
- enum: [
6400
- "json",
6401
- "json_string"
6402
- ],
6403
- type: "string"
6404
- },
6405
- from: {
6406
- minLength: 1,
6407
- type: "string"
6408
- },
6409
- pointer: {
6410
- pattern: "^(/.*)?$",
6411
- type: "string"
6412
- },
6413
- to: {
6414
- pattern: "^/.*$",
6415
- type: "string"
6416
- },
6417
- to_placeholder: {
6418
- minLength: 1,
6419
- type: "string"
6420
- }
6421
- },
6422
- required: [
6423
- "from"
6424
- ],
6425
- type: "object"
6426
- },
6427
- mapFanoutItemBinding: {
6428
- additionalProperties: false,
6429
- oneOf: [
6430
- {
6431
- required: [
6432
- "to"
6433
- ]
6434
- },
6435
- {
6436
- required: [
6437
- "to_placeholder"
6438
- ]
6439
- }
6440
- ],
6441
- properties: {
6442
- encoding: {
6443
- enum: [
6444
- "json",
6445
- "json_string"
6446
- ],
6447
- type: "string"
6448
- },
6449
- path: {
6450
- pattern: "^(/.*)?$",
6451
- type: "string"
6452
- },
6453
- to: {
6454
- pattern: "^/.*$",
6455
- type: "string"
6456
- },
6457
- to_placeholder: {
6458
- minLength: 1,
6459
- type: "string"
6460
- }
6461
- },
6462
- type: "object"
6463
- },
6464
- node: {
6465
- additionalProperties: false,
6466
- oneOf: [
6467
- {
6468
- allOf: [
6469
- {
6470
- properties: {
6471
- input: {
6472
- properties: {
6473
- bindings: {
6474
- items: {
6475
- $ref: "#/definitions/llmResponsesBinding"
6476
- },
6477
- type: "array"
6478
- },
6479
- request: {
6480
- type: "object"
6481
- },
6482
- stream: {
6483
- type: "boolean"
6484
- },
6485
- tool_execution: {
6486
- additionalProperties: false,
6487
- properties: {
6488
- mode: {
6489
- default: "server",
6490
- enum: [
6491
- "server",
6492
- "client"
6493
- ],
6494
- type: "string"
6495
- }
6496
- },
6497
- required: [
6498
- "mode"
6499
- ],
6500
- type: "object"
6501
- },
6502
- tool_limits: {
6503
- additionalProperties: false,
6504
- properties: {
6505
- max_llm_calls: {
6506
- default: 8,
6507
- maximum: 64,
6508
- minimum: 1,
6509
- type: "integer"
6510
- },
6511
- max_tool_calls_per_step: {
6512
- default: 16,
6513
- maximum: 64,
6514
- minimum: 1,
6515
- type: "integer"
6516
- },
6517
- wait_ttl_ms: {
6518
- default: 9e5,
6519
- maximum: 864e5,
6520
- minimum: 1,
6521
- type: "integer"
6522
- }
6523
- },
6524
- type: "object"
6525
- }
6526
- },
6527
- required: [
6528
- "request"
6529
- ],
6530
- type: "object"
6531
- }
6532
- }
6533
- }
6534
- ],
6535
- properties: {
6536
- type: {
6537
- const: "llm.responses"
6538
- }
6539
- },
6540
- required: [
6541
- "input"
6542
- ]
6543
- },
6544
- {
6545
- allOf: [
6546
- {
6547
- properties: {
6548
- input: {
6549
- properties: {
6550
- bindings: {
6551
- items: {
6552
- $ref: "#/definitions/llmResponsesBinding"
6553
- },
6554
- type: "array"
6555
- },
6556
- request: {
6557
- type: "object"
6558
- },
6559
- stream: {
6560
- type: "boolean"
6561
- },
6562
- tool_execution: {
6563
- additionalProperties: false,
6564
- properties: {
6565
- mode: {
6566
- default: "server",
6567
- enum: [
6568
- "server",
6569
- "client"
6570
- ],
6571
- type: "string"
6572
- }
6573
- },
6574
- required: [
6575
- "mode"
6576
- ],
6577
- type: "object"
6578
- },
6579
- tool_limits: {
6580
- additionalProperties: false,
6581
- properties: {
6582
- max_llm_calls: {
6583
- default: 8,
6584
- maximum: 64,
6585
- minimum: 1,
6586
- type: "integer"
6587
- },
6588
- max_tool_calls_per_step: {
6589
- default: 16,
6590
- maximum: 64,
6591
- minimum: 1,
6592
- type: "integer"
6593
- },
6594
- wait_ttl_ms: {
6595
- default: 9e5,
6596
- maximum: 864e5,
6597
- minimum: 1,
6598
- type: "integer"
6599
- }
6600
- },
6601
- type: "object"
6602
- }
6603
- },
6604
- required: [
6605
- "request"
6606
- ],
6607
- type: "object"
6608
- }
6609
- }
6610
- }
6611
- ],
6612
- properties: {
6613
- type: {
6614
- const: "route.switch"
6615
- }
6616
- },
6617
- required: [
6618
- "input"
6619
- ]
6620
- },
6621
- {
6622
- properties: {
6623
- type: {
6624
- const: "join.all"
6625
- }
6626
- }
6627
- },
6628
- {
6629
- allOf: [
6630
- {
6631
- properties: {
6632
- input: {
6633
- additionalProperties: false,
6634
- properties: {
6635
- predicate: {
6636
- $ref: "#/definitions/condition"
6637
- }
6638
- },
6639
- type: "object"
6640
- }
6641
- }
6642
- }
6643
- ],
6644
- properties: {
6645
- type: {
6646
- const: "join.any"
6647
- }
6648
- }
6649
- },
6650
- {
6651
- allOf: [
6652
- {
6653
- properties: {
6654
- input: {
6655
- additionalProperties: false,
6656
- properties: {
6657
- limit: {
6658
- minimum: 1,
6659
- type: "integer"
6660
- },
6661
- predicate: {
6662
- $ref: "#/definitions/condition"
6663
- },
6664
- timeout_ms: {
6665
- minimum: 1,
6666
- type: "integer"
6667
- }
6668
- },
6669
- type: "object"
6670
- }
6671
- }
6672
- }
6673
- ],
6674
- properties: {
6675
- type: {
6676
- const: "join.collect"
6677
- }
6678
- },
6679
- required: [
6680
- "input"
6681
- ]
6682
- },
6683
- {
6684
- allOf: [
6685
- {
6686
- properties: {
6687
- input: {
6688
- additionalProperties: false,
6689
- oneOf: [
6690
- {
6691
- not: {
6692
- required: [
6693
- "merge"
6694
- ]
6695
- },
6696
- required: [
6697
- "object"
6698
- ]
6699
- },
6700
- {
6701
- not: {
6702
- required: [
6703
- "object"
6704
- ]
6705
- },
6706
- required: [
6707
- "merge"
6708
- ]
6709
- }
6710
- ],
6711
- properties: {
6712
- merge: {
6713
- items: {
6714
- $ref: "#/definitions/transformValue"
6715
- },
6716
- minItems: 1,
6717
- type: "array"
6718
- },
6719
- object: {
6720
- additionalProperties: {
6721
- $ref: "#/definitions/transformValue"
6722
- },
6723
- minProperties: 1,
6724
- type: "object"
6725
- }
6726
- },
6727
- type: "object"
6728
- }
6729
- }
6730
- }
6731
- ],
6732
- properties: {
6733
- type: {
6734
- const: "transform.json"
6735
- }
6736
- },
6737
- required: [
6738
- "input"
6739
- ]
6740
- },
6741
- {
6742
- allOf: [
6743
- {
6744
- properties: {
6745
- input: {
6746
- additionalProperties: false,
6747
- properties: {
6748
- item_bindings: {
6749
- items: {
6750
- $ref: "#/definitions/mapFanoutItemBinding"
6751
- },
6752
- type: "array"
6753
- },
6754
- items: {
6755
- additionalProperties: false,
6756
- properties: {
6757
- from: {
6758
- minLength: 1,
6759
- type: "string"
6760
- },
6761
- path: {
6762
- pattern: "^(/.*)?$",
6763
- type: "string"
6764
- },
6765
- pointer: {
6766
- pattern: "^(/.*)?$",
6767
- type: "string"
6768
- }
6769
- },
6770
- required: [
6771
- "from"
6772
- ],
6773
- type: "object"
6774
- },
6775
- max_parallelism: {
6776
- minimum: 1,
6777
- type: "integer"
6778
- },
6779
- subnode: {
6780
- additionalProperties: false,
6781
- properties: {
6782
- id: {
6783
- minLength: 1,
6784
- type: "string"
6785
- },
6786
- input: {},
6787
- type: {
6788
- enum: [
6789
- "llm.responses",
6790
- "route.switch",
6791
- "transform.json"
6792
- ],
6793
- type: "string"
6794
- }
6795
- },
6796
- required: [
6797
- "id",
6798
- "type"
6799
- ],
6800
- type: "object"
6801
- }
6802
- },
6803
- required: [
6804
- "items",
6805
- "subnode"
6806
- ],
6807
- type: "object"
6808
- }
6809
- }
6810
- }
6811
- ],
6812
- properties: {
6813
- type: {
6814
- const: "map.fanout"
6815
- }
6816
- },
6817
- required: [
6818
- "input"
6819
- ]
6820
- },
6821
- {
6822
- allOf: [
6823
- {
6824
- properties: {
6825
- input: {
6826
- additionalProperties: false,
6827
- properties: {
6828
- bind_inputs: {
6829
- additionalProperties: {
6830
- $ref: "#/definitions/fragmentBindInput"
6831
- },
6832
- type: "object"
6833
- },
6834
- ref: {
6835
- minLength: 1,
6836
- type: "string"
6837
- }
6838
- },
6839
- required: [
6840
- "ref"
6841
- ],
6842
- type: "object"
6843
- }
6844
- }
6845
- }
6846
- ],
6847
- properties: {
6848
- type: {
6849
- const: "fragment"
6850
- }
6851
- },
6852
- required: [
6853
- "input"
6854
- ]
6855
- }
6856
- ],
6857
- properties: {
6858
- id: {
6859
- minLength: 1,
6860
- type: "string"
6861
- },
6862
- input: {},
6863
- type: {
6864
- enum: [
6865
- "llm.responses",
6866
- "route.switch",
6867
- "join.all",
6868
- "join.any",
6869
- "join.collect",
6870
- "transform.json",
6871
- "map.fanout",
6872
- "fragment"
6873
- ],
6874
- type: "string"
6875
- }
6876
- },
6877
- required: [
6878
- "id",
6879
- "type"
6880
- ],
6881
- type: "object"
6882
- },
6883
- output: {
6884
- additionalProperties: false,
6885
- properties: {
6886
- from: {
6887
- minLength: 1,
6888
- type: "string"
6889
- },
6890
- name: {
6891
- minLength: 1,
6892
- type: "string"
6893
- },
6894
- output: {
6895
- minLength: 1,
6896
- type: "string"
6897
- },
6898
- pointer: {
6899
- pattern: "^(/.*)?$",
6900
- type: "string"
6901
- }
6902
- },
6903
- required: [
6904
- "name",
6905
- "from"
6906
- ],
6907
- type: "object"
6908
- },
6909
- transformValue: {
6910
- additionalProperties: false,
6911
- properties: {
6912
- from: {
6913
- minLength: 1,
6914
- type: "string"
6915
- },
6916
- pointer: {
6917
- pattern: "^(/.*)?$",
6918
- type: "string"
6919
- }
6920
- },
6921
- required: [
6922
- "from"
6923
- ],
6924
- type: "object"
6925
- }
6926
- },
6927
- properties: {
6928
- edges: {
6929
- items: {
6930
- $ref: "#/definitions/edge"
6931
- },
6932
- type: "array"
6933
- },
6934
- execution: {
6935
- additionalProperties: false,
6936
- properties: {
6937
- max_parallelism: {
6938
- minimum: 1,
6939
- type: "integer"
6940
- },
6941
- node_timeout_ms: {
6942
- minimum: 1,
6943
- type: "integer"
6944
- },
6945
- run_timeout_ms: {
6946
- minimum: 1,
6947
- type: "integer"
6948
- }
6949
- },
6950
- type: "object"
6951
- },
6952
- fragments: {
6953
- additionalProperties: {
6954
- $ref: "#/definitions/fragmentDef"
6955
- },
6956
- type: "object"
6957
- },
6958
- kind: {
6959
- const: "workflow.v1",
6960
- type: "string"
6961
- },
6962
- name: {
6963
- type: "string"
6964
- },
6965
- nodes: {
6966
- items: {
6967
- $ref: "#/definitions/node"
6968
- },
6969
- minItems: 1,
6970
- type: "array"
6971
- },
6972
- outputs: {
6973
- items: {
6974
- $ref: "#/definitions/output"
6975
- },
6976
- minItems: 1,
6977
- type: "array"
6978
- }
6979
- },
6980
- required: [
6981
- "kind",
6982
- "nodes",
6983
- "outputs"
6984
- ],
6985
- title: "ModelRelay workflow.v1",
6986
- type: "object"
6987
- };
6988
-
6989
- // src/workflow_patterns.ts
6990
- var LLM_TEXT_OUTPUT_INTERNAL = "/output/0/content/0/text";
6991
- var LLM_USER_MESSAGE_TEXT_INTERNAL = "/input/1/content/0/text";
6992
- function wireRequest2(req) {
6993
- const raw = req;
6994
- if (raw && typeof raw === "object") {
6995
- if ("input" in raw) {
6996
- return req;
6997
- }
6998
- if ("body" in raw) {
6999
- return raw.body ?? {};
7000
- }
4595
+ return `targets ${pointer} but request only has ${input.length} messages (indices 0-${input.length - 1}); add placeholder messages or adjust binding target`;
7001
4596
  }
7002
- return asInternal(req).body;
7003
- }
7004
- function sortEdges(edges) {
7005
- return edges.slice().sort((a, b) => {
7006
- const af = String(a.from);
7007
- const bf = String(b.from);
7008
- if (af < bf) return -1;
7009
- if (af > bf) return 1;
7010
- const at = String(a.to);
7011
- const bt = String(b.to);
7012
- if (at < bt) return -1;
7013
- if (at > bt) return 1;
7014
- return 0;
7015
- });
7016
- }
7017
- function sortOutputs(outputs) {
7018
- return outputs.slice().sort((a, b) => {
7019
- const an = String(a.name);
7020
- const bn = String(b.name);
7021
- if (an < bn) return -1;
7022
- if (an > bn) return 1;
7023
- const af = String(a.from);
7024
- const bf = String(b.from);
7025
- if (af < bf) return -1;
7026
- if (af > bf) return 1;
7027
- const ap = a.pointer ?? "";
7028
- const bp = b.pointer ?? "";
7029
- if (ap < bp) return -1;
7030
- if (ap > bp) return 1;
7031
- return 0;
7032
- });
7033
- }
7034
- function LLMStep(id, request) {
7035
- const config = {
7036
- id,
7037
- request: wireRequest2(request),
7038
- stream: false
7039
- };
7040
- return {
7041
- ...config,
7042
- withStream() {
7043
- return { ...config, stream: true };
4597
+ if (match[2] !== void 0) {
4598
+ const contentIndex = parseInt(match[2], 10);
4599
+ const msg = input[msgIndex];
4600
+ if (contentIndex >= msg.content.length) {
4601
+ return `targets ${pointer} but message ${msgIndex} only has ${msg.content.length} content blocks (indices 0-${msg.content.length - 1})`;
7044
4602
  }
7045
- };
7046
- }
7047
- var ChainBuilder = class _ChainBuilder {
7048
- constructor(state) {
7049
- this.state = state;
7050
4603
  }
7051
- static create(name, steps) {
7052
- return new _ChainBuilder({ name, steps, outputs: [] });
4604
+ return void 0;
4605
+ }
4606
+ function validateMapFanoutInput(nodeId, input) {
4607
+ const subnode = input.subnode;
4608
+ if ((subnode.type === WorkflowNodeTypesV1.LLMResponses || subnode.type === WorkflowNodeTypesV1.RouteSwitch) && subnode.input.bindings && subnode.input.bindings.length > 0) {
4609
+ throw new MapFanoutInputError(nodeId, "map.fanout subnode bindings are not allowed");
7053
4610
  }
7054
- with(patch) {
7055
- return new _ChainBuilder({ ...this.state, ...patch });
4611
+ if (subnode.type !== WorkflowNodeTypesV1.TransformJSON) {
4612
+ return;
7056
4613
  }
7057
- /**
7058
- * Sets the workflow execution configuration.
7059
- */
7060
- execution(exec) {
7061
- return this.with({ execution: exec });
4614
+ if (input.item_bindings && input.item_bindings.length > 0) {
4615
+ throw new MapFanoutInputError(
4616
+ nodeId,
4617
+ "map.fanout transform.json subnode cannot use item_bindings"
4618
+ );
7062
4619
  }
7063
- /**
7064
- * Adds an output reference from a specific step.
7065
- */
7066
- output(name, from) {
7067
- return this.with({
7068
- outputs: [
7069
- ...this.state.outputs,
7070
- {
7071
- name,
7072
- from,
7073
- pointer: LLM_TEXT_OUTPUT_INTERNAL
7074
- }
7075
- ]
7076
- });
4620
+ const hasObject = !!subnode.input.object && Object.keys(subnode.input.object).length > 0;
4621
+ const hasMerge = !!subnode.input.merge && subnode.input.merge.length > 0;
4622
+ if (hasObject === hasMerge) {
4623
+ throw new MapFanoutInputError(
4624
+ nodeId,
4625
+ "map.fanout transform.json must provide exactly one of object or merge"
4626
+ );
7077
4627
  }
7078
- /**
7079
- * Adds an output reference from the last step.
7080
- */
7081
- outputLast(name) {
7082
- if (this.state.steps.length === 0) {
7083
- return this;
4628
+ if (hasObject) {
4629
+ for (const [key, value] of Object.entries(subnode.input.object ?? {})) {
4630
+ if (!key.trim()) continue;
4631
+ if (String(value.from) !== "item") {
4632
+ throw new MapFanoutInputError(
4633
+ nodeId,
4634
+ `map.fanout transform.json object.${key}.from must be "item"`
4635
+ );
4636
+ }
7084
4637
  }
7085
- return this.output(name, this.state.steps[this.state.steps.length - 1].id);
7086
4638
  }
7087
- /**
7088
- * Builds and returns the compiled workflow spec.
7089
- * @throws Error if no steps are provided
7090
- */
7091
- build() {
7092
- if (this.state.steps.length === 0) {
7093
- throw new Error("chain requires at least one step");
7094
- }
7095
- const nodes = [];
7096
- const edges = [];
7097
- for (let i = 0; i < this.state.steps.length; i++) {
7098
- const step = this.state.steps[i];
7099
- const bindings = [];
7100
- if (i > 0) {
7101
- const prevId = this.state.steps[i - 1].id;
7102
- bindings.push({
7103
- from: prevId,
7104
- pointer: LLM_TEXT_OUTPUT_INTERNAL,
7105
- to: LLM_USER_MESSAGE_TEXT_INTERNAL,
7106
- encoding: "json_string"
7107
- });
7108
- edges.push({ from: prevId, to: step.id });
4639
+ if (hasMerge) {
4640
+ for (const [index, value] of (subnode.input.merge ?? []).entries()) {
4641
+ if (String(value.from) !== "item") {
4642
+ throw new MapFanoutInputError(
4643
+ nodeId,
4644
+ `map.fanout transform.json merge[${index}].from must be "item"`
4645
+ );
7109
4646
  }
7110
- const input = {
7111
- id: step.id,
7112
- type: WorkflowNodeTypes.LLMResponses,
7113
- input: {
7114
- request: step.request,
7115
- ...step.stream ? { stream: true } : {},
7116
- ...bindings.length > 0 ? { bindings } : {}
7117
- }
7118
- };
7119
- nodes.push(input);
7120
4647
  }
7121
- return {
7122
- kind: WorkflowKinds.WorkflowV0,
7123
- name: this.state.name,
7124
- ...this.state.execution ? { execution: this.state.execution } : {},
7125
- nodes,
7126
- ...edges.length > 0 ? { edges: sortEdges(edges) } : {},
7127
- outputs: sortOutputs(this.state.outputs)
7128
- };
7129
4648
  }
7130
- };
7131
- function Chain(name, steps) {
7132
- return ChainBuilder.create(name, steps);
7133
4649
  }
7134
- var ParallelBuilder = class _ParallelBuilder {
7135
- constructor(state) {
4650
+ var WorkflowBuilderV1 = class _WorkflowBuilderV1 {
4651
+ constructor(state = { nodes: [], edges: [], outputs: [] }) {
7136
4652
  this.state = state;
7137
4653
  }
7138
- static create(name, steps) {
7139
- return new _ParallelBuilder({ name, steps, outputs: [] });
4654
+ static new() {
4655
+ return new _WorkflowBuilderV1();
7140
4656
  }
7141
4657
  with(patch) {
7142
- return new _ParallelBuilder({ ...this.state, ...patch });
7143
- }
7144
- /**
7145
- * Sets the workflow execution configuration.
7146
- */
7147
- execution(exec) {
7148
- return this.with({ execution: exec });
7149
- }
7150
- /**
7151
- * Adds a join node that waits for all parallel steps,
7152
- * followed by an aggregator LLM node that receives the combined output.
7153
- * The join node ID is automatically generated as "<id>_join".
7154
- */
7155
- aggregate(id, request) {
7156
- return this.with({
7157
- aggregate: {
7158
- id,
7159
- request: wireRequest2(request),
7160
- stream: false
7161
- }
4658
+ return new _WorkflowBuilderV1({
4659
+ ...this.state,
4660
+ ...patch
7162
4661
  });
7163
4662
  }
7164
- /**
7165
- * Like aggregate() but enables streaming on the aggregator node.
7166
- */
7167
- aggregateWithStream(id, request) {
7168
- return this.with({
7169
- aggregate: {
7170
- id,
7171
- request: wireRequest2(request),
7172
- stream: true
7173
- }
7174
- });
4663
+ name(name) {
4664
+ return this.with({ name: name.trim() || void 0 });
7175
4665
  }
7176
- /**
7177
- * Adds an output reference from a specific step.
7178
- */
7179
- output(name, from) {
7180
- return this.with({
7181
- outputs: [
7182
- ...this.state.outputs,
7183
- {
7184
- name,
7185
- from,
7186
- pointer: LLM_TEXT_OUTPUT_INTERNAL
7187
- }
7188
- ]
7189
- });
4666
+ execution(execution) {
4667
+ return this.with({ execution });
7190
4668
  }
7191
- /**
7192
- * Builds and returns the compiled workflow spec.
7193
- * @throws Error if no steps are provided
7194
- */
7195
- build() {
7196
- if (this.state.steps.length === 0) {
7197
- throw new Error("parallel requires at least one step");
7198
- }
7199
- const nodes = [];
7200
- const edges = [];
7201
- for (const step of this.state.steps) {
7202
- const input = {
7203
- id: step.id,
7204
- type: WorkflowNodeTypes.LLMResponses,
7205
- input: {
7206
- request: step.request,
7207
- ...step.stream ? { stream: true } : {}
7208
- }
7209
- };
7210
- nodes.push(input);
7211
- }
7212
- if (this.state.aggregate) {
7213
- const joinId = `${this.state.aggregate.id}_join`;
7214
- nodes.push({ id: joinId, type: WorkflowNodeTypes.JoinAll });
7215
- for (const step of this.state.steps) {
7216
- edges.push({ from: step.id, to: joinId });
7217
- }
7218
- const aggInput = {
7219
- id: this.state.aggregate.id,
7220
- type: WorkflowNodeTypes.LLMResponses,
7221
- input: {
7222
- request: this.state.aggregate.request,
7223
- ...this.state.aggregate.stream ? { stream: true } : {},
7224
- bindings: [
7225
- {
7226
- from: joinId,
7227
- // Empty pointer = full join output
7228
- to: LLM_USER_MESSAGE_TEXT_INTERNAL,
7229
- encoding: "json_string"
7230
- }
7231
- ]
7232
- }
7233
- };
7234
- nodes.push(aggInput);
7235
- edges.push({ from: joinId, to: this.state.aggregate.id });
4669
+ node(node) {
4670
+ return this.with({ nodes: [...this.state.nodes, node] });
4671
+ }
4672
+ llmResponses(id, request, options = {}) {
4673
+ const wiredRequest = wireRequest(request);
4674
+ if (options.bindings) {
4675
+ validateBindingTargets(id, wiredRequest.input, options.bindings);
7236
4676
  }
7237
- return {
7238
- kind: WorkflowKinds.WorkflowV0,
7239
- name: this.state.name,
7240
- ...this.state.execution ? { execution: this.state.execution } : {},
7241
- nodes,
7242
- ...edges.length > 0 ? { edges: sortEdges(edges) } : {},
7243
- outputs: sortOutputs(this.state.outputs)
4677
+ const input = {
4678
+ request: wiredRequest,
4679
+ ...options.stream === void 0 ? {} : { stream: options.stream },
4680
+ ...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
4681
+ ...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
4682
+ ...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
7244
4683
  };
4684
+ return this.node({
4685
+ id,
4686
+ type: WorkflowNodeTypesV1.LLMResponses,
4687
+ input
4688
+ });
7245
4689
  }
7246
- };
7247
- function Parallel(name, steps) {
7248
- return ParallelBuilder.create(name, steps);
7249
- }
7250
- function MapItem(id, request) {
7251
- const config = {
7252
- id,
7253
- request: wireRequest2(request),
7254
- stream: false
7255
- };
7256
- return {
7257
- ...config,
7258
- withStream() {
7259
- return { ...config, stream: true };
4690
+ routeSwitch(id, request, options = {}) {
4691
+ const wiredRequest = wireRequest(request);
4692
+ if (options.bindings) {
4693
+ validateBindingTargets(id, wiredRequest.input, options.bindings);
7260
4694
  }
7261
- };
7262
- }
7263
- var MapReduceBuilder = class _MapReduceBuilder {
7264
- constructor(state) {
7265
- this.state = state;
7266
- }
7267
- static create(name, items) {
7268
- return new _MapReduceBuilder({ name, items, outputs: [] });
4695
+ const input = {
4696
+ request: wiredRequest,
4697
+ ...options.stream === void 0 ? {} : { stream: options.stream },
4698
+ ...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
4699
+ ...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
4700
+ ...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
4701
+ };
4702
+ return this.node({
4703
+ id,
4704
+ type: WorkflowNodeTypesV1.RouteSwitch,
4705
+ input
4706
+ });
7269
4707
  }
7270
- with(patch) {
7271
- return new _MapReduceBuilder({ ...this.state, ...patch });
4708
+ joinAll(id) {
4709
+ return this.node({ id, type: WorkflowNodeTypesV1.JoinAll });
7272
4710
  }
7273
- /**
7274
- * Adds a mapper item to the workflow.
7275
- * Each item becomes a separate LLM node that runs in parallel.
7276
- */
7277
- item(id, request) {
7278
- return this.with({
7279
- items: [...this.state.items, { id, request: wireRequest2(request), stream: false }]
4711
+ joinAny(id, input) {
4712
+ return this.node({
4713
+ id,
4714
+ type: WorkflowNodeTypesV1.JoinAny,
4715
+ ...input ? { input } : {}
7280
4716
  });
7281
4717
  }
7282
- /**
7283
- * Adds a mapper item with streaming enabled.
7284
- */
7285
- itemWithStream(id, request) {
7286
- return this.with({
7287
- items: [...this.state.items, { id, request: wireRequest2(request), stream: true }]
7288
- });
4718
+ joinCollect(id, input) {
4719
+ return this.node({ id, type: WorkflowNodeTypesV1.JoinCollect, input });
7289
4720
  }
7290
- /**
7291
- * Sets the workflow execution configuration.
7292
- */
7293
- execution(exec) {
7294
- return this.with({ execution: exec });
4721
+ transformJSON(id, input) {
4722
+ return this.node({ id, type: WorkflowNodeTypesV1.TransformJSON, input });
7295
4723
  }
7296
- /**
7297
- * Adds a reducer node that receives all mapper outputs.
7298
- * The reducer receives a JSON object mapping each mapper ID to its text output.
7299
- * The join node ID is automatically generated as "<id>_join".
7300
- */
7301
- reduce(id, request) {
7302
- return this.with({
7303
- reducer: {
7304
- id,
7305
- request: wireRequest2(request),
7306
- stream: false
7307
- }
7308
- });
4724
+ mapFanout(id, input) {
4725
+ validateMapFanoutInput(id, input);
4726
+ return this.node({ id, type: WorkflowNodeTypesV1.MapFanout, input });
7309
4727
  }
7310
- /**
7311
- * Like reduce() but enables streaming on the reducer node.
7312
- */
7313
- reduceWithStream(id, request) {
4728
+ edge(from, to, when) {
7314
4729
  return this.with({
7315
- reducer: {
7316
- id,
7317
- request: wireRequest2(request),
7318
- stream: true
7319
- }
4730
+ edges: [...this.state.edges, { from, to, ...when ? { when } : {} }]
7320
4731
  });
7321
4732
  }
7322
- /**
7323
- * Adds an output reference from a specific node.
7324
- * Typically used to output from the reducer node.
7325
- */
7326
- output(name, from) {
4733
+ output(name, from, pointer) {
7327
4734
  return this.with({
7328
4735
  outputs: [
7329
4736
  ...this.state.outputs,
7330
- {
7331
- name,
7332
- from,
7333
- pointer: LLM_TEXT_OUTPUT_INTERNAL
7334
- }
4737
+ { name, from, ...pointer ? { pointer } : {} }
7335
4738
  ]
7336
4739
  });
7337
4740
  }
7338
- /**
7339
- * Builds and returns the compiled workflow spec.
7340
- * @throws Error if no items are provided or no reducer is configured
7341
- */
7342
4741
  build() {
7343
- if (this.state.items.length === 0) {
7344
- throw new Error("map-reduce requires at least one item");
7345
- }
7346
- if (!this.state.reducer) {
7347
- throw new Error("map-reduce requires a reducer (call reduce)");
7348
- }
7349
- const seenIds = /* @__PURE__ */ new Set();
7350
- for (const item of this.state.items) {
7351
- if (!item.id) {
7352
- throw new Error("item ID cannot be empty");
7353
- }
7354
- if (seenIds.has(item.id)) {
7355
- throw new Error(`duplicate item ID: "${item.id}"`);
7356
- }
7357
- seenIds.add(item.id);
7358
- }
7359
- const nodes = [];
7360
- const edges = [];
7361
- const joinId = `${this.state.reducer.id}_join`;
7362
- for (const item of this.state.items) {
7363
- const mapperId = `map_${item.id}`;
7364
- const input = {
7365
- id: mapperId,
7366
- type: WorkflowNodeTypes.LLMResponses,
7367
- input: {
7368
- request: item.request,
7369
- ...item.stream ? { stream: true } : {}
7370
- }
7371
- };
7372
- nodes.push(input);
7373
- edges.push({ from: mapperId, to: joinId });
7374
- }
7375
- nodes.push({ id: joinId, type: WorkflowNodeTypes.JoinAll });
7376
- const reducerInput = {
7377
- id: this.state.reducer.id,
7378
- type: WorkflowNodeTypes.LLMResponses,
7379
- input: {
7380
- request: this.state.reducer.request,
7381
- ...this.state.reducer.stream ? { stream: true } : {},
7382
- bindings: [
7383
- {
7384
- from: joinId,
7385
- // Empty pointer = full join output
7386
- to: LLM_USER_MESSAGE_TEXT_INTERNAL,
7387
- encoding: "json_string"
7388
- }
7389
- ]
7390
- }
7391
- };
7392
- nodes.push(reducerInput);
7393
- edges.push({ from: joinId, to: this.state.reducer.id });
4742
+ const edges = this.state.edges.slice().sort((a, b) => {
4743
+ const af = String(a.from);
4744
+ const bf = String(b.from);
4745
+ if (af < bf) return -1;
4746
+ if (af > bf) return 1;
4747
+ const at = String(a.to);
4748
+ const bt = String(b.to);
4749
+ if (at < bt) return -1;
4750
+ if (at > bt) return 1;
4751
+ const aw = a.when ? JSON.stringify(a.when) : "";
4752
+ const bw = b.when ? JSON.stringify(b.when) : "";
4753
+ if (aw < bw) return -1;
4754
+ if (aw > bw) return 1;
4755
+ return 0;
4756
+ });
4757
+ const outputs = this.state.outputs.slice().sort((a, b) => {
4758
+ const an = String(a.name);
4759
+ const bn = String(b.name);
4760
+ if (an < bn) return -1;
4761
+ if (an > bn) return 1;
4762
+ const af = String(a.from);
4763
+ const bf = String(b.from);
4764
+ if (af < bf) return -1;
4765
+ if (af > bf) return 1;
4766
+ const ap = a.pointer ?? "";
4767
+ const bp = b.pointer ?? "";
4768
+ if (ap < bp) return -1;
4769
+ if (ap > bp) return 1;
4770
+ return 0;
4771
+ });
7394
4772
  return {
7395
- kind: WorkflowKinds.WorkflowV0,
7396
- name: this.state.name,
4773
+ kind: WorkflowKinds.WorkflowV1,
4774
+ ...this.state.name ? { name: this.state.name } : {},
7397
4775
  ...this.state.execution ? { execution: this.state.execution } : {},
7398
- nodes,
7399
- ...edges.length > 0 ? { edges: sortEdges(edges) } : {},
7400
- outputs: sortOutputs(this.state.outputs)
4776
+ nodes: this.state.nodes.slice(),
4777
+ ...edges.length ? { edges } : {},
4778
+ outputs
7401
4779
  };
7402
4780
  }
7403
4781
  };
7404
- function MapReduce(name, items = []) {
7405
- return MapReduceBuilder.create(name, items);
4782
+ function workflowV1() {
4783
+ return WorkflowBuilderV1.new();
7406
4784
  }
7407
4785
 
7408
4786
  // src/testing.ts
@@ -7626,14 +5004,13 @@ __export(workflow_exports, {
7626
5004
  BindingBuilder: () => BindingBuilder,
7627
5005
  BindingEncodings: () => BindingEncodings,
7628
5006
  FanoutReduceV1: () => FanoutReduceV1,
7629
- KindV0: () => KindV0,
7630
5007
  KindV1: () => KindV1,
7631
5008
  LLM_TEXT_OUTPUT: () => LLM_TEXT_OUTPUT,
7632
5009
  LLM_USER_MESSAGE_TEXT: () => LLM_USER_MESSAGE_TEXT,
7633
- NodeTypes: () => NodeTypes,
7634
5010
  NodeTypesV1: () => NodeTypesV1,
7635
5011
  RouterV1: () => RouterV1,
7636
5012
  ToolExecutionModes: () => ToolExecutionModes,
5013
+ WorkflowBuilderV1: () => WorkflowBuilderV1,
7637
5014
  bindFrom: () => bindFrom,
7638
5015
  bindToPlaceholder: () => bindToPlaceholder,
7639
5016
  bindToPointer: () => bindToPointer,
@@ -7646,7 +5023,8 @@ __export(workflow_exports, {
7646
5023
  whenOutputMatches: () => whenOutputMatches,
7647
5024
  whenStatusEquals: () => whenStatusEquals,
7648
5025
  whenStatusExists: () => whenStatusExists,
7649
- whenStatusMatches: () => whenStatusMatches
5026
+ whenStatusMatches: () => whenStatusMatches,
5027
+ workflowV1: () => workflowV1
7650
5028
  });
7651
5029
 
7652
5030
  // src/workflow/helpers_v1.ts
@@ -7738,7 +5116,7 @@ var BindingBuilder = class {
7738
5116
  };
7739
5117
 
7740
5118
  // src/workflow/patterns_v1.ts
7741
- function wireRequest3(req) {
5119
+ function wireRequest2(req) {
7742
5120
  const raw = req;
7743
5121
  if (raw && typeof raw === "object") {
7744
5122
  if ("input" in raw) {
@@ -7831,7 +5209,7 @@ var FanoutReduceV1 = class {
7831
5209
  encoding: "json_string"
7832
5210
  }
7833
5211
  ];
7834
- const mapperRequest = wireRequest3(mapper);
5212
+ const mapperRequest = wireRequest2(mapper);
7835
5213
  builder = builder.mapFanout(fanoutId, {
7836
5214
  items: { from: generatorId, path: itemsPath },
7837
5215
  item_bindings: itemBindings,
@@ -7860,13 +5238,7 @@ var FanoutReduceV1 = class {
7860
5238
  };
7861
5239
 
7862
5240
  // src/workflow/index.ts
7863
- var KindV0 = WorkflowKinds.WorkflowV0;
7864
5241
  var KindV1 = WorkflowKinds.WorkflowV1;
7865
- var NodeTypes = {
7866
- LLMResponses: WorkflowNodeTypes.LLMResponses,
7867
- JoinAll: WorkflowNodeTypes.JoinAll,
7868
- TransformJSON: WorkflowNodeTypes.TransformJSON
7869
- };
7870
5242
  var NodeTypesV1 = {
7871
5243
  LLMResponses: WorkflowNodeTypesV1.LLMResponses,
7872
5244
  RouteSwitch: WorkflowNodeTypesV1.RouteSwitch,
@@ -7890,9 +5262,6 @@ var ModelRelay = class _ModelRelay {
7890
5262
  static fromSecretKey(secretKey, options = {}) {
7891
5263
  return new _ModelRelay({ ...options, key: parseSecretKey(secretKey) });
7892
5264
  }
7893
- static fromPublishableKey(publishableKey, options = {}) {
7894
- return new _ModelRelay({ ...options, key: parsePublishableKey(publishableKey) });
7895
- }
7896
5265
  static fromApiKey(apiKey, options = {}) {
7897
5266
  return new _ModelRelay({ ...options, key: parseApiKey(apiKey) });
7898
5267
  }
@@ -7921,7 +5290,6 @@ var ModelRelay = class _ModelRelay {
7921
5290
  const auth = new AuthClient(this.http, {
7922
5291
  apiKey,
7923
5292
  accessToken,
7924
- customer: cfg.customer,
7925
5293
  tokenProvider
7926
5294
  });
7927
5295
  this.auth = auth;
@@ -7939,7 +5307,7 @@ var ModelRelay = class _ModelRelay {
7939
5307
  });
7940
5308
  this.images = new ImagesClient(this.http, auth);
7941
5309
  this.sessions = new SessionsClient(this, this.http, auth);
7942
- this.tiers = new TiersClient(this.http, { apiKey });
5310
+ this.tiers = new TiersClient(this.http, { apiKey, accessToken });
7943
5311
  }
7944
5312
  forCustomer(customerId) {
7945
5313
  return new CustomerScopedModelRelay(this.responses, customerId, this.baseUrl);
@@ -7954,8 +5322,6 @@ export {
7954
5322
  AuthClient,
7955
5323
  BillingProviders,
7956
5324
  BindingTargetError,
7957
- Chain,
7958
- ChainBuilder,
7959
5325
  ConfigError,
7960
5326
  ContentPartTypes,
7961
5327
  CustomerResponsesClient,
@@ -7966,7 +5332,6 @@ export {
7966
5332
  DEFAULT_CONNECT_TIMEOUT_MS,
7967
5333
  DEFAULT_REQUEST_TIMEOUT_MS,
7968
5334
  ErrorCodes,
7969
- FrontendTokenProvider,
7970
5335
  ImagesClient,
7971
5336
  InputItemTypes,
7972
5337
  JoinOutput,
@@ -7978,29 +5343,21 @@ export {
7978
5343
  LLMInputPath,
7979
5344
  LLMInputSystemText,
7980
5345
  LLMInputUserText,
7981
- LLMNodeBuilder,
7982
5346
  LLMOutput,
7983
5347
  LLMOutputContentItemPath,
7984
5348
  LLMOutputContentPath,
7985
5349
  LLMOutputPath,
7986
5350
  LLMOutputText,
7987
- LLMStep,
7988
5351
  LLM_TEXT_OUTPUT,
7989
5352
  LLM_USER_MESSAGE_TEXT,
7990
5353
  LocalSession,
7991
5354
  MapFanoutInputError,
7992
- MapItem,
7993
- MapReduce,
7994
- MapReduceBuilder,
7995
5355
  MemorySessionStore,
7996
5356
  MessageRoles,
7997
5357
  ModelRelay,
7998
5358
  ModelRelayError,
7999
- OIDCExchangeTokenProvider,
8000
5359
  OutputFormatTypes,
8001
5360
  OutputItemTypes,
8002
- Parallel,
8003
- ParallelBuilder,
8004
5361
  PathEscapeError,
8005
5362
  ResponsesClient,
8006
5363
  ResponsesStream,
@@ -8023,15 +5380,13 @@ export {
8023
5380
  ToolRegistry,
8024
5381
  ToolRunner,
8025
5382
  ToolTypes,
8026
- TransformJSONNodeBuilder,
8027
5383
  TransportError,
8028
5384
  WORKFLOWS_COMPILE_PATH,
8029
5385
  WebToolIntents,
8030
- Workflow,
8031
- WorkflowBuilderV0,
8032
5386
  WorkflowBuilderV1,
8033
5387
  WorkflowKinds,
8034
- WorkflowNodeTypes,
5388
+ WorkflowNodeTypesV1 as WorkflowNodeTypes,
5389
+ WorkflowNodeTypesV1,
8035
5390
  WorkflowValidationError,
8036
5391
  WorkflowsClient,
8037
5392
  asModelId,
@@ -8067,17 +5422,10 @@ export {
8067
5422
  getRetryableErrors,
8068
5423
  hasRetryableErrors,
8069
5424
  hasToolCalls,
8070
- isAutoProvisionDisabled,
8071
- isAutoProvisionMisconfigured,
8072
- isEmailRequired,
8073
- isIdentityRequired,
8074
- isProvisioningError,
8075
- isPublishableKey,
8076
5425
  isSecretKey,
8077
5426
  mergeMetrics,
8078
5427
  mergeTrace,
8079
5428
  modelToString,
8080
- newWorkflow,
8081
5429
  normalizeModelId,
8082
5430
  normalizeStopReason,
8083
5431
  outputFormatFromZod,
@@ -8086,33 +5434,22 @@ export {
8086
5434
  parseNodeId,
8087
5435
  parseOutputName,
8088
5436
  parsePlanHash,
8089
- parsePublishableKey,
8090
5437
  parseRunId,
8091
5438
  parseSecretKey,
8092
5439
  parseToolArgs,
8093
5440
  parseToolArgsRaw,
8094
- pollOAuthDeviceToken,
8095
- pollUntil,
8096
5441
  respondToToolCall,
8097
- runOAuthDeviceFlowForIDToken,
8098
- startOAuthDeviceAuthorization,
8099
5442
  stopReasonToString,
8100
5443
  toolChoiceAuto,
8101
5444
  toolChoiceNone,
8102
5445
  toolChoiceRequired,
8103
5446
  toolResultMessage,
8104
5447
  transformJSONMerge,
8105
- transformJSONMergeV1,
8106
5448
  transformJSONObject,
8107
- transformJSONObjectV1,
8108
5449
  transformJSONValue,
8109
- transformJSONValueV1,
8110
5450
  tryParseToolArgs,
8111
5451
  validateWithZod,
8112
5452
  workflow_exports as workflow,
8113
- workflowV0,
8114
- workflow_v0_schema_default as workflowV0Schema,
8115
5453
  workflowV1,
8116
- workflow_v1_schema_default as workflowV1Schema,
8117
5454
  zodToJsonSchema
8118
5455
  };