@fastgpt-sdk/sandbox-adapter 0.0.36 → 0.0.38-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,39 +5,60 @@ var __defProp = Object.defineProperty;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ function __accessProp(key) {
9
+ return this[key];
10
+ }
11
+ var __toESMCache_node;
12
+ var __toESMCache_esm;
8
13
  var __toESM = (mod, isNodeMode, target) => {
14
+ var canCache = mod != null && typeof mod === "object";
15
+ if (canCache) {
16
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
+ var cached = cache.get(mod);
18
+ if (cached)
19
+ return cached;
20
+ }
9
21
  target = mod != null ? __create(__getProtoOf(mod)) : {};
10
22
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
23
  for (let key of __getOwnPropNames(mod))
12
24
  if (!__hasOwnProp.call(to, key))
13
25
  __defProp(to, key, {
14
- get: () => mod[key],
26
+ get: __accessProp.bind(mod, key),
15
27
  enumerable: true
16
28
  });
29
+ if (canCache)
30
+ cache.set(mod, to);
17
31
  return to;
18
32
  };
19
- var __moduleCache = /* @__PURE__ */ new WeakMap;
20
33
  var __toCommonJS = (from) => {
21
- var entry = __moduleCache.get(from), desc;
34
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
22
35
  if (entry)
23
36
  return entry;
24
37
  entry = __defProp({}, "__esModule", { value: true });
25
- if (from && typeof from === "object" || typeof from === "function")
26
- __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
27
- get: () => from[key],
28
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
29
- }));
38
+ if (from && typeof from === "object" || typeof from === "function") {
39
+ for (var key of __getOwnPropNames(from))
40
+ if (!__hasOwnProp.call(entry, key))
41
+ __defProp(entry, key, {
42
+ get: __accessProp.bind(from, key),
43
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
44
+ });
45
+ }
30
46
  __moduleCache.set(from, entry);
31
47
  return entry;
32
48
  };
49
+ var __moduleCache;
33
50
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
51
+ var __returnValue = (v) => v;
52
+ function __exportSetter(name, newValue) {
53
+ this[name] = __returnValue.bind(null, newValue);
54
+ }
34
55
  var __export = (target, all) => {
35
56
  for (var name in all)
36
57
  __defProp(target, name, {
37
58
  get: all[name],
38
59
  enumerable: true,
39
60
  configurable: true,
40
- set: (newValue) => all[name] = () => newValue
61
+ set: __exportSetter.bind(all, name)
41
62
  });
42
63
  };
