@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.
- package/dist/chunk-XDCHKFBX.js +897 -0
- package/dist/chunk-XDCHKFBX.js.map +1 -0
- package/dist/design-canvas-react/index.d.ts +89 -1
- package/dist/design-canvas-react/index.js +352 -26
- package/dist/design-canvas-react/index.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +78 -0
- package/dist/sandbox/index.d.ts +236 -3
- package/dist/sandbox/index.js +61 -284
- package/dist/sandbox/index.js.map +1 -1
- package/dist/web-react/index.d.ts +62 -1
- package/dist/web-react/index.js +435 -142
- package/dist/web-react/index.js.map +1 -1
- package/package.json +6 -1
package/dist/sandbox/index.d.ts
CHANGED
|
@@ -1,8 +1,191 @@
|
|
|
1
|
-
import { AgentProfileFileMount, AgentProfileMcpServer, AgentProfile,
|
|
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 };
|
package/dist/sandbox/index.js
CHANGED
|
@@ -1,299 +1,73 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
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
|