@forklaunch/core 3.3.0 → 3.4.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.
Files changed (38) hide show
  1. package/bin/gateway-mock/routes/payments.mjs +47 -0
  2. package/lib/agent/agent.d.ts +26 -0
  3. package/lib/agent/agent.d.ts.map +1 -0
  4. package/lib/agent/continuation.d.ts +29 -0
  5. package/lib/agent/continuation.d.ts.map +1 -0
  6. package/lib/agent/index.d.ts +8 -0
  7. package/lib/agent/index.d.ts.map +1 -0
  8. package/lib/agent/index.js +1049 -0
  9. package/lib/agent/index.js.map +1 -0
  10. package/lib/agent/index.mjs +1005 -0
  11. package/lib/agent/index.mjs.map +1 -0
  12. package/lib/agent/sources.d.ts +27 -0
  13. package/lib/agent/sources.d.ts.map +1 -0
  14. package/lib/agent/tools.d.ts +39 -0
  15. package/lib/agent/tools.d.ts.map +1 -0
  16. package/lib/agent/types.d.ts +130 -0
  17. package/lib/agent/types.d.ts.map +1 -0
  18. package/lib/http/index.d.ts +1 -0
  19. package/lib/http/index.d.ts.map +1 -1
  20. package/lib/http/index.js +203 -38
  21. package/lib/http/index.js.map +1 -1
  22. package/lib/http/index.mjs +202 -38
  23. package/lib/http/index.mjs.map +1 -1
  24. package/lib/http/localModelGatewayClient.d.ts +27 -0
  25. package/lib/http/localModelGatewayClient.d.ts.map +1 -0
  26. package/lib/http/modelGatewayClient.d.ts.map +1 -1
  27. package/lib/http/modelStream.d.ts +4 -0
  28. package/lib/http/modelStream.d.ts.map +1 -0
  29. package/lib/http/paymentsClient.d.ts +55 -1
  30. package/lib/http/paymentsClient.d.ts.map +1 -1
  31. package/lib/http/previewModelGatewayClient.d.ts +5 -1
  32. package/lib/http/previewModelGatewayClient.d.ts.map +1 -1
  33. package/lib/persistence/compliantField.d.ts.map +1 -1
  34. package/lib/persistence/index.js +6 -1
  35. package/lib/persistence/index.js.map +1 -1
  36. package/lib/persistence/index.mjs +6 -1
  37. package/lib/persistence/index.mjs.map +1 -1
  38. package/package.json +9 -2
package/lib/http/index.js CHANGED
@@ -71,6 +71,7 @@ __export(http_exports, {
71
71
  createEmailClient: () => createEmailClient,
72
72
  createHmacToken: () => createHmacToken,
73
73
  createInstanceGatewayTransport: () => createInstanceGatewayTransport,
74
+ createLocalModelGatewayClient: () => createLocalModelGatewayClient,
74
75
  createModelGatewayClient: () => createModelGatewayClient,
75
76
  createPaymentsClient: () => createPaymentsClient,
76
77
  createPreviewModelGatewayClient: () => createPreviewModelGatewayClient,
@@ -2978,12 +2979,55 @@ function signPlatformEvent(params) {
2978
2979
  });
2979
2980
  }
2980
2981
 
2982
+ // src/http/modelStream.ts
2983
+ async function* readModelStream(response) {
2984
+ const reader = response.body?.getReader();
2985
+ if (!reader)
2986
+ throw new ModelGatewayRequestError(502, "The model stream is empty.");
2987
+ const decoder = new TextDecoder();
2988
+ let buffer = "", bytes = 0;
2989
+ try {
2990
+ for (; ; ) {
2991
+ const part = await reader.read();
2992
+ if (part.done) break;
2993
+ bytes += part.value.byteLength;
2994
+ if (bytes > 512e3) throw new Error("oversized");
2995
+ buffer += decoder.decode(part.value, { stream: true });
2996
+ let match;
2997
+ while (match = buffer.match(/\r?\n\r?\n/)) {
2998
+ const event = buffer.slice(0, match.index);
2999
+ buffer = buffer.slice(match.index + match[0].length);
3000
+ const data = event.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
3001
+ if (!data) continue;
3002
+ if (data === "[DONE]") return;
3003
+ const value = JSON.parse(data);
3004
+ if (value.error || !Array.isArray(value.choices))
3005
+ throw new Error("invalid");
3006
+ yield value;
3007
+ }
3008
+ }
3009
+ throw new Error("interrupted");
3010
+ } catch {
3011
+ throw new ModelGatewayRequestError(
3012
+ 502,
3013
+ "The model stream was interrupted. No automatic retry was sent."
3014
+ );
3015
+ } finally {
3016
+ await reader.cancel().catch(() => {
3017
+ });
3018
+ reader.releaseLock();
3019
+ }
3020
+ }
3021
+
2981
3022
  // src/http/modelGatewayClient.ts