43
64
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -19141,7 +19162,7 @@ var require_frame = __commonJS((exports, module) => {
19141
19162
  var BUFFER_SIZE = 8 * 1024;
19142
19163
  var buffer = null;
19143
19164
  var bufIdx = BUFFER_SIZE;
19144
- var randomFillSync = runtimeFeatures.has("crypto") ? __require("node:crypto").randomFillSync : function randomFillSync(buffer2, _offset, _size) {
19165
+ var randomFillSync = runtimeFeatures.has("crypto") ? __require("node:crypto").randomFillSync : function randomFillSync2(buffer2, _offset, _size) {
19145
19166
  for (let i = 0;i < buffer2.length; ++i) {
19146
19167
  buffer2[i] = Math.random() * 255 | 0;
19147
19168
  }
@@ -21085,7 +21106,7 @@ var require_eventsource = __commonJS((exports, module) => {
21085
21106
 
21086
21107
  // node_modules/undici/index.js
21087
21108
  var require_undici = __commonJS((exports, module) => {
21088
- var __filename = "/Volumes/code/dev/agent-sandbox-adaptor/node_modules/undici/index.js";
21109
+ var __filename = "/Users/sealos/Documents/GitHub/agent-sandbox-adaptor/node_modules/undici/index.js";
21089
21110
  var Client = require_client();
21090
21111
  var Dispatcher = require_dispatcher();
21091
21112
  var Pool = require_pool();
@@ -21208,7 +21229,7 @@ var require_undici = __commonJS((exports, module) => {
21208
21229
  err.stack = stack ? `${stack}
21209
21230
  ${captureLines}` : capture.stack;
21210
21231
  }
21211
- exports.fetch = function fetch(init, options = undefined) {
21232
+ exports.fetch = function fetch2(init, options = undefined) {
21212
21233
  return fetchImpl(init, options).catch((err) => {
21213
21234
  appendFetchStackTrace(err, __filename);
21214
21235
  throw err;
@@ -45372,6 +45393,12 @@ class BaseSandboxAdapter {
45372
45393
  async renewExpiration(_additionalSeconds) {
45373
45394
  throw new FeatureNotSupportedError("Sandbox expiration renewal not supported by this provider", "renewExpiration", this.provider);
45374
45395
  }
45396
+ async getEndpoint(_selector) {
45397
+ throw new FeatureNotSupportedError("Endpoint resolution not supported by this provider", "getEndpoint", this.provider);
45398
+ }
45399
+ async getProxyTarget(_service = "code-server") {
45400
+ throw new FeatureNotSupportedError("Proxy target resolution not supported by this provider", "getProxyTarget", this.provider);
45401
+ }
45375
45402
  async executeStream(command, handlers, options) {
45376
45403
  const result = await this.execute(command, options);
45377
45404
  if (handlers.onStdout && result.stdout) {
@@ -45608,10 +45635,10 @@ class DevboxApi {
45608
45635
  const result = await res.json();
45609
45636
  return result;
45610
45637
  }
45611
- async create(name) {
45638
+ async create(req) {
45612
45639
  return this.request(this.url("/api/v1/devbox"), {
45613
45640
  method: "POST",
45614
- body: JSON.stringify({ name })
45641
+ body: JSON.stringify(req)
45615
45642
  });
45616
45643
  }
45617
45644
  async info(name) {
@@ -45624,6 +45651,11 @@ class DevboxApi {
45624
45651
  method: "POST"
45625
45652
  });
45626
45653
  }
45654
+ async stop(name) {
45655
+ return this.request(this.url(`/api/v1/devbox/${name}/stop`), {
45656
+ method: "POST"
45657
+ });
45658
+ }
45627
45659
  async resume(name) {
45628
45660
  return this.request(this.url(`/api/v1/devbox/${name}/resume`), {
45629
45661
  method: "POST"
@@ -45669,18 +45701,60 @@ class DevboxApi {
45669
45701
  }
45670
45702
  }
45671
45703
 
45704
+ // src/adapters/ports.ts
45705
+ var OPEN_SANDBOX_EXECD_PORT = 44772;
45706
+ var OPEN_SANDBOX_CODE_SERVER_PORT = 8080;
45707
+ var SEALOS_DEVBOX_CODE_SERVER_PORT = 1318;
45708
+
45709
+ // src/utils/image.ts
45710
+ function formatImageSpec(image) {
45711
+ const parts = [image.repository];
45712
+ if (image.tag)
45713
+ parts.push(":", image.tag);
45714
+ if (image.digest)
45715
+ parts.push("@", image.digest);
45716
+ return parts.join("");
45717
+ }
45718
+ function parseImageSpec(image) {
45719
+ if (!image)
45720
+ return { repository: "" };
45721
+ const atIndex = image.indexOf("@");
45722
+ if (atIndex > -1) {
45723
+ return { repository: image.slice(0, atIndex), digest: image.slice(atIndex + 1) };
45724
+ }
45725
+ const colonIndex = image.indexOf(":");
45726
+ if (colonIndex > -1) {
45727
+ return { repository: image.slice(0, colonIndex), tag: image.slice(colonIndex + 1) };
45728
+ }
45729
+ return { repository: image };
45730
+ }
45731
+
45732
+ // src/utils/url.ts
45733
+ function normalizePathPrefix(path) {
45734
+ if (!path)
45735
+ return "";
45736
+ const normalized = path.startsWith("/") ? path : `/${path}`;
45737
+ return normalized.length > 1 ? normalized.replace(/\/+$/, "") : "";
45738
+ }
45739
+ function joinUrlPath(url, path) {
45740
+ const normalizedPath = normalizePathPrefix(path);
45741
+ return normalizedPath ? `${url.replace(/\/+$/, "")}${normalizedPath}` : url.replace(/\/+$/, "");
45742
+ }
45743
+
45672
45744
  // src/adapters/SealosDevboxAdapter/index.ts
45673
45745
  class SealosDevboxAdapter extends BaseSandboxAdapter {
45674
45746
  config;
45747
+ createConfig;
45675
45748
  provider = "sealosdevbox";
45676
45749
  get rootPath() {
45677
45750
  return "/home/devbox/workspace";
45678
45751
  }
45679
45752
  api;
45680
45753
  _id;
45681
- constructor(config) {
45754
+ constructor(config, createConfig) {
45682
45755
  super();
45683
45756
  this.config = config;
45757
+ this.createConfig = createConfig;
45684
45758
  this.api = new DevboxApi({ baseUrl: config.baseUrl, token: config.token });
45685
45759
  this._id = config.sandboxId;
45686
45760
  this.polyfillService = new CommandPolyfillService(this);
@@ -45705,6 +45779,26 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45705
45779
  return "Error";
45706
45780
  }
45707
45781
  }
45782
+ buildCreateRequest() {
45783
+ const spec = this.createConfig ?? {};
45784
+ const env = { ...spec.env ?? {} };
45785
+ if (spec.workingDir && !env.CODEX_GATEWAY_CWD) {
45786
+ env.CODEX_GATEWAY_CWD = spec.workingDir;
45787
+ }
45788
+ return this.removeUndefined({
45789
+ name: this._id,
45790
+ image: spec.image ? formatImageSpec(spec.image) : undefined,
45791
+ env: Object.keys(env).length > 0 ? env : undefined,
45792
+ labels: spec.labels,
45793
+ upstreamID: spec.upstreamID,
45794
+ kubeAccess: spec.kubeAccess,
45795
+ pauseAt: spec.lifecycle?.pauseAt,
45796
+ archiveAfterPauseTime: spec.lifecycle?.archiveAfterPauseTime
45797
+ });
45798
+ }
45799
+ removeUndefined(obj) {
45800
+ return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
45801
+ }
45708
45802
  async getInfo() {
45709
45803
  try {
45710
45804
  const res = await this.api.info(this._id);
@@ -45716,10 +45810,10 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45716
45810
  this._status = { state: this.StatusAdapt(data), message: res.message };
45717
45811
  return {
45718
45812
  id: data.name,
45719
- image: { repository: "" },
45813
+ image: parseImageSpec(data.image),
45720
45814
  entrypoint: [],
45721
45815
  status: this._status,
45722
- createdAt: new Date
45816
+ createdAt: data.creationTimestamp ? new Date(data.creationTimestamp) : new Date
45723
45817
  };
45724
45818
  } catch (error) {
45725
45819
  throw new CommandExecutionError(`Failed to get sandbox info`, "getInfo", error instanceof Error ? error : undefined);
@@ -45757,7 +45851,10 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45757
45851
  async create() {
45758
45852
  try {
45759
45853
  this._status = { state: "Creating" };
45760
- await this.api.create(this._id);
45854
+ const res = await this.api.create(this.buildCreateRequest());
45855
+ if (res.code !== 200 && res.code !== 201) {
45856
+ throw new Error(res.message || `Devbox create failed with code ${res.code}`);
45857
+ }
45761
45858
  await this.waitUntilReady();
45762
45859
  await new Promise((resolve) => setTimeout(resolve, 1000));
45763
45860
  this._status = { state: "Running" };
@@ -45768,10 +45865,10 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45768
45865
  async stop() {
45769
45866
  try {
45770
45867
  this._status = { state: "Stopping" };
45771
- await this.api.pause(this._id);
45868
+ await this.api.stop(this._id);
45772
45869
  this._status = { state: "Stopped" };
45773
45870
  } catch (error) {
45774
- throw new CommandExecutionError("Failed to pause sandbox", "pause", error instanceof Error ? error : undefined);
45871
+ throw new CommandExecutionError("Failed to stop sandbox", "stop", error instanceof Error ? error : undefined);
45775
45872
  }
45776
45873
  }
45777
45874
  async start() {
@@ -45813,11 +45910,125 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45813
45910
  throw new CommandExecutionError(`Command execution failed: ${error?.message || error?.code}`, command, error instanceof Error ? error : undefined);
45814
45911
  }
45815
45912
  }
45913
+ async getEndpoint(selector) {
45914
+ const port = typeof selector === "number" ? selector : SEALOS_DEVBOX_CODE_SERVER_PORT;
45915
+ const target = await this.getHttpgateTarget(port);
45916
+ if (selector === "code-server") {
45917
+ await this.waitForCodeServerHealthz(target);
45918
+ }
45919
+ const url = new URL(target.origin);
45920
+ return {
45921
+ host: url.host,
45922
+ port: target.port,
45923
+ protocol: url.protocol === "https:" ? "https" : "http",
45924
+ url: joinUrlPath(target.origin, target.basePath)
45925
+ };
45926
+ }
45927
+ async getProxyTarget(service = "code-server") {
45928
+ if (service !== "code-server") {
45929
+ throw new FeatureNotSupportedError(`Proxy service "${service}" is not supported by this provider`, "getProxyTarget", this.provider);
45930
+ }
45931
+ const target = await this.getHttpgateTarget(SEALOS_DEVBOX_CODE_SERVER_PORT);
45932
+ return {
45933
+ service,
45934
+ origin: target.origin,
45935
+ basePath: target.basePath,
45936
+ auth: "code-server",
45937
+ ...target.password ? { password: target.password } : {}
45938
+ };
45939
+ }
45940
+ async waitForCodeServerHealthz(target) {
45941
+ const healthUrl = joinUrlPath(joinUrlPath(target.origin, target.basePath), "/healthz");
45942
+ const timeoutMs = 60000;
45943
+ const intervalMs = 500;
45944
+ const requestTimeoutMs = 3000;
45945
+ const deadline = Date.now() + timeoutMs;
45946
+ let lastResult = "not checked";
45947
+ while (Date.now() < deadline) {
45948
+ try {
45949
+ const res = await fetch(healthUrl, {
45950
+ method: "GET",
45951
+ signal: AbortSignal.timeout(requestTimeoutMs)
45952
+ });
45953
+ if (res.status >= 200 && res.status < 400) {
45954
+ return;
45955
+ }
45956
+ lastResult = `status ${res.status}`;
45957
+ } catch (error) {
45958
+ lastResult = error instanceof Error ? error.message : String(error);
45959
+ }
45960
+ await this.sleep(intervalMs);
45961
+ }
45962
+ throw new ConnectionError(`Devbox code-server health check ${healthUrl} did not become ready within ${timeoutMs}ms. Last result: ${lastResult}`, this.config.baseUrl);
45963
+ }
45964
+ async getHttpgateTarget(port) {
45965
+ const res = await this.api.info(this._id);
45966
+ if (res.code !== 200 || !res.data) {
45967
+ throw new ConnectionError(`Failed to get devbox info: ${res.message}`, this.config.baseUrl);
45968
+ }
45969
+ if (port === SEALOS_DEVBOX_CODE_SERVER_PORT) {
45970
+ const gateway2 = res.data.codeServerGateway;
45971
+ if (!gateway2?.url) {
45972
+ throw new ConnectionError("Devbox info does not include codeServerGateway.url; cannot resolve code-server endpoint", this.config.baseUrl);
45973
+ }
45974
+ const codeServerUrl = new URL(gateway2.url);
45975
+ return {
45976
+ origin: codeServerUrl.origin,
45977
+ basePath: normalizePathPrefix(codeServerUrl.pathname),
45978
+ port: gateway2.port ?? port,
45979
+ password: gateway2.password
45980
+ };
45981
+ }
45982
+ const gatewayUrl = res.data.gateway?.url;
45983
+ if (!gatewayUrl) {
45984
+ throw new ConnectionError("Devbox info does not include gateway.url; cannot derive httpgate endpoint", this.config.baseUrl);
45985
+ }
45986
+ const gateway = new URL(gatewayUrl);
45987
+ const uniqueID = this.getGatewayUniqueID(res.data, gateway);
45988
+ const domain = this.getHttpgateDomain(gateway);
45989
+ return {
45990
+ origin: `${gateway.protocol}//devbox-${uniqueID}-${port}.${domain}`,
45991
+ basePath: "",
45992
+ port
45993
+ };
45994
+ }
45995
+ getGatewayUniqueID(data, gateway) {
45996
+ if (data.gateway?.uniqueID)
45997
+ return data.gateway.uniqueID;
45998
+ const parts = gateway.pathname.split("/").filter(Boolean);
45999
+ const uniqueID = parts[parts.length - 1];
46000
+ if (!uniqueID) {
46001
+ throw new ConnectionError("Devbox gateway.url does not include uniqueID; cannot derive httpgate endpoint", this.config.baseUrl);
46002
+ }
46003
+ return uniqueID;
46004
+ }
46005
+ getHttpgateDomain(gateway) {
46006
+ if (this.config.httpgateDomain) {
46007
+ return this.normalizeHttpgateDomain(this.config.httpgateDomain);
46008
+ }
46009
+ const prefix = "devbox-gateway.";
46010
+ if (!gateway.host.startsWith(prefix)) {
46011
+ throw new ConnectionError(`Cannot derive httpgate domain from gateway host "${gateway.host}"`, this.config.baseUrl);
46012
+ }
46013
+ return gateway.host.slice(prefix.length);
46014
+ }
46015
+ normalizeHttpgateDomain(domain) {
46016
+ const trimmed = domain.trim().replace(/^\.+|\.+$/g, "");
46017
+ if (!trimmed) {
46018
+ throw new ConnectionError("httpgateDomain is empty", this.config.baseUrl);
46019
+ }
46020
+ if (trimmed.includes("://")) {
46021
+ return new URL(trimmed).host;
46022
+ }
46023
+ return trimmed;
46024
+ }
45816
46025
  async ping() {
45817
46026
  try {
45818
46027
  const res = await this.api.info(this._id);
45819
46028
  if (res.code !== 200)
45820
46029
  return false;
46030
+ if (!res.data)
46031
+ return false;
45821
46032
  return res.data.state.phase === "Running" /* Running */;
45822
46033
  } catch {
45823
46034
  return false;
@@ -48069,27 +48280,6 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48069
48280
  message: sdkStatus.message
48070
48281
  };
48071
48282
  }
48072
- convertImageSpec(image) {
48073
- const parts = [image.repository];
48074
- if (image.tag) {
48075
- parts.push(":", image.tag);
48076
- }
48077
- if (image.digest) {
48078
- parts.push("@", image.digest);
48079
- }
48080
- return parts.join("");
48081
- }
48082
- parseImageSpec(image) {
48083
- const atIndex = image.indexOf("@");
48084
- if (atIndex > -1) {
48085
- return { repository: image.slice(0, atIndex), digest: image.slice(atIndex + 1) };
48086
- }
48087
- const colonIndex = image.indexOf(":");
48088
- if (colonIndex > -1) {
48089
- return { repository: image.slice(0, colonIndex), tag: image.slice(colonIndex + 1) };
48090
- }
48091
- return { repository: image };
48092
- }
48093
48283
  convertResourceLimits(resourceLimits) {
48094
48284
  if (!resourceLimits)
48095
48285
  return;
@@ -48204,7 +48394,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48204
48394
  }
48205
48395
  try {
48206
48396
  this._status = { state: "Creating" };
48207
- const image = this.convertImageSpec(cfg.image);
48397
+ const image = formatImageSpec(cfg.image);
48208
48398
  const resource = this.convertResourceLimits(cfg.resourceLimits);
48209
48399
  this.sandbox = await Sandbox.create({
48210
48400
  connectionConfig: this._connection,
@@ -48308,7 +48498,18 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48308
48498
  async close() {
48309
48499
  await this.sandbox.close();
48310
48500
  }
48311
- async getEndpoint(port) {
48501
+ async getEndpoint(selector) {
48502
+ const port = typeof selector === "number" ? selector : OPEN_SANDBOX_EXECD_PORT;
48503
+ const endpoint = await this.getOpenSandboxEndpoint(port);
48504
+ if (selector === "code-server") {
48505
+ return {
48506
+ ...endpoint,
48507
+ url: joinUrlPath(endpoint.url, `/proxy/${OPEN_SANDBOX_CODE_SERVER_PORT}`)
48508
+ };
48509
+ }
48510
+ return endpoint;
48511
+ }
48512
+ async getOpenSandboxEndpoint(port) {
48312
48513
  const sdkEndpoint = await this.sandbox.getEndpoint(port);
48313
48514
  const raw = sdkEndpoint.endpoint;
48314
48515
  const colonIdx = raw.lastIndexOf(":");
@@ -48327,6 +48528,40 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48327
48528
  url: `https://${raw}`
48328
48529
  };
48329
48530
  }
48531
+ async getProxyTarget(service = "code-server") {
48532
+ if (service !== "code-server") {
48533
+ throw new FeatureNotSupportedError(`Proxy service "${service}" is not supported by this provider`, "getProxyTarget", this.provider);
48534
+ }
48535
+ return {
48536
+ service,
48537
+ origin: await this.getDirectEndpointOrigin(OPEN_SANDBOX_EXECD_PORT),
48538
+ basePath: `/proxy/${OPEN_SANDBOX_CODE_SERVER_PORT}`,
48539
+ auth: "code-server"
48540
+ };
48541
+ }
48542
+ async getDirectEndpointOrigin(port) {
48543
+ if (!this.id) {
48544
+ throw new SandboxStateError("Sandbox not initialized. Call create() or connect() first.", "UnExist", "Running");
48545
+ }
48546
+ const headers = {
48547
+ ...this._connection.headers,
48548
+ Accept: "application/json"
48549
+ };
48550
+ const response = await this._connection.fetch(`${this._connection.getBaseUrl()}/sandboxes/${this.id}/endpoints/${port}?use_server_proxy=false`, { method: "GET", headers });
48551
+ if (!response.ok) {
48552
+ throw new ConnectionError(`OpenSandbox endpoint lookup failed: HTTP ${response.status}`, this.connectionConfig.baseUrl);
48553
+ }
48554
+ const data = await response.json();
48555
+ if (!data.endpoint) {
48556
+ throw new ConnectionError("OpenSandbox returned no endpoint", this.connectionConfig.baseUrl);
48557
+ }
48558
+ let hostPort = data.endpoint.replace(/\/proxy\/\d+\/?$/, "");
48559
+ if (this.connectionConfig.replaceDockerInternalWithLocalhost) {
48560
+ hostPort = hostPort.replace(/^host\.docker\.internal\b/, "localhost");
48561
+ }
48562
+ const url = new URL(/^https?:\/\//.test(hostPort) ? hostPort : `http://${hostPort}`);
48563
+ return url.origin;
48564
+ }
48330
48565
  async getInfo() {
48331
48566
  if (!this._sandbox) {
48332
48567
  return null;
@@ -48335,7 +48570,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48335
48570
  const info = await this.sandbox.getInfo();
48336
48571
  return {
48337
48572
  id: info.id,
48338
- image: typeof info.image === "string" ? this.parseImageSpec(info.image) : ("uri" in info.image) ? this.parseImageSpec(info.image.uri) : info.image,
48573
+ image: typeof info.image === "string" ? parseImageSpec(info.image) : ("uri" in info.image) ? parseImageSpec(info.image.uri) : info.image,
48339
48574
  entrypoint: info.entrypoint,
48340
48575
  metadata: info.metadata,
48341
48576
  status: this.mapStatus(info.status),
@@ -48837,7 +49072,7 @@ function createSandbox(provider, config, createConfig) {
48837
49072
  case "opensandbox":
48838
49073
  return new OpenSandboxAdapter(config, createConfig);
48839
49074
  case "sealosdevbox":
48840
- return new SealosDevboxAdapter(config);
49075
+ return new SealosDevboxAdapter(config, createConfig);
48841
49076
  case "e2b":
48842
49077
  return new E2BAdapter(config);
48843
49078
  default:
@@ -2,6 +2,7 @@ import type { ICommandExecution } from './ICommandExecution';
2
2
  import type { IFileSystem } from './IFileSystem';
3
3
  import type { IHealthCheck } from './IHealthCheck';
4
4
  import type { ISandboxLifecycle } from './ISandboxLifecycle';
5
+ import type { Endpoint, SandboxEndpointSelector, SandboxProxyService, SandboxProxyTarget } from '../types';
5
6
  /**
6
7
  * Unified sandbox interface.
7
8
  * Composes all sandbox behaviors into a single interface.
@@ -15,4 +16,8 @@ import type { ISandboxLifecycle } from './ISandboxLifecycle';
15
16
  export interface ISandbox extends ISandboxLifecycle, ICommandExecution, IFileSystem, IHealthCheck {
16
17
  /** Provider name (e.g., 'opensandbox') */
17
18
  readonly provider: string;
19
+ /** Resolve an endpoint exposed by the sandbox provider. */
20
+ getEndpoint(selector: SandboxEndpointSelector): Promise<Endpoint>;
21
+ /** Resolve the upstream target used by FastGPT sandbox-proxy. */
22
+ getProxyTarget(service?: SandboxProxyService): Promise<SandboxProxyTarget>;
18
23
  }
@@ -1,3 +1,3 @@
1
1
  export type { BackgroundExecution, ExecuteOptions, ExecuteResult, OutputMessage, StreamHandlers } from './execution';
2
2
  export type { ContentReplaceEntry, DirectoryEntry, FileDeleteResult, FileInfo, FileReadResult, FileWriteEntry, FileWriteResult, MoveEntry, PermissionEntry, ReadFileOptions, SearchResult } from './filesystem';
3
- export type { Endpoint, ImageSpec, NetworkPolicy, ResourceLimits, SandboxId, SandboxInfo, SandboxMetrics, SandboxState, SandboxStatus } from './sandbox';
3
+ export type { Endpoint, ImageSpec, KubeAccessPolicy, LabelSpec, LifecyclePolicy, NetworkPolicy, ResourceLimits, SandboxCreateSpec, SandboxEndpointSelector, SandboxId, SandboxInfo, SandboxMetrics, SandboxProxyService, SandboxProxyTarget, SandboxState, SandboxStatus } from './sandbox';
@@ -37,6 +37,18 @@ export interface NetworkPolicy {
37
37
  allowEgress?: boolean;
38
38
  allowedHosts?: string[];
39
39
  }
40
+ export interface LabelSpec {
41
+ key: string;
42
+ value: string;
43
+ }
44
+ export interface LifecyclePolicy {
45
+ pauseAt?: string;
46
+ archiveAfterPauseTime?: string;
47
+ }
48
+ export interface KubeAccessPolicy {
49
+ enabled?: boolean;
50
+ roleTemplate?: 'view' | 'edit' | 'admin';
51
+ }
40
52
  /**
41
53
  * Information about a sandbox.
42
54
  */
@@ -69,3 +81,36 @@ export interface Endpoint {
69
81
  protocol: 'http' | 'https';
70
82
  url: string;
71
83
  }
84
+ /**
85
+ * App-facing create spec shared by callers that choose a provider at runtime.
86
+ * Individual adapters should map only the fields their backend actually supports.
87
+ */
88
+ export interface SandboxCreateSpec {
89
+ image?: ImageSpec;
90
+ entrypoint?: string[];
91
+ timeout?: number;
92
+ timeoutSeconds?: number | null;
93
+ resourceLimits?: ResourceLimits;
94
+ env?: Record<string, string>;
95
+ metadata?: Record<string, unknown>;
96
+ labels?: LabelSpec[];
97
+ lifecycle?: LifecyclePolicy;
98
+ kubeAccess?: KubeAccessPolicy;
99
+ networkPolicy?: NetworkPolicy;
100
+ volumes?: unknown[];
101
+ workingDir?: string;
102
+ upstreamID?: string;
103
+ extensions?: Record<string, unknown>;
104
+ skipHealthCheck?: boolean;
105
+ readyTimeoutSeconds?: number;
106
+ healthCheckPollingInterval?: number;
107
+ }
108
+ export type SandboxProxyService = 'code-server';
109
+ export type SandboxEndpointSelector = number | SandboxProxyService;
110
+ export interface SandboxProxyTarget {
111
+ service: SandboxProxyService;
112
+ origin: string;
113
+ basePath: string;
114
+ auth: 'code-server';
115
+ password?: string;
116
+ }
@@ -0,0 +1,3 @@
1
+ import type { ImageSpec } from '@/types';
2
+ export declare function formatImageSpec(image: ImageSpec): string;
3
+ export declare function parseImageSpec(image?: string): ImageSpec;
@@ -0,0 +1,2 @@
1
+ export declare function normalizePathPrefix(path: string): string;
2
+ export declare function joinUrlPath(url: string, path: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastgpt-sdk/sandbox-adapter",
3
- "version": "0.0.36",
3
+ "version": "0.0.38-beta.0",
4
4
  "description": "Unified abstraction layer for cloud sandbox providers with adapter pattern and feature polyfilling",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",