@tangle-network/agent-app 0.21.0 → 0.23.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.
@@ -1,8 +1,191 @@
1
- import { AgentProfileFileMount, AgentProfileMcpServer, AgentProfile, ScopedTokenScope, SandboxInstance, Sandbox } from '@tangle-network/sandbox';
1
+ import { AgentProfileFileMount, AgentProfileMcpServer, AgentProfile, StorageConfig, SandboxInstance, ScopedTokenScope, PromptResult, Sandbox } from '@tangle-network/sandbox';
2
+ export { StorageConfig } from '@tangle-network/sandbox';
2
3
  import { a as AppToolName, c as ToolHeaderNames } from '../auth-BlS9GWfL.js';
3
4
  import { b as AppToolContext } from '../types-2rOJo8Hc.js';
4
5
  import { Harness } from '../harness/index.js';
5
6
 
7
+ interface WorkspaceSandboxInstanceLike {
8
+ id: string;
9
+ name?: string;
10
+ status?: string;
11
+ connection?: {
12
+ runtimeUrl?: string;
13
+ sidecarUrl?: string;
14
+ authToken?: string;
15
+ sidecarToken?: string;
16
+ authTokenExpiresAt?: string;
17
+ } | null;
18
+ }
19
+ interface WorkspaceSandboxEnsureContext {
20
+ workspaceId: string;
21
+ userId: string;
22
+ }
23
+ interface WorkspaceSandboxManagerOptions<TClient, TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void> {
24
+ getClient: (ctx: WorkspaceSandboxEnsureContext) => Promise<TClient> | TClient;
25
+ nameForWorkspace: (workspaceId: string, ctx: WorkspaceSandboxEnsureContext) => string;
26
+ listSandboxes: (client: TClient, ctx: WorkspaceSandboxEnsureContext) => Promise<TBox[]>;
27
+ createSandbox: (args: {
28
+ client: TClient;
29
+ ctx: WorkspaceSandboxEnsureContext;
30
+ name: string;
31
+ options: TEnsureOptions;
32
+ listError?: unknown;
33
+ }) => Promise<TBox>;
34
+ waitForRunning?: (box: TBox, ctx: WorkspaceSandboxEnsureContext) => Promise<void>;
35
+ prepareExisting?: (box: TBox, ctx: WorkspaceSandboxEnsureContext, options: TEnsureOptions) => Promise<TBox | void>;
36
+ prepareCreated?: (box: TBox, ctx: WorkspaceSandboxEnsureContext, options: TEnsureOptions) => Promise<TBox | void>;
37
+ onListError?: (error: unknown, ctx: WorkspaceSandboxEnsureContext) => void;
38
+ }
39
+ interface WorkspaceSandboxManager<TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void> {
40
+ ensureWorkspaceSandbox: (workspaceId: string, userId: string, options?: TEnsureOptions) => Promise<TBox>;
41
+ }
42
+ declare function createWorkspaceSandboxManager<TClient, TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void>(opts: WorkspaceSandboxManagerOptions<TClient, TBox, TEnsureOptions>): WorkspaceSandboxManager<TBox, TEnsureOptions>;
43
+ interface SandboxTerminalTokenOptions {
44
+ secret?: string;
45
+ prefix?: string;
46
+ expiresInMs?: number;
47
+ now?: () => number;
48
+ }
49
+ interface SandboxTerminalTokenSubject {
50
+ userId: string;
51
+ workspaceId: string;
52
+ sandboxId: string;
53
+ }
54
+ interface SandboxTerminalTokenResult {
55
+ token: string;
56
+ expiresAt: Date;
57
+ }
58
+ declare function createSandboxTerminalToken(subject: SandboxTerminalTokenSubject, opts: SandboxTerminalTokenOptions): Promise<SandboxTerminalTokenResult>;
59
+ declare function verifySandboxTerminalToken(token: string, expected: SandboxTerminalTokenSubject, opts: SandboxTerminalTokenOptions): Promise<boolean>;
60
+ interface AuthenticatedSandboxUser {
61
+ id: string;
62
+ }
63
+ interface WorkspaceSandboxConnectionHandlerOptions<TBox extends WorkspaceSandboxInstanceLike> {
64
+ requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>;
65
+ requireWorkspaceAccess: (args: {
66
+ request: Request;
67
+ userId: string;
68
+ workspaceId: string;
69
+ }) => Promise<void>;
70
+ ensureWorkspaceSandbox: (workspaceId: string, userId: string) => Promise<TBox>;
71
+ tokenSecret: string | (() => string | undefined);
72
+ tokenExpiresInMs?: number;
73
+ tokenPrefix?: string;
74
+ proxyRuntimeUrl?: (args: {
75
+ request: Request;
76
+ workspaceId: string;
77
+ sandboxId: string;
78
+ box: TBox;
79
+ }) => string;
80
+ exposeDirectSidecar?: boolean;
81
+ }
82
+ interface WorkspaceSandboxConnectionArgs {
83
+ request: Request;
84
+ params: {
85
+ workspaceId?: string;
86
+ };
87
+ }
88
+ declare function createWorkspaceSandboxConnectionHandler<TBox extends WorkspaceSandboxInstanceLike>(opts: WorkspaceSandboxConnectionHandlerOptions<TBox>): ({ request, params }: WorkspaceSandboxConnectionArgs) => Promise<Response>;
89
+ interface SandboxApiCredentials {
90
+ baseUrl: string;
91
+ apiKey: string;
92
+ }
93
+ interface SandboxRuntimeConnection {
94
+ runtimeUrl: string;
95
+ authToken?: string;
96
+ }
97
+ interface WorkspaceSandboxRuntimeProxyHandlerOptions {
98
+ requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>;
99
+ requireWorkspaceAccess: (args: {
100
+ request: Request;
101
+ userId: string;
102
+ workspaceId: string;
103
+ sandboxId: string;
104
+ }) => Promise<void>;
105
+ getSandboxApiCredentials: (args: {
106
+ request: Request;
107
+ userId: string;
108
+ workspaceId: string;
109
+ sandboxId: string;
110
+ }) => Promise<SandboxApiCredentials>;
111
+ getSandboxRuntimeConnection?: (args: {
112
+ request: Request;
113
+ userId: string;
114
+ workspaceId: string;
115
+ sandboxId: string;
116
+ }) => Promise<SandboxRuntimeConnection | null | undefined>;
117
+ tokenSecret: string | (() => string | undefined);
118
+ tokenPrefix?: string;
119
+ fetch?: typeof fetch;
120
+ forwardHeaders?: string[];
121
+ }
122
+ interface WorkspaceSandboxRuntimeProxyArgs {
123
+ request: Request;
124
+ params: {
125
+ workspaceId?: string;
126
+ sandboxId?: string;
127
+ '*'?: string;
128
+ };
129
+ }
130
+ declare function createWorkspaceSandboxRuntimeProxyHandler(opts: WorkspaceSandboxRuntimeProxyHandlerOptions): ({ request, params }: WorkspaceSandboxRuntimeProxyArgs) => Promise<Response>;
131
+ interface SandboxTerminalWsMatch {
132
+ workspaceId: string;
133
+ sandboxId: string;
134
+ subPath: string;
135
+ }
136
+ /**
137
+ * Parse a same-origin terminal-WS pathname into its parts, or `null` when the
138
+ * path is not a sandbox terminal WebSocket. Matches the default `runtimeUrl`
139
+ * convention emitted by {@link createWorkspaceSandboxConnectionHandler}
140
+ * (`/api/workspaces/:workspaceId/sandbox/runtime/:sandboxId`) with a canonical
141
+ * `terminals/:id/ws` sub-path. `subPath` is left URL-encoded for re-use in the
142
+ * upstream URL; the ids are decoded for auth checks.
143
+ */
144
+ declare function matchSandboxTerminalWsPath(pathname: string): SandboxTerminalWsMatch | null;
145
+ /** True when `request` is a WebSocket upgrade for a sandbox terminal path. */
146
+ declare function isSandboxTerminalWsUpgrade(request: Request): boolean;
147
+ interface WorkspaceSandboxTerminalUpgradeHandlerOptions {
148
+ requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>;
149
+ requireWorkspaceAccess: (args: {
150
+ request: Request;
151
+ userId: string;
152
+ workspaceId: string;
153
+ sandboxId: string;
154
+ }) => Promise<void>;
155
+ getSandboxApiCredentials: (args: {
156
+ request: Request;
157
+ userId: string;
158
+ workspaceId: string;
159
+ sandboxId: string;
160
+ }) => Promise<SandboxApiCredentials>;
161
+ getSandboxRuntimeConnection?: (args: {
162
+ request: Request;
163
+ userId: string;
164
+ workspaceId: string;
165
+ sandboxId: string;
166
+ }) => Promise<SandboxRuntimeConnection | null | undefined>;
167
+ tokenSecret: string | (() => string | undefined);
168
+ tokenPrefix?: string;
169
+ fetch?: typeof fetch;
170
+ }
171
+ /**
172
+ * Build a Worker-entry handler that proxies a sandbox terminal WebSocket
173
+ * upgrade to the sandbox API runtime proxy. Returns `null` when the request is
174
+ * not a terminal WS upgrade, so the caller can fall through to its normal
175
+ * request handler:
176
+ *
177
+ * ```ts
178
+ * const handled = await handleSandboxTerminalUpgrade(request)
179
+ * if (handled) return handled
180
+ * ```
181
+ */
182
+ declare function createWorkspaceSandboxTerminalUpgradeHandler(opts: WorkspaceSandboxTerminalUpgradeHandlerOptions): (request: Request) => Promise<Response | null>;
183
+ declare function buildSandboxRuntimeProxyHeaders(source: Headers, sandboxApiKey: string, forwardHeaders?: string[]): Headers;
184
+ declare function encodeSandboxRuntimePath(runtimePath: string): string | null;
185
+ declare function bearerToken(value: string | null): string | null;
186
+ declare function bearerSubprotocolToken(value: string | null): string | null;
187
+ declare function terminalTokenFromRequest(headers: Headers): string | null;
188
+
6
189
  type Outcome<T> = {
7
190
  succeeded: true;
8
191
  value: T;
@@ -33,6 +216,21 @@ interface ProviderResolutionConfig {
33
216
  interface SandboxBuildContext {
34
217
  workspaceId: string;
35
218
  connectedIntegrationIds: string[];
219
+ userId?: string;
220
+ }
221
+
222
+ interface SandboxScope {
223
+ workspaceId: string;
224
+ userId?: string;
225
+ }
226
+ interface SandboxRestoreSpec {
227
+ fromSnapshot: string;
228
+ fromSandboxId: string;
229
+ }
230
+ interface LivenessProbeConfig {
231
+ sidecarProcessPattern: (harness: Harness) => string;
232
+ execTimeoutMs?: number;
233
+ psTimeoutMs?: number;
36
234
  }
37
235
  interface ProfileComposeOptions {
38
236
  systemPrompt?: string;
@@ -41,7 +239,7 @@ interface ProfileComposeOptions {
41
239
  name?: string;
42
240
  }
43
241
  interface SandboxRuntimeConfig {
44
- credentials: () => SandboxClientCredentials | null;
242
+ credentials: (scope?: SandboxScope) => SandboxClientCredentials | null | Promise<SandboxClientCredentials | null>;
45
243
  name: (workspaceId: string) => string;
46
244
  metadata: (harness: Harness) => Record<string, unknown>;
47
245
  connectedIntegrationIds: (workspaceId: string) => Promise<string[]>;
@@ -52,6 +250,14 @@ interface SandboxRuntimeConfig {
52
250
  permissionRole?: (workspaceRole: string) => SandboxPermissionLevel;
53
251
  resources?: SandboxResourceConfig;
54
252
  provider?: ProviderResolutionConfig;
253
+ storage?: (ctx: SandboxBuildContext) => StorageConfig | undefined;
254
+ restore?: (ctx: SandboxBuildContext) => SandboxRestoreSpec | undefined;
255
+ boxKey?: (scope: SandboxScope) => string;
256
+ childKeyMint?: (scope: SandboxScope) => Promise<Outcome<string>>;
257
+ bootstrap?: (box: SandboxInstance, scope: SandboxScope) => Promise<Outcome<void>>;
258
+ livenessProbe?: LivenessProbeConfig;
259
+ resumeStopped?: boolean;
260
+ backendModelAtCreate?: boolean;
55
261
  }
56
262
  declare const DEFAULT_SANDBOX_RESOURCES: SandboxResourceConfig;
57
263
  declare function getClient(shell: SandboxRuntimeConfig): Sandbox;
@@ -73,6 +279,7 @@ interface EnsureWorkspaceSandboxOptions {
73
279
  workspaceId: string;
74
280
  userId?: string;
75
281
  harness: Harness;
282
+ forceNew?: boolean;
76
283
  }
77
284
  declare function ensureWorkspaceSandbox(shell: SandboxRuntimeConfig, options: EnsureWorkspaceSandboxOptions): Promise<SandboxInstance>;
78
285
  interface ResolvedModel {
@@ -107,6 +314,9 @@ interface StreamSandboxPromptOptions {
107
314
  appToolMcp?: Record<string, AgentProfileMcpServer>;
108
315
  baseProfileMcp?: Record<string, AgentProfileMcpServer>;
109
316
  extraMcp?: Record<string, AgentProfileMcpServer>;
317
+ signal?: AbortSignal;
318
+ timeoutMs?: number;
319
+ disallowQuestions?: boolean;
110
320
  }
111
321
  declare function streamSandboxPrompt(shell: SandboxRuntimeConfig, box: SandboxInstance, message: string, options?: StreamSandboxPromptOptions): AsyncGenerator<unknown>;
112
322
  declare function runSandboxPrompt(shell: SandboxRuntimeConfig, box: SandboxInstance, message: string, options?: StreamSandboxPromptOptions): Promise<string>;
@@ -142,5 +352,28 @@ declare function mintSandboxScopedToken(box: SandboxInstance, options: {
142
352
  sessionId?: string;
143
353
  ttlMinutes?: number;
144
354
  }): Promise<Outcome<ScopedTokenResult>>;
355
+ declare function driveSandboxTurn(shell: SandboxRuntimeConfig, box: SandboxInstance, message: string, options: StreamSandboxPromptOptions & {
356
+ sessionId: string;
357
+ }): Promise<Outcome<PromptResult>>;
358
+ interface TerminalProxyIdentity {
359
+ userId: string;
360
+ workspaceId: string;
361
+ sandboxId: string;
362
+ }
363
+ declare function mintTerminalProxyToken(secret: string, identity: TerminalProxyIdentity, ttlMs?: number): Promise<Outcome<{
364
+ token: string;
365
+ expiresAt: Date;
366
+ }>>;
367
+ declare function verifyTerminalProxyToken(secret: string, token: string, expected: TerminalProxyIdentity): Promise<boolean>;
368
+ type SandboxStepTransition = {
369
+ kind: 'step-start';
370
+ } | {
371
+ kind: 'step-finish';
372
+ reason: string;
373
+ severed: boolean;
374
+ };
375
+ declare function classifySeveredStream(event: unknown): SandboxStepTransition | null;
376
+ declare function isTerminalPromptEvent(event: unknown): boolean;
377
+ declare function detectInteractiveQuestion(event: unknown): string | null;
145
378
 
146
- export { type AppToolDescriptor, type BuildAppToolMcpServersOptions, DEFAULT_SANDBOX_RESOURCES, type EnsureWorkspaceSandboxOptions, type MemberSyncSeam, type Outcome, type ProfileComposeOptions, type ProviderResolutionConfig, type ResolvedModel, type SandboxBuildContext, type SandboxClientCredentials, type SandboxPermissionLevel, type SandboxResourceConfig, type SandboxRuntimeConfig, type ScopedTokenResult, type SecretStore, type StreamSandboxPromptOptions, attachReasoningEffort, buildAppToolMcpServers, deleteSecret, ensureWorkspaceSandbox, flattenHistory, getClient, mergeExtraMcp, mintSandboxScopedToken, readSecret, resetClientCache, resolveModel, runSandboxPrompt, secretStoreFromClient, storeSecret, streamSandboxPrompt, syncSandboxMemberAdd, syncSandboxMemberRemove, syncSandboxMemberRole };
379
+ export { type AppToolDescriptor, type AuthenticatedSandboxUser, type BuildAppToolMcpServersOptions, DEFAULT_SANDBOX_RESOURCES, type EnsureWorkspaceSandboxOptions, type LivenessProbeConfig, type MemberSyncSeam, type Outcome, type ProfileComposeOptions, type ProviderResolutionConfig, type ResolvedModel, type SandboxApiCredentials, type SandboxBuildContext, type SandboxClientCredentials, type SandboxPermissionLevel, type SandboxResourceConfig, type SandboxRestoreSpec, type SandboxRuntimeConfig, type SandboxRuntimeConnection, type SandboxScope, type SandboxStepTransition, type SandboxTerminalTokenOptions, type SandboxTerminalTokenResult, type SandboxTerminalTokenSubject, type SandboxTerminalWsMatch, type ScopedTokenResult, type SecretStore, type StreamSandboxPromptOptions, type TerminalProxyIdentity, type WorkspaceSandboxConnectionArgs, type WorkspaceSandboxConnectionHandlerOptions, type WorkspaceSandboxEnsureContext, type WorkspaceSandboxInstanceLike, type WorkspaceSandboxManager, type WorkspaceSandboxManagerOptions, type WorkspaceSandboxRuntimeProxyArgs, type WorkspaceSandboxRuntimeProxyHandlerOptions, type WorkspaceSandboxTerminalUpgradeHandlerOptions, attachReasoningEffort, bearerSubprotocolToken, bearerToken, buildAppToolMcpServers, buildSandboxRuntimeProxyHeaders, classifySeveredStream, createSandboxTerminalToken, createWorkspaceSandboxConnectionHandler, createWorkspaceSandboxManager, createWorkspaceSandboxRuntimeProxyHandler, createWorkspaceSandboxTerminalUpgradeHandler, deleteSecret, detectInteractiveQuestion, driveSandboxTurn, encodeSandboxRuntimePath, ensureWorkspaceSandbox, flattenHistory, getClient, isSandboxTerminalWsUpgrade, isTerminalPromptEvent, matchSandboxTerminalWsPath, mergeExtraMcp, mintSandboxScopedToken, mintTerminalProxyToken, readSecret, resetClientCache, resolveModel, runSandboxPrompt, secretStoreFromClient, storeSecret, streamSandboxPrompt, syncSandboxMemberAdd, syncSandboxMemberRemove, syncSandboxMemberRole, terminalTokenFromRequest, verifySandboxTerminalToken, verifyTerminalProxyToken };
@@ -1,299 +1,73 @@
1
1
  import {
2
- assertHarnessModelCompatible
3
- } from "../chunk-5VXPDXZJ.js";
2
+ DEFAULT_SANDBOX_RESOURCES,
3
+ attachReasoningEffort,
4
+ bearerSubprotocolToken,
5
+ bearerToken,
6
+ buildAppToolMcpServers,
7
+ buildSandboxRuntimeProxyHeaders,
8
+ classifySeveredStream,
9
+ createSandboxTerminalToken,
10
+ createWorkspaceSandboxConnectionHandler,
11
+ createWorkspaceSandboxManager,
12
+ createWorkspaceSandboxRuntimeProxyHandler,
13
+ createWorkspaceSandboxTerminalUpgradeHandler,
14
+ deleteSecret,
15
+ detectInteractiveQuestion,
16
+ driveSandboxTurn,
17
+ encodeSandboxRuntimePath,
18
+ ensureWorkspaceSandbox,
19
+ flattenHistory,
20
+ getClient,
21
+ isSandboxTerminalWsUpgrade,
22
+ isTerminalPromptEvent,
23
+ matchSandboxTerminalWsPath,
24
+ mergeExtraMcp,
25
+ mintSandboxScopedToken,
26
+ mintTerminalProxyToken,
27
+ readSecret,
28
+ resetClientCache,
29
+ resolveModel,
30
+ runSandboxPrompt,
31
+ secretStoreFromClient,
32
+ storeSecret,
33
+ streamSandboxPrompt,
34
+ syncSandboxMemberAdd,
35
+ syncSandboxMemberRemove,
36
+ syncSandboxMemberRole,
37
+ terminalTokenFromRequest,
38
+ verifySandboxTerminalToken,
39
+ verifyTerminalProxyToken
40
+ } from "../chunk-XDCHKFBX.js";
41
+ import "../chunk-5VXPDXZJ.js";
4
42
  import "../chunk-MH6AVXQ7.js";
5
- import {
6
- buildAppToolMcpServer
7
- } from "../chunk-A76ZHWNF.js";
43
+ import "../chunk-A76ZHWNF.js";
8
44
  import "../chunk-JZZ6AWF4.js";
9
-
10
- // src/sandbox/index.ts
11
- import {
12
- Sandbox
13
- } from "@tangle-network/sandbox";
14
- var ok = (value) => ({ succeeded: true, value });
15
- var fail = (error) => ({
16
- succeeded: false,
17
- error: error instanceof Error ? error : new Error(String(error))
18
- });
19
- var DEFAULT_SANDBOX_RESOURCES = {
20
- image: "universal",
21
- cpuCores: 2,
22
- memoryMB: 4096,
23
- diskGB: 10,
24
- maxLifetimeSeconds: 86400,
25
- idleTimeoutSeconds: 3600
26
- };
27
- var _cached = null;
28
- function getClient(shell) {
29
- const creds = shell.credentials();
30
- if (!creds) throw new Error("sandbox credentials are required (apiKey/baseUrl)");
31
- const fingerprint = `${creds.apiKey} ${creds.baseUrl}`;
32
- if (_cached && _cached.fingerprint === fingerprint) return _cached.client;
33
- const client = new Sandbox({ apiKey: creds.apiKey, baseUrl: creds.baseUrl });
34
- _cached = { client, fingerprint };
35
- return client;
36
- }
37
- function resetClientCache() {
38
- _cached = null;
39
- }
40
- function buildAppToolMcpServers(options) {
41
- const entries = {};
42
- for (const { tool, key, description } of options.tools) {
43
- entries[key] = buildAppToolMcpServer({
44
- tool,
45
- baseUrl: options.baseUrl,
46
- token: options.token,
47
- ctx: options.ctx,
48
- description,
49
- headerNames: options.headerNames
50
- });
51
- }
52
- return entries;
53
- }
54
- async function listRunning(client, name) {
55
- try {
56
- const running = await client.list({ status: "running" });
57
- return ok(running.find((s) => s.name === name) ?? null);
58
- } catch (err) {
59
- return fail(err);
60
- }
61
- }
62
- async function deleteBox(box) {
63
- try {
64
- await box.delete();
65
- return ok(void 0);
66
- } catch (err) {
67
- return fail(err);
68
- }
69
- }
70
- async function ensureWorkspaceSandbox(shell, options) {
71
- const { workspaceId, userId, harness } = options;
72
- const client = getClient(shell);
73
- const name = shell.name(workspaceId);
74
- const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES;
75
- const existing = await listRunning(client, name);
76
- if (existing.succeeded && existing.value) {
77
- const found = existing.value;
78
- if (found.metadata?.harness === harness) return found;
79
- const dropped = await deleteBox(found);
80
- if (!dropped.succeeded) {
81
- throw new Error(
82
- `harness-mismatched sandbox ${name} (was ${String(found.metadata?.harness ?? "unknown")}, want ${harness}) could not be deleted`,
83
- { cause: dropped.error }
84
- );
85
- }
86
- }
87
- const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId);
88
- const buildCtx = { workspaceId, connectedIntegrationIds };
89
- const [secrets, env, files] = await Promise.all([
90
- shell.secrets(workspaceId),
91
- shell.env(buildCtx),
92
- shell.files(buildCtx)
93
- ]);
94
- const profile = shell.profile({ extraFiles: files });
95
- const role = userId && shell.permissionRole ? shell.permissionRole("developer") : void 0;
96
- const payload = {
97
- name,
98
- image: resources.image,
99
- metadata: shell.metadata(harness),
100
- ...userId ? { permissions: { initialUsers: [{ userId, role }] } } : {},
101
- env,
102
- secrets,
103
- backend: { type: harness, profile },
104
- maxLifetimeSeconds: resources.maxLifetimeSeconds,
105
- idleTimeoutSeconds: resources.idleTimeoutSeconds,
106
- resources: {
107
- cpuCores: resources.cpuCores,
108
- memoryMB: resources.memoryMB,
109
- diskGB: resources.diskGB
110
- }
111
- };
112
- const box = await client.create(payload);
113
- await box.waitFor("running", { timeoutMs: 12e4 });
114
- if (!box.connection?.runtimeUrl) await box.refresh();
115
- return box;
116
- }
117
- function resolveModel(config, override) {
118
- const c = config ?? {};
119
- const explicitBaseUrl = c.routerBaseUrl;
120
- const explicitApiKey = override?.modelApiKey ?? c.apiKey;
121
- const provider = c.providerName ?? (explicitApiKey ? "openai-compat" : c.openaiApiKey ? "openai" : void 0);
122
- const modelName = override?.model ?? c.modelName ?? (provider === "openai" || provider === "openai-compat" ? c.defaultModel : void 0);
123
- const apiKey = explicitApiKey ?? (provider === "openai" ? c.openaiApiKey : void 0);
124
- if (!provider || !modelName || !apiKey) return void 0;
125
- return {
126
- model: modelName,
127
- provider,
128
- apiKey,
129
- ...explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}
130
- };
131
- }
132
- function flattenHistory(message, history) {
133
- if (!history?.length) return message;
134
- const transcript = history.map((entry) => `${entry.role === "assistant" ? "Assistant" : "User"}: ${entry.content}`).join("\n\n");
135
- return `${transcript}
136
-
137
- User: ${message}`;
138
- }
139
- function mergeExtraMcp(appToolMcp, baseProfileMcp, extra) {
140
- for (const key of Object.keys(extra ?? {})) {
141
- if (key in appToolMcp || key in baseProfileMcp) {
142
- throw new Error(`extraMcp key '${key}' collides with an existing profile MCP server`);
143
- }
144
- }
145
- return { ...appToolMcp, ...extra ?? {} };
146
- }
147
- function attachReasoningEffort(profile, harness, effort) {
148
- if (!effort || effort === "auto") return profile;
149
- return {
150
- ...profile,
151
- extensions: {
152
- ...profile.extensions ?? {},
153
- [harness]: {
154
- ...profile.extensions?.[harness] ?? {},
155
- reasoningEffort: effort
156
- }
157
- }
158
- };
159
- }
160
- async function* streamSandboxPrompt(shell, box, message, options) {
161
- const harness = options?.harness ?? "opencode";
162
- const model = resolveModel(shell.provider, {
163
- model: options?.model,
164
- modelApiKey: options?.modelApiKey
165
- });
166
- if (model?.model) assertHarnessModelCompatible(harness, model.model);
167
- const prompt = flattenHistory(message, options?.history);
168
- const appToolMcp = options?.appToolMcp ?? {};
169
- const extraMcp = mergeExtraMcp(appToolMcp, options?.baseProfileMcp ?? {}, options?.extraMcp);
170
- const profile = shell.profile({ systemPrompt: options?.systemPrompt, extraMcp });
171
- const profileWithEffort = attachReasoningEffort(profile, harness, options?.effort);
172
- const stream = box.streamPrompt(prompt, {
173
- sessionId: options?.sessionId,
174
- executionId: options?.executionId,
175
- lastEventId: options?.lastEventId,
176
- backend: {
177
- type: harness,
178
- profile: profileWithEffort,
179
- ...model ? { model } : {}
180
- }
181
- });
182
- for await (const event of stream) yield event;
183
- }
184
- async function runSandboxPrompt(shell, box, message, options) {
185
- let fullText = "";
186
- let firstTextSeen = false;
187
- for await (const rawEvent of streamSandboxPrompt(shell, box, message, options)) {
188
- const event = rawEvent;
189
- if (!event.type) continue;
190
- if (event.type === "message.part.updated") {
191
- const part = event.data?.part;
192
- const delta = typeof event.data?.delta === "string" ? event.data.delta : null;
193
- if (String(part?.type ?? "") === "text") {
194
- if (!firstTextSeen) {
195
- firstTextSeen = true;
196
- continue;
197
- }
198
- if (delta) fullText += delta;
199
- else if (typeof part?.text === "string") fullText = part.text;
200
- }
201
- } else if (event.type === "result") {
202
- const finalText = typeof event.data?.finalText === "string" ? event.data.finalText : null;
203
- if (finalText) fullText = finalText;
204
- }
205
- }
206
- return fullText;
207
- }
208
- async function syncSandboxMemberAdd(box, seam, userId, role) {
209
- try {
210
- await box.permissions.add({ userId, role: seam.roleToSandboxRole(role) });
211
- return ok(void 0);
212
- } catch (err) {
213
- return fail(err);
214
- }
215
- }
216
- async function syncSandboxMemberRemove(box, userId) {
217
- try {
218
- await box.permissions.remove(userId, { preserveHomeDir: true });
219
- return ok(void 0);
220
- } catch (err) {
221
- return fail(err);
222
- }
223
- }
224
- async function syncSandboxMemberRole(box, seam, userId, role) {
225
- try {
226
- await box.permissions.update(userId, { role: seam.roleToSandboxRole(role) });
227
- return ok(void 0);
228
- } catch (err) {
229
- return fail(err);
230
- }
231
- }
232
- function secretStoreFromClient(shell) {
233
- const client = getClient(shell);
234
- return {
235
- create: async (name, value) => {
236
- await client.secrets.create(name, value);
237
- },
238
- update: async (name, value) => {
239
- await client.secrets.update(name, value);
240
- },
241
- get: (name) => client.secrets.get(name),
242
- delete: async (name) => {
243
- await client.secrets.delete(name);
244
- }
245
- };
246
- }
247
- async function storeSecret(store, name, value) {
248
- try {
249
- await store.create(name, value);
250
- return ok(void 0);
251
- } catch {
252
- try {
253
- await store.update(name, value);
254
- return ok(void 0);
255
- } catch (err) {
256
- return fail(new Error(`Failed to store sandbox secret ${name}`, { cause: err }));
257
- }
258
- }
259
- }
260
- async function readSecret(store, name) {
261
- try {
262
- return ok(await store.get(name));
263
- } catch (err) {
264
- return fail(err);
265
- }
266
- }
267
- async function deleteSecret(store, name) {
268
- try {
269
- await store.delete(name);
270
- return ok(void 0);
271
- } catch (err) {
272
- return fail(err);
273
- }
274
- }
275
- async function mintSandboxScopedToken(box, options) {
276
- try {
277
- const token = await box.mintScopedToken({
278
- scope: options.scope,
279
- ...options.sessionId ? { sessionId: options.sessionId } : {},
280
- ...options.ttlMinutes ? { ttlMinutes: options.ttlMinutes } : {}
281
- });
282
- return ok({ token: token.token, expiresAt: token.expiresAt, scope: token.scope });
283
- } catch (err) {
284
- return fail(err);
285
- }
286
- }
287
45
  export {
288
46
  DEFAULT_SANDBOX_RESOURCES,
289
47
  attachReasoningEffort,
48
+ bearerSubprotocolToken,
49
+ bearerToken,
290
50
  buildAppToolMcpServers,
51
+ buildSandboxRuntimeProxyHeaders,
52
+ classifySeveredStream,
53
+ createSandboxTerminalToken,
54
+ createWorkspaceSandboxConnectionHandler,
55
+ createWorkspaceSandboxManager,
56
+ createWorkspaceSandboxRuntimeProxyHandler,
57
+ createWorkspaceSandboxTerminalUpgradeHandler,
291
58
  deleteSecret,
59
+ detectInteractiveQuestion,
60
+ driveSandboxTurn,
61
+ encodeSandboxRuntimePath,
292
62
  ensureWorkspaceSandbox,
293
63
  flattenHistory,
294
64
  getClient,
65
+ isSandboxTerminalWsUpgrade,
66
+ isTerminalPromptEvent,
67
+ matchSandboxTerminalWsPath,
295
68
  mergeExtraMcp,
296
69
  mintSandboxScopedToken,
70
+ mintTerminalProxyToken,
297
71
  readSecret,
298
72
  resetClientCache,
299
73
  resolveModel,
@@ -303,6 +77,9 @@ export {
303
77
  streamSandboxPrompt,
304
78
  syncSandboxMemberAdd,
305
79
  syncSandboxMemberRemove,
306
- syncSandboxMemberRole
80
+ syncSandboxMemberRole,
81
+ terminalTokenFromRequest,
82
+ verifySandboxTerminalToken,
83
+ verifyTerminalProxyToken
307
84
  };
308
85
  //# sourceMappingURL=index.js.map