2982
3023
  var ModelGatewayRequestError = class extends InstanceGatewayRequestError {
2983
3024
  name = "ModelGatewayRequestError";
2984
3025
  };
2985
3026
  function createModelGatewayClient(options2 = {}) {
2986
- const transport = createInstanceGatewayTransport(options2, "The model gateway");
3027
+ const transport = createInstanceGatewayTransport(
3028
+ options2,
3029
+ "The model gateway"
3030
+ );
2987
3031
  async function send(method, route, body, signal) {
2988
3032
  try {
2989
3033
  return await transport.request(method, route, body, { signal });
@@ -3019,42 +3063,12 @@ function createModelGatewayClient(options2 = {}) {
3019
3063
  request,
3020
3064
  streamOptions.signal
3021
3065
  );
3022
- if (!response.body) return;
3023
- for await (const data of sseData(response.body)) {
3024
- if (data === "[DONE]") return;
3025
- try {
3026
- yield JSON.parse(data);
3027
- } catch {
3028
- }
3029
- }
3066
+ yield* readModelStream(response);
3030
3067
  }
3031
3068
  }
3032
3069
  }
3033
3070
  };
3034
3071
  }
3035
- async function* sseData(stream) {
3036
- const decoder = new TextDecoder();
3037
- let buffer = "";
3038
- const reader = stream.getReader();
3039
- try {
3040
- for (; ; ) {
3041
- const { value, done } = await reader.read();
3042
- if (done) break;
3043
- buffer += decoder.decode(value, { stream: true });
3044
- let boundary;
3045
- while ((boundary = buffer.search(/\r?\n\r?\n/)) !== -1) {
3046
- const event = buffer.slice(0, boundary);
3047
- buffer = buffer.slice(boundary).replace(/^\r?\n\r?\n/, "");
3048
- const data = event.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
3049
- if (data) yield data;
3050
- }
3051
- }
3052
- const tail = buffer.trim();
3053
- if (tail.startsWith("data:")) yield tail.slice(5).trimStart();
3054
- } finally {
3055
- reader.releaseLock();
3056
- }
3057
- }
3058
3072
 
3059
3073
  // src/http/previewModelGatewayClient.ts
