@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.cjs CHANGED
@@ -34,8 +34,6 @@ __export(index_exports, {
34
34
  AuthClient: () => AuthClient,
35
35
  BillingProviders: () => BillingProviders,
36
36
  BindingTargetError: () => BindingTargetError,
37
- Chain: () => Chain,
38
- ChainBuilder: () => ChainBuilder,
39
37
  ConfigError: () => ConfigError,
40
38
  ContentPartTypes: () => ContentPartTypes,
41
39
  CustomerResponsesClient: () => CustomerResponsesClient,
@@ -46,7 +44,6 @@ __export(index_exports, {
46
44
  DEFAULT_CONNECT_TIMEOUT_MS: () => DEFAULT_CONNECT_TIMEOUT_MS,
47
45
  DEFAULT_REQUEST_TIMEOUT_MS: () => DEFAULT_REQUEST_TIMEOUT_MS,
48
46
  ErrorCodes: () => ErrorCodes,
49
- FrontendTokenProvider: () => FrontendTokenProvider,
50
47
  ImagesClient: () => ImagesClient,
51
48
  InputItemTypes: () => InputItemTypes,
52
49
  JoinOutput: () => JoinOutput,
@@ -58,29 +55,21 @@ __export(index_exports, {
58
55
  LLMInputPath: () => LLMInputPath,
59
56
  LLMInputSystemText: () => LLMInputSystemText,
60
57
  LLMInputUserText: () => LLMInputUserText,
61
- LLMNodeBuilder: () => LLMNodeBuilder,
62
58
  LLMOutput: () => LLMOutput,
63
59
  LLMOutputContentItemPath: () => LLMOutputContentItemPath,
64
60
  LLMOutputContentPath: () => LLMOutputContentPath,
65
61
  LLMOutputPath: () => LLMOutputPath,
66
62
  LLMOutputText: () => LLMOutputText,
67
- LLMStep: () => LLMStep,
68
63
  LLM_TEXT_OUTPUT: () => LLM_TEXT_OUTPUT,
69
64
  LLM_USER_MESSAGE_TEXT: () => LLM_USER_MESSAGE_TEXT,
70
65
  LocalSession: () => LocalSession,
71
66
  MapFanoutInputError: () => MapFanoutInputError,
72
- MapItem: () => MapItem,
73
- MapReduce: () => MapReduce,
74
- MapReduceBuilder: () => MapReduceBuilder,
75
67
  MemorySessionStore: () => MemorySessionStore,
76
68
  MessageRoles: () => MessageRoles,
77
69
  ModelRelay: () => ModelRelay,
78
70
  ModelRelayError: () => ModelRelayError,
79
- OIDCExchangeTokenProvider: () => OIDCExchangeTokenProvider,
80
71
  OutputFormatTypes: () => OutputFormatTypes,
81
72
  OutputItemTypes: () => OutputItemTypes,
82
- Parallel: () => Parallel,
83
- ParallelBuilder: () => ParallelBuilder,
84
73
  PathEscapeError: () => PathEscapeError,
85
74
  ResponsesClient: () => ResponsesClient,
86
75
  ResponsesStream: () => ResponsesStream,
@@ -103,15 +92,13 @@ __export(index_exports, {
103
92
  ToolRegistry: () => ToolRegistry,
104
93
  ToolRunner: () => ToolRunner,
105
94
  ToolTypes: () => ToolTypes,
106
- TransformJSONNodeBuilder: () => TransformJSONNodeBuilder,
107
95
  TransportError: () => TransportError,
108
96
  WORKFLOWS_COMPILE_PATH: () => WORKFLOWS_COMPILE_PATH,
109
97
  WebToolIntents: () => WebToolIntents,
110
- Workflow: () => Workflow,
111
- WorkflowBuilderV0: () => WorkflowBuilderV0,
112
98
  WorkflowBuilderV1: () => WorkflowBuilderV1,
113
99
  WorkflowKinds: () => WorkflowKinds,
114
- WorkflowNodeTypes: () => WorkflowNodeTypes,
100
+ WorkflowNodeTypes: () => WorkflowNodeTypesV1,
101
+ WorkflowNodeTypesV1: () => WorkflowNodeTypesV1,
115
102
  WorkflowValidationError: () => WorkflowValidationError,
116
103
  WorkflowsClient: () => WorkflowsClient,
117
104
  asModelId: () => asModelId,
@@ -147,17 +134,10 @@ __export(index_exports, {
147
134
  getRetryableErrors: () => getRetryableErrors,
148
135
  hasRetryableErrors: () => hasRetryableErrors,
149
136
  hasToolCalls: () => hasToolCalls,
150
- isAutoProvisionDisabled: () => isAutoProvisionDisabled,
151
- isAutoProvisionMisconfigured: () => isAutoProvisionMisconfigured,
152
- isEmailRequired: () => isEmailRequired,
153
- isIdentityRequired: () => isIdentityRequired,
154
- isProvisioningError: () => isProvisioningError,
155
- isPublishableKey: () => isPublishableKey,
156
137
  isSecretKey: () => isSecretKey,
157
138
  mergeMetrics: () => mergeMetrics,
158
139
  mergeTrace: () => mergeTrace,
159
140
  modelToString: () => modelToString,
160
- newWorkflow: () => newWorkflow,
161
141
  normalizeModelId: () => normalizeModelId,
162
142
  normalizeStopReason: () => normalizeStopReason,
163
143
  outputFormatFromZod: () => outputFormatFromZod,
@@ -166,34 +146,23 @@ __export(index_exports, {
166
146
  parseNodeId: () => parseNodeId,
167
147
  parseOutputName: () => parseOutputName,
168
148
  parsePlanHash: () => parsePlanHash,
169
- parsePublishableKey: () => parsePublishableKey,
170
149
  parseRunId: () => parseRunId,
171
150
  parseSecretKey: () => parseSecretKey,
172
151
  parseToolArgs: () => parseToolArgs,
173
152
  parseToolArgsRaw: () => parseToolArgsRaw,
174
- pollOAuthDeviceToken: () => pollOAuthDeviceToken,
175
- pollUntil: () => pollUntil,
176
153
  respondToToolCall: () => respondToToolCall,
177
- runOAuthDeviceFlowForIDToken: () => runOAuthDeviceFlowForIDToken,
178
- startOAuthDeviceAuthorization: () => startOAuthDeviceAuthorization,
179
154
  stopReasonToString: () => stopReasonToString,
180
155
  toolChoiceAuto: () => toolChoiceAuto,
181
156
  toolChoiceNone: () => toolChoiceNone,
182
157
  toolChoiceRequired: () => toolChoiceRequired,
183
158
  toolResultMessage: () => toolResultMessage,
184
159
  transformJSONMerge: () => transformJSONMerge,
185
- transformJSONMergeV1: () => transformJSONMergeV1,
186
160
  transformJSONObject: () => transformJSONObject,
187
- transformJSONObjectV1: () => transformJSONObjectV1,
188
161
  transformJSONValue: () => transformJSONValue,
189
- transformJSONValueV1: () => transformJSONValueV1,
190
162
  tryParseToolArgs: () => tryParseToolArgs,
191
163
  validateWithZod: () => validateWithZod,
192
164
  workflow: () => workflow_exports,
193
- workflowV0: () => workflowV0,
194
- workflowV0Schema: () => workflow_v0_schema_default,
195
165
  workflowV1: () => workflowV1,
196
- workflowV1Schema: () => workflow_v1_schema_default,
197
166
  zodToJsonSchema: () => zodToJsonSchema
198
167
  });
199
168
  module.exports = __toCommonJS(index_exports);
@@ -210,15 +179,7 @@ var ErrorCodes = {
210
179
  SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE",
211
180
  INVALID_INPUT: "INVALID_INPUT",
212
181
  PAYMENT_REQUIRED: "PAYMENT_REQUIRED",
213
- METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED",
214
- /** Identity provider + subject required for identity-based auth. */
215
- IDENTITY_REQUIRED: "IDENTITY_REQUIRED",
216
- /** Auto-provision disabled for the project. */
217
- AUTO_PROVISION_DISABLED: "AUTO_PROVISION_DISABLED",
218
- /** Auto-provision tier misconfigured for the project. */
219
- AUTO_PROVISION_MISCONFIGURED: "AUTO_PROVISION_MISCONFIGURED",
220
- /** Email required for auto-provisioning a new customer. */
221
- EMAIL_REQUIRED: "EMAIL_REQUIRED"
182
+ METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED"
222
183
  };
223
184
  var ModelRelayError = class extends Error {
224
185
  constructor(message, opts) {
@@ -306,39 +267,6 @@ var APIError = class extends ModelRelayError {
306
267
  isUnavailable() {
307
268
  return this.code === ErrorCodes.SERVICE_UNAVAILABLE;
308
269
  }
309
- /**
310
- * Returns true if the error indicates identity is missing/invalid for identity-based auth.
311
- */
312
- isIdentityRequired() {
313
- return this.code === ErrorCodes.IDENTITY_REQUIRED;
314
- }
315
- /**
316
- * Returns true if auto-provisioning is disabled for the project.
317
- * To resolve: configure customer auto-provisioning on the project (select a default tier).
318
- */
319
- isAutoProvisionDisabled() {
320
- return this.code === ErrorCodes.AUTO_PROVISION_DISABLED;
321
- }
322
- /**
323
- * Returns true if email is required for auto-provisioning a new customer.
324
- * To resolve: provide the 'email' field in your frontend token request.
325
- */
326
- isEmailRequired() {
327
- return this.code === ErrorCodes.EMAIL_REQUIRED;
328
- }
329
- /**
330
- * Returns true if auto-provisioning is misconfigured for the project.
331
- * To resolve: ensure the configured auto-provision tier exists and belongs to the project.
332
- */
333
- isAutoProvisionMisconfigured() {
334
- return this.code === ErrorCodes.AUTO_PROVISION_MISCONFIGURED;
335
- }
336
- /**
337
- * Returns true if this is a customer provisioning error (identity not found + auto-provision disabled/misconfigured, or email required).
338
- */
339
- isProvisioningError() {
340
- return this.isAutoProvisionDisabled() || this.isAutoProvisionMisconfigured() || this.isEmailRequired();
341
- }
342
270
  };
343
271
  var WorkflowValidationError = class extends ModelRelayError {
344
272
  constructor(opts) {
@@ -375,21 +303,6 @@ var PathEscapeError = class extends ModelRelayError {
375
303
  this.resolvedPath = opts.resolvedPath;
376
304
  }
377
305
  };
378
- function isEmailRequired(err) {
379
- return err instanceof APIError && err.isEmailRequired();
380
- }
381
- function isIdentityRequired(err) {
382
- return err instanceof APIError && err.isIdentityRequired();
383
- }
384
- function isAutoProvisionDisabled(err) {
385
- return err instanceof APIError && err.isAutoProvisionDisabled();
386
- }
387
- function isAutoProvisionMisconfigured(err) {
388
- return err instanceof APIError && err.isAutoProvisionMisconfigured();
389
- }
390
- function isProvisioningError(err) {
391
- return err instanceof APIError && err.isProvisioningError();
392
- }
393
306
  async function parseErrorResponse(response, retries) {
394
307
  const requestId = response.headers.get("X-ModelRelay-Request-Id") || response.headers.get("X-Request-Id") || void 0;
395
308
  const fallbackMessage = response.statusText || "Request failed";
@@ -474,33 +387,21 @@ async function parseErrorResponse(response, retries) {
474
387
  }
475
388
 
476
389
  // src/api_keys.ts
477
- var PUBLISHABLE_PREFIX = "mr_pk_";
478
390
  var SECRET_PREFIX = "mr_sk_";
479
391
  function keyKindHint(raw) {
480
392
  const value = raw?.trim?.() ? raw.trim() : "";
481
- if (value.startsWith(PUBLISHABLE_PREFIX)) return "publishable";
482
393
  if (value.startsWith(SECRET_PREFIX)) return "secret";
483
394
  return "unknown";
484
395
  }
485
396
  function parseApiKey(raw) {
486
397
  const value = raw?.trim?.() ? raw.trim() : "";
487
- if (value.startsWith(PUBLISHABLE_PREFIX) && value.length > PUBLISHABLE_PREFIX.length) {
488
- return value;
489
- }
490
398
  if (value.startsWith(SECRET_PREFIX) && value.length > SECRET_PREFIX.length) {
491
399
  return value;
492
400
  }
493
- throw new ConfigError("Invalid API key format (expected mr_pk_* or mr_sk_*)", {
401
+ throw new ConfigError("Invalid API key format (expected mr_sk_*)", {
494
402
  keyKind: keyKindHint(raw)
495
403
  });
496
404
  }
497
- function parsePublishableKey(raw) {
498
- const key = parseApiKey(raw);
499
- if (!isPublishableKey(key)) {
500
- throw new ConfigError("Publishable key required (expected mr_pk_*)", { keyKind: keyKindHint(raw) });
501
- }
502
- return key;
503
- }
504
405
  function parseSecretKey(raw) {
505
406
  const key = parseApiKey(raw);
506
407
  if (!isSecretKey(key)) {
@@ -508,9 +409,6 @@ function parseSecretKey(raw) {
508
409
  }
509
410
  return key;
510
411
  }
511
- function isPublishableKey(key) {
512
- return key.startsWith(PUBLISHABLE_PREFIX);
513
- }
514
412
  function isSecretKey(key) {
515
413
  return key.startsWith(SECRET_PREFIX);
516
414
  }
@@ -518,7 +416,7 @@ function isSecretKey(key) {
518
416
  // package.json
519
417
  var package_default = {
520
418
  name: "@modelrelay/sdk",
521
- version: "1.42.0",
419
+ version: "2.1.0",
522
420
  description: "TypeScript SDK for the ModelRelay API",
523
421
  type: "module",
524
422
  main: "dist/index.cjs",
@@ -723,102 +621,15 @@ function createAccessTokenAuth(accessToken) {
723
621
  }
724
622
  var AuthClient = class {
725
623
  constructor(http, cfg) {
726
- this.cachedFrontend = /* @__PURE__ */ new Map();
727
624
  this.http = http;
728
625
  this.apiKey = cfg.apiKey ? parseApiKey(cfg.apiKey) : void 0;
729
- this.apiKeyIsPublishable = this.apiKey ? isPublishableKey(this.apiKey) : false;
730
626
  this.accessToken = cfg.accessToken;
731
- this.customer = cfg.customer;
732
627
  this.tokenProvider = cfg.tokenProvider;
733
628
  }
734
- /**
735
- * Exchange a publishable key for a short-lived frontend token for an existing customer.
736
- * Tokens are cached until they are close to expiry.
737
- *
738
- * Use this method when the customer already exists in the system.
739
- * For auto-provisioning new customers, use frontendTokenAutoProvision instead.
740
- */
741
- async frontendToken(request) {
742
- if (!request.publishableKey?.trim()) {
743
- throw new ConfigError("publishableKey is required");
744
- }
745
- if (!request.identityProvider?.trim()) {
746
- throw new ConfigError("identityProvider is required");
747
- }
748
- if (!request.identitySubject?.trim()) {
749
- throw new ConfigError("identitySubject is required");
750
- }
751
- return this.sendFrontendTokenRequest(request);
752
- }
753
- /**
754
- * Exchange a publishable key for a frontend token, creating the customer if needed.
755
- * The customer will be auto-provisioned on the project's free tier.
756
- * Tokens are cached until they are close to expiry.
757
- *
758
- * Use this method when the customer may not exist and should be created automatically.
759
- * The email is required for auto-provisioning.
760
- */
761
- async frontendTokenAutoProvision(request) {
762
- if (!request.publishableKey?.trim()) {
763
- throw new ConfigError("publishableKey is required");
764
- }
765
- if (!request.identityProvider?.trim()) {
766
- throw new ConfigError("identityProvider is required");
767
- }
768
- if (!request.identitySubject?.trim()) {
769
- throw new ConfigError("identitySubject is required");
770
- }
771
- if (!request.email?.trim()) {
772
- throw new ConfigError("email is required for auto-provisioning");
773
- }
774
- return this.sendFrontendTokenRequest(request);
775
- }
776
- /**
777
- * Internal method to send frontend token requests.
778
- */
779
- async sendFrontendTokenRequest(request) {
780
- const { publishableKey, identityProvider, identitySubject, deviceId, ttlSeconds } = request;
781
- const email = "email" in request ? request.email : void 0;
782
- const cacheKey = `${publishableKey}:${identityProvider}:${identitySubject}:${deviceId || ""}`;
783
- const cached = this.cachedFrontend.get(cacheKey);
784
- if (cached && isTokenReusable(cached)) {
785
- return cached;
786
- }
787
- const payload = {
788
- publishable_key: publishableKey,
789
- identity_provider: identityProvider,
790
- identity_subject: identitySubject
791
- };
792
- if (deviceId) {
793
- payload.device_id = deviceId;
794
- }
795
- if (typeof ttlSeconds === "number" && ttlSeconds > 0) {
796
- payload.ttl_seconds = ttlSeconds;
797
- }
798
- if (email) {
799
- payload.email = email;
800
- }
801
- const response = await this.http.json(
802
- "/auth/frontend-token",
803
- {
804
- method: "POST",
805
- body: payload
806
- }
807
- );
808
- const token = normalizeFrontendToken(response, {
809
- publishableKey,
810
- deviceId,
811
- identityProvider,
812
- identitySubject
813
- });
814
- this.cachedFrontend.set(cacheKey, token);
815
- return token;
816
- }
817
629
  /**
818
630
  * Determine the correct auth headers for /responses.
819
- * Publishable keys are automatically exchanged for frontend tokens.
820
631
  */
821
- async authForResponses(overrides) {
632
+ async authForResponses() {
822
633
  if (this.accessToken) {
823
634
  return createAccessTokenAuth(this.accessToken);
824
635
  }
@@ -832,32 +643,6 @@ var AuthClient = class {
832
643
  if (!this.apiKey) {
833
644
  throw new ConfigError("API key or token is required");
834
645
  }
835
- if (this.apiKeyIsPublishable) {
836
- const publishableKey = this.apiKey;
837
- const identityProvider = overrides?.provider || this.customer?.provider;
838
- const identitySubject = overrides?.subject || this.customer?.subject;
839
- const deviceId = overrides?.deviceId || this.customer?.deviceId;
840
- const ttlSeconds = overrides?.ttlSeconds ?? this.customer?.ttlSeconds;
841
- const email = overrides?.email || this.customer?.email;
842
- if (!identityProvider || !identitySubject) {
843
- throw new ConfigError("identity provider + subject are required to mint a frontend token");
844
- }
845
- const token = email ? await this.frontendTokenAutoProvision({
846
- publishableKey,
847
- identityProvider,
848
- identitySubject,
849
- email,
850
- deviceId,
851
- ttlSeconds
852
- }) : await this.frontendToken({
853
- publishableKey,
854
- identityProvider,
855
- identitySubject,
856
- deviceId,
857
- ttlSeconds
858
- });
859
- return createAccessTokenAuth(token.token);
860
- }
861
646
  return createApiKeyAuth(this.apiKey);
862
647
  }
863
648
  /**
@@ -872,7 +657,7 @@ var AuthClient = class {
872
657
  if (request.ttlSeconds !== void 0 && request.ttlSeconds < 0) {
873
658
  throw new ConfigError("ttlSeconds must be non-negative when provided");
874
659
  }
875
- if (!this.apiKey || this.apiKeyIsPublishable) {
660
+ if (!this.apiKey) {
876
661
  throw new ConfigError("Secret API key is required to mint customer tokens");
877
662
  }
878
663
  const payload = {};
@@ -897,44 +682,54 @@ var AuthClient = class {
897
682
  tokenType: apiResp.token_type,
898
683
  projectId: apiResp.project_id,
899
684
  customerId: apiResp.customer_id,
685
+ billingProfileId: apiResp.billing_profile_id,
900
686
  customerExternalId: apiResp.customer_external_id,
901
687
  tierCode: apiResp.tier_code ? asTierCode(apiResp.tier_code) : void 0
902
688
  };
903
689
  }
904
690
  /**
905
- * Verify an OIDC id_token and exchange it for a customer bearer token.
691
+ * Get or create a customer and mint a bearer token.
692
+ *
693
+ * This is a convenience method that:
694
+ * 1. Upserts the customer (creates if not exists)
695
+ * 2. Mints a customer-scoped bearer token
696
+ *
697
+ * Use this when you want to ensure the customer exists before minting a token,
698
+ * without needing to handle 404 errors from customerToken().
699
+ *
700
+ * Requires a secret key.
906
701
  */
907
- async oidcExchange(request) {
908
- const idToken = request.idToken?.trim();
909
- if (!idToken) {
910
- throw new ConfigError("idToken is required");
702
+ async getOrCreateCustomerToken(request) {
703
+ const externalId = request.externalId?.trim();
704
+ const email = request.email?.trim();
705
+ if (!externalId) {
706
+ throw new ConfigError("externalId is required");
707
+ }
708
+ if (!email) {
709
+ throw new ConfigError("email is required");
911
710
  }
912
711
  if (!this.apiKey) {
913
- throw new ConfigError("API key is required for OIDC exchange");
712
+ throw new ConfigError("Secret API key is required to get or create customer tokens");
914
713
  }
915
- const payload = { id_token: idToken };
916
- const projectId = request.projectId?.trim();
917
- if (projectId) {
918
- payload.project_id = projectId;
714
+ const upsertPayload = {
715
+ external_id: externalId,
716
+ email
717
+ };
718
+ if (request.metadata) {
719
+ upsertPayload.metadata = request.metadata;
919
720
  }
920
- const apiResp = await this.http.json("/auth/oidc/exchange", {
921
- method: "POST",
922
- body: payload,
721
+ await this.http.json("/customers", {
722
+ method: "PUT",
723
+ body: upsertPayload,
923
724
  apiKey: this.apiKey
924
725
  });
925
- return {
926
- token: apiResp.token,
927
- expiresAt: new Date(apiResp.expires_at),
928
- expiresIn: apiResp.expires_in,
929
- tokenType: apiResp.token_type,
930
- projectId: apiResp.project_id,
931
- customerId: apiResp.customer_id,
932
- customerExternalId: apiResp.customer_external_id,
933
- tierCode: apiResp.tier_code ? asTierCode(apiResp.tier_code) : void 0
934
- };
726
+ return this.customerToken({
727
+ customerExternalId: externalId,
728
+ ttlSeconds: request.ttlSeconds
729
+ });
935
730
  }
936
731
  /**
937
- * Billing calls accept either bearer tokens or API keys (including publishable keys).
732
+ * Billing calls accept either bearer tokens or API keys.
938
733
  */
939
734
  authForBilling() {
940
735
  if (this.accessToken) {
@@ -945,207 +740,7 @@ var AuthClient = class {
945
740
  }
946
741
  return createApiKeyAuth(this.apiKey);
947
742
  }
948
- /**
949
- * Start a device authorization flow (RFC 8628).
950
- *
951
- * @param request - Optional request options
952
- * @param request.provider - Set to "github" to use GitHub's native device flow
953
- *
954
- * @example Wrapped flow (default)
955
- * ```typescript
956
- * const auth = await client.auth.deviceStart();
957
- * console.log(`Go to ${auth.verificationUri} and enter code: ${auth.userCode}`);
958
- * ```
959
- *
960
- * @example Native GitHub flow
961
- * ```typescript
962
- * const auth = await client.auth.deviceStart({ provider: "github" });
963
- * // verificationUri will be "https://github.com/login/device"
964
- * console.log(`Go to ${auth.verificationUri} and enter code: ${auth.userCode}`);
965
- * ```
966
- */
967
- async deviceStart(request) {
968
- if (!this.apiKey) {
969
- throw new ConfigError("API key is required to start device flow");
970
- }
971
- const params = new URLSearchParams();
972
- if (request?.provider) {
973
- params.set("provider", request.provider);
974
- }
975
- const queryString = params.toString();
976
- const path = queryString ? `/auth/device/start?${queryString}` : "/auth/device/start";
977
- const apiResp = await this.http.json(path, {
978
- method: "POST",
979
- apiKey: this.apiKey
980
- });
981
- return {
982
- deviceCode: apiResp.device_code,
983
- userCode: apiResp.user_code,
984
- verificationUri: apiResp.verification_uri,
985
- verificationUriComplete: apiResp.verification_uri_complete,
986
- expiresAt: new Date(Date.now() + apiResp.expires_in * 1e3),
987
- interval: apiResp.interval
988
- };
989
- }
990
- /**
991
- * Poll the device token endpoint for authorization completion.
992
- *
993
- * Returns a discriminated union:
994
- * - `{ status: "approved", token }` - User authorized, token available
995
- * - `{ status: "pending", pending }` - User hasn't authorized yet, keep polling
996
- * - `{ status: "error", error }` - Authorization failed (expired, denied, etc.)
997
- *
998
- * @param deviceCode - The device code from deviceStart()
999
- *
1000
- * @example
1001
- * ```typescript
1002
- * const auth = await client.auth.deviceStart({ provider: "github" });
1003
- * console.log(`Go to ${auth.verificationUri} and enter: ${auth.userCode}`);
1004
- *
1005
- * let interval = auth.interval;
1006
- * while (true) {
1007
- * await sleep(interval * 1000);
1008
- * const result = await client.auth.deviceToken(auth.deviceCode);
1009
- *
1010
- * if (result.status === "approved") {
1011
- * console.log("Token:", result.token.token);
1012
- * break;
1013
- * } else if (result.status === "pending") {
1014
- * if (result.pending.interval) interval = result.pending.interval;
1015
- * continue;
1016
- * } else {
1017
- * throw new Error(`Authorization failed: ${result.error}`);
1018
- * }
1019
- * }
1020
- * ```
1021
- */
1022
- async deviceToken(deviceCode) {
1023
- if (!this.apiKey) {
1024
- throw new ConfigError("API key is required to poll device token");
1025
- }
1026
- if (!deviceCode?.trim()) {
1027
- throw new ConfigError("deviceCode is required");
1028
- }
1029
- try {
1030
- const apiResp = await this.http.json("/auth/device/token", {
1031
- method: "POST",
1032
- body: { device_code: deviceCode },
1033
- apiKey: this.apiKey
1034
- });
1035
- return {
1036
- status: "approved",
1037
- token: {
1038
- token: apiResp.token,
1039
- expiresAt: new Date(apiResp.expires_at),
1040
- expiresIn: apiResp.expires_in,
1041
- tokenType: "Bearer",
1042
- projectId: apiResp.project_id,
1043
- customerId: apiResp.customer_id,
1044
- customerExternalId: apiResp.customer_external_id,
1045
- tierCode: apiResp.tier_code ? asTierCode(apiResp.tier_code) : void 0
1046
- }
1047
- };
1048
- } catch (err) {
1049
- if (err instanceof APIError && err.status === 400) {
1050
- const data = err.data;
1051
- const errorCode = data?.error || err.code || "unknown";
1052
- if (errorCode === "authorization_pending" || errorCode === "slow_down") {
1053
- return {
1054
- status: "pending",
1055
- pending: {
1056
- error: errorCode,
1057
- errorDescription: data?.error_description,
1058
- interval: data?.interval
1059
- }
1060
- };
1061
- }
1062
- return {
1063
- status: "error",
1064
- error: errorCode,
1065
- errorDescription: data?.error_description || err.message
1066
- };
1067
- }
1068
- throw err;
1069
- }
1070
- }
1071
- /**
1072
- * Start an OAuth flow for customer authentication.
1073
- *
1074
- * This initiates the OAuth redirect flow where users authenticate with
1075
- * GitHub or Google and are redirected back to your application with a
1076
- * customer token.
1077
- *
1078
- * @param request - OAuth start parameters
1079
- * @param request.projectId - The project ID to authenticate against
1080
- * @param request.provider - OAuth provider: "github" or "google"
1081
- * @param request.redirectUri - Where to redirect after OAuth. Must be in project's whitelist.
1082
- * @returns Promise with the redirect URL
1083
- *
1084
- * @example
1085
- * ```typescript
1086
- * const { redirectUrl } = await client.auth.oauthStart({
1087
- * projectId: "your-project-id",
1088
- * provider: "github",
1089
- * redirectUri: "https://your-app.com/auth/callback",
1090
- * });
1091
- *
1092
- * // Redirect user to the OAuth provider
1093
- * window.location.href = redirectUrl;
1094
- *
1095
- * // After OAuth, your callback receives a POST with:
1096
- * // token, token_type, expires_at, expires_in, project_id, customer_id, customer_external_id, tier_code
1097
- * ```
1098
- */
1099
- async oauthStart(request) {
1100
- if (!request.projectId?.trim()) {
1101
- throw new ConfigError("projectId is required");
1102
- }
1103
- if (!request.provider?.trim()) {
1104
- throw new ConfigError("provider is required");
1105
- }
1106
- if (!request.redirectUri?.trim()) {
1107
- throw new ConfigError("redirectUri is required");
1108
- }
1109
- const apiResp = await this.http.json(
1110
- "/auth/customer/oauth/start",
1111
- {
1112
- method: "POST",
1113
- body: {
1114
- project_id: request.projectId,
1115
- provider: request.provider,
1116
- redirect_uri: request.redirectUri
1117
- }
1118
- }
1119
- );
1120
- return {
1121
- redirectUrl: apiResp.redirect_url
1122
- };
1123
- }
1124
743
  };
1125
- function normalizeFrontendToken(payload, meta) {
1126
- return {
1127
- token: payload.token,
1128
- expiresAt: new Date(payload.expires_at),
1129
- expiresIn: payload.expires_in,
1130
- tokenType: payload.token_type,
1131
- keyId: payload.key_id,
1132
- sessionId: payload.session_id,
1133
- projectId: payload.project_id,
1134
- customerId: payload.customer_id,
1135
- customerExternalId: payload.customer_external_id,
1136
- tierCode: payload.tier_code,
1137
- publishableKey: meta.publishableKey,
1138
- deviceId: meta.deviceId,
1139
- identityProvider: meta.identityProvider,
1140
- identitySubject: meta.identitySubject
1141
- };
1142
- }
1143
- function isTokenReusable(token) {
1144
- if (!token.token) {
1145
- return false;
1146
- }
1147
- return token.expiresAt.getTime() - Date.now() > 6e4;
1148
- }
1149
744
 
1150
745
  // src/tools.ts
1151
746
  function createUserMessage(content) {
@@ -2850,7 +2445,7 @@ var ResponsesClient = class {
2850
2445
  * import { z } from 'zod';
2851
2446
  *
2852
2447
  * const review = await client.responses.object({
2853
- * model: 'claude-sonnet-4-20250514',
2448
+ * model: 'claude-sonnet-4-5',
2854
2449
  * schema: z.object({
2855
2450
  * vulnerabilities: z.array(z.string()),
2856
2451
  * riskLevel: z.enum(['low', 'medium', 'high']),
@@ -2907,7 +2502,7 @@ var ResponsesClient = class {
2907
2502
  * @example
2908
2503
  * ```typescript
2909
2504
  * const result = await client.responses.objectWithMetadata({
2910
- * model: 'claude-sonnet-4-20250514',
2505
+ * model: 'claude-sonnet-4-5',
2911
2506
  * schema: ReviewSchema,
2912
2507
  * prompt: 'Review this code...',
2913
2508
  * });
@@ -3316,7 +2911,6 @@ var ResponsesClient = class {
3316
2911
 
3317
2912
  // src/runs_request.ts
3318
2913
  var RUNS_PATH = "/runs";
3319
- var WORKFLOW_V0_SCHEMA_PATH = "/schemas/workflow_v0.schema.json";
3320
2914
  var RUN_EVENT_V0_SCHEMA_PATH = "/schemas/run_event_v0.schema.json";
3321
2915
  function runByIdPath(runId) {
3322
2916
  return `${RUNS_PATH}/${encodeURIComponent(runId)}`;
@@ -3374,14 +2968,8 @@ function parseOutputName(raw) {
3374
2968
 
3375
2969
  // src/runs_types.ts
3376
2970
  var WorkflowKinds = {
3377
- WorkflowV0: "workflow.v0",
3378
2971
  WorkflowV1: "workflow.v1"
3379
2972
  };
3380
- var WorkflowNodeTypes = {
3381
- LLMResponses: "llm.responses",
3382
- JoinAll: "join.all",
3383
- TransformJSON: "transform.json"
3384
- };
3385
2973
  var WorkflowNodeTypesV1 = {
3386
2974
  LLMResponses: "llm.responses",
3387
2975
  RouteSwitch: "route.switch",
@@ -3770,22 +3358,6 @@ var RunsClient = class {
3770
3358
  });
3771
3359
  return { ...out, run_id: parseRunId(out.run_id), plan_hash: parsePlanHash(out.plan_hash) };
3772
3360
  }
3773
- async schemaV0(options = {}) {
3774
- const metrics = mergeMetrics(this.metrics, options.metrics);
3775
- const trace = mergeTrace(this.trace, options.trace);
3776
- return this.http.json(WORKFLOW_V0_SCHEMA_PATH, {
3777
- method: "GET",
3778
- headers: options.headers,
3779
- signal: options.signal,
3780
- timeoutMs: options.timeoutMs,
3781
- connectTimeoutMs: options.connectTimeoutMs,
3782
- retry: options.retry,
3783
- metrics,
3784
- trace,
3785
- context: { method: "GET", path: WORKFLOW_V0_SCHEMA_PATH },
3786
- accept: "application/schema+json"
3787
- });
3788
- }
3789
3361
  async runEventSchemaV0(options = {}) {
3790
3362
  const metrics = mergeMetrics(this.metrics, options.metrics);
3791
3363
  const trace = mergeTrace(this.trace, options.trace);
@@ -3960,65 +3532,6 @@ var WorkflowsClient = class {
3960
3532
  this.metrics = cfg.metrics;
3961
3533
  this.trace = cfg.trace;
3962
3534
  }
3963
- async compileV0(spec, options = {}) {
3964
- const metrics = mergeMetrics(this.metrics, options.metrics);
3965
- const trace = mergeTrace(this.trace, options.trace);
3966
- const authHeaders = await this.auth.authForResponses();
3967
- const headers = { ...options.headers || {} };
3968
- const customerId = options.customerId?.trim();
3969
- if (customerId) {
3970
- headers[CUSTOMER_ID_HEADER] = customerId;
3971
- }
3972
- try {
3973
- const out = await this.http.json(
3974
- WORKFLOWS_COMPILE_PATH,
3975
- {
3976
- method: "POST",
3977
- headers,
3978
- body: spec,
3979
- signal: options.signal,
3980
- apiKey: authHeaders.apiKey,
3981
- accessToken: authHeaders.accessToken,
3982
- timeoutMs: options.timeoutMs,
3983
- connectTimeoutMs: options.connectTimeoutMs,
3984
- retry: options.retry,
3985
- metrics,
3986
- trace,
3987
- context: { method: "POST", path: WORKFLOWS_COMPILE_PATH }
3988
- }
3989
- );
3990
- return {
3991
- ok: true,
3992
- plan_json: out.plan_json,
3993
- plan_hash: parsePlanHash(out.plan_hash)
3994
- };
3995
- } catch (err) {
3996
- if (err instanceof WorkflowValidationError) {
3997
- return { ok: false, error_type: "validation_error", issues: err.issues };
3998
- }
3999
- if (err instanceof APIError) {
4000
- return {
4001
- ok: false,
4002
- error_type: "internal_error",
4003
- status: err.status ?? 0,
4004
- message: err.message,
4005
- code: err.code,
4006
- requestId: err.requestId
4007
- };
4008
- }
4009
- if (err instanceof ModelRelayError && err.category === "api") {
4010
- return {
4011
- ok: false,
4012
- error_type: "internal_error",
4013
- status: err.status ?? 0,
4014
- message: err.message,
4015
- code: err.code,
4016
- requestId: err.requestId
4017
- };
4018
- }
4019
- throw err;
4020
- }
4021
- }
4022
3535
  async compileV1(spec, options = {}) {
4023
3536
  const metrics = mergeMetrics(this.metrics, options.metrics);
4024
3537
  const trace = mergeTrace(this.trace, options.trace);
@@ -4524,7 +4037,7 @@ var LocalSession = class _LocalSession {
4524
4037
  const input = await this.buildInput(options);
4525
4038
  const tools = mergeTools(this.defaultTools, options.tools);
4526
4039
  const spec = {
4527
- kind: "workflow.v0",
4040
+ kind: "workflow.v1",
4528
4041
  name: `session-${this.id}-turn-${this.nextSeq}`,
4529
4042
  nodes: [
4530
4043
  {
@@ -4837,21 +4350,34 @@ function mergeTools(defaults, overrides) {
4837
4350
  }
4838
4351
  return Array.from(merged.values());
4839
4352
  }
4353
+ function isOutputMessage(item) {
4354
+ return typeof item === "object" && item !== null && "type" in item && typeof item.type === "string";
4355
+ }
4356
+ function isContentPiece(c) {
4357
+ return typeof c === "object" && c !== null && "type" in c && typeof c.type === "string";
4358
+ }
4359
+ function hasOutputArray(obj) {
4360
+ return "output" in obj && Array.isArray(obj.output);
4361
+ }
4362
+ function hasContentArray(obj) {
4363
+ return "content" in obj && Array.isArray(obj.content);
4364
+ }
4840
4365
  function extractTextOutput(outputs) {
4841
4366
  const result = outputs.result;
4842
4367
  if (typeof result === "string") return result;
4843
4368
  if (result && typeof result === "object") {
4844
- const resp = result;
4845
- if (Array.isArray(resp.output)) {
4846
- const textParts = resp.output.filter((item) => item?.type === "message" && item?.role === "assistant").flatMap(
4847
- (item) => (item.content || []).filter((c) => c?.type === "text").map((c) => c.text)
4848
- );
4369
+ if (hasOutputArray(result)) {
4370
+ const textParts = result.output.filter(
4371
+ (item) => isOutputMessage(item) && item.type === "message" && item.role === "assistant"
4372
+ ).flatMap(
4373
+ (item) => (item.content || []).filter((c) => isContentPiece(c) && c.type === "text").map((c) => c.text ?? "")
4374
+ ).filter((text) => text.length > 0);
4849
4375
  if (textParts.length > 0) {
4850
4376
  return textParts.join("\n");
4851
4377
  }
4852
4378
  }
4853
- if (Array.isArray(resp.content)) {
4854
- const textParts = resp.content.filter((c) => c?.type === "text").map((c) => c.text);
4379
+ if (hasContentArray(result)) {
4380
+ const textParts = result.content.filter((c) => isContentPiece(c) && c.type === "text").map((c) => c.text ?? "").filter((text) => text.length > 0);
4855
4381
  if (textParts.length > 0) {
4856
4382
  return textParts.join("\n");
4857
4383
  }
@@ -4883,7 +4409,7 @@ var RemoteSession = class _RemoteSession {
4883
4409
  this.http = http;
4884
4410
  this.id = asSessionId(sessionData.id);
4885
4411
  this.metadata = sessionData.metadata;
4886
- this.endUserId = sessionData.end_user_id || options.endUserId;
4412
+ this.customerId = sessionData.customer_id || options.customerId;
4887
4413
  this.createdAt = new Date(sessionData.created_at);
4888
4414
  this.updatedAt = new Date(sessionData.updated_at);
4889
4415
  this.toolRegistry = options.toolRegistry;
@@ -4915,7 +4441,7 @@ var RemoteSession = class _RemoteSession {
4915
4441
  const response = await http.request("/sessions", {
4916
4442
  method: "POST",
4917
4443
  body: {
4918
- end_user_id: options.endUserId,
4444
+ customer_id: options.customerId,
4919
4445
  metadata: options.metadata || {}
4920
4446
  }
4921
4447
  });
@@ -4951,7 +4477,7 @@ var RemoteSession = class _RemoteSession {
4951
4477
  const params = new URLSearchParams();
4952
4478
  if (options.limit) params.set("limit", String(options.limit));
4953
4479
  if (options.offset) params.set("offset", String(options.offset));
4954
- if (options.endUserId) params.set("end_user_id", options.endUserId);
4480
+ if (options.customerId) params.set("customer_id", options.customerId);
4955
4481
  const response = await http.request(
4956
4482
  `/sessions${params.toString() ? `?${params.toString()}` : ""}`,
4957
4483
  { method: "GET" }
@@ -5004,7 +4530,7 @@ var RemoteSession = class _RemoteSession {
5004
4530
  const input = await this.buildInput(options);
5005
4531
  const tools = mergeTools2(this.defaultTools, options.tools);
5006
4532
  const spec = {
5007
- kind: "workflow.v0",
4533
+ kind: "workflow.v1",
5008
4534
  name: `session-${this.id}-turn-${this.nextSeq}`,
5009
4535
  nodes: [
5010
4536
  {
@@ -5024,7 +4550,7 @@ var RemoteSession = class _RemoteSession {
5024
4550
  outputs: [{ name: "result", from: "main" }]
5025
4551
  };
5026
4552
  const run = await this.client.runs.create(spec, {
5027
- customerId: options.customerId || this.endUserId,
4553
+ customerId: options.customerId || this.customerId,
5028
4554
  sessionId: String(this.id)
5029
4555
  });
5030
4556
  this.currentRunId = run.run_id;
@@ -5486,7 +5012,7 @@ var SessionsClient = class {
5486
5012
  /**
5487
5013
  * List remote sessions.
5488
5014
  *
5489
- * @param options - List options (limit, cursor, endUserId)
5015
+ * @param options - List options (limit, cursor, customerId)
5490
5016
  * @returns Paginated list of session summaries
5491
5017
  *
5492
5018
  * @example
@@ -5501,13 +5027,13 @@ var SessionsClient = class {
5501
5027
  return RemoteSession.list(this.modelRelay, {
5502
5028
  limit: options.limit,
5503
5029
  offset: options.cursor ? parseInt(options.cursor, 10) : void 0,
5504
- endUserId: options.endUserId
5030
+ customerId: options.customerId
5505
5031
  });
5506
5032
  }
5507
5033
  /**
5508
5034
  * Delete a remote session.
5509
5035
  *
5510
- * Requires a secret key (not publishable key).
5036
+ * Requires a secret key.
5511
5037
  *
5512
5038
  * @param sessionId - ID of the session to delete
5513
5039
  *
@@ -5533,11 +5059,12 @@ var TiersClient = class {
5533
5059
  this.http = http;
5534
5060
  this.apiKey = cfg.apiKey ? parseApiKey(cfg.apiKey) : void 0;
5535
5061
  this.hasSecretKey = this.apiKey ? isSecretKey(this.apiKey) : false;
5062
+ this.hasAccessToken = !!cfg.accessToken?.trim();
5536
5063
  }
5537
- ensureApiKey() {
5538
- if (!this.apiKey) {
5064
+ ensureAuth() {
5065
+ if (!this.apiKey && !this.hasAccessToken) {
5539
5066
  throw new ConfigError(
5540
- "API key (mr_pk_* or mr_sk_*) required for tier operations"
5067
+ "API key (mr_sk_*) or bearer token required for tier operations"
5541
5068
  );
5542
5069
  }
5543
5070
  }
@@ -5552,7 +5079,7 @@ var TiersClient = class {
5552
5079
  * List all tiers in the project.
5553
5080
  */
5554
5081
  async list() {
5555
- this.ensureApiKey();
5082
+ this.ensureAuth();
5556
5083
  const response = await this.http.json("/tiers", {
5557
5084
  method: "GET",
5558
5085
  apiKey: this.apiKey
@@ -5563,7 +5090,7 @@ var TiersClient = class {
5563
5090
  * Get a tier by ID.
5564
5091
  */
5565
5092
  async get(tierId) {
5566
- this.ensureApiKey();
5093
+ this.ensureAuth();
5567
5094
  if (!tierId?.trim()) {
5568
5095
  throw new ConfigError("tierId is required");
5569
5096
  }
@@ -5578,8 +5105,8 @@ var TiersClient = class {
5578
5105
  *
5579
5106
  * This enables users to subscribe before authenticating. Stripe collects
5580
5107
  * the customer's email during checkout. After checkout completes, a
5581
- * customer record is created with the email from Stripe. The customer
5582
- * can later be linked to an identity via POST /customers/claim.
5108
+ * customer record is created with the email from Stripe. Your backend
5109
+ * can map it to your app user and mint customer tokens as needed.
5583
5110
  *
5584
5111
  * Requires a secret key (mr_sk_*).
5585
5112
  *
@@ -6022,47 +5549,6 @@ function isReusable(token) {
6022
5549
  }
6023
5550
  return token.expiresAt.getTime() - Date.now() > 6e4;
6024
5551
  }
6025
- var FrontendTokenProvider = class {
6026
- constructor(cfg) {
6027
- const publishableKey = parsePublishableKey(cfg.publishableKey);
6028
- const http = new HTTPClient({
6029
- baseUrl: cfg.baseUrl || DEFAULT_BASE_URL,
6030
- fetchImpl: cfg.fetch,
6031
- clientHeader: cfg.clientHeader || DEFAULT_CLIENT_HEADER,
6032
- apiKey: publishableKey
6033
- });
6034
- this.publishableKey = publishableKey;
6035
- this.customer = cfg.customer;
6036
- this.auth = new AuthClient(http, { apiKey: publishableKey, customer: cfg.customer });
6037
- }
6038
- async getToken() {
6039
- if (!this.customer?.provider || !this.customer?.subject) {
6040
- throw new ConfigError("customer.provider and customer.subject are required");
6041
- }
6042
- const reqBase = {
6043
- publishableKey: this.publishableKey,
6044
- identityProvider: this.customer.provider,
6045
- identitySubject: this.customer.subject,
6046
- deviceId: this.customer.deviceId,
6047
- ttlSeconds: this.customer.ttlSeconds
6048
- };
6049
- let token;
6050
- if (this.customer.email) {
6051
- const req = {
6052
- ...reqBase,
6053
- email: this.customer.email
6054
- };
6055
- token = await this.auth.frontendTokenAutoProvision(req);
6056
- } else {
6057
- const req = reqBase;
6058
- token = await this.auth.frontendToken(req);
6059
- }
6060
- if (!token.token) {
6061
- throw new ConfigError("frontend token exchange returned an empty token");
6062
- }
6063
- return token.token;
6064
- }
6065
- };
6066
5552
  var CustomerTokenProvider = class {
6067
5553
  constructor(cfg) {
6068
5554
  const key = parseSecretKey(cfg.secretKey);
@@ -6084,242 +5570,6 @@ var CustomerTokenProvider = class {
6084
5570
  return token.token;
6085
5571
  }
6086
5572
  };
6087
- var OIDCExchangeTokenProvider = class {
6088
- constructor(cfg) {
6089
- const apiKey = parseApiKey(cfg.apiKey);
6090
- const http = new HTTPClient({
6091
- baseUrl: cfg.baseUrl || DEFAULT_BASE_URL,
6092
- fetchImpl: cfg.fetch,
6093
- clientHeader: cfg.clientHeader || DEFAULT_CLIENT_HEADER,
6094
- apiKey
6095
- });
6096
- this.auth = new AuthClient(http, { apiKey });
6097
- this.idTokenProvider = cfg.idTokenProvider;
6098
- this.request = { idToken: "", projectId: cfg.projectId };
6099
- }
6100
- async getToken() {
6101
- if (this.cached && isReusable(this.cached)) {
6102
- return this.cached.token;
6103
- }
6104
- const idToken = (await this.idTokenProvider())?.trim();
6105
- if (!idToken) {
6106
- throw new ConfigError("idTokenProvider returned an empty id_token");
6107
- }
6108
- const token = await this.auth.oidcExchange({ ...this.request, idToken });
6109
- this.cached = token;
6110
- return token.token;
6111
- }
6112
- };
6113
-
6114
- // src/device_flow.ts
6115
- async function pollUntil(opts) {
6116
- let intervalMs = Math.max(1, opts.intervalMs);
6117
- let attempt = 0;
6118
- while (true) {
6119
- if (opts.deadline && Date.now() >= opts.deadline.getTime()) {
6120
- throw opts.onTimeout?.() ?? new TransportError("polling timed out", { kind: "timeout" });
6121
- }
6122
- const result = await opts.poll(attempt);
6123
- if (result.done) {
6124
- return result.value;
6125
- }
6126
- const delay = Math.max(1, result.retryAfterMs ?? intervalMs);
6127
- intervalMs = delay;
6128
- await sleep(delay, opts.signal);
6129
- attempt += 1;
6130
- }
6131
- }
6132
- async function startOAuthDeviceAuthorization(req) {
6133
- const deviceAuthorizationEndpoint = req.deviceAuthorizationEndpoint?.trim();
6134
- if (!deviceAuthorizationEndpoint) {
6135
- throw new ConfigError("deviceAuthorizationEndpoint is required");
6136
- }
6137
- const clientId = req.clientId?.trim();
6138
- if (!clientId) {
6139
- throw new ConfigError("clientId is required");
6140
- }
6141
- const form = new URLSearchParams();
6142
- form.set("client_id", clientId);
6143
- if (req.scope?.trim()) {
6144
- form.set("scope", req.scope.trim());
6145
- }
6146
- if (req.audience?.trim()) {
6147
- form.set("audience", req.audience.trim());
6148
- }
6149
- const payload = await postOAuthForm(deviceAuthorizationEndpoint, form, {
6150
- fetch: req.fetch,
6151
- signal: req.signal
6152
- });
6153
- const deviceCode = String(payload.device_code || "").trim();
6154
- const userCode = String(payload.user_code || "").trim();
6155
- const verificationUri = String(payload.verification_uri || payload.verification_uri_complete || "").trim();
6156
- const verificationUriComplete = String(payload.verification_uri_complete || "").trim() || void 0;
6157
- const expiresIn = Number(payload.expires_in || 0);
6158
- const intervalSeconds = Math.max(1, Number(payload.interval || 5));
6159
- if (!deviceCode || !userCode || !verificationUri || !expiresIn) {
6160
- throw new TransportError("oauth device authorization returned an invalid response", {
6161
- kind: "request",
6162
- cause: payload
6163
- });
6164
- }
6165
- return {
6166
- deviceCode,
6167
- userCode,
6168
- verificationUri,
6169
- verificationUriComplete,
6170
- expiresAt: new Date(Date.now() + expiresIn * 1e3),
6171
- intervalSeconds
6172
- };
6173
- }
6174
- async function pollOAuthDeviceToken(req) {
6175
- const tokenEndpoint = req.tokenEndpoint?.trim();
6176
- if (!tokenEndpoint) {
6177
- throw new ConfigError("tokenEndpoint is required");
6178
- }
6179
- const clientId = req.clientId?.trim();
6180
- if (!clientId) {
6181
- throw new ConfigError("clientId is required");
6182
- }
6183
- const deviceCode = req.deviceCode?.trim();
6184
- if (!deviceCode) {
6185
- throw new ConfigError("deviceCode is required");
6186
- }
6187
- const deadline = req.deadline ?? new Date(Date.now() + 10 * 60 * 1e3);
6188
- let intervalMs = Math.max(1, req.intervalSeconds ?? 5) * 1e3;
6189
- return pollUntil({
6190
- intervalMs,
6191
- deadline,
6192
- signal: req.signal,
6193
- onTimeout: () => new TransportError("oauth device flow timed out", { kind: "timeout" }),
6194
- poll: async () => {
6195
- const form = new URLSearchParams();
6196
- form.set("grant_type", "urn:ietf:params:oauth:grant-type:device_code");
6197
- form.set("device_code", deviceCode);
6198
- form.set("client_id", clientId);
6199
- const payload = await postOAuthForm(tokenEndpoint, form, {
6200
- fetch: req.fetch,
6201
- signal: req.signal,
6202
- allowErrorPayload: true
6203
- });
6204
- const err = String(payload.error || "").trim();
6205
- if (err) {
6206
- switch (err) {
6207
- case "authorization_pending":
6208
- return { done: false };
6209
- case "slow_down":
6210
- intervalMs += 5e3;
6211
- return { done: false, retryAfterMs: intervalMs };
6212
- case "expired_token":
6213
- case "access_denied":
6214
- case "invalid_grant":
6215
- throw new TransportError(`oauth device flow failed: ${err}`, {
6216
- kind: "request",
6217
- cause: payload
6218
- });
6219
- default:
6220
- throw new TransportError(`oauth device flow error: ${err}`, {
6221
- kind: "request",
6222
- cause: payload
6223
- });
6224
- }
6225
- }
6226
- const accessToken = String(payload.access_token || "").trim() || void 0;
6227
- const idToken = String(payload.id_token || "").trim() || void 0;
6228
- const refreshToken = String(payload.refresh_token || "").trim() || void 0;
6229
- const tokenType = String(payload.token_type || "").trim() || void 0;
6230
- const scope = String(payload.scope || "").trim() || void 0;
6231
- const expiresIn = payload.expires_in !== void 0 ? Number(payload.expires_in) : void 0;
6232
- const expiresAt = typeof expiresIn === "number" && Number.isFinite(expiresIn) && expiresIn > 0 ? new Date(Date.now() + expiresIn * 1e3) : void 0;
6233
- if (!accessToken && !idToken) {
6234
- throw new TransportError("oauth device flow returned an invalid token response", {
6235
- kind: "request",
6236
- cause: payload
6237
- });
6238
- }
6239
- return { done: true, value: { accessToken, idToken, refreshToken, tokenType, scope, expiresAt } };
6240
- }
6241
- });
6242
- }
6243
- async function runOAuthDeviceFlowForIDToken(cfg) {
6244
- const auth = await startOAuthDeviceAuthorization({
6245
- deviceAuthorizationEndpoint: cfg.deviceAuthorizationEndpoint,
6246
- clientId: cfg.clientId,
6247
- scope: cfg.scope,
6248
- audience: cfg.audience,
6249
- fetch: cfg.fetch,
6250
- signal: cfg.signal
6251
- });
6252
- await cfg.onUserCode(auth);
6253
- const token = await pollOAuthDeviceToken({
6254
- tokenEndpoint: cfg.tokenEndpoint,
6255
- clientId: cfg.clientId,
6256
- deviceCode: auth.deviceCode,
6257
- intervalSeconds: auth.intervalSeconds,
6258
- deadline: auth.expiresAt,
6259
- fetch: cfg.fetch,
6260
- signal: cfg.signal
6261
- });
6262
- if (!token.idToken) {
6263
- throw new TransportError("oauth device flow did not return an id_token", {
6264
- kind: "request",
6265
- cause: token
6266
- });
6267
- }
6268
- return token.idToken;
6269
- }
6270
- async function postOAuthForm(url, form, opts) {
6271
- const fetchFn = opts.fetch ?? globalThis.fetch;
6272
- if (!fetchFn) {
6273
- throw new ConfigError("fetch is not available; provide a fetch implementation");
6274
- }
6275
- let resp;
6276
- try {
6277
- resp = await fetchFn(url, {
6278
- method: "POST",
6279
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
6280
- body: form.toString(),
6281
- signal: opts.signal
6282
- });
6283
- } catch (cause) {
6284
- throw new TransportError("oauth request failed", { kind: "request", cause });
6285
- }
6286
- let json;
6287
- try {
6288
- json = await resp.json();
6289
- } catch (cause) {
6290
- throw new TransportError("oauth response was not valid JSON", { kind: "request", cause });
6291
- }
6292
- if (!resp.ok && !opts.allowErrorPayload) {
6293
- throw new TransportError(`oauth request failed (${resp.status})`, {
6294
- kind: "request",
6295
- cause: json
6296
- });
6297
- }
6298
- return json || {};
6299
- }
6300
- async function sleep(ms, signal) {
6301
- if (!ms || ms <= 0) {
6302
- return;
6303
- }
6304
- if (!signal) {
6305
- await new Promise((resolve) => setTimeout(resolve, ms));
6306
- return;
6307
- }
6308
- if (signal.aborted) {
6309
- throw new TransportError("oauth device flow aborted", { kind: "request" });
6310
- }
6311
- await new Promise((resolve, reject) => {
6312
- const onAbort = () => {
6313
- signal.removeEventListener("abort", onAbort);
6314
- reject(new TransportError("oauth device flow aborted", { kind: "request" }));
6315
- };
6316
- signal.addEventListener("abort", onAbort);
6317
- setTimeout(() => {
6318
- signal.removeEventListener("abort", onAbort);
6319
- resolve();
6320
- }, ms);
6321
- });
6322
- }
6323
5573
 
6324
5574
  // src/json_path.ts
6325
5575
  var LLMOutputPath = class {
@@ -6457,9 +5707,6 @@ function transformJSONObject(object) {
6457
5707
  function transformJSONMerge(merge) {
6458
5708
  return { merge: merge.slice() };
6459
5709
  }
6460
- var transformJSONValueV1 = transformJSONValue;
6461
- var transformJSONObjectV1 = transformJSONObject;
6462
- var transformJSONMergeV1 = transformJSONMerge;
6463
5710
  function wireRequest(req) {
6464
5711
  const raw = req;
6465
5712
  if (raw && typeof raw === "object") {
@@ -6513,2142 +5760,191 @@ function validateInputPointer(pointer, input) {
6513
5760
  }
6514
5761
  if (match[2] !== void 0) {
6515
5762
  const contentIndex = parseInt(match[2], 10);
6516
- const msg = input[msgIndex];
6517
- if (contentIndex >= msg.content.length) {
6518
- return `targets ${pointer} but message ${msgIndex} only has ${msg.content.length} content blocks (indices 0-${msg.content.length - 1})`;
6519
- }
6520
- }
6521
- return void 0;
6522
- }
6523
- function validateMapFanoutInput(nodeId, input) {
6524
- const subnode = input.subnode;
6525
- if ((subnode.type === WorkflowNodeTypesV1.LLMResponses || subnode.type === WorkflowNodeTypesV1.RouteSwitch) && subnode.input.bindings && subnode.input.bindings.length > 0) {
6526
- throw new MapFanoutInputError(nodeId, "map.fanout subnode bindings are not allowed");
6527
- }
6528
- if (subnode.type !== WorkflowNodeTypesV1.TransformJSON) {
6529
- return;
6530
- }
6531
- if (input.item_bindings && input.item_bindings.length > 0) {
6532
- throw new MapFanoutInputError(
6533
- nodeId,
6534
- "map.fanout transform.json subnode cannot use item_bindings"
6535
- );
6536
- }
6537
- const hasObject = !!subnode.input.object && Object.keys(subnode.input.object).length > 0;
6538
- const hasMerge = !!subnode.input.merge && subnode.input.merge.length > 0;
6539
- if (hasObject === hasMerge) {
6540
- throw new MapFanoutInputError(
6541
- nodeId,
6542
- "map.fanout transform.json must provide exactly one of object or merge"
6543
- );
6544
- }
6545
- if (hasObject) {
6546
- for (const [key, value] of Object.entries(subnode.input.object ?? {})) {
6547
- if (!key.trim()) continue;
6548
- if (String(value.from) !== "item") {
6549
- throw new MapFanoutInputError(
6550
- nodeId,
6551
- `map.fanout transform.json object.${key}.from must be "item"`
6552
- );
6553
- }
6554
- }
6555
- }
6556
- if (hasMerge) {
6557
- for (const [index, value] of (subnode.input.merge ?? []).entries()) {
6558
- if (String(value.from) !== "item") {
6559
- throw new MapFanoutInputError(
6560
- nodeId,
6561
- `map.fanout transform.json merge[${index}].from must be "item"`
6562
- );
6563
- }
6564
- }
6565
- }
6566
- }
6567
- var WorkflowBuilderV0 = class _WorkflowBuilderV0 {
6568
- constructor(state = { nodes: [], edges: [], outputs: [] }) {
6569
- this.state = state;
6570
- }
6571
- static new() {
6572
- return new _WorkflowBuilderV0();
6573
- }
6574
- with(patch) {
6575
- return new _WorkflowBuilderV0({
6576
- ...this.state,
6577
- ...patch
6578
- });
6579
- }
6580
- name(name) {
6581
- return this.with({ name: name.trim() || void 0 });
6582
- }
6583
- execution(execution) {
6584
- return this.with({ execution });
6585
- }
6586
- node(node) {
6587
- return this.with({ nodes: [...this.state.nodes, node] });
6588
- }
6589
- llmResponses(id, request, options = {}) {
6590
- const wiredRequest = wireRequest(request);
6591
- if (options.bindings) {
6592
- validateBindingTargets(id, wiredRequest.input, options.bindings);
6593
- }
6594
- const input = {
6595
- request: wiredRequest,
6596
- ...options.stream === void 0 ? {} : { stream: options.stream },
6597
- ...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
6598
- ...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
6599
- ...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
6600
- };
6601
- return this.node({
6602
- id,
6603
- type: WorkflowNodeTypes.LLMResponses,
6604
- input
6605
- });
6606
- }
6607
- joinAll(id) {
6608
- return this.node({ id, type: WorkflowNodeTypes.JoinAll });
6609
- }
6610
- transformJSON(id, input) {
6611
- return this.node({ id, type: WorkflowNodeTypes.TransformJSON, input });
6612
- }
6613
- edge(from, to) {
6614
- return this.with({ edges: [...this.state.edges, { from, to }] });
6615
- }
6616
- output(name, from, pointer) {
6617
- return this.with({
6618
- outputs: [
6619
- ...this.state.outputs,
6620
- { name, from, ...pointer ? { pointer } : {} }
6621
- ]
6622
- });
6623
- }
6624
- build() {
6625
- const edges = this.state.edges.slice().sort((a, b) => {
6626
- const af = String(a.from);
6627
- const bf = String(b.from);
6628
- if (af < bf) return -1;
6629
- if (af > bf) return 1;
6630
- const at = String(a.to);
6631
- const bt = String(b.to);
6632
- if (at < bt) return -1;
6633
- if (at > bt) return 1;
6634
- return 0;
6635
- });
6636
- const outputs = this.state.outputs.slice().sort((a, b) => {
6637
- const an = String(a.name);
6638
- const bn = String(b.name);
6639
- if (an < bn) return -1;
6640
- if (an > bn) return 1;
6641
- const af = String(a.from);
6642
- const bf = String(b.from);
6643
- if (af < bf) return -1;
6644
- if (af > bf) return 1;
6645
- const ap = a.pointer ?? "";
6646
- const bp = b.pointer ?? "";
6647
- if (ap < bp) return -1;
6648
- if (ap > bp) return 1;
6649
- return 0;
6650
- });
6651
- return {
6652
- kind: WorkflowKinds.WorkflowV0,
6653
- ...this.state.name ? { name: this.state.name } : {},
6654
- ...this.state.execution ? { execution: this.state.execution } : {},
6655
- nodes: this.state.nodes.slice(),
6656
- ...edges.length ? { edges } : {},
6657
- outputs
6658
- };
6659
- }
6660
- };
6661
- function workflowV0() {
6662
- return WorkflowBuilderV0.new();
6663
- }
6664
- var WorkflowBuilderV1 = class _WorkflowBuilderV1 {
6665
- constructor(state = { nodes: [], edges: [], outputs: [] }) {
6666
- this.state = state;
6667
- }
6668
- static new() {
6669
- return new _WorkflowBuilderV1();
6670
- }
6671
- with(patch) {
6672
- return new _WorkflowBuilderV1({
6673
- ...this.state,
6674
- ...patch
6675
- });
6676
- }
6677
- name(name) {
6678
- return this.with({ name: name.trim() || void 0 });
6679
- }
6680
- execution(execution) {
6681
- return this.with({ execution });
6682
- }
6683
- node(node) {
6684
- return this.with({ nodes: [...this.state.nodes, node] });
6685
- }
6686
- llmResponses(id, request, options = {}) {
6687
- const wiredRequest = wireRequest(request);
6688
- if (options.bindings) {
6689
- validateBindingTargets(id, wiredRequest.input, options.bindings);
6690
- }
6691
- const input = {
6692
- request: wiredRequest,
6693
- ...options.stream === void 0 ? {} : { stream: options.stream },
6694
- ...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
6695
- ...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
6696
- ...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
6697
- };
6698
- return this.node({
6699
- id,
6700
- type: WorkflowNodeTypesV1.LLMResponses,
6701
- input
6702
- });
6703
- }
6704
- routeSwitch(id, request, options = {}) {
6705
- const wiredRequest = wireRequest(request);
6706
- if (options.bindings) {
6707
- validateBindingTargets(id, wiredRequest.input, options.bindings);
6708
- }
6709
- const input = {
6710
- request: wiredRequest,
6711
- ...options.stream === void 0 ? {} : { stream: options.stream },
6712
- ...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
6713
- ...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
6714
- ...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
6715
- };
6716
- return this.node({
6717
- id,
6718
- type: WorkflowNodeTypesV1.RouteSwitch,
6719
- input
6720
- });
6721
- }
6722
- joinAll(id) {
6723
- return this.node({ id, type: WorkflowNodeTypesV1.JoinAll });
6724
- }
6725
- joinAny(id, input) {
6726
- return this.node({
6727
- id,
6728
- type: WorkflowNodeTypesV1.JoinAny,
6729
- ...input ? { input } : {}
6730
- });
6731
- }
6732
- joinCollect(id, input) {
6733
- return this.node({ id, type: WorkflowNodeTypesV1.JoinCollect, input });
6734
- }
6735
- transformJSON(id, input) {
6736
- return this.node({ id, type: WorkflowNodeTypesV1.TransformJSON, input });
6737
- }
6738
- mapFanout(id, input) {
6739
- validateMapFanoutInput(id, input);
6740
- return this.node({ id, type: WorkflowNodeTypesV1.MapFanout, input });
6741
- }
6742
- edge(from, to, when) {
6743
- return this.with({
6744
- edges: [...this.state.edges, { from, to, ...when ? { when } : {} }]
6745
- });
6746
- }
6747
- output(name, from, pointer) {
6748
- return this.with({
6749
- outputs: [
6750
- ...this.state.outputs,
6751
- { name, from, ...pointer ? { pointer } : {} }
6752
- ]
6753
- });
6754
- }
6755
- build() {
6756
- const edges = this.state.edges.slice().sort((a, b) => {
6757
- const af = String(a.from);
6758
- const bf = String(b.from);
6759
- if (af < bf) return -1;
6760
- if (af > bf) return 1;
6761
- const at = String(a.to);
6762
- const bt = String(b.to);
6763
- if (at < bt) return -1;
6764
- if (at > bt) return 1;
6765
- const aw = a.when ? JSON.stringify(a.when) : "";
6766
- const bw = b.when ? JSON.stringify(b.when) : "";
6767
- if (aw < bw) return -1;
6768
- if (aw > bw) return 1;
6769
- return 0;
6770
- });
6771
- const outputs = this.state.outputs.slice().sort((a, b) => {
6772
- const an = String(a.name);
6773
- const bn = String(b.name);
6774
- if (an < bn) return -1;
6775
- if (an > bn) return 1;
6776
- const af = String(a.from);
6777
- const bf = String(b.from);
6778
- if (af < bf) return -1;
6779
- if (af > bf) return 1;
6780
- const ap = a.pointer ?? "";
6781
- const bp = b.pointer ?? "";
6782
- if (ap < bp) return -1;
6783
- if (ap > bp) return 1;
6784
- return 0;
6785
- });
6786
- return {
6787
- kind: WorkflowKinds.WorkflowV1,
6788
- ...this.state.name ? { name: this.state.name } : {},
6789
- ...this.state.execution ? { execution: this.state.execution } : {},
6790
- nodes: this.state.nodes.slice(),
6791
- ...edges.length ? { edges } : {},
6792
- outputs
6793
- };
6794
- }
6795
- };
6796
- function workflowV1() {
6797
- return WorkflowBuilderV1.new();
6798
- }
6799
- var Workflow = class _Workflow {
6800
- constructor(name) {
6801
- this._nodes = [];
6802
- this._edges = /* @__PURE__ */ new Set();
6803
- this._outputs = [];
6804
- this._pendingNode = null;
6805
- this._name = name?.trim() || void 0;
6806
- }
6807
- /**
6808
- * Create a new workflow builder with the given name.
6809
- */
6810
- static create(name) {
6811
- return new _Workflow(name);
6812
- }
6813
- /**
6814
- * Set the workflow execution configuration.
6815
- */
6816
- execution(exec) {
6817
- this.flushPendingNode();
6818
- this._execution = exec;
6819
- return this;
6820
- }
6821
- /**
6822
- * Add an LLM responses node and return a node builder for configuration.
6823
- */
6824
- addLLMNode(id, request) {
6825
- this.flushPendingNode();
6826
- this._pendingNode = {
6827
- id,
6828
- request: wireRequest(request),
6829
- bindings: []
6830
- };
6831
- return new LLMNodeBuilder(this);
6832
- }
6833
- /**
6834
- * Add a join.all node that waits for all incoming edges.
6835
- */
6836
- addJoinAllNode(id) {
6837
- this.flushPendingNode();
6838
- this._nodes.push({ id, type: WorkflowNodeTypes.JoinAll });
6839
- return this;
6840
- }
6841
- /**
6842
- * Add a transform.json node and return a builder for configuration.
6843
- */
6844
- addTransformJSONNode(id) {
6845
- this.flushPendingNode();
6846
- return new TransformJSONNodeBuilder(this, id);
6847
- }
6848
- /**
6849
- * Add an output reference extracting the full node output.
6850
- */
6851
- output(name, from, pointer) {
6852
- this.flushPendingNode();
6853
- this._outputs.push({ name, from, ...pointer ? { pointer } : {} });
6854
- return this;
6855
- }
6856
- /**
6857
- * Add an output reference extracting text content from an LLM response.
6858
- * This is a convenience method that uses the LLM_TEXT_OUTPUT pointer.
6859
- */
6860
- outputText(name, from) {
6861
- return this.output(name, from, LLM_TEXT_OUTPUT);
6862
- }
6863
- /**
6864
- * Explicitly add an edge between nodes.
6865
- * Note: edges are automatically inferred from bindings, so this is rarely needed.
6866
- */
6867
- edge(from, to) {
6868
- this.flushPendingNode();
6869
- this._edges.add(`${from}->${to}`);
6870
- return this;
6871
- }
6872
- /**
6873
- * Build the workflow specification.
6874
- */
6875
- build() {
6876
- this.flushPendingNode();
6877
- const edges = Array.from(this._edges).map((key) => {
6878
- const [from, to] = key.split("->");
6879
- return { from, to };
6880
- }).sort((a, b) => {
6881
- const af = String(a.from);
6882
- const bf = String(b.from);
6883
- if (af < bf) return -1;
6884
- if (af > bf) return 1;
6885
- const at = String(a.to);
6886
- const bt = String(b.to);
6887
- if (at < bt) return -1;
6888
- if (at > bt) return 1;
6889
- return 0;
6890
- });
6891
- const outputs = this._outputs.slice().sort((a, b) => {
6892
- const an = String(a.name);
6893
- const bn = String(b.name);
6894
- if (an < bn) return -1;
6895
- if (an > bn) return 1;
6896
- const af = String(a.from);
6897
- const bf = String(b.from);
6898
- if (af < bf) return -1;
6899
- if (af > bf) return 1;
6900
- const ap = a.pointer ?? "";
6901
- const bp = b.pointer ?? "";
6902
- if (ap < bp) return -1;
6903
- if (ap > bp) return 1;
6904
- return 0;
6905
- });
6906
- return {
6907
- kind: WorkflowKinds.WorkflowV0,
6908
- ...this._name ? { name: this._name } : {},
6909
- ...this._execution ? { execution: this._execution } : {},
6910
- nodes: this._nodes.slice(),
6911
- ...edges.length ? { edges } : {},
6912
- outputs
6913
- };
6914
- }
6915
- /** @internal */
6916
- _getPendingNode() {
6917
- return this._pendingNode;
6918
- }
6919
- /** @internal */
6920
- _addEdge(from, to) {
6921
- this._edges.add(`${from}->${to}`);
6922
- }
6923
- /** @internal */
6924
- _addNode(node) {
6925
- this._nodes.push(node);
6926
- }
6927
- flushPendingNode() {
6928
- const pending = this._pendingNode;
6929
- if (!pending) return;
6930
- this._pendingNode = null;
6931
- if (pending.bindings.length > 0) {
6932
- validateBindingTargets(pending.id, pending.request.input, pending.bindings);
6933
- }
6934
- const input = {
6935
- id: pending.id,
6936
- type: WorkflowNodeTypes.LLMResponses,
6937
- input: {
6938
- request: pending.request,
6939
- ...pending.stream !== void 0 ? { stream: pending.stream } : {},
6940
- ...pending.toolExecution ? { tool_execution: { mode: pending.toolExecution } } : {},
6941
- ...pending.toolLimits ? { tool_limits: pending.toolLimits } : {},
6942
- ...pending.bindings.length ? { bindings: pending.bindings } : {}
6943
- }
6944
- };
6945
- this._nodes.push(input);
6946
- for (const binding of pending.bindings) {
6947
- this._edges.add(`${binding.from}->${pending.id}`);
6948
- }
6949
- }
6950
- };
6951
- var LLMNodeBuilder = class {
6952
- constructor(workflow) {
6953
- this.workflow = workflow;
6954
- }
6955
- /**
6956
- * Enable or disable streaming for this node.
6957
- */
6958
- stream(enabled) {
6959
- const pending = this.workflow._getPendingNode();
6960
- if (pending) {
6961
- pending.stream = enabled;
6962
- }
6963
- return this;
6964
- }
6965
- /**
6966
- * Add a binding from another LLM node's text output to this node's user message.
6967
- * This is the most common binding pattern: LLM text → user message with json_string encoding.
6968
- * The edge from the source node is automatically inferred.
6969
- */
6970
- bindTextFrom(from) {
6971
- return this.bindFromTo(from, LLM_TEXT_OUTPUT, LLM_USER_MESSAGE_TEXT, "json_string");
6972
- }
6973
- /**
6974
- * Add a binding from another node's output to this node's user message text.
6975
- * Use bindTextFrom for the common case of binding LLM text output.
6976
- * The edge from the source node is automatically inferred.
6977
- */
6978
- bindFrom(from, pointer) {
6979
- return this.bindFromTo(from, pointer, LLM_USER_MESSAGE_TEXT, "json_string");
6980
- }
6981
- /**
6982
- * Add a full binding with explicit source/destination pointers and encoding.
6983
- * The edge from the source node is automatically inferred.
6984
- */
6985
- bindFromTo(from, fromPointer, toPointer, encoding) {
6986
- const pending = this.workflow._getPendingNode();
6987
- if (pending) {
6988
- pending.bindings.push({
6989
- from,
6990
- ...fromPointer ? { pointer: fromPointer } : {},
6991
- to: toPointer,
6992
- ...encoding ? { encoding } : {}
6993
- });
6994
- }
6995
- return this;
6996
- }
6997
- /**
6998
- * Add a binding that replaces a {{placeholder}} in the prompt text.
6999
- * This is useful when the prompt contains placeholder markers like {{tier_data}}.
7000
- * The edge from the source node is automatically inferred.
7001
- */
7002
- bindToPlaceholder(from, fromPointer, placeholder) {
7003
- const pending = this.workflow._getPendingNode();
7004
- if (pending) {
7005
- pending.bindings.push({
7006
- from,
7007
- ...fromPointer ? { pointer: fromPointer } : {},
7008
- to_placeholder: placeholder,
7009
- encoding: "json_string"
7010
- });
7011
- }
7012
- return this;
7013
- }
7014
- /**
7015
- * Add a binding from an LLM node's text output to a placeholder.
7016
- * This is the most common placeholder binding: LLM text → {{placeholder}}.
7017
- * The edge from the source node is automatically inferred.
7018
- */
7019
- bindTextToPlaceholder(from, placeholder) {
7020
- return this.bindToPlaceholder(from, LLM_TEXT_OUTPUT, placeholder);
7021
- }
7022
- /**
7023
- * Set the tool execution mode (server or client).
7024
- */
7025
- toolExecution(mode) {
7026
- const pending = this.workflow._getPendingNode();
7027
- if (pending) {
7028
- pending.toolExecution = mode;
7029
- }
7030
- return this;
7031
- }
7032
- /**
7033
- * Set the tool execution limits.
7034
- */
7035
- toolLimits(limits) {
7036
- const pending = this.workflow._getPendingNode();
7037
- if (pending) {
7038
- pending.toolLimits = limits;
7039
- }
7040
- return this;
7041
- }
7042
- // Workflow methods for chaining back
7043
- addLLMNode(id, request) {
7044
- return this.workflow.addLLMNode(id, request);
7045
- }
7046
- addJoinAllNode(id) {
7047
- return this.workflow.addJoinAllNode(id);
7048
- }
7049
- addTransformJSONNode(id) {
7050
- return this.workflow.addTransformJSONNode(id);
7051
- }
7052
- edge(from, to) {
7053
- return this.workflow.edge(from, to);
7054
- }
7055
- output(name, from, pointer) {
7056
- return this.workflow.output(name, from, pointer);
7057
- }
7058
- outputText(name, from) {
7059
- return this.workflow.outputText(name, from);
7060
- }
7061
- execution(exec) {
7062
- return this.workflow.execution(exec);
7063
- }
7064
- build() {
7065
- return this.workflow.build();
7066
- }
7067
- };
7068
- var TransformJSONNodeBuilder = class {
7069
- constructor(workflow, id) {
7070
- this.workflow = workflow;
7071
- this.id = id;
7072
- }
7073
- /**
7074
- * Set the object transformation with field mappings.
7075
- */
7076
- object(fields) {
7077
- this._object = fields;
7078
- return this;
7079
- }
7080
- /**
7081
- * Set the merge transformation with source references.
7082
- */
7083
- merge(items) {
7084
- this._merge = items;
7085
- return this;
7086
- }
7087
- finalize() {
7088
- const input = {};
7089
- if (this._object) input.object = this._object;
7090
- if (this._merge) input.merge = this._merge;
7091
- this.workflow._addNode({
7092
- id: this.id,
7093
- type: WorkflowNodeTypes.TransformJSON,
7094
- input
7095
- });
7096
- if (this._object) {
7097
- for (const ref of Object.values(this._object)) {
7098
- this.workflow._addEdge(ref.from, this.id);
7099
- }
7100
- }
7101
- if (this._merge) {
7102
- for (const ref of this._merge) {
7103
- this.workflow._addEdge(ref.from, this.id);
7104
- }
7105
- }
7106
- }
7107
- // Workflow methods for chaining back
7108
- addLLMNode(id, request) {
7109
- this.finalize();
7110
- return this.workflow.addLLMNode(id, request);
7111
- }
7112
- addJoinAllNode(id) {
7113
- this.finalize();
7114
- return this.workflow.addJoinAllNode(id);
7115
- }
7116
- edge(from, to) {
7117
- this.finalize();
7118
- return this.workflow.edge(from, to);
7119
- }
7120
- output(name, from, pointer) {
7121
- this.finalize();
7122
- return this.workflow.output(name, from, pointer);
7123
- }
7124
- execution(exec) {
7125
- this.finalize();
7126
- return this.workflow.execution(exec);
7127
- }
7128
- build() {
7129
- this.finalize();
7130
- return this.workflow.build();
7131
- }
7132
- };
7133
- function newWorkflow(name) {
7134
- return Workflow.create(name);
7135
- }
7136
-
7137
- // src/workflow_v0.schema.json
7138
- var workflow_v0_schema_default = {
7139
- $id: "https://modelrelay.ai/schemas/workflow_v0.schema.json",
7140
- $schema: "http://json-schema.org/draft-07/schema#",
7141
- additionalProperties: false,
7142
- definitions: {
7143
- edge: {
7144
- additionalProperties: false,
7145
- properties: {
7146
- from: {
7147
- minLength: 1,
7148
- type: "string"
7149
- },
7150
- to: {
7151
- minLength: 1,
7152
- type: "string"
7153
- }
7154
- },
7155
- required: [
7156
- "from",
7157
- "to"
7158
- ],
7159
- type: "object"
7160
- },
7161
- llmResponsesBinding: {
7162
- additionalProperties: false,
7163
- oneOf: [
7164
- {
7165
- required: [
7166
- "to"
7167
- ]
7168
- },
7169
- {
7170
- required: [
7171
- "to_placeholder"
7172
- ]
7173
- }
7174
- ],
7175
- properties: {
7176
- encoding: {
7177
- enum: [
7178
- "json",
7179
- "json_string"
7180
- ],
7181
- type: "string"
7182
- },
7183
- from: {
7184
- minLength: 1,
7185
- type: "string"
7186
- },
7187
- pointer: {
7188
- pattern: "^(/.*)?$",
7189
- type: "string"
7190
- },
7191
- to: {
7192
- pattern: "^/.*$",
7193
- type: "string"
7194
- },
7195
- to_placeholder: {
7196
- minLength: 1,
7197
- type: "string"
7198
- }
7199
- },
7200
- required: [
7201
- "from"
7202
- ],
7203
- type: "object"
7204
- },
7205
- node: {
7206
- additionalProperties: false,
7207
- oneOf: [
7208
- {
7209
- allOf: [
7210
- {
7211
- properties: {
7212
- input: {
7213
- properties: {
7214
- bindings: {
7215
- items: {
7216
- $ref: "#/definitions/llmResponsesBinding"
7217
- },
7218
- type: "array"
7219
- },
7220
- request: {
7221
- type: "object"
7222
- },
7223
- stream: {
7224
- type: "boolean"
7225
- },
7226
- tool_execution: {
7227
- additionalProperties: false,
7228
- properties: {
7229
- mode: {
7230
- default: "server",
7231
- enum: [
7232
- "server",
7233
- "client"
7234
- ],
7235
- type: "string"
7236
- }
7237
- },
7238
- required: [
7239
- "mode"
7240
- ],
7241
- type: "object"
7242
- },
7243
- tool_limits: {
7244
- additionalProperties: false,
7245
- properties: {
7246
- max_llm_calls: {
7247
- default: 8,
7248
- maximum: 64,
7249
- minimum: 1,
7250
- type: "integer"
7251
- },
7252
- max_tool_calls_per_step: {
7253
- default: 16,
7254
- maximum: 64,
7255
- minimum: 1,
7256
- type: "integer"
7257
- },
7258
- wait_ttl_ms: {
7259
- default: 9e5,
7260
- maximum: 864e5,
7261
- minimum: 1,
7262
- type: "integer"
7263
- }
7264
- },
7265
- type: "object"
7266
- }
7267
- },
7268
- required: [
7269
- "request"
7270
- ],
7271
- type: "object"
7272
- }
7273
- }
7274
- }
7275
- ],
7276
- properties: {
7277
- type: {
7278
- const: "llm.responses"
7279
- }
7280
- },
7281
- required: [
7282
- "input"
7283
- ]
7284
- },
7285
- {
7286
- properties: {
7287
- type: {
7288
- const: "join.all"
7289
- }
7290
- }
7291
- },
7292
- {
7293
- allOf: [
7294
- {
7295
- properties: {
7296
- input: {
7297
- additionalProperties: false,
7298
- oneOf: [
7299
- {
7300
- not: {
7301
- required: [
7302
- "merge"
7303
- ]
7304
- },
7305
- required: [
7306
- "object"
7307
- ]
7308
- },
7309
- {
7310
- not: {
7311
- required: [
7312
- "object"
7313
- ]
7314
- },
7315
- required: [
7316
- "merge"
7317
- ]
7318
- }
7319
- ],
7320
- properties: {
7321
- merge: {
7322
- items: {
7323
- $ref: "#/definitions/transformValue"
7324
- },
7325
- minItems: 1,
7326
- type: "array"
7327
- },
7328
- object: {
7329
- additionalProperties: {
7330
- $ref: "#/definitions/transformValue"
7331
- },
7332
- minProperties: 1,
7333
- type: "object"
7334
- }
7335
- },
7336
- type: "object"
7337
- }
7338
- }
7339
- }
7340
- ],
7341
- properties: {
7342
- type: {
7343
- const: "transform.json"
7344
- }
7345
- },
7346
- required: [
7347
- "input"
7348
- ]
7349
- }
7350
- ],
7351
- properties: {
7352
- id: {
7353
- minLength: 1,
7354
- type: "string"
7355
- },
7356
- input: {},
7357
- type: {
7358
- enum: [
7359
- "llm.responses",
7360
- "join.all",
7361
- "transform.json"
7362
- ],
7363
- type: "string"
7364
- }
7365
- },
7366
- required: [
7367
- "id",
7368
- "type"
7369
- ],
7370
- type: "object"
7371
- },
7372
- output: {
7373
- additionalProperties: false,
7374
- properties: {
7375
- from: {
7376
- minLength: 1,
7377
- type: "string"
7378
- },
7379
- name: {
7380
- minLength: 1,
7381
- type: "string"
7382
- },
7383
- pointer: {
7384
- pattern: "^(/.*)?$",
7385
- type: "string"
7386
- }
7387
- },
7388
- required: [
7389
- "name",
7390
- "from"
7391
- ],
7392
- type: "object"
7393
- },
7394
- transformValue: {
7395
- additionalProperties: false,
7396
- properties: {
7397
- from: {
7398
- minLength: 1,
7399
- type: "string"
7400
- },
7401
- pointer: {
7402
- pattern: "^(/.*)?$",
7403
- type: "string"
7404
- }
7405
- },
7406
- required: [
7407
- "from"
7408
- ],
7409
- type: "object"
7410
- }
7411
- },
7412
- properties: {
7413
- edges: {
7414
- items: {
7415
- $ref: "#/definitions/edge"
7416
- },
7417
- type: "array"
7418
- },
7419
- execution: {
7420
- additionalProperties: false,
7421
- properties: {
7422
- max_parallelism: {
7423
- minimum: 1,
7424
- type: "integer"
7425
- },
7426
- node_timeout_ms: {
7427
- minimum: 1,
7428
- type: "integer"
7429
- },
7430
- run_timeout_ms: {
7431
- minimum: 1,
7432
- type: "integer"
7433
- }
7434
- },
7435
- type: "object"
7436
- },
7437
- kind: {
7438
- const: "workflow.v0",
7439
- type: "string"
7440
- },
7441
- name: {
7442
- type: "string"
7443
- },
7444
- nodes: {
7445
- items: {
7446
- $ref: "#/definitions/node"
7447
- },
7448
- minItems: 1,
7449
- type: "array"
7450
- },
7451
- outputs: {
7452
- items: {
7453
- $ref: "#/definitions/output"
7454
- },
7455
- minItems: 1,
7456
- type: "array"
7457
- }
7458
- },
7459
- required: [
7460
- "kind",
7461
- "nodes",
7462
- "outputs"
7463
- ],
7464
- title: "ModelRelay workflow.v0",
7465
- type: "object"
7466
- };
7467
-
7468
- // src/workflow_v1.schema.json
7469
- var workflow_v1_schema_default = {
7470
- $id: "https://modelrelay.ai/schemas/workflow_v1.schema.json",
7471
- $schema: "http://json-schema.org/draft-07/schema#",
7472
- additionalProperties: false,
7473
- definitions: {
7474
- condition: {
7475
- additionalProperties: false,
7476
- properties: {
7477
- op: {
7478
- enum: [
7479
- "equals",
7480
- "matches",
7481
- "exists"
7482
- ],
7483
- type: "string"
7484
- },
7485
- path: {
7486
- pattern: "^\\$.*$",
7487
- type: "string"
7488
- },
7489
- source: {
7490
- enum: [
7491
- "node_output",
7492
- "node_status"
7493
- ],
7494
- type: "string"
7495
- },
7496
- value: {}
7497
- },
7498
- required: [
7499
- "source",
7500
- "op"
7501
- ],
7502
- type: "object"
7503
- },
7504
- edge: {
7505
- additionalProperties: false,
7506
- properties: {
7507
- from: {
7508
- minLength: 1,
7509
- type: "string"
7510
- },
7511
- to: {
7512
- minLength: 1,
7513
- type: "string"
7514
- },
7515
- when: {
7516
- $ref: "#/definitions/condition"
7517
- }
7518
- },
7519
- required: [
7520
- "from",
7521
- "to"
7522
- ],
7523
- type: "object"
7524
- },
7525
- fragmentBindInput: {
7526
- additionalProperties: false,
7527
- oneOf: [
7528
- {
7529
- required: [
7530
- "from_node"
7531
- ]
7532
- },
7533
- {
7534
- required: [
7535
- "from_input"
7536
- ]
7537
- }
7538
- ],
7539
- properties: {
7540
- from_input: {
7541
- minLength: 1,
7542
- type: "string"
7543
- },
7544
- from_node: {
7545
- minLength: 1,
7546
- type: "string"
7547
- },
7548
- pointer: {
7549
- pattern: "^(/.*)?$",
7550
- type: "string"
7551
- }
7552
- },
7553
- type: "object"
7554
- },
7555
- fragmentDef: {
7556
- additionalProperties: false,
7557
- properties: {
7558
- edges: {
7559
- items: {
7560
- $ref: "#/definitions/edge"
7561
- },
7562
- type: "array"
7563
- },
7564
- inputs: {
7565
- items: {
7566
- $ref: "#/definitions/fragmentInput"
7567
- },
7568
- type: "array"
7569
- },
7570
- nodes: {
7571
- items: {
7572
- $ref: "#/definitions/node"
7573
- },
7574
- minItems: 1,
7575
- type: "array"
7576
- },
7577
- outputs: {
7578
- items: {
7579
- $ref: "#/definitions/fragmentOutput"
7580
- },
7581
- minItems: 1,
7582
- type: "array"
7583
- }
7584
- },
7585
- required: [
7586
- "outputs",
7587
- "nodes"
7588
- ],
7589
- type: "object"
7590
- },
7591
- fragmentInput: {
7592
- additionalProperties: false,
7593
- properties: {
7594
- name: {
7595
- minLength: 1,
7596
- type: "string"
7597
- },
7598
- type: {
7599
- type: "string"
7600
- }
7601
- },
7602
- required: [
7603
- "name"
7604
- ],
7605
- type: "object"
7606
- },
7607
- fragmentOutput: {
7608
- additionalProperties: false,
7609
- properties: {
7610
- from_node: {
7611
- minLength: 1,
7612
- type: "string"
7613
- },
7614
- name: {
7615
- minLength: 1,
7616
- type: "string"
7617
- },
7618
- pointer: {
7619
- pattern: "^(/.*)?$",
7620
- type: "string"
7621
- }
7622
- },
7623
- required: [
7624
- "name",
7625
- "from_node"
7626
- ],
7627
- type: "object"
7628
- },
7629
- llmResponsesBinding: {
7630
- additionalProperties: false,
7631
- oneOf: [
7632
- {
7633
- required: [
7634
- "to"
7635
- ]
7636
- },
7637
- {
7638
- required: [
7639
- "to_placeholder"
7640
- ]
7641
- }
7642
- ],
7643
- properties: {
7644
- encoding: {
7645
- enum: [
7646
- "json",
7647
- "json_string"
7648
- ],
7649
- type: "string"
7650
- },
7651
- from: {
7652
- minLength: 1,
7653
- type: "string"
7654
- },
7655
- pointer: {
7656
- pattern: "^(/.*)?$",
7657
- type: "string"
7658
- },
7659
- to: {
7660
- pattern: "^/.*$",
7661
- type: "string"
7662
- },
7663
- to_placeholder: {
7664
- minLength: 1,
7665
- type: "string"
7666
- }
7667
- },
7668
- required: [
7669
- "from"
7670
- ],
7671
- type: "object"
7672
- },
7673
- mapFanoutItemBinding: {
7674
- additionalProperties: false,
7675
- oneOf: [
7676
- {
7677
- required: [
7678
- "to"
7679
- ]
7680
- },
7681
- {
7682
- required: [
7683
- "to_placeholder"
7684
- ]
7685
- }
7686
- ],
7687
- properties: {
7688
- encoding: {
7689
- enum: [
7690
- "json",
7691
- "json_string"
7692
- ],
7693
- type: "string"
7694
- },
7695
- path: {
7696
- pattern: "^(/.*)?$",
7697
- type: "string"
7698
- },
7699
- to: {
7700
- pattern: "^/.*$",
7701
- type: "string"
7702
- },
7703
- to_placeholder: {
7704
- minLength: 1,
7705
- type: "string"
7706
- }
7707
- },
7708
- type: "object"
7709
- },
7710
- node: {
7711
- additionalProperties: false,
7712
- oneOf: [
7713
- {
7714
- allOf: [
7715
- {
7716
- properties: {
7717
- input: {
7718
- properties: {
7719
- bindings: {
7720
- items: {
7721
- $ref: "#/definitions/llmResponsesBinding"
7722
- },
7723
- type: "array"
7724
- },
7725
- request: {
7726
- type: "object"
7727
- },
7728
- stream: {
7729
- type: "boolean"
7730
- },
7731
- tool_execution: {
7732
- additionalProperties: false,
7733
- properties: {
7734
- mode: {
7735
- default: "server",
7736
- enum: [
7737
- "server",
7738
- "client"
7739
- ],
7740
- type: "string"
7741
- }
7742
- },
7743
- required: [
7744
- "mode"
7745
- ],
7746
- type: "object"
7747
- },
7748
- tool_limits: {
7749
- additionalProperties: false,
7750
- properties: {
7751
- max_llm_calls: {
7752
- default: 8,
7753
- maximum: 64,
7754
- minimum: 1,
7755
- type: "integer"
7756
- },
7757
- max_tool_calls_per_step: {
7758
- default: 16,
7759
- maximum: 64,
7760
- minimum: 1,
7761
- type: "integer"
7762
- },
7763
- wait_ttl_ms: {
7764
- default: 9e5,
7765
- maximum: 864e5,
7766
- minimum: 1,
7767
- type: "integer"
7768
- }
7769
- },
7770
- type: "object"
7771
- }
7772
- },
7773
- required: [
7774
- "request"
7775
- ],
7776
- type: "object"
7777
- }
7778
- }
7779
- }
7780
- ],
7781
- properties: {
7782
- type: {
7783
- const: "llm.responses"
7784
- }
7785
- },
7786
- required: [
7787
- "input"
7788
- ]
7789
- },
7790
- {
7791
- allOf: [
7792
- {
7793
- properties: {
7794
- input: {
7795
- properties: {
7796
- bindings: {
7797
- items: {
7798
- $ref: "#/definitions/llmResponsesBinding"
7799
- },
7800
- type: "array"
7801
- },
7802
- request: {
7803
- type: "object"
7804
- },
7805
- stream: {
7806
- type: "boolean"
7807
- },
7808
- tool_execution: {
7809
- additionalProperties: false,
7810
- properties: {
7811
- mode: {
7812
- default: "server",
7813
- enum: [
7814
- "server",
7815
- "client"
7816
- ],
7817
- type: "string"
7818
- }
7819
- },
7820
- required: [
7821
- "mode"
7822
- ],
7823
- type: "object"
7824
- },
7825
- tool_limits: {
7826
- additionalProperties: false,
7827
- properties: {
7828
- max_llm_calls: {
7829
- default: 8,
7830
- maximum: 64,
7831
- minimum: 1,
7832
- type: "integer"
7833
- },
7834
- max_tool_calls_per_step: {
7835
- default: 16,
7836
- maximum: 64,
7837
- minimum: 1,
7838
- type: "integer"
7839
- },
7840
- wait_ttl_ms: {
7841
- default: 9e5,
7842
- maximum: 864e5,
7843
- minimum: 1,
7844
- type: "integer"
7845
- }
7846
- },
7847
- type: "object"
7848
- }
7849
- },
7850
- required: [
7851
- "request"
7852
- ],
7853
- type: "object"
7854
- }
7855
- }
7856
- }
7857
- ],
7858
- properties: {
7859
- type: {
7860
- const: "route.switch"
7861
- }
7862
- },
7863
- required: [
7864
- "input"
7865
- ]
7866
- },
7867
- {
7868
- properties: {
7869
- type: {
7870
- const: "join.all"
7871
- }
7872
- }
7873
- },
7874
- {
7875
- allOf: [
7876
- {
7877
- properties: {
7878
- input: {
7879
- additionalProperties: false,
7880
- properties: {
7881
- predicate: {
7882
- $ref: "#/definitions/condition"
7883
- }
7884
- },
7885
- type: "object"
7886
- }
7887
- }
7888
- }
7889
- ],
7890
- properties: {
7891
- type: {
7892
- const: "join.any"
7893
- }
7894
- }
7895
- },
7896
- {
7897
- allOf: [
7898
- {
7899
- properties: {
7900
- input: {
7901
- additionalProperties: false,
7902
- properties: {
7903
- limit: {
7904
- minimum: 1,
7905
- type: "integer"
7906
- },
7907
- predicate: {
7908
- $ref: "#/definitions/condition"
7909
- },
7910
- timeout_ms: {
7911
- minimum: 1,
7912
- type: "integer"
7913
- }
7914
- },
7915
- type: "object"
7916
- }
7917
- }
7918
- }
7919
- ],
7920
- properties: {
7921
- type: {
7922
- const: "join.collect"
7923
- }
7924
- },
7925
- required: [
7926
- "input"
7927
- ]
7928
- },
7929
- {
7930
- allOf: [
7931
- {
7932
- properties: {
7933
- input: {
7934
- additionalProperties: false,
7935
- oneOf: [
7936
- {
7937
- not: {
7938
- required: [
7939
- "merge"
7940
- ]
7941
- },
7942
- required: [
7943
- "object"
7944
- ]
7945
- },
7946
- {
7947
- not: {
7948
- required: [
7949
- "object"
7950
- ]
7951
- },
7952
- required: [
7953
- "merge"
7954
- ]
7955
- }
7956
- ],
7957
- properties: {
7958
- merge: {
7959
- items: {
7960
- $ref: "#/definitions/transformValue"
7961
- },
7962
- minItems: 1,
7963
- type: "array"
7964
- },
7965
- object: {
7966
- additionalProperties: {
7967
- $ref: "#/definitions/transformValue"
7968
- },
7969
- minProperties: 1,
7970
- type: "object"
7971
- }
7972
- },
7973
- type: "object"
7974
- }
7975
- }
7976
- }
7977
- ],
7978
- properties: {
7979
- type: {
7980
- const: "transform.json"
7981
- }
7982
- },
7983
- required: [
7984
- "input"
7985
- ]
7986
- },
7987
- {
7988
- allOf: [
7989
- {
7990
- properties: {
7991
- input: {
7992
- additionalProperties: false,
7993
- properties: {
7994
- item_bindings: {
7995
- items: {
7996
- $ref: "#/definitions/mapFanoutItemBinding"
7997
- },
7998
- type: "array"
7999
- },
8000
- items: {
8001
- additionalProperties: false,
8002
- properties: {
8003
- from: {
8004
- minLength: 1,
8005
- type: "string"
8006
- },
8007
- path: {
8008
- pattern: "^(/.*)?$",
8009
- type: "string"
8010
- },
8011
- pointer: {
8012
- pattern: "^(/.*)?$",
8013
- type: "string"
8014
- }
8015
- },
8016
- required: [
8017
- "from"
8018
- ],
8019
- type: "object"
8020
- },
8021
- max_parallelism: {
8022
- minimum: 1,
8023
- type: "integer"
8024
- },
8025
- subnode: {
8026
- additionalProperties: false,
8027
- properties: {
8028
- id: {
8029
- minLength: 1,
8030
- type: "string"
8031
- },
8032
- input: {},
8033
- type: {
8034
- enum: [
8035
- "llm.responses",
8036
- "route.switch",
8037
- "transform.json"
8038
- ],
8039
- type: "string"
8040
- }
8041
- },
8042
- required: [
8043
- "id",
8044
- "type"
8045
- ],
8046
- type: "object"
8047
- }
8048
- },
8049
- required: [
8050
- "items",
8051
- "subnode"
8052
- ],
8053
- type: "object"
8054
- }
8055
- }
8056
- }
8057
- ],
8058
- properties: {
8059
- type: {
8060
- const: "map.fanout"
8061
- }
8062
- },
8063
- required: [
8064
- "input"
8065
- ]
8066
- },
8067
- {
8068
- allOf: [
8069
- {
8070
- properties: {
8071
- input: {
8072
- additionalProperties: false,
8073
- properties: {
8074
- bind_inputs: {
8075
- additionalProperties: {
8076
- $ref: "#/definitions/fragmentBindInput"
8077
- },
8078
- type: "object"
8079
- },
8080
- ref: {
8081
- minLength: 1,
8082
- type: "string"
8083
- }
8084
- },
8085
- required: [
8086
- "ref"
8087
- ],
8088
- type: "object"
8089
- }
8090
- }
8091
- }
8092
- ],
8093
- properties: {
8094
- type: {
8095
- const: "fragment"
8096
- }
8097
- },
8098
- required: [
8099
- "input"
8100
- ]
8101
- }
8102
- ],
8103
- properties: {
8104
- id: {
8105
- minLength: 1,
8106
- type: "string"
8107
- },
8108
- input: {},
8109
- type: {
8110
- enum: [
8111
- "llm.responses",
8112
- "route.switch",
8113
- "join.all",
8114
- "join.any",
8115
- "join.collect",
8116
- "transform.json",
8117
- "map.fanout",
8118
- "fragment"
8119
- ],
8120
- type: "string"
8121
- }
8122
- },
8123
- required: [
8124
- "id",
8125
- "type"
8126
- ],
8127
- type: "object"
8128
- },
8129
- output: {
8130
- additionalProperties: false,
8131
- properties: {
8132
- from: {
8133
- minLength: 1,
8134
- type: "string"
8135
- },
8136
- name: {
8137
- minLength: 1,
8138
- type: "string"
8139
- },
8140
- output: {
8141
- minLength: 1,
8142
- type: "string"
8143
- },
8144
- pointer: {
8145
- pattern: "^(/.*)?$",
8146
- type: "string"
8147
- }
8148
- },
8149
- required: [
8150
- "name",
8151
- "from"
8152
- ],
8153
- type: "object"
8154
- },
8155
- transformValue: {
8156
- additionalProperties: false,
8157
- properties: {
8158
- from: {
8159
- minLength: 1,
8160
- type: "string"
8161
- },
8162
- pointer: {
8163
- pattern: "^(/.*)?$",
8164
- type: "string"
8165
- }
8166
- },
8167
- required: [
8168
- "from"
8169
- ],
8170
- type: "object"
8171
- }
8172
- },
8173
- properties: {
8174
- edges: {
8175
- items: {
8176
- $ref: "#/definitions/edge"
8177
- },
8178
- type: "array"
8179
- },
8180
- execution: {
8181
- additionalProperties: false,
8182
- properties: {
8183
- max_parallelism: {
8184
- minimum: 1,
8185
- type: "integer"
8186
- },
8187
- node_timeout_ms: {
8188
- minimum: 1,
8189
- type: "integer"
8190
- },
8191
- run_timeout_ms: {
8192
- minimum: 1,
8193
- type: "integer"
8194
- }
8195
- },
8196
- type: "object"
8197
- },
8198
- fragments: {
8199
- additionalProperties: {
8200
- $ref: "#/definitions/fragmentDef"
8201
- },
8202
- type: "object"
8203
- },
8204
- kind: {
8205
- const: "workflow.v1",
8206
- type: "string"
8207
- },
8208
- name: {
8209
- type: "string"
8210
- },
8211
- nodes: {
8212
- items: {
8213
- $ref: "#/definitions/node"
8214
- },
8215
- minItems: 1,
8216
- type: "array"
8217
- },
8218
- outputs: {
8219
- items: {
8220
- $ref: "#/definitions/output"
8221
- },
8222
- minItems: 1,
8223
- type: "array"
8224
- }
8225
- },
8226
- required: [
8227
- "kind",
8228
- "nodes",
8229
- "outputs"
8230
- ],
8231
- title: "ModelRelay workflow.v1",
8232
- type: "object"
8233
- };
8234
-
8235
- // src/workflow_patterns.ts
8236
- var LLM_TEXT_OUTPUT_INTERNAL = "/output/0/content/0/text";
8237
- var LLM_USER_MESSAGE_TEXT_INTERNAL = "/input/1/content/0/text";
8238
- function wireRequest2(req) {
8239
- const raw = req;
8240
- if (raw && typeof raw === "object") {
8241
- if ("input" in raw) {
8242
- return req;
8243
- }
8244
- if ("body" in raw) {
8245
- return raw.body ?? {};
5763
+ const msg = input[msgIndex];
5764
+ if (contentIndex >= msg.content.length) {
5765
+ return `targets ${pointer} but message ${msgIndex} only has ${msg.content.length} content blocks (indices 0-${msg.content.length - 1})`;
8246
5766
  }
8247
5767
  }
8248
- return asInternal(req).body;
8249
- }
8250
- function sortEdges(edges) {
8251
- return edges.slice().sort((a, b) => {
8252
- const af = String(a.from);
8253
- const bf = String(b.from);
8254
- if (af < bf) return -1;
8255
- if (af > bf) return 1;
8256
- const at = String(a.to);
8257
- const bt = String(b.to);
8258
- if (at < bt) return -1;
8259
- if (at > bt) return 1;
8260
- return 0;
8261
- });
8262
- }
8263
- function sortOutputs(outputs) {
8264
- return outputs.slice().sort((a, b) => {
8265
- const an = String(a.name);
8266
- const bn = String(b.name);
8267
- if (an < bn) return -1;
8268
- if (an > bn) return 1;
8269
- const af = String(a.from);
8270
- const bf = String(b.from);
8271
- if (af < bf) return -1;
8272
- if (af > bf) return 1;
8273
- const ap = a.pointer ?? "";
8274
- const bp = b.pointer ?? "";
8275
- if (ap < bp) return -1;
8276
- if (ap > bp) return 1;
8277
- return 0;
8278
- });
8279
- }
8280
- function LLMStep(id, request) {
8281
- const config = {
8282
- id,
8283
- request: wireRequest2(request),
8284
- stream: false
8285
- };
8286
- return {
8287
- ...config,
8288
- withStream() {
8289
- return { ...config, stream: true };
8290
- }
8291
- };
5768
+ return void 0;
8292
5769
  }
8293
- var ChainBuilder = class _ChainBuilder {
8294
- constructor(state) {
8295
- this.state = state;
8296
- }
8297
- static create(name, steps) {
8298
- return new _ChainBuilder({ name, steps, outputs: [] });
5770
+ function validateMapFanoutInput(nodeId, input) {
5771
+ const subnode = input.subnode;
5772
+ if ((subnode.type === WorkflowNodeTypesV1.LLMResponses || subnode.type === WorkflowNodeTypesV1.RouteSwitch) && subnode.input.bindings && subnode.input.bindings.length > 0) {
5773
+ throw new MapFanoutInputError(nodeId, "map.fanout subnode bindings are not allowed");
8299
5774
  }
8300
- with(patch) {
8301
- return new _ChainBuilder({ ...this.state, ...patch });
5775
+ if (subnode.type !== WorkflowNodeTypesV1.TransformJSON) {
5776
+ return;
8302
5777
  }
8303
- /**
8304
- * Sets the workflow execution configuration.
8305
- */
8306
- execution(exec) {
8307
- return this.with({ execution: exec });
5778
+ if (input.item_bindings && input.item_bindings.length > 0) {
5779
+ throw new MapFanoutInputError(
5780
+ nodeId,
5781
+ "map.fanout transform.json subnode cannot use item_bindings"
5782
+ );
8308
5783
  }
8309
- /**
8310
- * Adds an output reference from a specific step.
8311
- */
8312
- output(name, from) {
8313
- return this.with({
8314
- outputs: [
8315
- ...this.state.outputs,
8316
- {
8317
- name,
8318
- from,
8319
- pointer: LLM_TEXT_OUTPUT_INTERNAL
8320
- }
8321
- ]
8322
- });
5784
+ const hasObject = !!subnode.input.object && Object.keys(subnode.input.object).length > 0;
5785
+ const hasMerge = !!subnode.input.merge && subnode.input.merge.length > 0;
5786
+ if (hasObject === hasMerge) {
5787
+ throw new MapFanoutInputError(
5788
+ nodeId,
5789
+ "map.fanout transform.json must provide exactly one of object or merge"
5790
+ );
8323
5791
  }
8324
- /**
8325
- * Adds an output reference from the last step.
8326
- */
8327
- outputLast(name) {
8328
- if (this.state.steps.length === 0) {
8329
- return this;
5792
+ if (hasObject) {
5793
+ for (const [key, value] of Object.entries(subnode.input.object ?? {})) {
5794
+ if (!key.trim()) continue;
5795
+ if (String(value.from) !== "item") {
5796
+ throw new MapFanoutInputError(
5797
+ nodeId,
5798
+ `map.fanout transform.json object.${key}.from must be "item"`
5799
+ );
5800
+ }
8330
5801
  }
8331
- return this.output(name, this.state.steps[this.state.steps.length - 1].id);
8332
5802
  }
8333
- /**
8334
- * Builds and returns the compiled workflow spec.
8335
- * @throws Error if no steps are provided
8336
- */
8337
- build() {
8338
- if (this.state.steps.length === 0) {
8339
- throw new Error("chain requires at least one step");
8340
- }
8341
- const nodes = [];
8342
- const edges = [];
8343
- for (let i = 0; i < this.state.steps.length; i++) {
8344
- const step = this.state.steps[i];
8345
- const bindings = [];
8346
- if (i > 0) {
8347
- const prevId = this.state.steps[i - 1].id;
8348
- bindings.push({
8349
- from: prevId,
8350
- pointer: LLM_TEXT_OUTPUT_INTERNAL,
8351
- to: LLM_USER_MESSAGE_TEXT_INTERNAL,
8352
- encoding: "json_string"
8353
- });
8354
- edges.push({ from: prevId, to: step.id });
5803
+ if (hasMerge) {
5804
+ for (const [index, value] of (subnode.input.merge ?? []).entries()) {
5805
+ if (String(value.from) !== "item") {
5806
+ throw new MapFanoutInputError(
5807
+ nodeId,
5808
+ `map.fanout transform.json merge[${index}].from must be "item"`
5809
+ );
8355
5810
  }
8356
- const input = {
8357
- id: step.id,
8358
- type: WorkflowNodeTypes.LLMResponses,
8359
- input: {
8360
- request: step.request,
8361
- ...step.stream ? { stream: true } : {},
8362
- ...bindings.length > 0 ? { bindings } : {}
8363
- }
8364
- };
8365
- nodes.push(input);
8366
5811
  }
8367
- return {
8368
- kind: WorkflowKinds.WorkflowV0,
8369
- name: this.state.name,
8370
- ...this.state.execution ? { execution: this.state.execution } : {},
8371
- nodes,
8372
- ...edges.length > 0 ? { edges: sortEdges(edges) } : {},
8373
- outputs: sortOutputs(this.state.outputs)
8374
- };
8375
5812
  }
8376
- };
8377
- function Chain(name, steps) {
8378
- return ChainBuilder.create(name, steps);
8379
5813
  }
8380
- var ParallelBuilder = class _ParallelBuilder {
8381
- constructor(state) {
5814
+ var WorkflowBuilderV1 = class _WorkflowBuilderV1 {
5815
+ constructor(state = { nodes: [], edges: [], outputs: [] }) {
8382
5816
  this.state = state;
8383
5817
  }
8384
- static create(name, steps) {
8385
- return new _ParallelBuilder({ name, steps, outputs: [] });
5818
+ static new() {
5819
+ return new _WorkflowBuilderV1();
8386
5820
  }
8387
5821
  with(patch) {
8388
- return new _ParallelBuilder({ ...this.state, ...patch });
8389
- }
8390
- /**
8391
- * Sets the workflow execution configuration.
8392
- */
8393
- execution(exec) {
8394
- return this.with({ execution: exec });
8395
- }
8396
- /**
8397
- * Adds a join node that waits for all parallel steps,
8398
- * followed by an aggregator LLM node that receives the combined output.
8399
- * The join node ID is automatically generated as "<id>_join".
8400
- */
8401
- aggregate(id, request) {
8402
- return this.with({
8403
- aggregate: {
8404
- id,
8405
- request: wireRequest2(request),
8406
- stream: false
8407
- }
5822
+ return new _WorkflowBuilderV1({
5823
+ ...this.state,
5824
+ ...patch
8408
5825
  });
8409
5826
  }
8410
- /**
8411
- * Like aggregate() but enables streaming on the aggregator node.
8412
- */
8413
- aggregateWithStream(id, request) {
8414
- return this.with({
8415
- aggregate: {
8416
- id,
8417
- request: wireRequest2(request),
8418
- stream: true
8419
- }
8420
- });
5827
+ name(name) {
5828
+ return this.with({ name: name.trim() || void 0 });
8421
5829
  }
8422
- /**
8423
- * Adds an output reference from a specific step.
8424
- */
8425
- output(name, from) {
8426
- return this.with({
8427
- outputs: [
8428
- ...this.state.outputs,
8429
- {
8430
- name,
8431
- from,
8432
- pointer: LLM_TEXT_OUTPUT_INTERNAL
8433
- }
8434
- ]
8435
- });
5830
+ execution(execution) {
5831
+ return this.with({ execution });
8436
5832
  }
8437
- /**
8438
- * Builds and returns the compiled workflow spec.
8439
- * @throws Error if no steps are provided
8440
- */
8441
- build() {
8442
- if (this.state.steps.length === 0) {
8443
- throw new Error("parallel requires at least one step");
8444
- }
8445
- const nodes = [];
8446
- const edges = [];
8447
- for (const step of this.state.steps) {
8448
- const input = {
8449
- id: step.id,
8450
- type: WorkflowNodeTypes.LLMResponses,
8451
- input: {
8452
- request: step.request,
8453
- ...step.stream ? { stream: true } : {}
8454
- }
8455
- };
8456
- nodes.push(input);
8457
- }
8458
- if (this.state.aggregate) {
8459
- const joinId = `${this.state.aggregate.id}_join`;
8460
- nodes.push({ id: joinId, type: WorkflowNodeTypes.JoinAll });
8461
- for (const step of this.state.steps) {
8462
- edges.push({ from: step.id, to: joinId });
8463
- }
8464
- const aggInput = {
8465
- id: this.state.aggregate.id,
8466
- type: WorkflowNodeTypes.LLMResponses,
8467
- input: {
8468
- request: this.state.aggregate.request,
8469
- ...this.state.aggregate.stream ? { stream: true } : {},
8470
- bindings: [
8471
- {
8472
- from: joinId,
8473
- // Empty pointer = full join output
8474
- to: LLM_USER_MESSAGE_TEXT_INTERNAL,
8475
- encoding: "json_string"
8476
- }
8477
- ]
8478
- }
8479
- };
8480
- nodes.push(aggInput);
8481
- edges.push({ from: joinId, to: this.state.aggregate.id });
5833
+ node(node) {
5834
+ return this.with({ nodes: [...this.state.nodes, node] });
5835
+ }
5836
+ llmResponses(id, request, options = {}) {
5837
+ const wiredRequest = wireRequest(request);
5838
+ if (options.bindings) {
5839
+ validateBindingTargets(id, wiredRequest.input, options.bindings);
8482
5840
  }
8483
- return {
8484
- kind: WorkflowKinds.WorkflowV0,
8485
- name: this.state.name,
8486
- ...this.state.execution ? { execution: this.state.execution } : {},
8487
- nodes,
8488
- ...edges.length > 0 ? { edges: sortEdges(edges) } : {},
8489
- outputs: sortOutputs(this.state.outputs)
5841
+ const input = {
5842
+ request: wiredRequest,
5843
+ ...options.stream === void 0 ? {} : { stream: options.stream },
5844
+ ...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
5845
+ ...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
5846
+ ...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
8490
5847
  };
5848
+ return this.node({
5849
+ id,
5850
+ type: WorkflowNodeTypesV1.LLMResponses,
5851
+ input
5852
+ });
8491
5853
  }
8492
- };
8493
- function Parallel(name, steps) {
8494
- return ParallelBuilder.create(name, steps);
8495
- }
8496
- function MapItem(id, request) {
8497
- const config = {
8498
- id,
8499
- request: wireRequest2(request),
8500
- stream: false
8501
- };
8502
- return {
8503
- ...config,
8504
- withStream() {
8505
- return { ...config, stream: true };
5854
+ routeSwitch(id, request, options = {}) {
5855
+ const wiredRequest = wireRequest(request);
5856
+ if (options.bindings) {
5857
+ validateBindingTargets(id, wiredRequest.input, options.bindings);
8506
5858
  }
8507
- };
8508
- }
8509
- var MapReduceBuilder = class _MapReduceBuilder {
8510
- constructor(state) {
8511
- this.state = state;
8512
- }
8513
- static create(name, items) {
8514
- return new _MapReduceBuilder({ name, items, outputs: [] });
5859
+ const input = {
5860
+ request: wiredRequest,
5861
+ ...options.stream === void 0 ? {} : { stream: options.stream },
5862
+ ...options.toolExecution === void 0 ? {} : { tool_execution: { mode: options.toolExecution } },
5863
+ ...options.toolLimits === void 0 ? {} : { tool_limits: { ...options.toolLimits } },
5864
+ ...options.bindings === void 0 ? {} : { bindings: options.bindings.slice() }
5865
+ };
5866
+ return this.node({
5867
+ id,
5868
+ type: WorkflowNodeTypesV1.RouteSwitch,
5869
+ input
5870
+ });
8515
5871
  }
8516
- with(patch) {
8517
- return new _MapReduceBuilder({ ...this.state, ...patch });
5872
+ joinAll(id) {
5873
+ return this.node({ id, type: WorkflowNodeTypesV1.JoinAll });
8518
5874
  }
8519
- /**
8520
- * Adds a mapper item to the workflow.
8521
- * Each item becomes a separate LLM node that runs in parallel.
8522
- */
8523
- item(id, request) {
8524
- return this.with({
8525
- items: [...this.state.items, { id, request: wireRequest2(request), stream: false }]
5875
+ joinAny(id, input) {
5876
+ return this.node({
5877
+ id,
5878
+ type: WorkflowNodeTypesV1.JoinAny,
5879
+ ...input ? { input } : {}
8526
5880
  });
8527
5881
  }
8528
- /**
8529
- * Adds a mapper item with streaming enabled.
8530
- */
8531
- itemWithStream(id, request) {
8532
- return this.with({
8533
- items: [...this.state.items, { id, request: wireRequest2(request), stream: true }]
8534
- });
5882
+ joinCollect(id, input) {
5883
+ return this.node({ id, type: WorkflowNodeTypesV1.JoinCollect, input });
8535
5884
  }
8536
- /**
8537
- * Sets the workflow execution configuration.
8538
- */
8539
- execution(exec) {
8540
- return this.with({ execution: exec });
5885
+ transformJSON(id, input) {
5886
+ return this.node({ id, type: WorkflowNodeTypesV1.TransformJSON, input });
8541
5887
  }
8542
- /**
8543
- * Adds a reducer node that receives all mapper outputs.
8544
- * The reducer receives a JSON object mapping each mapper ID to its text output.
8545
- * The join node ID is automatically generated as "<id>_join".
8546
- */
8547
- reduce(id, request) {
8548
- return this.with({
8549
- reducer: {
8550
- id,
8551
- request: wireRequest2(request),
8552
- stream: false
8553
- }
8554
- });
5888
+ mapFanout(id, input) {
5889
+ validateMapFanoutInput(id, input);
5890
+ return this.node({ id, type: WorkflowNodeTypesV1.MapFanout, input });
8555
5891
  }
8556
- /**
8557
- * Like reduce() but enables streaming on the reducer node.
8558
- */
8559
- reduceWithStream(id, request) {
5892
+ edge(from, to, when) {
8560
5893
  return this.with({
8561
- reducer: {
8562
- id,
8563
- request: wireRequest2(request),
8564
- stream: true
8565
- }
5894
+ edges: [...this.state.edges, { from, to, ...when ? { when } : {} }]
8566
5895
  });
8567
5896
  }
8568
- /**
8569
- * Adds an output reference from a specific node.
8570
- * Typically used to output from the reducer node.
8571
- */
8572
- output(name, from) {
5897
+ output(name, from, pointer) {
8573
5898
  return this.with({
8574
5899
  outputs: [
8575
5900
  ...this.state.outputs,
8576
- {
8577
- name,
8578
- from,
8579
- pointer: LLM_TEXT_OUTPUT_INTERNAL
8580
- }
5901
+ { name, from, ...pointer ? { pointer } : {} }
8581
5902
  ]
8582
5903
  });
8583
5904
  }
8584
- /**
8585
- * Builds and returns the compiled workflow spec.
8586
- * @throws Error if no items are provided or no reducer is configured
8587
- */
8588
5905
  build() {
8589
- if (this.state.items.length === 0) {
8590
- throw new Error("map-reduce requires at least one item");
8591
- }
8592
- if (!this.state.reducer) {
8593
- throw new Error("map-reduce requires a reducer (call reduce)");
8594
- }
8595
- const seenIds = /* @__PURE__ */ new Set();
8596
- for (const item of this.state.items) {
8597
- if (!item.id) {
8598
- throw new Error("item ID cannot be empty");
8599
- }
8600
- if (seenIds.has(item.id)) {
8601
- throw new Error(`duplicate item ID: "${item.id}"`);
8602
- }
8603
- seenIds.add(item.id);
8604
- }
8605
- const nodes = [];
8606
- const edges = [];
8607
- const joinId = `${this.state.reducer.id}_join`;
8608
- for (const item of this.state.items) {
8609
- const mapperId = `map_${item.id}`;
8610
- const input = {
8611
- id: mapperId,
8612
- type: WorkflowNodeTypes.LLMResponses,
8613
- input: {
8614
- request: item.request,
8615
- ...item.stream ? { stream: true } : {}
8616
- }
8617
- };
8618
- nodes.push(input);
8619
- edges.push({ from: mapperId, to: joinId });
8620
- }
8621
- nodes.push({ id: joinId, type: WorkflowNodeTypes.JoinAll });
8622
- const reducerInput = {
8623
- id: this.state.reducer.id,
8624
- type: WorkflowNodeTypes.LLMResponses,
8625
- input: {
8626
- request: this.state.reducer.request,
8627
- ...this.state.reducer.stream ? { stream: true } : {},
8628
- bindings: [
8629
- {
8630
- from: joinId,
8631
- // Empty pointer = full join output
8632
- to: LLM_USER_MESSAGE_TEXT_INTERNAL,
8633
- encoding: "json_string"
8634
- }
8635
- ]
8636
- }
8637
- };
8638
- nodes.push(reducerInput);
8639
- edges.push({ from: joinId, to: this.state.reducer.id });
5906
+ const edges = this.state.edges.slice().sort((a, b) => {
5907
+ const af = String(a.from);
5908
+ const bf = String(b.from);
5909
+ if (af < bf) return -1;
5910
+ if (af > bf) return 1;
5911
+ const at = String(a.to);
5912
+ const bt = String(b.to);
5913
+ if (at < bt) return -1;
5914
+ if (at > bt) return 1;
5915
+ const aw = a.when ? JSON.stringify(a.when) : "";
5916
+ const bw = b.when ? JSON.stringify(b.when) : "";
5917
+ if (aw < bw) return -1;
5918
+ if (aw > bw) return 1;
5919
+ return 0;
5920
+ });
5921
+ const outputs = this.state.outputs.slice().sort((a, b) => {
5922
+ const an = String(a.name);
5923
+ const bn = String(b.name);
5924
+ if (an < bn) return -1;
5925
+ if (an > bn) return 1;
5926
+ const af = String(a.from);
5927
+ const bf = String(b.from);
5928
+ if (af < bf) return -1;
5929
+ if (af > bf) return 1;
5930
+ const ap = a.pointer ?? "";
5931
+ const bp = b.pointer ?? "";
5932
+ if (ap < bp) return -1;
5933
+ if (ap > bp) return 1;
5934
+ return 0;
5935
+ });
8640
5936
  return {
8641
- kind: WorkflowKinds.WorkflowV0,
8642
- name: this.state.name,
5937
+ kind: WorkflowKinds.WorkflowV1,
5938
+ ...this.state.name ? { name: this.state.name } : {},
8643
5939
  ...this.state.execution ? { execution: this.state.execution } : {},
8644
- nodes,
8645
- ...edges.length > 0 ? { edges: sortEdges(edges) } : {},
8646
- outputs: sortOutputs(this.state.outputs)
5940
+ nodes: this.state.nodes.slice(),
5941
+ ...edges.length ? { edges } : {},
5942
+ outputs
8647
5943
  };
8648
5944
  }
8649
5945
  };
8650
- function MapReduce(name, items = []) {
8651
- return MapReduceBuilder.create(name, items);
5946
+ function workflowV1() {
5947
+ return WorkflowBuilderV1.new();
8652
5948
  }
8653
5949
 
8654
5950
  // src/testing.ts
@@ -8872,14 +6168,13 @@ __export(workflow_exports, {
8872
6168
  BindingBuilder: () => BindingBuilder,
8873
6169
  BindingEncodings: () => BindingEncodings,
8874
6170
  FanoutReduceV1: () => FanoutReduceV1,
8875
- KindV0: () => KindV0,
8876
6171
  KindV1: () => KindV1,
8877
6172
  LLM_TEXT_OUTPUT: () => LLM_TEXT_OUTPUT,
8878
6173
  LLM_USER_MESSAGE_TEXT: () => LLM_USER_MESSAGE_TEXT,
8879
- NodeTypes: () => NodeTypes,
8880
6174
  NodeTypesV1: () => NodeTypesV1,
8881
6175
  RouterV1: () => RouterV1,
8882
6176
  ToolExecutionModes: () => ToolExecutionModes,
6177
+ WorkflowBuilderV1: () => WorkflowBuilderV1,
8883
6178
  bindFrom: () => bindFrom,
8884
6179
  bindToPlaceholder: () => bindToPlaceholder,
8885
6180
  bindToPointer: () => bindToPointer,
@@ -8892,7 +6187,8 @@ __export(workflow_exports, {
8892
6187
  whenOutputMatches: () => whenOutputMatches,
8893
6188
  whenStatusEquals: () => whenStatusEquals,
8894
6189
  whenStatusExists: () => whenStatusExists,
8895
- whenStatusMatches: () => whenStatusMatches
6190
+ whenStatusMatches: () => whenStatusMatches,
6191
+ workflowV1: () => workflowV1
8896
6192
  });
8897
6193
 
8898
6194
  // src/workflow/helpers_v1.ts
@@ -8984,7 +6280,7 @@ var BindingBuilder = class {
8984
6280
  };
8985
6281
 
8986
6282
  // src/workflow/patterns_v1.ts
8987
- function wireRequest3(req) {
6283
+ function wireRequest2(req) {
8988
6284
  const raw = req;
8989
6285
  if (raw && typeof raw === "object") {
8990
6286
  if ("input" in raw) {
@@ -9077,7 +6373,7 @@ var FanoutReduceV1 = class {
9077
6373
  encoding: "json_string"
9078
6374
  }
9079
6375
  ];
9080
- const mapperRequest = wireRequest3(mapper);
6376
+ const mapperRequest = wireRequest2(mapper);
9081
6377
  builder = builder.mapFanout(fanoutId, {
9082
6378
  items: { from: generatorId, path: itemsPath },
9083
6379
  item_bindings: itemBindings,
@@ -9106,13 +6402,7 @@ var FanoutReduceV1 = class {
9106
6402
  };
9107
6403
 
9108
6404
  // src/workflow/index.ts
9109
- var KindV0 = WorkflowKinds.WorkflowV0;
9110
6405
  var KindV1 = WorkflowKinds.WorkflowV1;
9111
- var NodeTypes = {
9112
- LLMResponses: WorkflowNodeTypes.LLMResponses,
9113
- JoinAll: WorkflowNodeTypes.JoinAll,
9114
- TransformJSON: WorkflowNodeTypes.TransformJSON
9115
- };
9116
6406
  var NodeTypesV1 = {
9117
6407
  LLMResponses: WorkflowNodeTypesV1.LLMResponses,
9118
6408
  RouteSwitch: WorkflowNodeTypesV1.RouteSwitch,
@@ -9136,9 +6426,6 @@ var ModelRelay = class _ModelRelay {
9136
6426
  static fromSecretKey(secretKey, options = {}) {
9137
6427
  return new _ModelRelay({ ...options, key: parseSecretKey(secretKey) });
9138
6428
  }
9139
- static fromPublishableKey(publishableKey, options = {}) {
9140
- return new _ModelRelay({ ...options, key: parsePublishableKey(publishableKey) });
9141
- }
9142
6429
  static fromApiKey(apiKey, options = {}) {
9143
6430
  return new _ModelRelay({ ...options, key: parseApiKey(apiKey) });
9144
6431
  }
@@ -9167,7 +6454,6 @@ var ModelRelay = class _ModelRelay {
9167
6454
  const auth = new AuthClient(this.http, {
9168
6455
  apiKey,
9169
6456
  accessToken,
9170
- customer: cfg.customer,
9171
6457
  tokenProvider
9172
6458
  });
9173
6459
  this.auth = auth;
@@ -9185,7 +6471,7 @@ var ModelRelay = class _ModelRelay {
9185
6471
  });
9186
6472
  this.images = new ImagesClient(this.http, auth);
9187
6473
  this.sessions = new SessionsClient(this, this.http, auth);
9188
- this.tiers = new TiersClient(this.http, { apiKey });
6474
+ this.tiers = new TiersClient(this.http, { apiKey, accessToken });
9189
6475
  }
9190
6476
  forCustomer(customerId) {
9191
6477
  return new CustomerScopedModelRelay(this.responses, customerId, this.baseUrl);
@@ -9201,8 +6487,6 @@ function resolveBaseUrl(override) {
9201
6487
  AuthClient,
9202
6488
  BillingProviders,
9203
6489
  BindingTargetError,
9204
- Chain,
9205
- ChainBuilder,
9206
6490
  ConfigError,
9207
6491
  ContentPartTypes,
9208
6492
  CustomerResponsesClient,
@@ -9213,7 +6497,6 @@ function resolveBaseUrl(override) {
9213
6497
  DEFAULT_CONNECT_TIMEOUT_MS,
9214
6498
  DEFAULT_REQUEST_TIMEOUT_MS,
9215
6499
  ErrorCodes,
9216
- FrontendTokenProvider,
9217
6500
  ImagesClient,
9218
6501
  InputItemTypes,
9219
6502
  JoinOutput,
@@ -9225,29 +6508,21 @@ function resolveBaseUrl(override) {
9225
6508
  LLMInputPath,
9226
6509
  LLMInputSystemText,
9227
6510
  LLMInputUserText,
9228
- LLMNodeBuilder,
9229
6511
  LLMOutput,
9230
6512
  LLMOutputContentItemPath,
9231
6513
  LLMOutputContentPath,
9232
6514
  LLMOutputPath,
9233
6515
  LLMOutputText,
9234
- LLMStep,
9235
6516
  LLM_TEXT_OUTPUT,
9236
6517
  LLM_USER_MESSAGE_TEXT,
9237
6518
  LocalSession,
9238
6519
  MapFanoutInputError,
9239
- MapItem,
9240
- MapReduce,
9241
- MapReduceBuilder,
9242
6520
  MemorySessionStore,
9243
6521
  MessageRoles,
9244
6522
  ModelRelay,
9245
6523
  ModelRelayError,
9246
- OIDCExchangeTokenProvider,
9247
6524
  OutputFormatTypes,
9248
6525
  OutputItemTypes,
9249
- Parallel,
9250
- ParallelBuilder,
9251
6526
  PathEscapeError,
9252
6527
  ResponsesClient,
9253
6528
  ResponsesStream,
@@ -9270,15 +6545,13 @@ function resolveBaseUrl(override) {
9270
6545
  ToolRegistry,
9271
6546
  ToolRunner,
9272
6547
  ToolTypes,
9273
- TransformJSONNodeBuilder,
9274
6548
  TransportError,
9275
6549
  WORKFLOWS_COMPILE_PATH,
9276
6550
  WebToolIntents,
9277
- Workflow,
9278
- WorkflowBuilderV0,
9279
6551
  WorkflowBuilderV1,
9280
6552
  WorkflowKinds,
9281
6553
  WorkflowNodeTypes,
6554
+ WorkflowNodeTypesV1,
9282
6555
  WorkflowValidationError,
9283
6556
  WorkflowsClient,
9284
6557
  asModelId,
@@ -9314,17 +6587,10 @@ function resolveBaseUrl(override) {
9314
6587
  getRetryableErrors,
9315
6588
  hasRetryableErrors,
9316
6589
  hasToolCalls,
9317
- isAutoProvisionDisabled,
9318
- isAutoProvisionMisconfigured,
9319
- isEmailRequired,
9320
- isIdentityRequired,
9321
- isProvisioningError,
9322
- isPublishableKey,
9323
6590
  isSecretKey,
9324
6591
  mergeMetrics,
9325
6592
  mergeTrace,
9326
6593
  modelToString,
9327
- newWorkflow,
9328
6594
  normalizeModelId,
9329
6595
  normalizeStopReason,
9330
6596
  outputFormatFromZod,
@@ -9333,33 +6599,22 @@ function resolveBaseUrl(override) {
9333
6599
  parseNodeId,
9334
6600
  parseOutputName,
9335
6601
  parsePlanHash,
9336
- parsePublishableKey,
9337
6602
  parseRunId,
9338
6603
  parseSecretKey,
9339
6604
  parseToolArgs,
9340
6605
  parseToolArgsRaw,
9341
- pollOAuthDeviceToken,
9342
- pollUntil,
9343
6606
  respondToToolCall,
9344
- runOAuthDeviceFlowForIDToken,
9345
- startOAuthDeviceAuthorization,
9346
6607
  stopReasonToString,
9347
6608
  toolChoiceAuto,
9348
6609
  toolChoiceNone,
9349
6610
  toolChoiceRequired,
9350
6611
  toolResultMessage,
9351
6612
  transformJSONMerge,
9352
- transformJSONMergeV1,
9353
6613
  transformJSONObject,
9354
- transformJSONObjectV1,
9355
6614
  transformJSONValue,
9356
- transformJSONValueV1,
9357
6615
  tryParseToolArgs,
9358
6616
  validateWithZod,
9359
6617
  workflow,
9360
- workflowV0,
9361
- workflowV0Schema,
9362
6618
  workflowV1,
9363
- workflowV1Schema,
9364
6619
  zodToJsonSchema
9365
6620
  });