@tangle-network/agent-app 0.16.1 → 0.19.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/{mcp-eZCmkgCF.d.ts → auth-BlS9GWfL.d.ts} +1 -51
- package/dist/chunk-KOG473C4.js +132 -0
- package/dist/chunk-KOG473C4.js.map +1 -0
- package/dist/design-canvas/index.d.ts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +100 -100
- package/dist/mcp-BShTlESm.d.ts +54 -0
- package/dist/model-resolution/index.d.ts +83 -0
- package/dist/model-resolution/index.js +123 -0
- package/dist/model-resolution/index.js.map +1 -0
- package/dist/platform/index.d.ts +71 -1
- package/dist/platform/index.js +55 -0
- package/dist/platform/index.js.map +1 -1
- package/dist/profile/index.d.ts +145 -0
- package/dist/profile/index.js +63 -0
- package/dist/profile/index.js.map +1 -0
- package/dist/prompt/index.d.ts +77 -0
- package/dist/prompt/index.js +22 -0
- package/dist/prompt/index.js.map +1 -0
- package/dist/run/index.d.ts +64 -0
- package/dist/run/index.js +30 -0
- package/dist/run/index.js.map +1 -0
- package/dist/runtime/index.d.ts +2 -1
- package/dist/sandbox/index.d.ts +146 -0
- package/dist/sandbox/index.js +304 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sequences/index.d.ts +2 -1
- package/dist/skills/index.d.ts +136 -0
- package/dist/skills/index.js +15 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/tools/index.d.ts +3 -2
- package/dist/web-react/index.d.ts +37 -1
- package/dist/web-react/index.js +199 -122
- package/dist/web-react/index.js.map +1 -1
- package/package.json +37 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/prompt/index.ts"],"sourcesContent":["/**\n * System-prompt assembler for agent products.\n *\n * Every agent product composes its system prompt the same way: a base profile\n * prompt (the operator persona + tools block + any skills section the consumer\n * already rendered), an always-on operating directive, then an ordered list of\n * optional per-turn context sections (known-context, board, approval history,\n * learned-style, pending questions, the active artifact). The ORDERING and the\n * whitespace contract are identical across products; only the section BODIES are\n * domain. This module owns the ordering and the joins; the product injects every\n * body as an already-rendered string through the `sections` array.\n *\n * Whitespace contract (preserves the join/concat/trim algebra of the per-product\n * pre-lift composers — a product adopting this asserts byte-for-byte parity in\n * its own suite):\n * - base is emitted verbatim, with no leading/trailing normalization.\n * - directive is appended after base with a single `\\n\\n` join.\n * - each section in `sections` is appended with NO separator: a section is\n * either '' (absent — contributes nothing) or already carries its own\n * leading `\\n\\n` (and its `## ` heading). The assembler concatenates them\n * unconditionally, which is why the conditional-prefix-or-empty contract\n * lives in the product's section renderers, not here.\n * - `trim` (default false) applies a final `.trim()` to the whole result.\n * Branches that historically trimmed pass `trim: true`; branches that did\n * not (e.g. the new-workspace paths) leave it false, preserving that\n * asymmetry rather than silently changing trailing whitespace.\n *\n * Pure string composition: no SDK runtime symbol, no node builtins, no glob.\n * The base profile prompt and the skills-section insertion point both live\n * INSIDE the product-built `base` string — the assembler never reaches into an\n * AgentProfile and never loads a corpus. The sibling\n * `@tangle-network/agent-app/skills` subpath loads the corpus and returns file\n * mounts (`AgentProfileFileMount[]`); the PRODUCT renders any `## Skills` text\n * section and folds it into `base` before calling this assembler. This module\n * never renders a skills heading.\n */\n\n/** Inputs to {@link assembleSystemPrompt}. */\nexport interface AssembleSystemPromptInput {\n /** The product's already-composed base block: persona/system prompt + tools\n * block + (optionally) the rendered skills section. The product is\n * responsible for resolving its profile system prompt and failing loud if it\n * is absent — an empty base reaches this assembler only as a programmer\n * error, which it rejects (see {@link AssembleResult}). */\n base: string\n /** The always-on operating directive, placed immediately after base with a\n * `\\n\\n` join. Pass '' to omit it (the join is then suppressed). */\n directive?: string\n /** Ordered per-turn context sections, each already rendered by the product to\n * either '' (absent) or a `\\n\\n## …`-prefixed string. Concatenated in order\n * with no added separator. */\n sections?: string[]\n /** Apply a final `.trim()` to the composed result. Default false — set true\n * only on branches whose pre-lift output was trimmed. */\n trim?: boolean\n}\n\n/** Typed outcome of {@link assembleSystemPrompt}. `succeeded: false` is returned\n * for a programmer error (an empty base) rather than emitting a roleless\n * prompt — callers MUST inspect `succeeded` before using `prompt`. */\nexport type AssembleResult =\n | { succeeded: true; prompt: string }\n | { succeeded: false; error: string }\n\n/** True when a string is empty or whitespace-only. */\nfunction isBlank(value: string): boolean {\n return value.trim().length === 0\n}\n\n/**\n * Assemble a system prompt from a base block, an operating directive, and an\n * ordered list of pre-rendered context sections.\n *\n * Returns a typed outcome: an empty/blank `base` is a defect (an agent with no\n * persona/system prompt), so it fails loud instead of silently producing a\n * prompt with no role. The product resolves and validates its profile prompt\n * upstream; this is the last-line guard at the seam.\n */\nexport function assembleSystemPrompt(input: AssembleSystemPromptInput): AssembleResult {\n const { base, directive = '', sections = [], trim = false } = input\n\n if (isBlank(base)) {\n return {\n succeeded: false,\n error: 'assembleSystemPrompt: base is empty — a system prompt with no persona/base block is a defect, not a default',\n }\n }\n\n let prompt = directive.length > 0 ? `${base}\\n\\n${directive}` : base\n for (const section of sections) prompt += section\n\n return { succeeded: true, prompt: trim ? prompt.trim() : prompt }\n}"],"mappings":";AAiEA,SAAS,QAAQ,OAAwB;AACvC,SAAO,MAAM,KAAK,EAAE,WAAW;AACjC;AAWO,SAAS,qBAAqB,OAAkD;AACrF,QAAM,EAAE,MAAM,YAAY,IAAI,WAAW,CAAC,GAAG,OAAO,MAAM,IAAI;AAE9D,MAAI,QAAQ,IAAI,GAAG;AACjB,WAAO;AAAA,MACL,WAAW;AAAA,MACX,OAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,SAAS,UAAU,SAAS,IAAI,GAAG,IAAI;AAAA;AAAA,EAAO,SAAS,KAAK;AAChE,aAAW,WAAW,SAAU,WAAU;AAE1C,SAAO,EAAE,WAAW,MAAM,QAAQ,OAAO,OAAO,KAAK,IAAI,OAAO;AAClE;","names":[]}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Harness } from '../harness/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Execution-mode dispatch — the shell entry that infers *how* to run an agent
|
|
5
|
+
* from its profile's harness, so a product hands over one profile and the
|
|
6
|
+
* framework routes to the router tool loop or a sandbox without separate wiring.
|
|
7
|
+
*
|
|
8
|
+
* The discriminator is the harness: absent / null / 'router' => the router tool
|
|
9
|
+
* agent (`@tangle-network/agent-app/runtime`); any member of `KNOWN_HARNESSES`
|
|
10
|
+
* (opencode, claude-code, …) => a sandbox (`@tangle-network/agent-app/sandbox`).
|
|
11
|
+
* `KNOWN_HARNESSES` is exactly the set of sandbox backends; the *absence* of a
|
|
12
|
+
* harness is the router signal.
|
|
13
|
+
*
|
|
14
|
+
* `runAgent` owns the inference + routing; the two branch runners are injected,
|
|
15
|
+
* because their inputs and event shapes legitimately differ (the router loop
|
|
16
|
+
* yields `LoopEvent`s, the sandbox yields its own events). A product supplies a
|
|
17
|
+
* `router`/`sandbox` thunk and can lazy-import the sandbox driver inside its own
|
|
18
|
+
* thunk, so a router-only app never resolves `@tangle-network/sandbox`.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
type ExecutionMode = 'router' | 'sandbox';
|
|
22
|
+
/** The router pseudo-harness — the absence of a sandbox backend. Not a member
|
|
23
|
+
* of `KNOWN_HARNESSES`; callers may pass it explicitly instead of null. */
|
|
24
|
+
declare const ROUTER_HARNESS: "router";
|
|
25
|
+
type RouterHarness = typeof ROUTER_HARNESS;
|
|
26
|
+
type ProfileHarness = Harness | RouterHarness | null | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Infer the execution mode from a profile's harness. Absent / null / 'router'
|
|
29
|
+
* => 'router'; a known sandbox harness => 'sandbox'. An unrecognized non-null
|
|
30
|
+
* string is treated as a sandbox backend (the box installs all harnesses, so an
|
|
31
|
+
* unknown id is a sandbox the runtime resolves, not a router) — callers that
|
|
32
|
+
* want strictness can validate against `KNOWN_HARNESSES` first.
|
|
33
|
+
*/
|
|
34
|
+
declare function resolveExecutionMode(harness: ProfileHarness): ExecutionMode;
|
|
35
|
+
/** True when `harness` names a sandbox backend the SDK knows about. */
|
|
36
|
+
declare function isKnownSandboxHarness(harness: ProfileHarness): harness is Harness;
|
|
37
|
+
/**
|
|
38
|
+
* The superset the dispatch reads: the SDK `AgentProfile` plus the harness
|
|
39
|
+
* discriminator. Intentionally pins only `harness` — the rest of the profile is
|
|
40
|
+
* carried opaquely so this module stays free of the SDK type (router-only apps
|
|
41
|
+
* import it without `@tangle-network/sandbox`).
|
|
42
|
+
*/
|
|
43
|
+
interface ShellProfile {
|
|
44
|
+
harness?: ProfileHarness;
|
|
45
|
+
}
|
|
46
|
+
/** Execution mode for a profile — `harness` omitted/null => router. */
|
|
47
|
+
declare function executionModeForProfile(profile: ShellProfile): ExecutionMode;
|
|
48
|
+
/** The two branch runners. Each returns (or resolves to) an async iterable of
|
|
49
|
+
* the product's own event type — the shapes differ, so the product owns them.
|
|
50
|
+
* A `sandbox` thunk can `await import('@tangle-network/agent-app/sandbox')`
|
|
51
|
+
* internally so the SDK is pulled only on the sandbox path. */
|
|
52
|
+
interface RunAgentBranches<T> {
|
|
53
|
+
router: () => AsyncIterable<T> | Promise<AsyncIterable<T>>;
|
|
54
|
+
sandbox: () => AsyncIterable<T> | Promise<AsyncIterable<T>>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Route a turn to the branch the harness selects and stream its events through.
|
|
58
|
+
* The shell does the inference; the product supplies how each branch runs. The
|
|
59
|
+
* unselected branch's thunk is never invoked — so its dependencies (e.g. the
|
|
60
|
+
* sandbox SDK) are never loaded on the other path.
|
|
61
|
+
*/
|
|
62
|
+
declare function runAgent<T>(harness: ProfileHarness, branches: RunAgentBranches<T>): AsyncGenerator<T>;
|
|
63
|
+
|
|
64
|
+
export { type ExecutionMode, type ProfileHarness, ROUTER_HARNESS, type RouterHarness, type RunAgentBranches, type ShellProfile, executionModeForProfile, isKnownSandboxHarness, resolveExecutionMode, runAgent };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
KNOWN_HARNESSES
|
|
3
|
+
} from "../chunk-SD2H4FWY.js";
|
|
4
|
+
|
|
5
|
+
// src/run/index.ts
|
|
6
|
+
var ROUTER_HARNESS = "router";
|
|
7
|
+
function resolveExecutionMode(harness) {
|
|
8
|
+
if (harness == null || harness === ROUTER_HARNESS) return "router";
|
|
9
|
+
return "sandbox";
|
|
10
|
+
}
|
|
11
|
+
function isKnownSandboxHarness(harness) {
|
|
12
|
+
return harness != null && harness !== ROUTER_HARNESS && KNOWN_HARNESSES.includes(harness);
|
|
13
|
+
}
|
|
14
|
+
function executionModeForProfile(profile) {
|
|
15
|
+
return resolveExecutionMode(profile.harness);
|
|
16
|
+
}
|
|
17
|
+
async function* runAgent(harness, branches) {
|
|
18
|
+
const mode = resolveExecutionMode(harness);
|
|
19
|
+
const source = mode === "sandbox" ? branches.sandbox() : branches.router();
|
|
20
|
+
const iterable = await source;
|
|
21
|
+
for await (const event of iterable) yield event;
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
ROUTER_HARNESS,
|
|
25
|
+
executionModeForProfile,
|
|
26
|
+
isKnownSandboxHarness,
|
|
27
|
+
resolveExecutionMode,
|
|
28
|
+
runAgent
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/run/index.ts"],"sourcesContent":["/**\n * Execution-mode dispatch — the shell entry that infers *how* to run an agent\n * from its profile's harness, so a product hands over one profile and the\n * framework routes to the router tool loop or a sandbox without separate wiring.\n *\n * The discriminator is the harness: absent / null / 'router' => the router tool\n * agent (`@tangle-network/agent-app/runtime`); any member of `KNOWN_HARNESSES`\n * (opencode, claude-code, …) => a sandbox (`@tangle-network/agent-app/sandbox`).\n * `KNOWN_HARNESSES` is exactly the set of sandbox backends; the *absence* of a\n * harness is the router signal.\n *\n * `runAgent` owns the inference + routing; the two branch runners are injected,\n * because their inputs and event shapes legitimately differ (the router loop\n * yields `LoopEvent`s, the sandbox yields its own events). A product supplies a\n * `router`/`sandbox` thunk and can lazy-import the sandbox driver inside its own\n * thunk, so a router-only app never resolves `@tangle-network/sandbox`.\n */\n\nimport { KNOWN_HARNESSES, type Harness } from '../harness/index'\n\nexport type ExecutionMode = 'router' | 'sandbox'\n\n/** The router pseudo-harness — the absence of a sandbox backend. Not a member\n * of `KNOWN_HARNESSES`; callers may pass it explicitly instead of null. */\nexport const ROUTER_HARNESS = 'router' as const\nexport type RouterHarness = typeof ROUTER_HARNESS\n\nexport type ProfileHarness = Harness | RouterHarness | null | undefined\n\n/**\n * Infer the execution mode from a profile's harness. Absent / null / 'router'\n * => 'router'; a known sandbox harness => 'sandbox'. An unrecognized non-null\n * string is treated as a sandbox backend (the box installs all harnesses, so an\n * unknown id is a sandbox the runtime resolves, not a router) — callers that\n * want strictness can validate against `KNOWN_HARNESSES` first.\n */\nexport function resolveExecutionMode(harness: ProfileHarness): ExecutionMode {\n if (harness == null || harness === ROUTER_HARNESS) return 'router'\n return 'sandbox'\n}\n\n/** True when `harness` names a sandbox backend the SDK knows about. */\nexport function isKnownSandboxHarness(harness: ProfileHarness): harness is Harness {\n return harness != null && harness !== ROUTER_HARNESS && (KNOWN_HARNESSES as readonly string[]).includes(harness)\n}\n\n/**\n * The superset the dispatch reads: the SDK `AgentProfile` plus the harness\n * discriminator. Intentionally pins only `harness` — the rest of the profile is\n * carried opaquely so this module stays free of the SDK type (router-only apps\n * import it without `@tangle-network/sandbox`).\n */\nexport interface ShellProfile {\n harness?: ProfileHarness\n}\n\n/** Execution mode for a profile — `harness` omitted/null => router. */\nexport function executionModeForProfile(profile: ShellProfile): ExecutionMode {\n return resolveExecutionMode(profile.harness)\n}\n\n/** The two branch runners. Each returns (or resolves to) an async iterable of\n * the product's own event type — the shapes differ, so the product owns them.\n * A `sandbox` thunk can `await import('@tangle-network/agent-app/sandbox')`\n * internally so the SDK is pulled only on the sandbox path. */\nexport interface RunAgentBranches<T> {\n router: () => AsyncIterable<T> | Promise<AsyncIterable<T>>\n sandbox: () => AsyncIterable<T> | Promise<AsyncIterable<T>>\n}\n\n/**\n * Route a turn to the branch the harness selects and stream its events through.\n * The shell does the inference; the product supplies how each branch runs. The\n * unselected branch's thunk is never invoked — so its dependencies (e.g. the\n * sandbox SDK) are never loaded on the other path.\n */\nexport async function* runAgent<T>(\n harness: ProfileHarness,\n branches: RunAgentBranches<T>,\n): AsyncGenerator<T> {\n const mode = resolveExecutionMode(harness)\n const source = mode === 'sandbox' ? branches.sandbox() : branches.router()\n const iterable = await source\n for await (const event of iterable) yield event\n}\n"],"mappings":";;;;;AAwBO,IAAM,iBAAiB;AAYvB,SAAS,qBAAqB,SAAwC;AAC3E,MAAI,WAAW,QAAQ,YAAY,eAAgB,QAAO;AAC1D,SAAO;AACT;AAGO,SAAS,sBAAsB,SAA6C;AACjF,SAAO,WAAW,QAAQ,YAAY,kBAAmB,gBAAsC,SAAS,OAAO;AACjH;AAaO,SAAS,wBAAwB,SAAsC;AAC5E,SAAO,qBAAqB,QAAQ,OAAO;AAC7C;AAiBA,gBAAuB,SACrB,SACA,UACmB;AACnB,QAAM,OAAO,qBAAqB,OAAO;AACzC,QAAM,SAAS,SAAS,YAAY,SAAS,QAAQ,IAAI,SAAS,OAAO;AACzE,QAAM,WAAW,MAAM;AACvB,mBAAiB,SAAS,SAAU,OAAM;AAC5C;","names":[]}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ export { C as CatalogModel, M as ModelCatalog, R as RouterModel, _ as __resetCat
|
|
|
5
5
|
export { C as CreateTangleRouterModelConfigOptions, D as DEFAULT_TANGLE_BILLING_ENFORCEMENT_ENV_VAR, a as DEFAULT_TANGLE_ROUTER_BASE_URL, R as ResolveModelOptions, b as ResolveUserTangleExecutionKeyForUserOptions, c as ResolveUserTangleExecutionKeyOptions, d as ResolvedTangleExecutionKey, T as TangleBillingEnforcementOptions, e as TangleExecutionEnvironment, f as TangleExecutionKeyError, g as TangleExecutionKeyErrorCode, h as TangleExecutionKeyHttpError, i as TangleExecutionKeySource, j as TangleModelConfig, k as createTangleRouterModelConfig, l as isTangleBillingEnforcementDisabled, m as isTangleExecutionKeyError, r as resolveTangleExecutionEnvironment, n as resolveTangleModelConfig, o as resolveUserTangleExecutionKey, p as resolveUserTangleExecutionKeyForUser, t as tangleExecutionKeyHttpError } from '../model-CKzniMMr.js';
|
|
6
6
|
import { b as AppToolContext, e as AppToolProducedEvent, f as AppToolTaxonomy, c as AppToolHandlers, d as AppToolOutcome } from '../types-2rOJo8Hc.js';
|
|
7
7
|
import { CertifiedProfile } from '@tangle-network/agent-runtime/intelligence';
|
|
8
|
-
import {
|
|
8
|
+
import { A as AppToolMcpServer } from '../mcp-BShTlESm.js';
|
|
9
|
+
import '../auth-BlS9GWfL.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* OpenAI-compatible stream → `LoopEvent` adapter, for NON-sandbox copilots.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { AgentProfileFileMount, AgentProfileMcpServer, AgentProfile, ScopedTokenScope, SandboxInstance, Sandbox } from '@tangle-network/sandbox';
|
|
2
|
+
import { a as AppToolName, c as ToolHeaderNames } from '../auth-BlS9GWfL.js';
|
|
3
|
+
import { b as AppToolContext } from '../types-2rOJo8Hc.js';
|
|
4
|
+
import { Harness } from '../harness/index.js';
|
|
5
|
+
|
|
6
|
+
type Outcome<T> = {
|
|
7
|
+
succeeded: true;
|
|
8
|
+
value: T;
|
|
9
|
+
} | {
|
|
10
|
+
succeeded: false;
|
|
11
|
+
error: Error;
|
|
12
|
+
};
|
|
13
|
+
interface SandboxClientCredentials {
|
|
14
|
+
apiKey: string;
|
|
15
|
+
baseUrl: string;
|
|
16
|
+
}
|
|
17
|
+
interface SandboxResourceConfig {
|
|
18
|
+
image: string;
|
|
19
|
+
cpuCores: number;
|
|
20
|
+
memoryMB: number;
|
|
21
|
+
diskGB: number;
|
|
22
|
+
maxLifetimeSeconds: number;
|
|
23
|
+
idleTimeoutSeconds: number;
|
|
24
|
+
}
|
|
25
|
+
interface ProviderResolutionConfig {
|
|
26
|
+
routerBaseUrl?: string;
|
|
27
|
+
apiKey?: string;
|
|
28
|
+
providerName?: string;
|
|
29
|
+
modelName?: string;
|
|
30
|
+
defaultModel?: string;
|
|
31
|
+
openaiApiKey?: string;
|
|
32
|
+
}
|
|
33
|
+
interface SandboxBuildContext {
|
|
34
|
+
workspaceId: string;
|
|
35
|
+
connectedIntegrationIds: string[];
|
|
36
|
+
}
|
|
37
|
+
interface ProfileComposeOptions {
|
|
38
|
+
systemPrompt?: string;
|
|
39
|
+
extraFiles?: AgentProfileFileMount[];
|
|
40
|
+
extraMcp?: Record<string, AgentProfileMcpServer>;
|
|
41
|
+
name?: string;
|
|
42
|
+
}
|
|
43
|
+
interface SandboxRuntimeConfig {
|
|
44
|
+
credentials: () => SandboxClientCredentials | null;
|
|
45
|
+
name: (workspaceId: string) => string;
|
|
46
|
+
metadata: (harness: Harness) => Record<string, unknown>;
|
|
47
|
+
connectedIntegrationIds: (workspaceId: string) => Promise<string[]>;
|
|
48
|
+
env: (ctx: SandboxBuildContext) => Promise<Record<string, string>>;
|
|
49
|
+
files: (ctx: SandboxBuildContext) => Promise<AgentProfileFileMount[]>;
|
|
50
|
+
secrets: (workspaceId: string) => Promise<string[]>;
|
|
51
|
+
profile: (options: ProfileComposeOptions) => AgentProfile;
|
|
52
|
+
permissionRole?: (workspaceRole: string) => SandboxPermissionLevel;
|
|
53
|
+
resources?: SandboxResourceConfig;
|
|
54
|
+
provider?: ProviderResolutionConfig;
|
|
55
|
+
}
|
|
56
|
+
declare const DEFAULT_SANDBOX_RESOURCES: SandboxResourceConfig;
|
|
57
|
+
declare function getClient(shell: SandboxRuntimeConfig): Sandbox;
|
|
58
|
+
declare function resetClientCache(): void;
|
|
59
|
+
interface AppToolDescriptor {
|
|
60
|
+
tool: AppToolName;
|
|
61
|
+
key: string;
|
|
62
|
+
description: string;
|
|
63
|
+
}
|
|
64
|
+
interface BuildAppToolMcpServersOptions {
|
|
65
|
+
tools: AppToolDescriptor[];
|
|
66
|
+
baseUrl: string;
|
|
67
|
+
token: string;
|
|
68
|
+
ctx: AppToolContext;
|
|
69
|
+
headerNames?: ToolHeaderNames;
|
|
70
|
+
}
|
|
71
|
+
declare function buildAppToolMcpServers(options: BuildAppToolMcpServersOptions): Record<string, AgentProfileMcpServer>;
|
|
72
|
+
interface EnsureWorkspaceSandboxOptions {
|
|
73
|
+
workspaceId: string;
|
|
74
|
+
userId?: string;
|
|
75
|
+
harness: Harness;
|
|
76
|
+
}
|
|
77
|
+
declare function ensureWorkspaceSandbox(shell: SandboxRuntimeConfig, options: EnsureWorkspaceSandboxOptions): Promise<SandboxInstance>;
|
|
78
|
+
interface ResolvedModel {
|
|
79
|
+
model: string;
|
|
80
|
+
provider: string;
|
|
81
|
+
apiKey: string;
|
|
82
|
+
baseUrl?: string;
|
|
83
|
+
}
|
|
84
|
+
declare function resolveModel(config: ProviderResolutionConfig | undefined, override?: {
|
|
85
|
+
model?: string;
|
|
86
|
+
modelApiKey?: string;
|
|
87
|
+
}): ResolvedModel | undefined;
|
|
88
|
+
declare function flattenHistory(message: string, history?: Array<{
|
|
89
|
+
role: 'user' | 'assistant';
|
|
90
|
+
content: string;
|
|
91
|
+
}>): string;
|
|
92
|
+
declare function mergeExtraMcp(appToolMcp: Record<string, AgentProfileMcpServer>, baseProfileMcp: Record<string, AgentProfileMcpServer>, extra: Record<string, AgentProfileMcpServer> | undefined): Record<string, AgentProfileMcpServer>;
|
|
93
|
+
declare function attachReasoningEffort(profile: AgentProfile, harness: Harness, effort: 'auto' | 'low' | 'medium' | 'high' | undefined): AgentProfile;
|
|
94
|
+
interface StreamSandboxPromptOptions {
|
|
95
|
+
sessionId?: string;
|
|
96
|
+
executionId?: string;
|
|
97
|
+
lastEventId?: string;
|
|
98
|
+
systemPrompt?: string;
|
|
99
|
+
model?: string;
|
|
100
|
+
modelApiKey?: string;
|
|
101
|
+
history?: Array<{
|
|
102
|
+
role: 'user' | 'assistant';
|
|
103
|
+
content: string;
|
|
104
|
+
}>;
|
|
105
|
+
harness?: Harness;
|
|
106
|
+
effort?: 'auto' | 'low' | 'medium' | 'high';
|
|
107
|
+
appToolMcp?: Record<string, AgentProfileMcpServer>;
|
|
108
|
+
baseProfileMcp?: Record<string, AgentProfileMcpServer>;
|
|
109
|
+
extraMcp?: Record<string, AgentProfileMcpServer>;
|
|
110
|
+
}
|
|
111
|
+
declare function streamSandboxPrompt(shell: SandboxRuntimeConfig, box: SandboxInstance, message: string, options?: StreamSandboxPromptOptions): AsyncGenerator<unknown>;
|
|
112
|
+
declare function runSandboxPrompt(shell: SandboxRuntimeConfig, box: SandboxInstance, message: string, options?: StreamSandboxPromptOptions): Promise<string>;
|
|
113
|
+
type SandboxPermissionLevel = 'owner' | 'admin' | 'developer' | 'viewer';
|
|
114
|
+
interface MemberSyncSeam {
|
|
115
|
+
roleToSandboxRole: (workspaceRole: string) => SandboxPermissionLevel;
|
|
116
|
+
}
|
|
117
|
+
declare function syncSandboxMemberAdd(box: SandboxInstance, seam: MemberSyncSeam, userId: string, role: string): Promise<Outcome<void>>;
|
|
118
|
+
declare function syncSandboxMemberRemove(box: SandboxInstance, userId: string): Promise<Outcome<void>>;
|
|
119
|
+
declare function syncSandboxMemberRole(box: SandboxInstance, seam: MemberSyncSeam, userId: string, role: string): Promise<Outcome<void>>;
|
|
120
|
+
interface SecretStore {
|
|
121
|
+
create: (name: string, value: string) => Promise<void>;
|
|
122
|
+
update: (name: string, value: string) => Promise<void>;
|
|
123
|
+
get: (name: string) => Promise<string>;
|
|
124
|
+
delete: (name: string) => Promise<void>;
|
|
125
|
+
}
|
|
126
|
+
declare function secretStoreFromClient(shell: SandboxRuntimeConfig): SecretStore;
|
|
127
|
+
declare function storeSecret(store: SecretStore, name: string, value: string): Promise<Outcome<void>>;
|
|
128
|
+
declare function readSecret(store: SecretStore, name: string): Promise<Outcome<string>>;
|
|
129
|
+
declare function deleteSecret(store: SecretStore, name: string): Promise<Outcome<void>>;
|
|
130
|
+
interface ScopedTokenResult {
|
|
131
|
+
token: string;
|
|
132
|
+
expiresAt: Date;
|
|
133
|
+
scope: ScopedTokenScope;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Mint a scoped token for an already-provisioned box (e.g. to hand a terminal
|
|
137
|
+
* proxy a narrowed credential). Uses the SDK's native `box.mintScopedToken`,
|
|
138
|
+
* which normalizes `expiresAt` to a Date — no hand-rolled wire call.
|
|
139
|
+
*/
|
|
140
|
+
declare function mintSandboxScopedToken(box: SandboxInstance, options: {
|
|
141
|
+
scope: ScopedTokenScope;
|
|
142
|
+
sessionId?: string;
|
|
143
|
+
ttlMinutes?: number;
|
|
144
|
+
}): Promise<Outcome<ScopedTokenResult>>;
|
|
145
|
+
|
|
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 };
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import "../chunk-MH6AVXQ7.js";
|
|
2
|
+
import {
|
|
3
|
+
buildAppToolMcpServer
|
|
4
|
+
} from "../chunk-A76ZHWNF.js";
|
|
5
|
+
import "../chunk-JZZ6AWF4.js";
|
|
6
|
+
|
|
7
|
+
// src/sandbox/index.ts
|
|
8
|
+
import {
|
|
9
|
+
Sandbox
|
|
10
|
+
} from "@tangle-network/sandbox";
|
|
11
|
+
var ok = (value) => ({ succeeded: true, value });
|
|
12
|
+
var fail = (error) => ({
|
|
13
|
+
succeeded: false,
|
|
14
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
15
|
+
});
|
|
16
|
+
var DEFAULT_SANDBOX_RESOURCES = {
|
|
17
|
+
image: "universal",
|
|
18
|
+
cpuCores: 2,
|
|
19
|
+
memoryMB: 4096,
|
|
20
|
+
diskGB: 10,
|
|
21
|
+
maxLifetimeSeconds: 86400,
|
|
22
|
+
idleTimeoutSeconds: 3600
|
|
23
|
+
};
|
|
24
|
+
var _cached = null;
|
|
25
|
+
function getClient(shell) {
|
|
26
|
+
const creds = shell.credentials();
|
|
27
|
+
if (!creds) throw new Error("sandbox credentials are required (apiKey/baseUrl)");
|
|
28
|
+
const fingerprint = `${creds.apiKey} ${creds.baseUrl}`;
|
|
29
|
+
if (_cached && _cached.fingerprint === fingerprint) return _cached.client;
|
|
30
|
+
const client = new Sandbox({ apiKey: creds.apiKey, baseUrl: creds.baseUrl });
|
|
31
|
+
_cached = { client, fingerprint };
|
|
32
|
+
return client;
|
|
33
|
+
}
|
|
34
|
+
function resetClientCache() {
|
|
35
|
+
_cached = null;
|
|
36
|
+
}
|
|
37
|
+
function buildAppToolMcpServers(options) {
|
|
38
|
+
const entries = {};
|
|
39
|
+
for (const { tool, key, description } of options.tools) {
|
|
40
|
+
entries[key] = buildAppToolMcpServer({
|
|
41
|
+
tool,
|
|
42
|
+
baseUrl: options.baseUrl,
|
|
43
|
+
token: options.token,
|
|
44
|
+
ctx: options.ctx,
|
|
45
|
+
description,
|
|
46
|
+
headerNames: options.headerNames
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return entries;
|
|
50
|
+
}
|
|
51
|
+
async function listRunning(client, name) {
|
|
52
|
+
try {
|
|
53
|
+
const running = await client.list({ status: "running" });
|
|
54
|
+
return ok(running.find((s) => s.name === name) ?? null);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
return fail(err);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function deleteBox(box) {
|
|
60
|
+
try {
|
|
61
|
+
await box.delete();
|
|
62
|
+
return ok(void 0);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
return fail(err);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function ensureWorkspaceSandbox(shell, options) {
|
|
68
|
+
const { workspaceId, userId, harness } = options;
|
|
69
|
+
const client = getClient(shell);
|
|
70
|
+
const name = shell.name(workspaceId);
|
|
71
|
+
const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES;
|
|
72
|
+
const existing = await listRunning(client, name);
|
|
73
|
+
if (existing.succeeded && existing.value) {
|
|
74
|
+
const found = existing.value;
|
|
75
|
+
if (found.metadata?.harness === harness) return found;
|
|
76
|
+
const dropped = await deleteBox(found);
|
|
77
|
+
if (!dropped.succeeded) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`harness-mismatched sandbox ${name} (was ${String(found.metadata?.harness ?? "unknown")}, want ${harness}) could not be deleted`,
|
|
80
|
+
{ cause: dropped.error }
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId);
|
|
85
|
+
const buildCtx = { workspaceId, connectedIntegrationIds };
|
|
86
|
+
const [secrets, env, files] = await Promise.all([
|
|
87
|
+
shell.secrets(workspaceId),
|
|
88
|
+
shell.env(buildCtx),
|
|
89
|
+
shell.files(buildCtx)
|
|
90
|
+
]);
|
|
91
|
+
const profile = shell.profile({ extraFiles: files });
|
|
92
|
+
const role = userId && shell.permissionRole ? shell.permissionRole("developer") : void 0;
|
|
93
|
+
const payload = {
|
|
94
|
+
name,
|
|
95
|
+
image: resources.image,
|
|
96
|
+
metadata: shell.metadata(harness),
|
|
97
|
+
...userId ? { permissions: { initialUsers: [{ userId, role }] } } : {},
|
|
98
|
+
env,
|
|
99
|
+
secrets,
|
|
100
|
+
backend: { type: harness, profile },
|
|
101
|
+
maxLifetimeSeconds: resources.maxLifetimeSeconds,
|
|
102
|
+
idleTimeoutSeconds: resources.idleTimeoutSeconds,
|
|
103
|
+
resources: {
|
|
104
|
+
cpuCores: resources.cpuCores,
|
|
105
|
+
memoryMB: resources.memoryMB,
|
|
106
|
+
diskGB: resources.diskGB
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const box = await client.create(payload);
|
|
110
|
+
await box.waitFor("running", { timeoutMs: 12e4 });
|
|
111
|
+
if (!box.connection?.runtimeUrl) await box.refresh();
|
|
112
|
+
return box;
|
|
113
|
+
}
|
|
114
|
+
function resolveModel(config, override) {
|
|
115
|
+
const c = config ?? {};
|
|
116
|
+
const explicitBaseUrl = c.routerBaseUrl;
|
|
117
|
+
const explicitApiKey = override?.modelApiKey ?? c.apiKey;
|
|
118
|
+
const provider = c.providerName ?? (explicitApiKey ? "openai-compat" : c.openaiApiKey ? "openai" : void 0);
|
|
119
|
+
const modelName = override?.model ?? c.modelName ?? (provider === "openai" || provider === "openai-compat" ? c.defaultModel : void 0);
|
|
120
|
+
const apiKey = explicitApiKey ?? (provider === "openai" ? c.openaiApiKey : void 0);
|
|
121
|
+
if (!provider || !modelName || !apiKey) return void 0;
|
|
122
|
+
return {
|
|
123
|
+
model: modelName,
|
|
124
|
+
provider,
|
|
125
|
+
apiKey,
|
|
126
|
+
...explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function flattenHistory(message, history) {
|
|
130
|
+
if (!history?.length) return message;
|
|
131
|
+
const transcript = history.map((entry) => `${entry.role === "assistant" ? "Assistant" : "User"}: ${entry.content}`).join("\n\n");
|
|
132
|
+
return `${transcript}
|
|
133
|
+
|
|
134
|
+
User: ${message}`;
|
|
135
|
+
}
|
|
136
|
+
function mergeExtraMcp(appToolMcp, baseProfileMcp, extra) {
|
|
137
|
+
for (const key of Object.keys(extra ?? {})) {
|
|
138
|
+
if (key in appToolMcp || key in baseProfileMcp) {
|
|
139
|
+
throw new Error(`extraMcp key '${key}' collides with an existing profile MCP server`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { ...appToolMcp, ...extra ?? {} };
|
|
143
|
+
}
|
|
144
|
+
function attachReasoningEffort(profile, harness, effort) {
|
|
145
|
+
if (!effort || effort === "auto") return profile;
|
|
146
|
+
return {
|
|
147
|
+
...profile,
|
|
148
|
+
extensions: {
|
|
149
|
+
...profile.extensions ?? {},
|
|
150
|
+
[harness]: {
|
|
151
|
+
...profile.extensions?.[harness] ?? {},
|
|
152
|
+
reasoningEffort: effort
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
async function* streamSandboxPrompt(shell, box, message, options) {
|
|
158
|
+
const harness = options?.harness ?? "opencode";
|
|
159
|
+
const model = resolveModel(shell.provider, {
|
|
160
|
+
model: options?.model,
|
|
161
|
+
modelApiKey: options?.modelApiKey
|
|
162
|
+
});
|
|
163
|
+
const prompt = flattenHistory(message, options?.history);
|
|
164
|
+
const appToolMcp = options?.appToolMcp ?? {};
|
|
165
|
+
const extraMcp = mergeExtraMcp(appToolMcp, options?.baseProfileMcp ?? {}, options?.extraMcp);
|
|
166
|
+
const profile = shell.profile({ systemPrompt: options?.systemPrompt, extraMcp });
|
|
167
|
+
const profileWithEffort = attachReasoningEffort(profile, harness, options?.effort);
|
|
168
|
+
const stream = box.streamPrompt(prompt, {
|
|
169
|
+
sessionId: options?.sessionId,
|
|
170
|
+
executionId: options?.executionId,
|
|
171
|
+
lastEventId: options?.lastEventId,
|
|
172
|
+
backend: {
|
|
173
|
+
type: harness,
|
|
174
|
+
profile: profileWithEffort,
|
|
175
|
+
...model ? { model } : {}
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
for await (const event of stream) yield event;
|
|
179
|
+
}
|
|
180
|
+
async function runSandboxPrompt(shell, box, message, options) {
|
|
181
|
+
let fullText = "";
|
|
182
|
+
let firstTextSeen = false;
|
|
183
|
+
for await (const rawEvent of streamSandboxPrompt(shell, box, message, options)) {
|
|
184
|
+
const event = rawEvent;
|
|
185
|
+
if (!event.type) continue;
|
|
186
|
+
if (event.type === "message.part.updated") {
|
|
187
|
+
const part = event.data?.part;
|
|
188
|
+
const delta = typeof event.data?.delta === "string" ? event.data.delta : null;
|
|
189
|
+
if (String(part?.type ?? "") === "text") {
|
|
190
|
+
if (!firstTextSeen) {
|
|
191
|
+
firstTextSeen = true;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (delta) fullText += delta;
|
|
195
|
+
else if (typeof part?.text === "string") fullText = part.text;
|
|
196
|
+
}
|
|
197
|
+
} else if (event.type === "result") {
|
|
198
|
+
const finalText = typeof event.data?.finalText === "string" ? event.data.finalText : null;
|
|
199
|
+
if (finalText) fullText = finalText;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return fullText;
|
|
203
|
+
}
|
|
204
|
+
async function syncSandboxMemberAdd(box, seam, userId, role) {
|
|
205
|
+
try {
|
|
206
|
+
await box.permissions.add({ userId, role: seam.roleToSandboxRole(role) });
|
|
207
|
+
return ok(void 0);
|
|
208
|
+
} catch (err) {
|
|
209
|
+
return fail(err);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async function syncSandboxMemberRemove(box, userId) {
|
|
213
|
+
try {
|
|
214
|
+
await box.permissions.remove(userId, { preserveHomeDir: true });
|
|
215
|
+
return ok(void 0);
|
|
216
|
+
} catch (err) {
|
|
217
|
+
return fail(err);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async function syncSandboxMemberRole(box, seam, userId, role) {
|
|
221
|
+
try {
|
|
222
|
+
await box.permissions.update(userId, { role: seam.roleToSandboxRole(role) });
|
|
223
|
+
return ok(void 0);
|
|
224
|
+
} catch (err) {
|
|
225
|
+
return fail(err);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function secretStoreFromClient(shell) {
|
|
229
|
+
const client = getClient(shell);
|
|
230
|
+
return {
|
|
231
|
+
create: async (name, value) => {
|
|
232
|
+
await client.secrets.create(name, value);
|
|
233
|
+
},
|
|
234
|
+
update: async (name, value) => {
|
|
235
|
+
await client.secrets.update(name, value);
|
|
236
|
+
},
|
|
237
|
+
get: (name) => client.secrets.get(name),
|
|
238
|
+
delete: async (name) => {
|
|
239
|
+
await client.secrets.delete(name);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
async function storeSecret(store, name, value) {
|
|
244
|
+
try {
|
|
245
|
+
await store.create(name, value);
|
|
246
|
+
return ok(void 0);
|
|
247
|
+
} catch {
|
|
248
|
+
try {
|
|
249
|
+
await store.update(name, value);
|
|
250
|
+
return ok(void 0);
|
|
251
|
+
} catch (err) {
|
|
252
|
+
return fail(new Error(`Failed to store sandbox secret ${name}`, { cause: err }));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async function readSecret(store, name) {
|
|
257
|
+
try {
|
|
258
|
+
return ok(await store.get(name));
|
|
259
|
+
} catch (err) {
|
|
260
|
+
return fail(err);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async function deleteSecret(store, name) {
|
|
264
|
+
try {
|
|
265
|
+
await store.delete(name);
|
|
266
|
+
return ok(void 0);
|
|
267
|
+
} catch (err) {
|
|
268
|
+
return fail(err);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
async function mintSandboxScopedToken(box, options) {
|
|
272
|
+
try {
|
|
273
|
+
const token = await box.mintScopedToken({
|
|
274
|
+
scope: options.scope,
|
|
275
|
+
...options.sessionId ? { sessionId: options.sessionId } : {},
|
|
276
|
+
...options.ttlMinutes ? { ttlMinutes: options.ttlMinutes } : {}
|
|
277
|
+
});
|
|
278
|
+
return ok({ token: token.token, expiresAt: token.expiresAt, scope: token.scope });
|
|
279
|
+
} catch (err) {
|
|
280
|
+
return fail(err);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
export {
|
|
284
|
+
DEFAULT_SANDBOX_RESOURCES,
|
|
285
|
+
attachReasoningEffort,
|
|
286
|
+
buildAppToolMcpServers,
|
|
287
|
+
deleteSecret,
|
|
288
|
+
ensureWorkspaceSandbox,
|
|
289
|
+
flattenHistory,
|
|
290
|
+
getClient,
|
|
291
|
+
mergeExtraMcp,
|
|
292
|
+
mintSandboxScopedToken,
|
|
293
|
+
readSecret,
|
|
294
|
+
resetClientCache,
|
|
295
|
+
resolveModel,
|
|
296
|
+
runSandboxPrompt,
|
|
297
|
+
secretStoreFromClient,
|
|
298
|
+
storeSecret,
|
|
299
|
+
streamSandboxPrompt,
|
|
300
|
+
syncSandboxMemberAdd,
|
|
301
|
+
syncSandboxMemberRemove,
|
|
302
|
+
syncSandboxMemberRole
|
|
303
|
+
};
|
|
304
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/sandbox/index.ts"],"sourcesContent":["import {\n Sandbox,\n type AgentProfile,\n type AgentProfileFileMount,\n type AgentProfileMcpServer,\n type SandboxInstance,\n type ScopedTokenScope,\n} from '@tangle-network/sandbox'\nimport {\n buildAppToolMcpServer,\n type AppToolName,\n type AppToolContext,\n type ToolHeaderNames,\n} from '../tools/index'\nimport type { Harness } from '../harness/index'\n\nexport type Outcome<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: Error }\n\nconst ok = <T>(value: T): Outcome<T> => ({ succeeded: true, value })\nconst fail = (error: unknown): Outcome<never> => ({\n succeeded: false,\n error: error instanceof Error ? error : new Error(String(error)),\n})\n\nexport interface SandboxClientCredentials {\n apiKey: string\n baseUrl: string\n}\n\nexport interface SandboxResourceConfig {\n image: string\n cpuCores: number\n memoryMB: number\n diskGB: number\n maxLifetimeSeconds: number\n idleTimeoutSeconds: number\n}\n\nexport interface ProviderResolutionConfig {\n routerBaseUrl?: string\n apiKey?: string\n providerName?: string\n modelName?: string\n defaultModel?: string\n openaiApiKey?: string\n}\n\nexport interface SandboxBuildContext {\n workspaceId: string\n connectedIntegrationIds: string[]\n}\n\nexport interface ProfileComposeOptions {\n systemPrompt?: string\n extraFiles?: AgentProfileFileMount[]\n extraMcp?: Record<string, AgentProfileMcpServer>\n name?: string\n}\n\nexport interface SandboxRuntimeConfig {\n credentials: () => SandboxClientCredentials | null\n name: (workspaceId: string) => string\n metadata: (harness: Harness) => Record<string, unknown>\n connectedIntegrationIds: (workspaceId: string) => Promise<string[]>\n env: (ctx: SandboxBuildContext) => Promise<Record<string, string>>\n files: (ctx: SandboxBuildContext) => Promise<AgentProfileFileMount[]>\n secrets: (workspaceId: string) => Promise<string[]>\n profile: (options: ProfileComposeOptions) => AgentProfile\n permissionRole?: (workspaceRole: string) => SandboxPermissionLevel\n resources?: SandboxResourceConfig\n provider?: ProviderResolutionConfig\n}\n\nexport const DEFAULT_SANDBOX_RESOURCES: SandboxResourceConfig = {\n image: 'universal',\n cpuCores: 2,\n memoryMB: 4096,\n diskGB: 10,\n maxLifetimeSeconds: 86400,\n idleTimeoutSeconds: 3600,\n}\n\ninterface ClientCacheEntry {\n client: Sandbox\n fingerprint: string\n}\n\nlet _cached: ClientCacheEntry | null = null\n\nexport function getClient(shell: SandboxRuntimeConfig): Sandbox {\n const creds = shell.credentials()\n if (!creds) throw new Error('sandbox credentials are required (apiKey/baseUrl)')\n\n const fingerprint = `${creds.apiKey} ${creds.baseUrl}`\n if (_cached && _cached.fingerprint === fingerprint) return _cached.client\n\n const client = new Sandbox({ apiKey: creds.apiKey, baseUrl: creds.baseUrl })\n _cached = { client, fingerprint }\n return client\n}\n\nexport function resetClientCache(): void {\n _cached = null\n}\n\nexport interface AppToolDescriptor {\n tool: AppToolName\n key: string\n description: string\n}\n\nexport interface BuildAppToolMcpServersOptions {\n tools: AppToolDescriptor[]\n baseUrl: string\n token: string\n ctx: AppToolContext\n headerNames?: ToolHeaderNames\n}\n\nexport function buildAppToolMcpServers(\n options: BuildAppToolMcpServersOptions,\n): Record<string, AgentProfileMcpServer> {\n const entries: Record<string, AgentProfileMcpServer> = {}\n for (const { tool, key, description } of options.tools) {\n entries[key] = buildAppToolMcpServer({\n tool,\n baseUrl: options.baseUrl,\n token: options.token,\n ctx: options.ctx,\n description,\n headerNames: options.headerNames,\n }) as AgentProfileMcpServer\n }\n return entries\n}\n\nexport interface EnsureWorkspaceSandboxOptions {\n workspaceId: string\n userId?: string\n harness: Harness\n}\n\nasync function listRunning(\n client: Sandbox,\n name: string,\n): Promise<Outcome<SandboxInstance | null>> {\n try {\n const running = await client.list({ status: 'running' })\n return ok(running.find((s) => s.name === name) ?? null)\n } catch (err) {\n return fail(err)\n }\n}\n\nasync function deleteBox(box: SandboxInstance): Promise<Outcome<void>> {\n try {\n await box.delete()\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\n// The SDK narrows `backend.type` to its own BackendType union and\n// `initialUsers[].role` to PermissionLevel — neither symbol is exported. The\n// create payload is assembled with the product's Harness/role strings, which\n// are a superset surface; the localized cast at the boundary is the only place\n// this widening is allowed, and the runtime contract (the sidecar boots the\n// named harness) is what enforces correctness.\ntype CreatePayload = Parameters<Sandbox['create']>[0]\n\nexport async function ensureWorkspaceSandbox(\n shell: SandboxRuntimeConfig,\n options: EnsureWorkspaceSandboxOptions,\n): Promise<SandboxInstance> {\n const { workspaceId, userId, harness } = options\n const client = getClient(shell)\n const name = shell.name(workspaceId)\n const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES\n\n const existing = await listRunning(client, name)\n if (existing.succeeded && existing.value) {\n const found = existing.value\n if (found.metadata?.harness === harness) return found\n const dropped = await deleteBox(found)\n if (!dropped.succeeded) {\n throw new Error(\n `harness-mismatched sandbox ${name} ` +\n `(was ${String(found.metadata?.harness ?? 'unknown')}, want ${harness}) could not be deleted`,\n { cause: dropped.error },\n )\n }\n }\n\n const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId)\n const buildCtx: SandboxBuildContext = { workspaceId, connectedIntegrationIds }\n const [secrets, env, files] = await Promise.all([\n shell.secrets(workspaceId),\n shell.env(buildCtx),\n shell.files(buildCtx),\n ])\n const profile = shell.profile({ extraFiles: files })\n\n const role = userId && shell.permissionRole ? shell.permissionRole('developer') : undefined\n\n const payload = {\n name,\n image: resources.image,\n metadata: shell.metadata(harness),\n ...(userId ? { permissions: { initialUsers: [{ userId, role }] } } : {}),\n env,\n secrets,\n backend: { type: harness, profile },\n maxLifetimeSeconds: resources.maxLifetimeSeconds,\n idleTimeoutSeconds: resources.idleTimeoutSeconds,\n resources: {\n cpuCores: resources.cpuCores,\n memoryMB: resources.memoryMB,\n diskGB: resources.diskGB,\n },\n } as CreatePayload\n\n const box = await client.create(payload)\n\n await box.waitFor('running', { timeoutMs: 120_000 })\n if (!box.connection?.runtimeUrl) await box.refresh()\n return box\n}\n\nexport interface ResolvedModel {\n model: string\n provider: string\n apiKey: string\n baseUrl?: string\n}\n\nexport function resolveModel(\n config: ProviderResolutionConfig | undefined,\n override?: { model?: string; modelApiKey?: string },\n): ResolvedModel | undefined {\n const c = config ?? {}\n const explicitBaseUrl = c.routerBaseUrl\n const explicitApiKey = override?.modelApiKey ?? c.apiKey\n const provider =\n c.providerName ?? (explicitApiKey ? 'openai-compat' : c.openaiApiKey ? 'openai' : undefined)\n const modelName =\n override?.model ??\n c.modelName ??\n (provider === 'openai' || provider === 'openai-compat' ? c.defaultModel : undefined)\n const apiKey = explicitApiKey ?? (provider === 'openai' ? c.openaiApiKey : undefined)\n if (!provider || !modelName || !apiKey) return undefined\n return {\n model: modelName,\n provider,\n apiKey,\n ...(explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}),\n }\n}\n\nexport function flattenHistory(\n message: string,\n history?: Array<{ role: 'user' | 'assistant'; content: string }>,\n): string {\n if (!history?.length) return message\n const transcript = history\n .map((entry) => `${entry.role === 'assistant' ? 'Assistant' : 'User'}: ${entry.content}`)\n .join('\\n\\n')\n return `${transcript}\\n\\nUser: ${message}`\n}\n\nexport function mergeExtraMcp(\n appToolMcp: Record<string, AgentProfileMcpServer>,\n baseProfileMcp: Record<string, AgentProfileMcpServer>,\n extra: Record<string, AgentProfileMcpServer> | undefined,\n): Record<string, AgentProfileMcpServer> {\n for (const key of Object.keys(extra ?? {})) {\n if (key in appToolMcp || key in baseProfileMcp) {\n throw new Error(`extraMcp key '${key}' collides with an existing profile MCP server`)\n }\n }\n return { ...appToolMcp, ...(extra ?? {}) }\n}\n\nexport function attachReasoningEffort(\n profile: AgentProfile,\n harness: Harness,\n effort: 'auto' | 'low' | 'medium' | 'high' | undefined,\n): AgentProfile {\n if (!effort || effort === 'auto') return profile\n return {\n ...profile,\n extensions: {\n ...(profile.extensions ?? {}),\n [harness]: {\n ...(profile.extensions?.[harness] ?? {}),\n reasoningEffort: effort,\n },\n },\n }\n}\n\nexport interface StreamSandboxPromptOptions {\n sessionId?: string\n executionId?: string\n lastEventId?: string\n systemPrompt?: string\n model?: string\n modelApiKey?: string\n history?: Array<{ role: 'user' | 'assistant'; content: string }>\n harness?: Harness\n effort?: 'auto' | 'low' | 'medium' | 'high'\n appToolMcp?: Record<string, AgentProfileMcpServer>\n baseProfileMcp?: Record<string, AgentProfileMcpServer>\n extraMcp?: Record<string, AgentProfileMcpServer>\n}\n\ntype StreamPromptOptions = Parameters<SandboxInstance['streamPrompt']>[1]\n\nexport async function* streamSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string,\n options?: StreamSandboxPromptOptions,\n): AsyncGenerator<unknown> {\n const harness = options?.harness ?? 'opencode'\n const model = resolveModel(shell.provider, {\n model: options?.model,\n modelApiKey: options?.modelApiKey,\n })\n\n const prompt = flattenHistory(message, options?.history)\n\n const appToolMcp = options?.appToolMcp ?? {}\n const extraMcp = mergeExtraMcp(appToolMcp, options?.baseProfileMcp ?? {}, options?.extraMcp)\n\n const profile = shell.profile({ systemPrompt: options?.systemPrompt, extraMcp })\n const profileWithEffort = attachReasoningEffort(profile, harness, options?.effort)\n\n const stream = box.streamPrompt(prompt, {\n sessionId: options?.sessionId,\n executionId: options?.executionId,\n lastEventId: options?.lastEventId,\n backend: {\n type: harness,\n profile: profileWithEffort,\n ...(model ? { model } : {}),\n },\n } as StreamPromptOptions)\n\n for await (const event of stream) yield event\n}\n\nexport async function runSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string,\n options?: StreamSandboxPromptOptions,\n): Promise<string> {\n let fullText = ''\n let firstTextSeen = false\n\n for await (const rawEvent of streamSandboxPrompt(shell, box, message, options)) {\n const event = rawEvent as { type?: string; data?: Record<string, unknown> }\n if (!event.type) continue\n\n if (event.type === 'message.part.updated') {\n const part = event.data?.part as Record<string, unknown> | undefined\n const delta = typeof event.data?.delta === 'string' ? event.data.delta : null\n if (String(part?.type ?? '') === 'text') {\n if (!firstTextSeen) {\n firstTextSeen = true\n continue\n }\n if (delta) fullText += delta\n else if (typeof part?.text === 'string') fullText = part.text\n }\n } else if (event.type === 'result') {\n const finalText = typeof event.data?.finalText === 'string' ? event.data.finalText : null\n if (finalText) fullText = finalText\n }\n }\n\n return fullText\n}\n\n// Mirrors the SDK's PermissionLevel union (not re-exported by\n// @tangle-network/sandbox). The product's role-mapping seam must produce one of\n// these; binding the seam's return type to the union makes a wrong mapping a\n// compile error rather than a runtime 400 from the orchestrator.\nexport type SandboxPermissionLevel = 'owner' | 'admin' | 'developer' | 'viewer'\n\nexport interface MemberSyncSeam {\n roleToSandboxRole: (workspaceRole: string) => SandboxPermissionLevel\n}\n\nexport async function syncSandboxMemberAdd(\n box: SandboxInstance,\n seam: MemberSyncSeam,\n userId: string,\n role: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.add({ userId, role: seam.roleToSandboxRole(role) })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function syncSandboxMemberRemove(\n box: SandboxInstance,\n userId: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.remove(userId, { preserveHomeDir: true })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function syncSandboxMemberRole(\n box: SandboxInstance,\n seam: MemberSyncSeam,\n userId: string,\n role: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.update(userId, { role: seam.roleToSandboxRole(role) })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface SecretStore {\n create: (name: string, value: string) => Promise<void>\n update: (name: string, value: string) => Promise<void>\n get: (name: string) => Promise<string>\n delete: (name: string) => Promise<void>\n}\n\nexport function secretStoreFromClient(shell: SandboxRuntimeConfig): SecretStore {\n const client = getClient(shell)\n return {\n create: async (name, value) => {\n await client.secrets.create(name, value)\n },\n update: async (name, value) => {\n await client.secrets.update(name, value)\n },\n get: (name) => client.secrets.get(name),\n delete: async (name) => {\n await client.secrets.delete(name)\n },\n }\n}\n\nexport async function storeSecret(\n store: SecretStore,\n name: string,\n value: string,\n): Promise<Outcome<void>> {\n try {\n await store.create(name, value)\n return ok(undefined)\n } catch {\n try {\n await store.update(name, value)\n return ok(undefined)\n } catch (err) {\n return fail(new Error(`Failed to store sandbox secret ${name}`, { cause: err }))\n }\n }\n}\n\nexport async function readSecret(store: SecretStore, name: string): Promise<Outcome<string>> {\n try {\n return ok(await store.get(name))\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function deleteSecret(store: SecretStore, name: string): Promise<Outcome<void>> {\n try {\n await store.delete(name)\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface ScopedTokenResult {\n token: string\n expiresAt: Date\n scope: ScopedTokenScope\n}\n\n/**\n * Mint a scoped token for an already-provisioned box (e.g. to hand a terminal\n * proxy a narrowed credential). Uses the SDK's native `box.mintScopedToken`,\n * which normalizes `expiresAt` to a Date — no hand-rolled wire call.\n */\nexport async function mintSandboxScopedToken(\n box: SandboxInstance,\n options: { scope: ScopedTokenScope; sessionId?: string; ttlMinutes?: number },\n): Promise<Outcome<ScopedTokenResult>> {\n try {\n const token = await box.mintScopedToken({\n scope: options.scope,\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...(options.ttlMinutes ? { ttlMinutes: options.ttlMinutes } : {}),\n })\n return ok({ token: token.token, expiresAt: token.expiresAt, scope: token.scope })\n } catch (err) {\n return fail(err)\n }\n}"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { j as SequenceMediaKind, o as SequenceTimeline, r as TimelineInterval, m as SequenceStore } from '../store-gckrNq-g.js';
|
|
2
2
|
export { M as MIN_SEQUENCE_CLIP_FRAMES, N as NewSequenceClip, a as NewSequenceDecision, b as NewSequenceTrack, S as SequenceClip, c as SequenceClipMedia, d as SequenceClipPatch, e as SequenceDecision, f as SequenceExportFormat, g as SequenceExportRecord, h as SequenceExportStatus, i as SequenceFrameSnapshot, k as SequenceMeta, l as SequenceStatus, n as SequenceStoreScope, p as SequenceTrack, q as SequenceTrackKind, T as TimelineClipBounds, s as assertClipFitsSequence, t as chooseCaptionPlacement, u as clampClipDuration, v as clampClipStart, w as formatSeconds, x as formatTimecode, y as framesToSeconds, z as secondsToFrames, A as snapshotFrame, B as trackIntervals } from '../store-gckrNq-g.js';
|
|
3
3
|
export { A as AddCaptionOperation, C as CaptionTargetResolution, a as CreateTrackOperation, D as DeleteClipOperation, E as ExtendSequenceOperation, M as MoveClipOperation, P as PlaceClipOperation, Q as QueueExportOperation, S as SEQUENCE_OPERATION_TYPES, b as SequenceApplyResult, c as SequenceOperation, d as SequenceOperationContext, e as SequenceOperationType, f as SequencePlan, g as SetClipDisabledOperation, h as SetClipTextOperation, i as SplitClipOperation, T as TrimClipOperation, j as applySequenceOperation, k as applySequenceOperations, l as assertSequenceMediaUrl, m as captionTrackNameForLanguage, n as lastClipEndFrame, p as parseSequenceOperations, r as resolveCaptionPlacement, o as resolveCaptionTarget, q as resolvePlaceClipTrack, v as validateAddCaption, s as validateCreateTrack, t as validateDeleteClip, u as validateExtendSequence, w as validateMoveClip, x as validatePlaceClip, y as validateQueueExport, z as validateSequenceOperation, B as validateSequenceOperations, F as validateSetClipDisabled, G as validateSetClipText, H as validateSplitClip, I as validateTrimClip } from '../apply-Cp8c3K9D.js';
|
|
4
|
-
import {
|
|
4
|
+
import { c as ToolHeaderNames } from '../auth-BlS9GWfL.js';
|
|
5
|
+
import { A as AppToolMcpServer } from '../mcp-BShTlESm.js';
|
|
5
6
|
import { b as AppToolContext } from '../types-2rOJo8Hc.js';
|
|
6
7
|
|
|
7
8
|
/**
|