3060
3074
  function record(value) {
@@ -3110,9 +3124,9 @@ function createPreviewModelGatewayClient(options2 = {}) {
3110
3124
  options2,
3111
3125
  "The local preview model gateway"
3112
3126
  );
3113
- async function send(method, route, body) {
3127
+ async function send(method, route, body, signal) {
3114
3128
  try {
3115
- return await transport.request(method, route, body);
3129
+ return await transport.request(method, route, body, { signal });
3116
3130
  } catch (error) {
3117
3131
  if (error instanceof InstanceGatewayRequestError)
3118
3132
  throw new ModelGatewayRequestError(
@@ -3130,6 +3144,15 @@ function createPreviewModelGatewayClient(options2 = {}) {
3130
3144
  },
3131
3145
  chat: {
3132
3146
  completions: {
3147
+ async *stream(request, options3 = {}) {
3148
+ const response = await send(
3149
+ "POST",
3150
+ "/models/chat/completions",
3151
+ { ...request, stream: true },
3152
+ options3.signal
3153
+ );
3154
+ yield* readModelStream(response);
3155
+ },
3133
3156
  async create(request) {
3134
3157
  return await (await send(
3135
3158
  "POST",
@@ -3664,6 +3687,19 @@ function createPaymentsClient(options2 = {}) {
3664
3687
  },
3665
3688
  status() {
3666
3689
  return call("GET", "/payments/status");
3690
+ },
3691
+ payouts(params = {}) {
3692
+ const { limit } = params;
3693
+ if (limit !== void 0 && (!Number.isInteger(limit) || limit < 1 || limit > 50)) {
3694
+ throw new TypeError("limit must be a whole number from 1 to 50");
3695
+ }
3696
+ return call(
3697
+ "GET",
3698
+ limit === void 0 ? "/payments/payouts" : `/payments/payouts?limit=${limit}`
3699
+ );
3700
+ },
3701
+ dashboardLink() {
3702
+ return call("POST", "/payments/dashboard-link", {});
3667
3703
  }
3668
3704
  };
3669
3705
  }
@@ -3748,8 +3784,8 @@ function createStripeClient(options2 = {}) {
3748
3784
  return new StripeClass(options2.apiKey, options2.config);
3749
3785
  }
3750
3786
  const settings = instanceGatewaySettings(options2, "Payments");
3751
- const gateway = new URL(settings.gatewayUrl);
3752
- const protocol = gateway.protocol === "http:" ? "http" : "https";
3787
+ const gateway2 = new URL(settings.gatewayUrl);
3788
+ const protocol = gateway2.protocol === "http:" ? "http" : "https";
3753
3789
  return new StripeClass(
3754
3790
  // No key: the authenticator below replaces it, and the gateway holds the
3755
3791
  // real one. (stripe-node accepts an authenticator in place of a key.)
@@ -3757,8 +3793,8 @@ function createStripeClient(options2 = {}) {
3757
3793
  {
3758
3794
  maxNetworkRetries: 2,
3759
3795
  ...options2.config,
3760
- host: gateway.hostname,
3761
- port: gateway.port || (protocol === "http" ? 80 : 443),
3796
+ host: gateway2.hostname,
3797
+ port: gateway2.port || (protocol === "http" ? 80 : 443),
3762
3798
  protocol,
3763
3799
  telemetry: false,
3764
3800
  // The signed fetch sets `authorization`; nothing else may.
@@ -5871,6 +5907,134 @@ function registerDelegatedSurface(surface, mount, register) {
5871
5907
  }
5872
5908
  return register(mount);
5873
5909
  }
5910
+
5911
+ // src/http/localModelGatewayClient.ts
5912
+ var import_node_child_process = require("child_process");
5913
+ var import_node_util = require("util");
5914
+ var execute = (0, import_node_util.promisify)(import_node_child_process.execFile);
5915
+ var gateway = "https://studio-orchestrator.forklaunch.com/studio-orchestrator/desktop-runtime-model-gateway";
5916
+ function validate(value) {
5917
+ if (!value || !/^[a-f0-9]{64}$/.test(value.grantId) || !/^[a-f0-9]{64}$/.test(value.capability) || value.gatewayBaseUrl !== `${gateway}/${value.grantId}/v1` || value.scope !== "local-runtime" || !Number.isSafeInteger(value.expiresAt) || value.expiresAt <= Date.now() || value.expiresAt > Date.now() + 9e5 || !/^[A-Za-z0-9._-]{1,128}$/.test(value.model) || !Number.isInteger(value.maxCalls) || value.maxCalls < 1 || value.maxCalls > 20 || !Number.isInteger(value.maxUnits) || value.maxUnits < 1 || value.maxUnits > 1e5) {
5918
+ throw new Error(
5919
+ "Invalid local model connection. No model request was sent."
5920
+ );
5921
+ }
5922
+ return value;
5923
+ }
5924
+ function createLocalModelGatewayClient(options2 = {}) {
5925
+ if (process.env.FORKLAUNCH_API_KEY === void 0 && !options2.credentialProvider && process.env.FORKLAUNCH_LOCAL_MODEL_RELAY === "1") {
5926
+ return createPreviewModelGatewayClient({ fetch: options2.fetch });
5927
+ }
5928
+ const applicationId = options2.applicationId ?? process.env.FORKLAUNCH_APPLICATION_ID;
5929
+ const model = options2.model ?? process.env.AGENT_MODEL;
5930
+ if (applicationId && !/^[a-f0-9-]{36}$/i.test(applicationId)) {
5931
+ throw new Error(
5932
+ "FORKLAUNCH_APPLICATION_ID must be a saved application UUID."
5933
+ );
5934
+ }
5935
+ const provider = options2.credentialProvider ?? (async () => {
5936
+ const args = ["model", "credential", "--json"];
5937
+ if (applicationId) args.push("--application-id", applicationId);
5938
+ if (model) args.push("--model", model);
5939
+ try {
5940
+ const { stdout } = await execute("forklaunch", args, {
5941
+ timeout: 35e3,
5942
+ maxBuffer: 65536,
5943
+ windowsHide: true
5944
+ });
5945
+ return JSON.parse(stdout);
5946
+ } catch {
5947
+ throw new Error(
5948
+ "Could not connect the local agent. Run forklaunch login, check app access, and use a CLI that supports model credential."
5949
+ );
5950
+ }
5951
+ });
5952
+ const optionsFetch = options2.fetch ?? fetch;
5953
+ let pending;
5954
+ let credential;
5955
+ async function connection() {
5956
+ if (credential && credential.expiresAt > Date.now()) return credential;
5957
+ pending ??= provider().then(validate).then((value) => credential = value).finally(() => {
5958
+ pending = void 0;
5959
+ });
5960
+ return pending;
5961
+ }
5962
+ return {
5963
+ async models() {
5964
+ const c = await connection();
5965
+ return {
5966
+ models: [{ id: c.model }],
5967
+ preview: {
5968
+ expiresAt: c.expiresAt,
5969
+ maxCalls: c.maxCalls,
5970
+ maxUnits: c.maxUnits
5971
+ }
5972
+ };
5973
+ },
5974
+ chat: {
5975
+ completions: {
5976
+ async *stream(request, options3 = {}) {
5977
+ const c = await connection();
5978
+ if (request.model !== c.model)
5979
+ throw new ModelGatewayRequestError(
5980
+ 400,
5981
+ "Choose the model authorized for this local session."
5982
+ );
5983
+ const response = await optionsFetch(
5984
+ `${c.gatewayBaseUrl}/chat/completions`,
5985
+ {
5986
+ method: "POST",
5987
+ redirect: "error",
5988
+ signal: options3.signal ? AbortSignal.any([options3.signal, AbortSignal.timeout(6e4)]) : AbortSignal.timeout(6e4),
5989
+ headers: {
5990
+ authorization: `Bearer ${c.capability}`,
5991
+ "content-type": "application/json"
5992
+ },
5993
+ body: JSON.stringify({ ...request, stream: true })
5994
+ }
5995
+ );
5996
+ if (!response.ok) {
5997
+ await response.body?.cancel();
5998
+ throw new ModelGatewayRequestError(
5999
+ response.status,
6000
+ "The local model stream was refused. No automatic retry was sent."
6001
+ );
6002
+ }
6003
+ yield* readModelStream(response);
6004
+ },
6005
+ async create(request) {
6006
+ const c = await connection();
6007
+ if (request.model !== c.model)
6008
+ throw new ModelGatewayRequestError(
6009
+ 400,
6010
+ "Choose the model authorized for this local session."
6011
+ );
6012
+ const response = await (options2.fetch ?? fetch)(
6013
+ `${c.gatewayBaseUrl}/chat/completions`,
6014
+ {
6015
+ method: "POST",
6016
+ redirect: "error",
6017
+ signal: AbortSignal.timeout(6e4),
6018
+ headers: {
6019
+ authorization: `Bearer ${c.capability}`,
6020
+ "content-type": "application/json"
6021
+ },
6022
+ body: JSON.stringify({ ...request, stream: false })
6023
+ }
6024
+ );
6025
+ if (!response.ok) {
6026
+ await response.body?.cancel();
6027
+ throw new ModelGatewayRequestError(
6028
+ response.status,
6029
+ "The local model request was refused or failed. No automatic retry was sent."
6030
+ );
6031
+ }
6032
+ return response.json();
6033
+ }
6034
+ }
6035
+ }
6036
+ };
6037
+ }
5874
6038
  // Annotate the CommonJS export names for ESM import in node:
5875
6039
  0 && (module.exports = {
5876
6040
  ATTR_API_NAME,
@@ -5914,6 +6078,7 @@ function registerDelegatedSurface(surface, mount, register) {
5914
6078
  createEmailClient,
5915
6079
  createHmacToken,
5916
6080
  createInstanceGatewayTransport,
6081
+ createLocalModelGatewayClient,
5917
6082
  createModelGatewayClient,
5918
6083
  createPaymentsClient,
5919
6084
  createPreviewModelGatewayClient,