@tangle-network/agent-app 0.60.198 → 0.60.199

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/chat-routes/index.js +6 -4
  2. package/dist/chat-routes/index.js.map +1 -1
  3. package/dist/chat-routes/turn-routes.d.ts +28 -0
  4. package/dist/{chunk-XJEIGVMQ.js → chunk-2OWT3TNV.js} +2 -2
  5. package/dist/{chunk-XP77DJEF.js → chunk-6XXKFYIM.js} +72 -30
  6. package/dist/chunk-6XXKFYIM.js.map +1 -0
  7. package/dist/chunk-7XQIY2LU.js +151 -0
  8. package/dist/chunk-7XQIY2LU.js.map +1 -0
  9. package/dist/chunk-BKPJFES3.js +229 -0
  10. package/dist/chunk-BKPJFES3.js.map +1 -0
  11. package/dist/{chunk-SUIH5B55.js → chunk-RJJRRR5Z.js} +184 -16
  12. package/dist/chunk-RJJRRR5Z.js.map +1 -0
  13. package/dist/{chunk-FPOOBGRG.js → chunk-T4BLISYH.js} +40 -5
  14. package/dist/chunk-T4BLISYH.js.map +1 -0
  15. package/dist/public-consultation/index.d.ts +1 -1
  16. package/dist/public-consultation/index.js +2 -1
  17. package/dist/public-consultation/index.js.map +1 -1
  18. package/dist/runtime/index.js +4 -2
  19. package/dist/runtime/index.js.map +1 -1
  20. package/dist/runtime/router-turn.d.ts +14 -1
  21. package/dist/runtime/router-turn.js +3 -1
  22. package/dist/sandbox/index.d.ts +19 -0
  23. package/dist/sandbox/index.js +2 -1
  24. package/dist/sandbox/prompt-trace.d.ts +20 -0
  25. package/dist/sandbox/sandbox-run-tool.d.ts +8 -0
  26. package/dist/trace/index.d.ts +0 -1
  27. package/dist/trace/index.js +0 -240
  28. package/dist/trace/index.js.map +1 -1
  29. package/dist/turn-trace/index.d.ts +11 -0
  30. package/dist/turn-trace/index.js +121 -0
  31. package/dist/turn-trace/index.js.map +1 -0
  32. package/dist/turn-trace/otel.d.ts +36 -0
  33. package/dist/turn-trace/recorder.d.ts +122 -0
  34. package/dist/turn-trace/server-timing.d.ts +15 -0
  35. package/dist/turn-trace/traced-fetch.d.ts +31 -0
  36. package/package.json +6 -1
  37. package/dist/chunk-FPOOBGRG.js.map +0 -1
  38. package/dist/chunk-SUIH5B55.js.map +0 -1
  39. package/dist/chunk-XP77DJEF.js.map +0 -1
  40. package/dist/trace/stage-timing.d.ts +0 -61
  41. /package/dist/{chunk-XJEIGVMQ.js.map → chunk-2OWT3TNV.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sandbox/index.ts","../src/sandbox/outcome.ts","../src/sandbox/prompt-trace.ts","../src/sandbox/model.ts","../src/sandbox/binary-read.ts","../src/sandbox/workspace-sandbox-manager.ts","../src/sandbox/terminal-connection.ts","../src/sandbox/prewarm.ts","../src/sandbox/sandbox-run-tool.ts","../src/sandbox/sandbox-exec-tool.ts","../src/sandbox/prewarm-claim-d1.ts","../src/sandbox/prewarm-route.ts","../src/sandbox/foreground-single-flight.ts","../src/sandbox/warm-lease.ts","../src/sandbox/warm-lease-d1.ts","../src/sandbox/escalation-speculator.ts"],"sourcesContent":["import {\n Sandbox,\n type ExecResult,\n} from '@tangle-network/sandbox/core'\nimport type {\n EgressPolicy,\n MintScopedTokenOptions,\n SandboxConnection,\n SandboxInstance,\n ScopedTokenScope,\n StorageConfig,\n TurnDriveResult,\n ProvisionEvent,\n} from '@tangle-network/sandbox'\nimport type {\n AgentProfile,\n AgentProfileFileMount,\n AgentProfileMcpServer,\n ReasoningEffort,\n} from '@tangle-network/agent-interface'\nimport { createHash } from 'node:crypto'\nimport {\n buildAppToolMcpServer,\n type AppToolName,\n type AppToolContext,\n type ToolHeaderNames,\n} from '../tools/index'\nimport { assertHarnessModelCompatible, DEFAULT_HARNESS, isHarness, type Harness } from '../harness/index'\nimport { mergeAgentProfiles } from '@tangle-network/agent-interface'\nimport {\n resolveTangleExecutionEnvironment,\n trimOrNull,\n type TangleExecutionEnvironment,\n} from '../runtime/model'\nimport { ok, fail, type Outcome } from './outcome'\nimport type { TurnSpan, TurnTrace } from '../turn-trace/recorder'\nimport { createPromptTrace } from './prompt-trace'\nimport {\n SandboxTransientDeadlineError,\n classifySandboxTransientFailure,\n sandboxTransientBackoffMs,\n} from './transient-failure'\nimport { fingerprintAgentProfile, type ProfileFingerprint } from '../profile/fingerprint'\nimport {\n assertProfilePromptWithinBudget,\n type ComposeProfileBudget,\n} from '../profile/budget'\nimport {\n resolveModel,\n resolveModelSelection,\n backendModelFields,\n requireTransportableModel,\n SandboxModelResolutionError,\n type ProviderResolutionConfig,\n type ResolvedModel,\n type ModelSelection,\n type ModelSelectionFailure,\n type ModelSelectionError,\n type ModelSelectionSource,\n} from './model'\n\nexport type { Outcome } from './outcome'\nexport * from './binary-read'\nexport * from './transient-failure'\nexport {\n resolveModel,\n resolveModelSelection,\n backendModelFields,\n requireTransportableModel,\n SandboxModelResolutionError,\n}\nexport type {\n ProviderResolutionConfig,\n ResolvedModel,\n ModelSelection,\n ModelSelectionFailure,\n ModelSelectionError,\n ModelSelectionSource,\n}\n\n/** Define client credentials for accessing the sandbox environment with API key and base URL */\nexport interface SandboxClientCredentials {\n apiKey: string\n baseUrl: string\n}\n\n/**\n * Sandbox credential policy reuses the canonical execution-environment union\n * (development/test/staging/production) so env classification stays in one place\n * (see resolveTangleExecutionEnvironment in runtime/model).\n */\nexport type SandboxCredentialEnvironment = TangleExecutionEnvironment\n\n/** Resolve options for obtaining sandbox client credentials from environment variables and classification */\nexport interface ResolveSandboxClientCredentialsOptions {\n /**\n * Environment object to read from. Defaults to process.env when available.\n */\n env?: Record<string, string | undefined>\n /**\n * Explicit environment classification. Defaults to APP_ENV/NODE_ENV derived\n * behavior: local/development/test use direct env credentials; staging/prod\n * require the provision callback unless allowDirectEnvCredentials opts in.\n */\n environment?: SandboxCredentialEnvironment\n /**\n * Env names that may carry a sandbox-compatible bearer. The first non-empty\n * value wins when direct env credentials are allowed.\n */\n directKeyNames?: readonly string[]\n /**\n * Env names that may carry the sandbox gateway URL. The first non-empty value\n * wins, then defaultBaseUrl.\n */\n baseUrlNames?: readonly string[]\n /**\n * Base URL used when none of baseUrlNames are present.\n */\n defaultBaseUrl?: string\n /**\n * Whether direct env credentials are allowed for this environment. Defaults\n * to true in development/test and false in staging/production.\n */\n allowDirectEnvCredentials?: boolean | ((environment: SandboxCredentialEnvironment) => boolean)\n /**\n * Product-owned provision path, usually minting a per-user sandbox key from a\n * linked platform account. Called before direct env credentials in\n * staging/production and after direct env credentials in development/test.\n */\n provision?: (\n context: {\n environment: SandboxCredentialEnvironment\n env: Record<string, string | undefined>\n },\n ) => SandboxClientCredentials | null | undefined | Promise<SandboxClientCredentials | null | undefined>\n}\n\nconst DEFAULT_SANDBOX_DIRECT_KEY_NAMES = [\n 'TCLOUD_SANDBOX_API_KEY',\n 'SANDBOX_API_KEY',\n 'TANGLE_API_KEY',\n] as const\nconst DEFAULT_SANDBOX_BASE_URL_NAMES = ['SANDBOX_GATEWAY_URL', 'SANDBOX_API_URL'] as const\n\nfunction normalizeBaseUrl(value: string): string {\n return value.trim().replace(/\\/v1\\/?$/, '').replace(/\\/+$/, '')\n}\n\nfunction processEnv(): Record<string, string | undefined> {\n return typeof process === 'undefined' ? {} : process.env\n}\n\nfunction directEnvCredentialsAllowed(\n environment: SandboxCredentialEnvironment,\n allow: ResolveSandboxClientCredentialsOptions['allowDirectEnvCredentials'],\n): boolean {\n if (typeof allow === 'function') return allow(environment)\n if (typeof allow === 'boolean') return allow\n return environment === 'development' || environment === 'test'\n}\n\nfunction resolveSandboxBaseUrl(\n env: Record<string, string | undefined>,\n names: readonly string[],\n defaultBaseUrl: string | undefined,\n): string {\n for (const name of names) {\n const value = trimOrNull(env[name])\n if (value) return normalizeBaseUrl(value)\n }\n const value = trimOrNull(defaultBaseUrl)\n if (value) return normalizeBaseUrl(value)\n throw new Error(\n `Sandbox base URL is required (set one of ${names.join(', ')} or pass defaultBaseUrl).`,\n )\n}\n\nfunction resolveDirectSandboxCredentials(\n env: Record<string, string | undefined>,\n keyNames: readonly string[],\n baseUrlNames: readonly string[],\n defaultBaseUrl: string | undefined,\n): SandboxClientCredentials | null {\n for (const name of keyNames) {\n const apiKey = trimOrNull(env[name])\n if (!apiKey) continue\n return {\n apiKey,\n baseUrl: resolveSandboxBaseUrl(env, baseUrlNames, defaultBaseUrl),\n }\n }\n return null\n}\n\n/** Resolve sandbox client credentials based on environment and provided options asynchronously */\nexport async function resolveSandboxClientCredentials(\n options: ResolveSandboxClientCredentialsOptions = {},\n): Promise<SandboxClientCredentials> {\n const env = options.env ?? processEnv()\n const environment = options.environment ?? resolveTangleExecutionEnvironment(env)\n const keyNames = options.directKeyNames ?? DEFAULT_SANDBOX_DIRECT_KEY_NAMES\n const baseUrlNames = options.baseUrlNames ?? DEFAULT_SANDBOX_BASE_URL_NAMES\n const directAllowed = directEnvCredentialsAllowed(environment, options.allowDirectEnvCredentials)\n const direct = () =>\n directAllowed\n ? resolveDirectSandboxCredentials(env, keyNames, baseUrlNames, options.defaultBaseUrl)\n : null\n\n if (environment === 'development' || environment === 'test') {\n const credentials = direct()\n if (credentials) return credentials\n }\n\n const provisioned = await options.provision?.({ environment, env })\n if (provisioned) {\n return {\n apiKey: provisioned.apiKey,\n baseUrl: normalizeBaseUrl(provisioned.baseUrl),\n }\n }\n\n const credentials = direct()\n if (credentials) return credentials\n\n const directHint = directAllowed\n ? ` or set one of ${keyNames.join(', ')}`\n : ''\n throw new Error(\n `Sandbox credentials are required for ${environment} (provide a provision callback${directHint}).`,\n )\n}\n\n/**\n * Configure sandbox resources and lifecycle limits.\n * Set `advisory` for application defaults that the Sandbox API may clamp to account limits.\n * Omit it when the requested allocation must be honored or rejected.\n */\nexport interface SandboxResourceConfig {\n image: string\n cpuCores: number\n memoryMB: number\n diskGB: number\n /** Let the Sandbox API clamp these resource defaults to the account's limits. */\n advisory?: boolean\n maxLifetimeSeconds: number\n idleTimeoutSeconds: number\n}\n\n/** Define the context for building a sandbox including workspace, integrations, and optional user ID */\nexport interface SandboxBuildContext {\n workspaceId: string\n connectedIntegrationIds: string[]\n userId?: string\n}\n\n/**\n * Build the standard outbound policy for a product sandbox.\n *\n * Product code supplies its public origin and only the extra product-specific\n * destinations. The model capability registry is named explicitly because a\n * strict product sandbox must not inherit the platform's broad developer list.\n */\nfunction isWellFormedDomainPattern(pattern: string): boolean {\n if (!pattern || pattern.startsWith('.') || pattern.includes('..')) return false\n const labels = pattern.split('.')\n if (labels.some((label) => label.length === 0)) return false\n\n for (let index = 1; index < labels.length; index += 1) {\n if (labels[index]!.includes('*')) return false\n }\n\n const head = labels[0]!\n if (head === '*' || head === '**') return labels.length >= 2\n return !head.includes('*')\n}\n\n/** Hosts required when a product installs its pinned Python tooling at boot. */\nexport const PYPI_EGRESS_DOMAINS = ['pypi.org', 'files.pythonhosted.org', 'pypi.python.org'] as const\n\nexport function buildProductEgressPolicy(\n publicOrigin: string | URL,\n extraDomains: readonly string[] = [],\n): EgressPolicy {\n const origin = typeof publicOrigin === 'string' ? new URL(publicOrigin) : publicOrigin\n if (origin.protocol !== 'http:' && origin.protocol !== 'https:') {\n throw new Error(`Product egress origin must use http or https: ${origin.protocol}`)\n }\n if (!origin.hostname) throw new Error('Product egress origin must include a hostname')\n\n const domains = new Set<string>([origin.hostname.toLowerCase(), 'models.dev'])\n for (const value of extraDomains) {\n const domain = value.trim().toLowerCase().replace(/\\.$/, '')\n if (\n !domain\n || domain.includes('://')\n || domain.includes('/')\n || domain.includes(':')\n || !isWellFormedDomainPattern(domain)\n ) {\n throw new Error(`Product egress domain must be a hostname or wildcard: ${value}`)\n }\n domains.add(domain)\n }\n\n return {\n mode: 'strict',\n allowDomains: [...domains],\n includeImplicitDomains: false,\n }\n}\n\n// SDK-typed snapshot storage config (re-exported for product seam closures).\nexport type { StorageConfig }\n\n// Scope handed to per-identity seams. workspaceId is always present; userId is\n// present when the lifecycle op carries one. Workspace-keyed products ignore userId.\n/** Define a scope containing workspace and optional user identifiers for sandbox environments */\nexport interface SandboxScope {\n workspaceId: string\n userId?: string\n}\n\n// Snapshot RESTORE-on-create. Returned alongside storage; undefined => fresh box.\n/** Define the specification for restoring a sandbox from a snapshot or another sandbox ID */\nexport interface SandboxRestoreSpec {\n fromSnapshot: string\n fromSandboxId: string\n}\n\n/** Describe the failure details when resuming a stopped sandbox instance */\nexport interface StoppedSandboxResumeFailure {\n box: SandboxInstance\n error: Error\n scope: SandboxScope\n boxKey: string\n}\n\n/** Describe a sandbox that disappeared after the platform listed it. */\nexport interface MissingSandboxFailure extends StoppedSandboxResumeFailure {\n stage: SandboxExistingBoxStage\n}\n\n/** Define the structure for resuming a stopped sandbox with replacement key and optional restore options */\nexport interface StoppedSandboxResumeRecovery {\n // Used for both the replacement sandbox name and idempotency key.\n replacementBoxKey: string\n // undefined preserves the configured restore seam; null creates without one.\n restore?: SandboxRestoreSpec | null\n}\n\n/** Configure runtime exec verification before reusing a sandbox. */\nexport interface LivenessProbeConfig {\n /** Process timeout passed to the Sandbox SDK. Defaults to 5 seconds.\n * SDK readiness and transport deadlines also apply. */\n execTimeoutMs?: number\n /**\n * Reuse a successful liveness result for this many milliseconds for the\n * same box id. Defaults to 5 seconds; set to 0 to probe on every reuse.\n *\n * Only the exec probe is cached. Runtime readiness, egress policy,\n * deferred-file materialization, and bootstrap still run on every reuse.\n * A box that dies during this window is surfaced by the next dispatch and\n * is probed again after the TTL; the cache never triggers box deletion.\n */\n cacheTtlMs?: number\n}\n\n/** Define options for composing a user profile including prompts, files, servers, and name */\nexport interface ProfileComposeOptions {\n systemPrompt?: string\n extraFiles?: AgentProfileFileMount[]\n extraMcp?: Record<string, AgentProfileMcpServer>\n name?: string\n /**\n * The harness this profile is being composed for.\n *\n * Where a resource lands is harness-specific — skills resolve to\n * `.opencode/skills/`, `.claude/skills/`, `.pi/skills/`, and so on\n * (`skillDirForHarness`), and some harnesses take no cwd skills at all.\n * Without this, an app composing a profile cannot place a harness-native\n * resource and is pushed into hardcoding one harness's path, which then\n * silently disagrees with the path its own prompt cites: the agent is told\n * to read a directory nothing was written to and its skills are invisible.\n * Prefer declaring `resources.skills` and letting the platform place them;\n * use this when composing paths directly.\n */\n harness: Harness\n}\n\n/** Define runtime configuration methods for sandbox environments including credentials, metadata, and permissions */\nexport interface SandboxRuntimeConfig {\n // Widened to accept an optional scope and be async so a per-user key can be\n // minted. The sync, no-arg form still satisfies the type (back-compat).\n credentials: (\n scope?: SandboxScope,\n ) => SandboxClientCredentials | null | Promise<SandboxClientCredentials | null>\n name: (workspaceId: string) => string\n metadata: (harness: Harness) => Record<string, unknown>\n connectedIntegrationIds: (workspaceId: string) => Promise<string[]>\n /**\n * Creation-only environment. Use runtimeEnv for expiring app credentials.\n * Values remain private; profiles reference their names through secret-ref.\n * Workspace-wide values cannot carry per-user or per-resource authority.\n */\n env: (ctx: SandboxBuildContext) => Promise<Record<string, string>>\n /**\n * Workspace app credentials resolved on creation and before every reuse,\n * resume, or recovery. Fresh values override env in the creation payload.\n * The SDK updates retained runtimes before bootstrap and refuses runtime-managed keys.\n * A resume receives only the keys the platform names as required to rebuild a runtime.\n * Throw when required credentials cannot be minted; renewal failure preserves\n * the sandbox and prevents dispatch. Requires the matching Sandbox runtime.\n */\n runtimeEnv?: (scope: SandboxScope) => 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 /**\n * Portable directory where the sandbox starts its agent processes.\n *\n * The value is relative to the sandbox workspace. The sandbox platform\n * validates it and applies it when the box is created.\n */\n cwd?: string\n\n /**\n * Product-declared outbound network policy. Applied when a sandbox is\n * created. A reused or resumed sandbox is returned only when its explicit\n * policy already matches; existing mismatches are rejected without updating\n * or deleting the sandbox unless migration is explicitly enabled below.\n */\n egressPolicy?: EgressPolicy\n /**\n * Update an existing box to {@link egressPolicy} before reuse when its\n * recorded policy is absent or different. This is an explicit fleet\n * migration switch: the updated policy is read back and must match before\n * the box is returned. It never deletes the box.\n */\n migrateEgressPolicy?: boolean\n\n // BYOS3/R2 snapshot storage. Returns undefined => key omitted entirely\n // (fail-closed when creds absent). Product owns bucket/endpoint/credentials/prefix.\n storage?: (ctx: SandboxBuildContext) => StorageConfig | undefined\n // Snapshot RESTORE-on-create. undefined => fresh box. Called only when a box\n // is about to be created, so a product can resolve the restore point lazily\n // (listing snapshots is a Sandbox API round trip a reused box never needs).\n restore?: (ctx: SandboxBuildContext) => SandboxRestoreSpec | undefined | Promise<SandboxRestoreSpec | undefined>\n // Per-identity box NAME. Defaults to name(scope.workspaceId) when absent.\n boxKey?: (scope: SandboxScope) => string\n // Per-workspace child-key mint: overrides the resolved model apiKey before create.\n // Applied only when a model is resolved and its provider is openai-compat.\n childKeyMint?: (scope: SandboxScope) => Promise<Outcome<string>>\n // One-shot post-running bootstrap, on BOTH create and reuse paths (idempotency\n // is the closure's job — it owns the marker check).\n bootstrap?: (box: SandboxInstance, scope: SandboxScope) => Promise<Outcome<void>>\n // Reuse health gate + sidecar liveness probe.\n livenessProbe?: LivenessProbeConfig\n // Enable browser terminal endpoints on newly-created sandboxes.\n webTerminalEnabled?: boolean\n // default true: try stopped-resume before create.\n resumeStopped?: boolean\n /**\n * How long to wait for a box to reach `running`, in ms. Default 120_000.\n *\n * Raise it when a cold create legitimately takes longer than that — a large\n * vault restore, a heavy image, a loaded fleet. The failure it prevents is\n * ugly: every attempt burns the full wait, times out, and the NEXT attempt\n * starts the same slow create from scratch, so a workspace whose provision\n * takes 130s never succeeds no matter how many times a user retries.\n */\n provisionTimeoutMs?: number\n // Opt in to replacing a box the platform cannot bring up.\n //\n // Default false, and the default is the conservative one on purpose: a\n // replacement is a delete, and delete DEPROVISIONS the persistent workspace\n // (#299). An app whose durable state lives in the box's filesystem must not\n // set this — losing the box loses the user's work.\n //\n // Set it when the box is a CACHE of state held elsewhere (a vault, a DB, an\n // object store) and can be rebuilt. Then a box that cannot be started is\n // abandoned and re-created once, instead of leaving the workspace unable to\n // run for as long as the box stays unbringable — which, without this, is\n // forever: the box key is derived from the workspace, so every later attempt\n // resumes the same dead box and fails identically.\n replaceUnbringableBox?: boolean\n // Product-owned retention/recovery policy after a stopped box fails to resume.\n // Return ok(null) to preserve the original resume error. A replacement key is\n // required before this shell creates a new box, so it cannot resolve the\n // failed stopped box through the original idempotency identity.\n recoverStoppedSandbox?: (\n failure: StoppedSandboxResumeFailure,\n ) => Promise<Outcome<StoppedSandboxResumeRecovery | null>>\n /**\n * Replace a sandbox resource or backing container that disappears after listing.\n *\n * The shell calls this for a sandbox resource 404 or an exact resume 500 that\n * wraps a host-agent container 404. It excludes runtime 404 and unrelated\n * reuse failures. Return a fresh key without deleting the stale sandbox record.\n */\n recoverMissingSandbox?: (\n failure: MissingSandboxFailure,\n ) => Promise<Outcome<StoppedSandboxResumeRecovery | null>>\n // default false: bake resolveModel() into the backend's model fields at create.\n backendModelAtCreate?: boolean\n // default false: write the profile's `resources.files` INTO the box after it\n // reaches running (via `box.exec`), instead of inlining them in the create\n // payload. The orchestrator caps the provision body at 256 KiB; a large\n // file corpus (skills, tool scripts) blows that cap. Deferring it keeps the\n // provision body small and uncapped in corpus size, and lands real files on\n // disk — which is also the only path that works for harnesses whose backend\n // does not materialize the provider-neutral `resources.files` channel.\n //\n // Only `kind: 'inline'` files are deferred; non-inline refs (e.g. github)\n // stay in the create payload so the orchestrator resolves them. Runs on the\n // create AND resume/reuse paths (idempotent overwrite). Inline files are\n // Removed from create and per-turn profiles; the deferred writer owns them.\n deferProfileFiles?: boolean\n // Byte budget on the system prompt of the profile this shell actually SENDS\n // (provision + every turn). Defaults to the same 40 KB cap\n // `composeAgentProfile` applies; set `warnOnly` + `overBudgetReason` to\n // downgrade it. Wired here because the composer is opt-in: a product may\n // hand-build its profile, or carry its real prompt only on the PER-TURN\n // backend, and then the compose-time gate never runs on the bytes the model\n // sees. An over-budget prompt degrades toward empty answers, which is\n // indistinguishable from a broken stream — so it fails loud instead.\n promptBudget?: ComposeProfileBudget\n}\n\n/** Define default resource limits and settings for sandbox environments */\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\nconst livenessVerifiedAt = new Map<string, number>()\n/** Reused boxes whose `open` egress this isolate verified, by {@link verifiedEgressKey}. */\nconst verifiedEgress = new Map<string, number>()\n\nfunction getClientFromCreds(creds: SandboxClientCredentials): Sandbox {\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\n// Sync client for non-scoped callers (secretStoreFromClient etc.). Resolves\n// credentials with no scope; throws if the seam returns a Promise — scoped\n// products must use the async ensureWorkspaceSandbox path.\n/** Resolve a synchronous sandbox client from provided runtime configuration credentials */\nexport function getClient(shell: SandboxRuntimeConfig): Sandbox {\n const creds = shell.credentials()\n if (creds && typeof (creds as Promise<unknown>).then === 'function') {\n throw new Error('getClient: scoped (async) credentials require the async sandbox path')\n }\n if (!creds) throw new Error('sandbox credentials are required (apiKey/baseUrl)')\n return getClientFromCreds(creds as SandboxClientCredentials)\n}\n\n/** Reset the process-local sandbox client and liveness-verification caches. */\nexport function resetClientCache(): void {\n _cached = null\n livenessVerifiedAt.clear()\n verifiedEgress.clear()\n}\n\n/** Describe an application tool with its name, unique key, and description */\nexport interface AppToolDescriptor {\n tool: AppToolName\n key: string\n description: string\n}\n\n/** Define options for building MCP server configurations in the app tool environment */\nexport interface BuildAppToolMcpServersOptions {\n tools: AppToolDescriptor[]\n baseUrl: string\n /**\n * NAME of the box-environment variable holding the capability token — never\n * the token itself. Every emitted `Authorization` header is a `secret-ref` to\n * this key, which the sandbox resolves privately; see\n * `BuildHttpMcpServerOptions.tokenEnvKey` in `../tools/mcp`.\n *\n * The key must name a variable the box carries — placed by\n * {@link SandboxRuntimeConfig.env} at creation, refreshed by\n * {@link SandboxRuntimeConfig.runtimeEnv} before retained-box bootstrap, or\n * injected from the platform secret store via\n * {@link SandboxRuntimeConfig.secrets}.\n */\n tokenEnvKey: string\n ctx: AppToolContext\n headerNames?: ToolHeaderNames\n}\n\n/** Build a mapping of MCP server profiles keyed by tool identifiers from provided options */\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 // No cast: since the tagged-config contract (agent-interface 0.38.0) the\n // builder's own return type IS an AgentProfileMcpServer. The cast that used\n // to sit here is what let the pre-0.38.0 plain-string shape ship.\n entries[key] = buildAppToolMcpServer({\n tool,\n baseUrl: options.baseUrl,\n tokenEnvKey: options.tokenEnvKey,\n ctx: options.ctx,\n description,\n headerNames: options.headerNames,\n })\n }\n return entries\n}\n\n/** Define options for ensuring a workspace sandbox with provisioning and progress handling */\nexport interface EnsureWorkspaceSandboxOptions {\n workspaceId: string\n userId?: string\n harness: Harness\n // When set, both the running-reuse and stopped-resume short-circuits are\n // skipped and any name-matched box is removed before create. Replacement\n // fails if removal remains pending after the SDK's bounded wait. This is the\n // ONLY way a liveness-failed box is discarded: a failed probe triggers a\n // state-preserving stop→resume recovery (or a SandboxRecoveryFailedError),\n // never a delete — delete deprovisions the persistent workspace (#299).\n forceNew?: boolean\n // Real-time provisioning progress from the SDK's SSE stream, forwarded from\n // the `waitFor('running')` calls on the resume and cold-create paths. Callers\n // surface it as live \"warming up\" status. Only fires while a box is actually\n // being provisioned; a reused running box emits nothing.\n onProgress?: (event: ProvisionEvent) => void\n // Billing owner for the created box, forwarded VERBATIM on the create\n // payload. The sandbox platform honors it only when the create-auth\n // principal is a trusted first-party service; the box's usage then bills\n // this platform user's wallet (the platform's per-user router-key mint)\n // instead of the service account that authenticated the create. Omitted =>\n // platform default (billing owner = create-auth principal) — unchanged.\n billingOwnerId?: string\n // Optional consumer-side spend verification. Omitted, nothing here changes:\n // no extra call, no extra await, no behavior difference. Wired, it is the one\n // seam where a product both refuses to provision past a compute cap and\n // records that a box is now billable against it.\n //\n // Structural on purpose. `@tangle-network/agent-app/spend` supplies an\n // implementation (`createSandboxSpendHooks`), but this module takes no\n // dependency on it — /spend composes /sandbox, and importing back the other\n // way would invert the layering.\n spend?: SandboxSpendHooks\n /** Optional stage timing for the steps of an ensure (`sandbox.ensure.*`), so a\n * product can see which round trip a slow acquisition spent its time in.\n * Omitted, nothing is measured. */\n measure?: <T>(stage: string, operation: () => Promise<T>) => Promise<T>\n /**\n * The turn's trace. The ensure is recorded as one `sandbox.claim` span whose children are the\n * `sandbox.ensure.*` steps (`credentials`, `list_running`, `finalize` for a reused box; `list_stopped`,\n * `resume` for a stopped one; `create`, `wait_running`, `bootstrap` for a new one), so a slow claim names\n * the step it waited on. Omitted, nothing is recorded; `measure` is unchanged and still called.\n */\n trace?: TurnTrace\n /** The span the claim hangs from. Default: the trace's root. */\n traceParent?: TurnSpan\n}\n\n/** What `/sandbox` reports once a box is provisioned, reused, or resumed. */\nexport interface SandboxProvisionedObservation {\n readonly workspaceId: string\n readonly userId?: string\n /** The platform's sandbox id — the join key to every settlement row. */\n readonly sandboxId: string\n /** The deterministic box key this workspace resolves to. */\n readonly boxKey?: string | undefined\n /** The idle timeout this box was asked to run with, seconds. */\n readonly idleTimeoutSeconds: number\n /** The max lifetime it was asked to run with, seconds, when one was asked for. */\n readonly maxLifetimeSeconds?: number | undefined\n readonly at: number\n}\n\n/**\n * Optional spend-verification seam on `ensureWorkspaceSandbox`.\n *\n * The two halves have deliberately opposite failure contracts.\n * `beforeProvision` is a GATE: it runs before anything is created and its throw\n * propagates, because refusing to provision is the whole point of a budget cap.\n * `onProvisioned` is an OBSERVER: its failures are swallowed, because\n * bookkeeping must never take down the provisioning it is bookkeeping.\n */\nexport interface SandboxSpendHooks {\n /** Runs before any create, resume, or reuse. Throw to refuse provisioning. */\n beforeProvision?(input: { workspaceId: string; userId?: string }): Promise<void> | void\n /** Runs after a box is available. Throwing here cannot fail the provision. */\n onProvisioned?(observation: SandboxProvisionedObservation): Promise<void> | void\n /**\n * The box is doing work. Fired by the turn primitives at the start of a turn\n * and again when it settles.\n *\n * Deliberately SYNCHRONOUS and unawaited — this sits on the turn path, and a\n * store write must not add latency to it or hold a stream open. An\n * implementation that persists should enqueue and return; errors are\n * swallowed here as they are for `onProvisioned`.\n *\n * Wiring it is what keeps the expectation ceiling honest for long turns:\n * without it, `lastActivityAt` only advances when a box is provisioned, so a\n * three-hour turn leaves the ceiling three hours too tight and manufactures a\n * discrepancy out of the product's own silence.\n */\n onActivity?(input: { sandboxId: string; at: number }): void\n}\n\n/** Fire an activity tap without letting it affect the turn it reports on. */\nfunction emitSandboxActivity(spend: SandboxSpendHooks | undefined, box: SandboxInstance): void {\n if (!spend?.onActivity) return\n try {\n spend.onActivity({ sandboxId: box.id, at: Date.now() })\n } catch {\n // An observability seam must never take down the turn it reports on.\n }\n}\n\n// Single-quote a string for safe interpolation into a shell command.\nfunction shellSingleQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`\n}\n\n/** Define the specification for a sandbox tool including its name, content, and optional executability */\nexport interface SandboxToolSpec {\n name: string\n content: string\n executable?: boolean\n}\n\n/** Define options for resolving sandbox tool paths including appName, baseDir, and binDir */\nexport interface SandboxToolPathOptions {\n appName: string\n baseDir?: string\n binDir?: string\n}\n\n/** Define options for building sandbox tool file mounts including tool specifications and paths */\nexport interface BuildSandboxToolFileMountsOptions extends SandboxToolPathOptions {\n tools: readonly SandboxToolSpec[]\n}\n\nconst DEFAULT_SANDBOX_TOOL_BASE_DIR = '/home/agent/tools'\nconst SAFE_TOOL_SEGMENT = /^[A-Za-z0-9._-]+$/\n\nfunction normalizeSandboxToolSegment(value: string, label: string): string {\n const segment = value.trim()\n if (!segment || segment === '.' || segment === '..' || !SAFE_TOOL_SEGMENT.test(segment)) {\n throw new Error(`${label} must contain only letters, numbers, dots, underscores, or hyphens.`)\n }\n return segment\n}\n\nfunction normalizeSandboxToolDir(value: string, label: string): string {\n const dir = value.trim().replace(/\\/+$/, '')\n if (!dir || !dir.startsWith('/') || dir.includes('\\0') || dir.includes('\\n')) {\n throw new Error(`${label} must be an absolute sandbox path.`)\n }\n return dir === '' ? '/' : dir\n}\n\n/** Resolve the root directory path for a sandbox tool based on provided options */\nexport function sandboxToolRootDir(options: SandboxToolPathOptions): string {\n const appName = normalizeSandboxToolSegment(options.appName, 'sandbox tool appName')\n const baseDir = normalizeSandboxToolDir(\n options.baseDir ?? DEFAULT_SANDBOX_TOOL_BASE_DIR,\n 'sandbox tool baseDir',\n )\n return `${baseDir}/${appName}`\n}\n\n/** Resolve the binary directory path for a sandbox tool based on provided options */\nexport function sandboxToolBinDir(options: SandboxToolPathOptions): string {\n normalizeSandboxToolSegment(options.appName, 'sandbox tool appName')\n if (options.binDir) return normalizeSandboxToolDir(options.binDir, 'sandbox tool binDir')\n return `${sandboxToolRootDir(options)}/bin`\n}\n\n/** Resolve the file system path to a specified sandbox tool based on given options */\nexport function sandboxToolPath(options: SandboxToolPathOptions & { toolName: string }): string {\n const toolName = normalizeSandboxToolSegment(options.toolName, 'sandbox tool name')\n return `${sandboxToolBinDir(options)}/${toolName}`\n}\n\n/** Build file mounts for sandbox tools based on provided options and tool configurations */\nexport function buildSandboxToolFileMounts(\n options: BuildSandboxToolFileMountsOptions,\n): AgentProfileFileMount[] {\n return options.tools.map((tool) => {\n const name = normalizeSandboxToolSegment(tool.name, 'sandbox tool name')\n return {\n path: sandboxToolPath({ ...options, toolName: name }),\n resource: { kind: 'inline' as const, name, content: tool.content },\n executable: tool.executable ?? true,\n }\n })\n}\n\n/**\n * Build the `SANDBOX_TOOL_BIN_DIRS` entry that puts these apps' tool bin dirs on\n * a sandbox PATH. Declare it in the same box env as the mounts from\n * {@link buildSandboxToolFileMounts}: the mounts place the executables, this\n * places the directory that makes a bare tool name resolve.\n *\n * Every sandbox PATH builder appends these directories at the TAIL, after the\n * Nix, npm, and image entries, so a tool never shadows a platform or system\n * binary of the same name. That placement is identical for a non-interactive\n * exec, a sidecar-spawned CLI, and an SSH shell, which is why this variable and\n * not a shell rc file is the mechanism: an exec reads no rc file, and the SSH\n * shell environment assigns PATH absolutely.\n *\n * Entries come from {@link sandboxToolBinDir}, so the value can never name a\n * directory the mounts did not use — a caller that hand-writes the literal\n * instead drifts silently the moment a base dir changes. Order is preserved,\n * and two apps that resolve to one directory collapse to the FIRST position it\n * appeared in.\n *\n * A `:` in a resolved bin dir throws here. The character separates entries both\n * in this variable and in PATH itself, so such a directory is unrepresentable\n * rather than merely awkward: joining it would split one absolute path into a\n * leading path and a relative remainder, and the runtime rejects a relative\n * segment by failing the whole box. Throwing names the offending directory\n * instead.\n *\n * The consuming half lives in agent-container: `resolveSandboxToolBinDirs`\n * parses this value and every PATH builder appends it at the tail — sidecar\n * exec and PTY through `packages/shared/src/cache-env.ts`, an SSH session\n * through `packages/shared/src/ssh-bootstrap.ts`, and a spawned CLI through\n * `packages/sdk-cli-runner/src/cli-process.ts`, each with its own tests. This\n * package has no sandbox runtime, so tail placement is pinned there, not here.\n */\nexport function buildSandboxToolBinDirsEnv(\n apps: readonly SandboxToolPathOptions[],\n): { SANDBOX_TOOL_BIN_DIRS: string } {\n if (apps.length === 0) {\n throw new Error(\n 'buildSandboxToolBinDirsEnv: name at least one app whose tool bin dir belongs on PATH.',\n )\n }\n const binDirs = new Set<string>()\n for (const app of apps) {\n const binDir = sandboxToolBinDir(app)\n if (binDir.includes(':')) {\n throw new Error(\n `sandbox tool bin dir ${binDir} contains ':', which separates entries in ` +\n 'SANDBOX_TOOL_BIN_DIRS and in PATH. Place the tools under a colon-free directory.',\n )\n }\n binDirs.add(binDir)\n }\n return { SANDBOX_TOOL_BIN_DIRS: [...binDirs].join(':') }\n}\n\n/**\n * Build a shell script that creates the sandbox tool binary directory.\n * {@link buildSandboxToolBinDirsEnv}, not this script, puts that directory on a\n * sandbox PATH.\n *\n * The `mkdir -p` makes the directory exist before a tool mount lands in it.\n */\nexport function buildSandboxToolBinDirScript(options: SandboxToolPathOptions): string {\n return ['set -eu', `mkdir -p ${shellSingleQuote(sandboxToolBinDir(options))}`].join('\\n')\n}\n\n/** Build a shell script that creates the sandbox tool binary directory.\n *\n * @deprecated Renamed to {@link buildSandboxToolBinDirScript}, and the script\n * no longer appends the bin dir to PATH in `~/.profile`, `~/.bashrc` and\n * `~/.zshrc`. Those edits never reached the contexts that run a tool: an exec\n * and a spawned CLI read no rc file, and the SSH shell assigns PATH\n * absolutely, which discards an appended entry. Put the directory on PATH with\n * {@link buildSandboxToolBinDirsEnv} instead. This name forwards to the new\n * one so an existing import keeps resolving; removal is a major.\n */\nexport function buildSandboxToolPathSetupScript(options: SandboxToolPathOptions): string {\n return buildSandboxToolBinDirScript(options)\n}\n\n/**\n * Create the sandbox tool binary directory in a running box.\n * {@link buildSandboxToolBinDirsEnv}, not this call, puts it on a sandbox PATH.\n */\nexport async function ensureSandboxToolBinDir(\n box: SandboxInstance,\n options: SandboxToolPathOptions,\n): Promise<Outcome<void>> {\n try {\n const res = await box.exec(buildSandboxToolBinDirScript(options))\n if (res.exitCode !== 0) {\n return fail(\n new Error(\n `ensureSandboxToolBinDir: failed to create the tool bin dir ${sandboxToolBinDir(options)} ` +\n `(exit ${res.exitCode}): ${res.stderr.slice(0, 500)}`,\n ),\n )\n }\n return ok(undefined)\n } catch (err) {\n return fail(new Error('ensureSandboxToolBinDir: exec failed', { cause: err }))\n }\n}\n\n/** Create the sandbox tool binary directory in a running box.\n *\n * @deprecated Renamed to {@link ensureSandboxToolBinDir}, and the call no\n * longer appends the bin dir to PATH in `~/.profile`, `~/.bashrc` and\n * `~/.zshrc`. Those edits never reached the contexts that run a tool: an exec\n * and a spawned CLI read no rc file, and the SSH shell assigns PATH\n * absolutely, which discards an appended entry. Put the directory on PATH with\n * {@link buildSandboxToolBinDirsEnv} instead. This name forwards to the new\n * one so an existing import keeps resolving; removal is a major.\n */\nexport async function runSandboxToolPathSetup(\n box: SandboxInstance,\n options: SandboxToolPathOptions,\n): Promise<Outcome<void>> {\n return ensureSandboxToolBinDir(box, options)\n}\n\n// Build a shell-safe path token that preserves tilde-home semantics. A path\n// beginning `~/` (or a bare `~`) must resolve to the box user's real `$HOME`,\n// but single-quoting the whole path suppresses shell `~` expansion and lands\n// the file in a literal directory named `~`. Expand the leading `~` to an\n// UNQUOTED `\"$HOME\"` (so the shell expands it) and single-quote only the\n// remainder. Absolute and relative paths are single-quoted unchanged.\nfunction shellPath(path: string): string {\n if (path === '~') return '\"$HOME\"'\n if (path.startsWith('~/')) {\n const rest = path.slice(2)\n return rest ? `\"$HOME\"/${shellSingleQuote(rest)}` : '\"$HOME\"'\n }\n return shellSingleQuote(path)\n}\n\n// Split a profile's `resources.files` into the inline mounts that can be\n// written into a running box and the rest (non-inline refs that the\n// orchestrator must resolve, so they stay in the create payload). Returns the\n// inline set to defer and a profile copy with those inline files removed.\n/** Split profile files into inline deferred files and a lean profile without them */\nexport function splitDeferredProfileFiles(\n profile: AgentProfile,\n): { leanProfile: AgentProfile; deferredFiles: AgentProfileFileMount[] } {\n const files = profile.resources?.files ?? []\n const deferredFiles: AgentProfileFileMount[] = []\n const keptFiles: AgentProfileFileMount[] = []\n for (const mount of files) {\n if (mount.resource.kind === 'inline') deferredFiles.push(mount)\n else keptFiles.push(mount)\n }\n if (deferredFiles.length === 0) return { leanProfile: profile, deferredFiles }\n const leanProfile: AgentProfile = {\n ...profile,\n resources: { ...(profile.resources ?? {}), files: keptFiles },\n }\n return { leanProfile, deferredFiles }\n}\n\n// The runtime exec proxy (`box.exec` → /terminals/commands) hangs (30s\n// timeout) on any request whose body crosses ~4096 bytes, and one oversized\n// exec wedges the channel so every later exec on the box hangs too. We slice\n// each file's base64 into appends whose full command string stays well under\n// that cap. 3000 chars of base64 leaves ~1000 bytes of headroom for the\n// surrounding `printf '%s' '<slice>' >> <path>.b64` command plus the proxy's\n// JSON request envelope — comfortably below 4096.\nconst PROFILE_WRITE_B64_CHUNK_CHARS = 3000\n\n// gtm's corpus is ~135 small execs; on a cold box the runtime exec proxy\n// hard-throttles (HTTP 429 after ~21 execs in ~34s) and, under sustained load,\n// SILENTLY HANGS instead of returning 429 — one parked exec wedges the channel\n// and `writeProfileFilesToBox` never returns, so `ensureWorkspaceSandbox`\n// parks the worker (~140s, no exception). These failures plus sidecar exec-plane\n// readiness/transport failures (5xx, reset, fetch/network errors) are transient:\n// retry the SAME exec with exponential backoff before failing loud. A non-zero\n// exit is a real command failure, never retried.\nconst PROFILE_WRITE_MAX_RETRIES = 4\nconst PROFILE_WRITE_RETRY_BASE_MS = 250\nconst PROFILE_WRITE_RETRY_MAX_MS = 2000\n\n// Client-side hard ceiling per exec. The proxy's own 30s timeout is unreliable\n// once the channel wedges (it can hang past it), so we race each exec against an\n// independent timer we control: a wedged exec is abandoned here and retried as a\n// transient transport error, never silently parked. We also pass timeoutMs to\n// the SDK as defense-in-depth, but the race is the guarantee.\nconst PROFILE_WRITE_EXEC_TIMEOUT_MS = 30_000\n\n// Pacing between execs to stay under the proxy throttle that triggers the hang.\n// The drill saw throttling at ~0.6 exec/s bursts; ~150ms between ~135 execs\n// adds well under a minute total and keeps the burst rate below the trip point.\n// On by default for the deferred path; overridable for tests/tuning.\nconst PROFILE_WRITE_PACE_MS = 150\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms))\n\n// A mount whose path sits in a bin directory is made executable. Shared so the\n// file-API eligibility check and the exec branch agree on \"executable by dir\".\nconst PROFILE_BIN_DIR_RE = /(^|\\/)(s?bin)\\//\n\n// Sentinel cause for a client-side per-exec timeout (a hung/wedged proxy exec).\n// Carried as the `.cause` of the fail-loud Outcome so callers see the wedged\n// command instead of an opaque infinite hang.\nclass ProfileWriteExecTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`exec exceeded ${timeoutMs}ms (proxy hang/wedge)`)\n this.name = 'ProfileWriteExecTimeoutError'\n }\n}\n\n// Run a box.exec, abandoning it if it does not settle within timeoutMs. The\n// returned promise rejects with ProfileWriteExecTimeoutError on timeout so the\n// retry loop treats a hang exactly like a transient transport error. We also\n// forward timeoutMs to the SDK so the underlying request is cancelled when the\n// SDK honors it; the race covers the case where it does not.\nfunction execWithTimeout(\n box: SandboxInstance,\n cmd: string,\n timeoutMs: number,\n): Promise<ExecResult> {\n return new Promise<ExecResult>((resolve, reject) => {\n let settled = false\n const timer = setTimeout(() => {\n if (settled) return\n settled = true\n reject(new ProfileWriteExecTimeoutError(timeoutMs))\n }, timeoutMs)\n box.exec(cmd, { timeoutMs }).then(\n (res) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n resolve(res)\n },\n (err) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n reject(err)\n },\n )\n })\n}\n\nconst TRANSIENT_EXEC_STATUS_CODES = new Set([408, 409, 425, 429, 500, 502, 503, 504])\nconst TRANSIENT_EXEC_CODE_RE = /^(ECONNRESET|ECONNREFUSED|ETIMEDOUT|EPIPE|ECONNABORTED)$/i\nconst TRANSIENT_EXEC_MESSAGE_RE =\n /\\b(408|409|425|429|500|502|503|504)\\b|rate.?limit|too many requests|\\bfetch failed\\b|network error|connection reset|socket hang up|timed? out|service unavailable|bad gateway|gateway timeout|internal server error|\\b(?:sidecar|runtime|exec(?:ution)?|terminal|sandbox|service|command(?:s)?|proxy)\\b.{0,80}\\bnot ready\\b|\\bnot ready\\b.{0,80}\\b(?:sidecar|runtime|exec(?:ution)?|terminal|sandbox|service|command(?:s)?|proxy)\\b/i\nconst RUNTIME_AUTH_REFRESH_SKEW_MS = 60_000\n\nfunction errorStatus(err: { status?: unknown; statusCode?: unknown; response?: unknown }): number | undefined {\n const rawStatus = err.status ?? err.statusCode ?? (\n err.response && typeof err.response === 'object'\n ? (err.response as { status?: unknown }).status\n : undefined\n )\n if (typeof rawStatus === 'number') return rawStatus\n if (typeof rawStatus === 'string' && /^\\d+$/.test(rawStatus)) return Number(rawStatus)\n return undefined\n}\n\nfunction retryAfterMs(err: unknown, seen = new Set<object>()): number | undefined {\n if (!err || typeof err !== 'object') return undefined\n if (seen.has(err)) return undefined\n seen.add(err)\n const e = err as { retryAfterMs?: unknown; cause?: unknown }\n if (typeof e.retryAfterMs === 'number') return e.retryAfterMs\n return retryAfterMs(e.cause, seen)\n}\n\nfunction isTransientExecError(err: unknown, seen = new Set<object>()): boolean {\n if (!err || typeof err !== 'object') return false\n if (seen.has(err)) return false\n seen.add(err)\n const e = err as {\n status?: unknown\n statusCode?: unknown\n response?: unknown\n code?: unknown\n message?: unknown\n cause?: unknown\n }\n const status = errorStatus(e)\n if (status !== undefined && TRANSIENT_EXEC_STATUS_CODES.has(status)) return true\n if (typeof e.code === 'string') {\n if (TRANSIENT_EXEC_CODE_RE.test(e.code)) return true\n if (/rate.?limit|too.?many.?requests|429|server.?error|service.?unavailable/i.test(e.code)) return true\n }\n if (typeof e.message === 'string' && TRANSIENT_EXEC_MESSAGE_RE.test(e.message)) return true\n return isTransientExecError(e.cause, seen)\n}\n\nfunction isRuntimeExecAuthError(err: unknown, seen = new Set<object>()): boolean {\n if (!err || typeof err !== 'object') return false\n if (seen.has(err)) return false\n seen.add(err)\n const e = err as {\n status?: unknown\n statusCode?: unknown\n response?: unknown\n code?: unknown\n name?: unknown\n message?: unknown\n cause?: unknown\n }\n if (errorStatus(e) === 401) return true\n if (\n typeof e.code === 'string' &&\n /^(AUTH_ERROR|AUTHENTICATION_ERROR|UNAUTHORIZED|UNAUTHENTICATED|ERR_UNAUTHORIZED|ERR_UNAUTHENTICATED|401)$/i.test(e.code)\n ) {\n return true\n }\n if (\n typeof e.name === 'string' &&\n /^(AuthError|AuthenticationError|UnauthorizedError|UnauthenticatedError|SandboxAuthError)$/i.test(e.name)\n ) {\n return true\n }\n return isRuntimeExecAuthError(e.cause, seen)\n}\n\nfunction isRuntimeAuthRefreshDenied(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false\n return (\n isRuntimeExecAuthError(err) ||\n errorStatus(err as { status?: unknown; statusCode?: unknown; response?: unknown }) === 403\n )\n}\n\n// Classify an exec failure as transient-retryable. Retryable shapes share the\n// same backoff path: rate-limit (HTTP 429 + retryAfterMs), client-side timeout,\n// and transient sidecar/transport/readiness failures surfaced as SandboxError-\n// shaped objects, fetch errors, network resets, or 5xx-ish messages. Everything\n// else fails loud. Non-zero shell exits never reach this classifier.\nfunction transientExecError(err: unknown): { retryable: boolean; retryAfterMs?: number } {\n if (err instanceof ProfileWriteExecTimeoutError) return { retryable: true }\n if (isTransientExecError(err)) return { retryable: true, retryAfterMs: retryAfterMs(err) }\n return { retryable: false }\n}\n\nfunction deferredProfileWriteFailed(stage: 'new' | 'reused' | 'resumed', name: string, cause: Error): Error {\n return new Error(`deferred file write failed on ${stage} box ${name}: ${cause.message}`, { cause })\n}\n\nexport type SandboxExistingBoxStage = 'reused' | 'resumed'\n\nexport type SandboxEgressPolicySource = Awaited<\n ReturnType<SandboxInstance['egress']['get']>\n>['source']\n\n/**\n * Thrown when an existing sandbox cannot be proven to have the requested\n * outbound network policy. The sandbox is preserved and its policy is not\n * changed. The caller explicitly decides whether to preserve, migrate, or\n * replace the sandbox.\n */\nexport class SandboxEgressPolicyMismatchError extends Error {\n readonly stage: SandboxExistingBoxStage\n readonly boxName: string\n readonly currentPolicy: EgressPolicy\n readonly currentSource: SandboxEgressPolicySource\n readonly desiredPolicy: EgressPolicy\n\n constructor(\n stage: SandboxExistingBoxStage,\n boxName: string,\n currentPolicy: EgressPolicy,\n currentSource: SandboxEgressPolicySource,\n desiredPolicy: EgressPolicy,\n ) {\n super(\n `egress policy mismatch on ${stage} box ${boxName}: ` +\n `current ${currentPolicy.mode} policy from ${currentSource} does not explicitly match ` +\n `desired ${desiredPolicy.mode} policy; the existing box was preserved and egress was not updated.`,\n )\n this.name = 'SandboxEgressPolicyMismatchError'\n this.stage = stage\n this.boxName = boxName\n this.currentPolicy = currentPolicy\n this.currentSource = currentSource\n this.desiredPolicy = desiredPolicy\n }\n}\n\nimport {\n isSandboxApiSandboxMissingFailure,\n isLegacySandboxBackingContainerMissingMessage,\n SANDBOX_BACKING_CONTAINER_MISSING_CODE,\n isSandboxBoxConfigFailure,\n isSandboxHostCapacityFailure,\n serializeSandboxProvisioningError,\n} from './diagnostics'\n\nexport * from './recovery'\n\nexport {\n serializeSandboxProvisioningError,\n formatSandboxProvisioningSupportDetails,\n formatSandboxProvisioningUserMessage,\n isSandboxAuthFailure,\n isSandboxApiBearerAuthFailure,\n isSandboxApiSandboxMissingFailure,\n isSandboxApiTransientFailure,\n SANDBOX_BACKING_CONTAINER_MISSING_CODE,\n isSandboxHostCapacityFailure,\n type SafeSandboxErrorCause,\n type SafeSandboxErrorDiagnostics,\n} from './diagnostics'\n\n/** Represent an error thrown when sandbox runtime authentication refresh fails for a specific stage and name */\nexport class SandboxRuntimeAuthRefreshError extends Error {\n constructor(stage: SandboxExistingBoxStage, name: string, detail: string, cause?: unknown) {\n super(`${stage} sandbox auth refresh failed for ${name}: ${detail}`, { cause })\n this.name = 'SandboxRuntimeAuthRefreshError'\n }\n}\n\n/** Which step of the state-preserving stop→resume recovery failed. `stop` with a\n * driver-unsupported cause means the platform cannot restart this box (the\n * `tangle` driver exposes create/delete only); `probe` means the box restarted\n * but is still unresponsive. */\nexport type SandboxRecoveryPhase = 'stop' | 'resume' | 'probe'\n\n/**\n * Thrown when an unresponsive box could not be recovered by a state-preserving\n * restart. Contract: this error is only ever thrown with the workspace intact —\n * recovery never deletes. The caller decides what to do next (retry, surface to\n * the user, or explicitly replace via `forceNew`).\n */\nexport class SandboxRecoveryFailedError extends Error {\n readonly boxKey: string\n readonly stage: SandboxExistingBoxStage\n readonly phase: SandboxRecoveryPhase\n constructor(\n stage: SandboxExistingBoxStage,\n boxKey: string,\n phase: SandboxRecoveryPhase,\n detail: string,\n cause?: unknown,\n ) {\n super(\n `${stage} sandbox ${boxKey} failed liveness recovery at ${phase}: ${detail}. ` +\n `The workspace is preserved; pass forceNew to replace the box.`,\n { cause },\n )\n this.name = 'SandboxRecoveryFailedError'\n this.boxKey = boxKey\n this.stage = stage\n this.phase = phase\n }\n}\n\n/**\n * Thrown instead of restarting a box that failed the reuse gate because it is\n * not connectable (runtime URL missing or edge readiness failed) while its\n * runtime reports running sessions. A restart would end those sessions, so the\n * box is left running and only the request that asked for it fails. The box is\n * not replaced either; retry once its sessions finish.\n */\nexport class SandboxBoxBusyError extends Error {\n readonly boxKey: string\n readonly stage: SandboxExistingBoxStage\n readonly runningSessions: number\n constructor(stage: SandboxExistingBoxStage, boxKey: string, runningSessions: number, detail: string) {\n super(\n `${stage} sandbox ${boxKey} is not connectable (${detail}) but is serving ${runningSessions} running ` +\n `session${runningSessions === 1 ? '' : 's'}, so it was not restarted. Retry when they finish.`,\n )\n this.name = 'SandboxBoxBusyError'\n this.boxKey = boxKey\n this.stage = stage\n this.runningSessions = runningSessions\n }\n}\n\n// Materialize inline profile files into a running box via `box.exec`. Uses a\n// base64 pipe so arbitrary content (scripts, unicode, special chars) lands\n// byte-exact, and writes to ANY absolute path (e.g. /usr/local/bin) or a\n// `~`-relative path — the exec runs as the sidecar, which is not bound by the\n// safe-prefix allow-list the /files/write API enforces. Sets the executable\n// bit when the mount declares it OR the target is a bin directory.\n//\n// Each file is written in several small execs (mkdir, one append per base64\n// chunk, then a decode+cleanup) so no single exec request body trips the\n// ~4 KiB proxy cap. Writes are sequential; a single bad mount stops the batch\n// and the first failure is returned (fail-loud), the rest are not attempted.\n//\n// Each exec is bounded by a client-side hard timeout and retried with backoff\n// on transient rate-limit/readiness/transport failures, so one wedged or early\n// exec-plane request can never park the caller (and thus never park provisioning).\n// A small pace between execs keeps the burst rate below the proxy throttle that\n// triggers the hang.\n/** Define options to control execution timeout, pacing, and retry behavior when writing profile files */\nexport interface WriteProfileFilesOptions {\n // Hard ceiling per exec (ms). A hung/wedged exec is abandoned and retried.\n execTimeoutMs?: number\n // Delay between execs (ms) to stay under the proxy throttle. 0 disables it.\n paceMs?: number\n // Max retries for a transient exec before failing loud.\n maxRetries?: number\n}\n\n// The workspace-relative target for a deferred inline mount when it can be\n// materialized through the sidecar file API (`box.fs.writeMany` — FILES rate\n// group, 300/min, whole-file, auto-mkdir) instead of the chunked terminal-exec\n// path (50/min); null when it must stay on exec. The file API resolves relative\n// paths from the workspace root, so eligibility is: inline and a path that\n// resolves under the workspace root with no `..`/`.sidecar` segment. `~/…` and\n// `/home/agent/…` are home-relative; agent sandboxes set $HOME to the workspace\n// root, so both map to the same relative target. Other absolute (`/…`) and bare\n// `~`/`~user` mounts stay on exec.\nfunction fileApiTarget(mount: AgentProfileFileMount): string | null {\n if (mount.resource.kind !== 'inline') return null\n let rel: string\n if (mount.path.startsWith('~/')) rel = mount.path.slice(2)\n else if (mount.path.startsWith('/home/agent/')) rel = mount.path.slice('/home/agent/'.length)\n else if (mount.path.startsWith('/') || mount.path.startsWith('~')) return null\n else rel = mount.path\n if (rel.length === 0 || rel.startsWith('/') || rel.split('/').some((seg) => seg === '..' || seg === '.sidecar')) {\n return null\n }\n return rel\n}\n\nfunction isExecutableProfileFile(mount: AgentProfileFileMount): boolean {\n return mount.executable ?? PROFILE_BIN_DIR_RE.test(mount.path)\n}\n\nfunction profileFileMode(mount: AgentProfileFileMount): number | undefined {\n return isExecutableProfileFile(mount) ? 0o755 : undefined\n}\n\n// The sandbox gateway rejects request bodies over 1 MiB, and `writeMany` sends\n// each file as one JSON string, so a file larger than one request can never\n// land through it — the SDK splits batches but not files. Such a file goes\n// through the chunked `fs.uploadData` when the SDK has it and the chunked exec\n// path otherwise: the rule the SDK's `materializeProfileFileMounts` applies.\nconst PROFILE_FILE_API_MAX_JSON_BYTES = 1024 * 1024 - 16 * 1024\n\nfunction fitsProfileFileApi(content: string): boolean {\n const encoder = new TextEncoder()\n // JSON escaping grows one byte to at most six (`\\u001f`).\n if (encoder.encode(content).byteLength * 6 <= PROFILE_FILE_API_MAX_JSON_BYTES) return true\n return encoder.encode(JSON.stringify(content)).byteLength <= PROFILE_FILE_API_MAX_JSON_BYTES\n}\n\ntype ProfileFileUpload = (remotePath: string, data: string, options?: { mode?: number }) => Promise<unknown>\n\nfunction fileApiSupportsMode(box: SandboxInstance): boolean {\n const fs = box.fs as (SandboxInstance['fs'] & { supportsWriteMode?: boolean }) | undefined\n return fs?.supportsWriteMode === true\n}\n\n/** Write profile files to a sandbox with pacing, retries, and optional execution timeout handling */\nexport async function writeProfileFilesToBox(\n box: SandboxInstance,\n files: AgentProfileFileMount[],\n options: WriteProfileFilesOptions = {},\n): Promise<Outcome<void>> {\n const execTimeoutMs = options.execTimeoutMs ?? PROFILE_WRITE_EXEC_TIMEOUT_MS\n const paceMs = options.paceMs ?? PROFILE_WRITE_PACE_MS\n const maxRetries = options.maxRetries ?? PROFILE_WRITE_MAX_RETRIES\n // The bulk of a profile corpus (skills, `~/.claude/skills/…`, config) is\n // inline and workspace-relative — write it in ONE paced,\n // retry-aware batch via the SDK's file API (`box.fs.writeMany`, FILES rate\n // group 300/min). The SDK owns the pacing + transient-retry this module used\n // to hand-roll. Absolute / bare-`~` paths can't use the file API\n // (prefix-restricted), so they stay on the chunked exec path.\n // Capability-guarded: SDKs without `writeMany` route everything through\n // exec; SDKs before @tangle-network/sandbox 0.9.4 keep executable files on\n // exec because they do not expose `supportsWriteMode` or forward file modes.\n const fileApiAvailable = typeof box.fs?.writeMany === 'function'\n const modeAwareFileApi = fileApiSupportsMode(box)\n const uploadData = (box.fs as { uploadData?: ProfileFileUpload } | undefined)?.uploadData\n const viaFileApi: { path: string; content: string; mode?: number }[] = []\n const viaUpload: { path: string; content: string; mode?: number }[] = []\n const viaExec: AgentProfileFileMount[] = []\n for (const mount of files) {\n if (mount.resource.kind !== 'inline') continue\n const fileApiPath = fileApiAvailable ? fileApiTarget(mount) : null\n const executable = isExecutableProfileFile(mount)\n if (fileApiPath !== null && (!executable || modeAwareFileApi)) {\n const mode = profileFileMode(mount)\n const content = mount.resource.content ?? ''\n const write = { path: fileApiPath, content, ...(mode !== undefined ? { mode } : {}) }\n if (fitsProfileFileApi(content)) viaFileApi.push(write)\n else if (typeof uploadData === 'function') viaUpload.push(write)\n else viaExec.push(mount)\n }\n else viaExec.push(mount)\n }\n if (viaFileApi.length > 0) {\n // `writeMany` is fail-loud on the first file it can't write. Preserve the\n // cause so the runtime-auth-refresh wrapper still detects a 401 — it\n // recurses `.cause` for an AuthError/401 shape (see isRuntimeExecAuthError).\n try {\n await box.fs.writeMany(viaFileApi, { paceMs, maxRetries })\n } catch (err) {\n return fail(new Error('writeProfileFilesToBox: file-API batch write failed', { cause: err }))\n }\n }\n for (const upload of viaUpload) {\n // The SDK paces, retries, and checksums each chunked upload session.\n try {\n await uploadData!.call(box.fs, upload.path, upload.content, upload.mode !== undefined ? { mode: upload.mode } : undefined)\n } catch (err) {\n return fail(new Error(`writeProfileFilesToBox: chunked upload failed for ${upload.path}`, { cause: err }))\n }\n }\n\n // Pace BETWEEN execs, not before the first or after the last. Shared across\n // the exec mounts so the (now smaller) executable/edge-case set stays paced.\n let execStarted = false\n\n // Pace + transient-retry ONE exec attempt: backoff/pace/fail-loud in one place.\n // `run` must be idempotent under unknown-outcome retries (exec writes\n // deterministic parts). A transient error retries with backoff up to\n // maxRetries (honoring a server Retry-After); anything else, or exhausting\n // retries, fails loud with the cause.\n const paceAndRetry = async <T>(run: () => Promise<T>, path: string): Promise<Outcome<T>> => {\n for (let attempt = 0; ; attempt++) {\n if (execStarted && paceMs > 0) await sleep(paceMs)\n execStarted = true\n try {\n return ok(await run())\n } catch (err) {\n const { retryable, retryAfterMs } = transientExecError(err)\n if (retryable && attempt < maxRetries) {\n const backoff = Math.min(PROFILE_WRITE_RETRY_BASE_MS * 2 ** attempt, PROFILE_WRITE_RETRY_MAX_MS)\n await sleep(retryAfterMs ?? backoff)\n continue\n }\n return fail(new Error(`writeProfileFilesToBox: exec failed for ${path}`, { cause: err }))\n }\n }\n }\n\n for (const mount of viaExec) {\n if (mount.resource.kind !== 'inline') continue // always true (viaExec is inline) — narrows for TS\n const content = mount.resource.content ?? ''\n const path = mount.path\n\n const b64 = Buffer.from(content, 'utf8').toString('base64')\n const b64Chunks: string[] = []\n for (let i = 0; i < b64.length; i += PROFILE_WRITE_B64_CHUNK_CHARS) {\n b64Chunks.push(b64.slice(i, i + PROFILE_WRITE_B64_CHUNK_CHARS))\n }\n const expectedSha256 = createHash('sha256').update(content, 'utf8').digest('hex')\n const dir = path.replace(/\\/[^/]*$/, '')\n const executable = isExecutableProfileFile(mount)\n const q = shellPath(path)\n const qb64 = shellPath(`${path}.b64`)\n const qtmp = shellPath(`${path}.tmp`)\n const qpartPrefix = shellPath(`${path}.b64.part.`)\n\n // Run one exec step. Transport errors (incl. a wedged-proxy timeout) are\n // paced + retried by paceAndRetry; a non-zero exit is a REAL command failure\n // — surfaced immediately, never retried.\n const step = async (cmd: string): Promise<Outcome<void>> => {\n const res = await paceAndRetry(() => execWithTimeout(box, cmd, execTimeoutMs), path)\n if (!res.succeeded) return res\n const exec = res.value\n if (exec.exitCode !== 0) {\n return fail(\n new Error(\n `writeProfileFilesToBox: failed to write ${path} (exit ${exec.exitCode}): ${exec.stderr.slice(0, 500)}`,\n ),\n )\n }\n return ok(undefined)\n }\n\n // Ensure the target directory exists. Chunk/final commands below are\n // idempotent under unknown-outcome transport retries; this no-op/mkdir is too.\n const mkdir = dir && dir !== path ? `mkdir -p ${shellPath(dir)}` : ':'\n let res = await step(mkdir)\n if (!res.succeeded) return res\n\n // Write each deterministic part with overwrite, not append. If the server\n // writes a part but the HTTP response is lost, retrying the same step lands\n // the same bytes instead of duplicating them.\n for (let i = 0; i < b64Chunks.length; i++) {\n const slice = b64Chunks[i]!\n res = await step(`printf '%s' '${slice}' > ${shellPath(`${path}.b64.part.${i}`)}`)\n if (!res.succeeded) return res\n }\n\n // Materialize from deterministic parts into a temp file, verify its content\n // hash, then atomically move into place. If the final exec succeeds but its\n // response is lost, a retry first accepts an already-correct target and only\n // re-runs idempotent chmod/cleanup. Parts are cleaned only after the target\n // hash is known-good, so a retried final step can always reconstruct.\n const chmod = executable ? `chmod +x ${q} || exit 1; ` : ''\n const checksumMismatch = shellSingleQuote(`writeProfileFilesToBox: checksum mismatch for ${path}`)\n const finalCmd =\n `expected='${expectedSha256}'; ` +\n `if [ -f ${q} ] && [ \"$(sha256sum ${q} | awk '{print $1}')\" = \"$expected\" ]; then ` +\n `${chmod}rm -f ${qb64} ${qtmp}; i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do rm -f ${qpartPrefix}$i; i=$((i+1)); done; exit 0; fi; ` +\n `: > ${qb64} && ` +\n `i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do cat ${qpartPrefix}$i >> ${qb64} || exit 1; i=$((i+1)); done && ` +\n `base64 -d < ${qb64} > ${qtmp} && ` +\n `[ \"$(sha256sum ${qtmp} | awk '{print $1}')\" = \"$expected\" ] || { echo ${checksumMismatch} >&2; exit 1; }; ` +\n `mv ${qtmp} ${q} && ` +\n `${executable ? `chmod +x ${q} && ` : ''}` +\n `[ \"$(sha256sum ${q} | awk '{print $1}')\" = \"$expected\" ] || { echo ${checksumMismatch} >&2; exit 1; }; ` +\n `rm -f ${qb64} ${qtmp}; i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do rm -f ${qpartPrefix}$i; i=$((i+1)); done`\n res = await step(finalCmd)\n if (!res.succeeded) return res\n }\n return ok(undefined)\n}\n\n// Resolve the shell's deferred (inline) profile files and write them into a\n// box that already exists (reuse/resume paths). No-op unless the shell opts\n// into deferProfileFiles. Idempotent overwrite — a redeploy with new skills\n// refreshes the corpus on the next ensure call.\n// Box-metadata key holding the content hash of the deferred corpus that was\n// written to the box at CREATE. On reuse, an unchanged hash means the skills are\n// already on disk, so the (large, file-API) re-write can be skipped.\nconst DEFERRED_CORPUS_HASH_KEY = 'agentAppDeferredCorpusHash'\n\n/** Stable content hash of the deferred file corpus (path + inline content).\n * Unchanged corpus ⇒ same hash; a new/edited/removed skill ⇒ different hash.\n * Exported for the reuse-skip test. */\nexport function deferredCorpusHash(files: AgentProfileFileMount[]): string {\n const norm = files\n .map((f) => ({\n p: f.path,\n c: f.resource.kind === 'inline' ? ((f.resource as { content?: string }).content ?? '') : `ref:${f.resource.kind}`,\n }))\n .sort((a, b) => (a.p < b.p ? -1 : a.p > b.p ? 1 : 0))\n return createHash('sha256').update(JSON.stringify(norm), 'utf8').digest('hex')\n}\n\nasync function materializeDeferredFilesForExistingBox(\n shell: SandboxRuntimeConfig,\n client: Sandbox,\n box: SandboxInstance,\n stage: SandboxExistingBoxStage,\n name: string,\n workspaceId: string,\n userId: string | undefined,\n harness: Harness,\n corpusMarker?: Promise<string | null>,\n): Promise<Outcome<SandboxInstance>> {\n if (!shell.deferProfileFiles) return ok(box)\n const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId)\n const buildCtx: SandboxBuildContext = {\n workspaceId,\n connectedIntegrationIds,\n ...(userId ? { userId } : {}),\n }\n const files = await shell.files(buildCtx)\n const fullProfile = shell.profile({ extraFiles: files, harness })\n const { deferredFiles } = splitDeferredProfileFiles(fullProfile)\n if (deferredFiles.length === 0) return ok(box)\n // Skip the whole re-write when the corpus is UNCHANGED since the box was\n // created with it. The skill corpus is large and the bulk goes through the\n // file API (writeMany) UNCONDITIONALLY, so re-writing it on every reuse adds\n // seconds of latency to each turn. The create payload stamps the corpus hash\n // into box metadata; a matching hash means the skills are already on disk.\n // Fail-safe: a missing or mismatched hash (e.g. a redeploy with new skills, or\n // a box created before this optimization) WRITES — a stale skip is never\n // risked. Reads metadata only, so no extra exec/round-trip.\n const corpusHash = deferredCorpusHash(deferredFiles)\n const stampedHash = (box.metadata as Record<string, unknown> | undefined)?.[DEFERRED_CORPUS_HASH_KEY]\n if (typeof stampedHash === 'string' && stampedHash === corpusHash) return ok(box)\n // The create-time stamp goes stale on the first release that changes the\n // corpus, and without this the box rewrote the whole corpus on every reuse\n // after it (a ~0.7 s file batch per GTM turn, 2026-10-11). The marker is\n // written only after a corpus write succeeds and lives on the same disk as\n // the files, so a lost disk loses both and the corpus is written again.\n if (corpusMarker && await corpusMarker === corpusHash) return ok(box)\n const written = await writeDeferredFilesWithRuntimeAuthRefresh(client, box, deferredFiles, stage, name)\n if (written.succeeded) await writeDeferredCorpusMarker(written.value, corpusHash)\n return written\n}\n\n/** Where a reused box records the deferred corpus it last received in full,\n * relative to /home/agent like every file-API profile write. */\nconst DEFERRED_CORPUS_MARKER_PATH = '.agent-app/deferred-corpus-hash'\nconst DEFERRED_CORPUS_HASH_RE = /^[0-9a-f]{64}$/\n\n/** The corpus hash a box last recorded, or null when it is absent or unreadable. */\nasync function readDeferredCorpusMarker(box: SandboxInstance): Promise<string | null> {\n if (typeof box.read !== 'function') return null\n try {\n const value = (await box.read(`/home/agent/${DEFERRED_CORPUS_MARKER_PATH}`)).trim()\n return DEFERRED_CORPUS_HASH_RE.test(value) ? value : null\n } catch {\n return null\n }\n}\n\n/** Best effort: a failed marker write only costs the next reuse a corpus rewrite. */\nasync function writeDeferredCorpusMarker(box: SandboxInstance, corpusHash: string): Promise<void> {\n if (typeof box.fs?.writeMany !== 'function') return\n try {\n await box.fs.writeMany([{ path: DEFERRED_CORPUS_MARKER_PATH, content: corpusHash }])\n } catch {\n // The corpus itself is on disk; the next reuse writes it and the marker again.\n }\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 listStopped(\n client: Sandbox,\n name: string,\n): Promise<Outcome<SandboxInstance | null>> {\n try {\n const stopped = await client.list({ status: 'stopped' })\n return ok(stopped.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 const acknowledgement = await box.delete({ until: 'removed' })\n livenessVerifiedAt.delete(box.id)\n // Creation reuses this box's name as its idempotency key.\n if (acknowledgement.removal === 'pending') {\n return fail(new Error(`sandbox ${box.id} removal is still pending; retry replacement after removal completes`))\n }\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\n// ---------------------------------------------------------------------------\n// Provision-time S-cost gates. Both run immediately before `client.create` —\n// each catches an input class that can NEVER produce a working sandbox, so\n// failing at POST-time with actionable detail beats a platform 4xx (or a box\n// that boots and then E2BIGs on every exec).\n\n/** Appended to a prompt-budget throw from any of this module's three choke\n * points. A product that already raised the cap at compose time\n * (`composeAgentProfile(base, channels, overlay, { maxSystemPromptBytes })` —\n * gtm-agent uses 50_000) has to declare the SAME decision on the shell, or the\n * shell's default reads as a contradiction instead of a missing declaration. */\nconst SHELL_PROMPT_BUDGET_HINT =\n 'If this prompt size is a decision you already made at compose time, mirror it on the shell as ' +\n '`promptBudget: { maxSystemPromptBytes, overBudgetReason }` — the shell gate is the one that sees the profile actually sent.'\n\n/** Gate on the provision body: the platform orchestrator caps the create\n * payload at 256 KiB; 240 KB leaves headroom for transport framing. An\n * over-cap payload fails provisioning 100% of the time (a 282 KB payload\n * shipped once and no sandbox could ever be created). */\nexport const PROVISION_PAYLOAD_MAX_BYTES = 240_000\n\n/** Per-variable env gate: the kernel rejects any single `NAME=value` env entry\n * over MAX_ARG_STRLEN (131072 bytes) with E2BIG, killing every exec inside\n * the box. 120 KB leaves headroom for the name and framing. */\nexport const ENV_VALUE_MAX_BYTES = 120_000\n\n/** Default wait for a box to reach `running`. Overridable per shell via\n * {@link SandboxRuntimeConfig.provisionTimeoutMs}. */\nexport const DEFAULT_PROVISION_TIMEOUT_MS = 120_000\n\n/** Total env gate: the whole environment block shares the payload budget with\n * the profile; past 200 KB the provision body cannot stay under the cap. */\nexport const ENV_TOTAL_MAX_BYTES = 200_000\n\nfunction utf8ByteLength(value: unknown): number {\n return new TextEncoder().encode(typeof value === 'string' ? value : JSON.stringify(value ?? null))\n .byteLength\n}\n\n/** Structural slice of the profile the payload gate reads: it only measures\n * the profile's serialized size and names `resources.files` in the breakdown,\n * so callers composing a payload outside the SDK (products, tests) can pass a\n * plain object without casting through `AgentProfile`. */\nexport interface ProvisionProfileSection {\n resources?: { files?: readonly unknown[] }\n}\n\n/** The provision-payload sections the size gates need to see. Structural so\n * the gate is testable without the SDK's (unexported) create-payload type. */\nexport interface ProvisionPayloadSections {\n env?: Record<string, string>\n secrets?: readonly string[] | 'all'\n /** `profile` may also be a named-profile string ref (the SDK's\n * `BackendConfig` union) — a string ref is tiny and has no files channel. */\n backend?: { profile?: string | ProvisionProfileSection }\n}\n\n/**\n * Throw when the serialized provision payload exceeds\n * {@link PROVISION_PAYLOAD_MAX_BYTES}. The error carries a per-section byte\n * breakdown (profile/files/env/secrets) so the offending channel is named, not\n * guessed.\n */\nexport function assertProvisionPayloadWithinCap(payload: ProvisionPayloadSections): void {\n const total = utf8ByteLength(payload)\n if (total <= PROVISION_PAYLOAD_MAX_BYTES) return\n const profile = payload.backend?.profile\n const files = (typeof profile === 'string' ? undefined : profile?.resources?.files) ?? []\n const breakdown =\n `profile=${utf8ByteLength(profile ?? null)}B ` +\n `(files=${utf8ByteLength(files)}B), ` +\n `env=${utf8ByteLength(payload.env ?? {})}B, ` +\n `secrets=${utf8ByteLength(payload.secrets ?? [])}B`\n throw new Error(\n `sandbox provision payload is ${total} bytes — over the ${PROVISION_PAYLOAD_MAX_BYTES}-byte gate ` +\n `(the platform caps the create body at 256 KiB; an over-cap payload can never create a sandbox). ` +\n `Breakdown: ${breakdown}. ` +\n `Hint: set deferProfileFiles: true or move content to resources.`,\n )\n}\n\n/**\n * Throw when any single env value exceeds {@link ENV_VALUE_MAX_BYTES} or the\n * whole env block exceeds {@link ENV_TOTAL_MAX_BYTES}, naming the offending\n * variable. This is the E2BIG incident class: the box may even provision, but\n * every exec inside it dies on the oversized entry.\n */\nexport function assertEnvWithinLimits(env: Record<string, string>): void {\n let total = 0\n let largest: { name: string; bytes: number } | null = null\n for (const [name, value] of Object.entries(env)) {\n const bytes = utf8ByteLength(`${name}=${value}`)\n total += bytes\n if (!largest || bytes > largest.bytes) largest = { name, bytes }\n if (bytes > ENV_VALUE_MAX_BYTES) {\n throw new Error(\n `sandbox env var ${name} is ${bytes} bytes — over the ${ENV_VALUE_MAX_BYTES}-byte gate ` +\n `(kernel MAX_ARG_STRLEN is 131072 bytes per env entry; anything larger E2BIGs every exec). ` +\n `Write large content to a file mount or resource instead of an env var.`,\n )\n }\n }\n if (total > ENV_TOTAL_MAX_BYTES) {\n const worst = largest ? ` Largest: ${largest.name} (${largest.bytes}B).` : ''\n throw new Error(\n `sandbox env block is ${total} bytes total — over the ${ENV_TOTAL_MAX_BYTES}-byte gate.${worst} ` +\n `Write large content to a file mount or resource instead of env vars.`,\n )\n }\n}\n\n// The SDK owns the exec deadline. Await settlement before starting recovery;\n// an application timeout race would leave the original request in flight.\nasync function isBoxAlive(\n box: SandboxInstance,\n probe: LivenessProbeConfig | undefined,\n): Promise<Outcome<void>> {\n if (!probe) return ok(undefined)\n try {\n const alive = await box.exec('echo alive', { timeoutMs: probe.execTimeoutMs ?? 5000 })\n if (alive.exitCode !== 0 || alive.stdout.trim() !== 'alive') {\n return fail(new Error('alive check did not return a successful alive marker'))\n }\n return ok(undefined)\n } catch (cause) {\n return fail(new Error('alive check failed', { cause }))\n }\n}\n\nconst DEFAULT_LIVENESS_CACHE_TTL_MS = 5_000\n\nfunction hasRecentLivenessVerification(\n box: SandboxInstance,\n probe: LivenessProbeConfig,\n now = Date.now(),\n): boolean {\n const ttlMs = probe.cacheTtlMs ?? DEFAULT_LIVENESS_CACHE_TTL_MS\n if (!Number.isFinite(ttlMs) || ttlMs <= 0) return false\n const verifiedAt = livenessVerifiedAt.get(box.id)\n if (verifiedAt !== undefined && now - verifiedAt < ttlMs) return true\n livenessVerifiedAt.delete(box.id)\n return false\n}\n\nconst RUNTIME_CONNECTION_WAIT_MS = 30_000\nconst RUNTIME_CONNECTION_POLL_MS = 1_000\n\n// `sidecarUrl` is a product/forward-compat field the orchestrator may set on\n// the connection ahead of the SDK declaring it — the v0.6 `SandboxConnection`\n// exposes only `runtimeUrl`. Read it through a typed augmentation rather than an\n// ad-hoc cast (a plain `SandboxConnection` satisfies the optional field), and\n// fall back to the SDK runtime URL. The product-facing `WorkspaceSandboxInstanceLike`\n// carries the same field for consumers driving their own box types.\ntype RuntimeConnectionFields = SandboxConnection & {\n sidecarUrl?: string\n authToken?: string\n sidecarToken?: string\n authTokenExpiresAt?: string | number | Date\n sidecarTokenExpiresAt?: string | number | Date\n}\n\nfunction sandboxRuntimeUrl(box: SandboxInstance): string | undefined {\n const connection: RuntimeConnectionFields | undefined = box.connection\n return connection?.sidecarUrl ?? connection?.runtimeUrl\n}\n\nfunction runtimeAuthExpiresAtMs(value: string | number | Date | undefined): number | undefined {\n if (value instanceof Date) return value.getTime()\n if (typeof value === 'number') return value\n if (typeof value !== 'string' || value.trim() === '') return undefined\n const parsed = Date.parse(value)\n return Number.isNaN(parsed) ? undefined : parsed\n}\n\nfunction hasFreshRuntimeExecAuth(box: SandboxInstance, now = Date.now()): boolean {\n const connection: RuntimeConnectionFields | undefined = box.connection\n const token = connection?.authToken ?? connection?.sidecarToken\n if (!sandboxRuntimeUrl(box) || !token) return false\n const expiresAt = runtimeAuthExpiresAtMs(\n connection?.authTokenExpiresAt ?? connection?.sidecarTokenExpiresAt,\n )\n return expiresAt === undefined || expiresAt > now + RUNTIME_AUTH_REFRESH_SKEW_MS\n}\n\nfunction sandboxEdgeFailed(box: SandboxInstance): boolean {\n // `edgeStatus`/`edgeError` are declared on the SDK's `SandboxConnection`, so no cast.\n const connection = box.connection\n return connection?.edgeStatus === 'failed' || Boolean(connection?.edgeError)\n}\n\nasync function refreshRuntimeConnection(\n client: Sandbox,\n box: SandboxInstance,\n): Promise<SandboxInstance> {\n let current = box\n if (sandboxRuntimeUrl(current)) return current\n\n const deadline = Date.now() + RUNTIME_CONNECTION_WAIT_MS\n while (Date.now() < deadline) {\n // Tolerate transient refresh/get failures (5xx, network blips) while the\n // orchestrator is still attaching the connection: swallow and retry. A box\n // that never surfaces a runtime URL is returned as-is so the caller's\n // readiness gate (isReusableBox) sends it into state-preserving recovery\n // (or fails loud) — rather than this poll throwing a hard provisioning\n // failure on a recoverable hiccup.\n try {\n await current.refresh()\n if (sandboxRuntimeUrl(current)) return current\n\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (sandboxRuntimeUrl(current)) return current\n } catch {\n // transient — fall through to the poll delay and retry\n }\n\n await new Promise((resolve) => setTimeout(resolve, RUNTIME_CONNECTION_POLL_MS))\n }\n\n return current\n}\n\nasync function bestEffortRefreshRuntimeExecAuth(\n client: Sandbox,\n box: SandboxInstance,\n stage: SandboxExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let current = box\n\n try {\n await current.refresh()\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n if (isRuntimeAuthRefreshDenied(err)) {\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec auth refresh was unauthorized',\n err,\n ),\n )\n }\n }\n\n try {\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n if (isRuntimeAuthRefreshDenied(err)) {\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec auth re-fetch was unauthorized',\n err,\n ),\n )\n }\n }\n\n return ok(current)\n}\n\nasync function refreshRuntimeExecAuth(\n client: Sandbox,\n box: SandboxInstance,\n stage: SandboxExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let current = box\n let lastError: unknown\n const deadline = Date.now() + RUNTIME_CONNECTION_WAIT_MS\n\n while (Date.now() < deadline) {\n try {\n await current.refresh()\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n lastError = err\n }\n\n await new Promise((resolve) => setTimeout(resolve, RUNTIME_CONNECTION_POLL_MS))\n }\n\n const detail = sandboxRuntimeUrl(current)\n ? 'runtime exec credentials are missing or expired after refresh'\n : 'runtime connection is missing after refresh'\n return fail(new SandboxRuntimeAuthRefreshError(stage, name, detail, lastError))\n}\n\nasync function writeDeferredFilesWithRuntimeAuthRefresh(\n client: Sandbox,\n box: SandboxInstance,\n files: AgentProfileFileMount[],\n stage: SandboxExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let writeBox = box\n\n if (!hasFreshRuntimeExecAuth(writeBox)) {\n const refreshed = await bestEffortRefreshRuntimeExecAuth(client, writeBox, stage, name)\n if (!refreshed.succeeded) return fail(refreshed.error)\n writeBox = refreshed.value\n }\n\n const first = await writeProfileFilesToBox(writeBox, files)\n if (first.succeeded) return ok(writeBox)\n if (!isRuntimeExecAuthError(first.error)) return fail(first.error)\n\n const refreshed = await refreshRuntimeExecAuth(client, writeBox, stage, name)\n if (!refreshed.succeeded) return fail(refreshed.error)\n\n const second = await writeProfileFilesToBox(refreshed.value, files)\n if (second.succeeded) return ok(refreshed.value)\n if (!isRuntimeExecAuthError(second.error)) return fail(second.error)\n\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec remained unauthorized after auth refresh',\n second.error,\n ),\n )\n}\n\n// Decide whether an existing (reused or resumed) box is safe to hand back.\n// `refreshRuntimeConnection` has already polled for the runtime URL, so a box\n// that still has none never became connectable and must not be silently\n// reused — downstream exec/terminal traffic would fail against it. A failed\n// edge is likewise unusable. Only when the connection is present do we spend\n// an exec round-trip on the liveness probe. A box that fails this gate is\n// RECOVERED (stop→resume, workspace intact) or fails loud — never deleted.\nasync function isReusableBox(\n box: SandboxInstance,\n probe: LivenessProbeConfig | undefined,\n): Promise<Outcome<void>> {\n if (sandboxEdgeFailed(box) || !sandboxRuntimeUrl(box)) {\n livenessVerifiedAt.delete(box.id)\n return fail(new Error(sandboxEdgeFailed(box) ? 'runtime edge readiness failed' : 'runtime URL is missing'))\n }\n if (!probe) return ok(undefined)\n if (hasRecentLivenessVerification(box, probe)) return ok(undefined)\n const alive = await isBoxAlive(box, probe)\n if (alive.succeeded) livenessVerifiedAt.set(box.id, Date.now())\n else livenessVerifiedAt.delete(box.id)\n return alive\n}\n\n// Resume a stopped box and wait for it to reach running.\nfunction stoppedBoxResumeError(box: SandboxInstance, cause: unknown): unknown {\n const error = cause instanceof Error ? cause : new Error(String(cause))\n const code = (error as { code?: unknown }).code\n if (code === SANDBOX_BACKING_CONTAINER_MISSING_CODE) return cause\n if (code !== undefined && code !== 'SERVER_ERROR') return cause\n if (!isLegacySandboxBackingContainerMissingMessage(error.message)) return cause\n\n const status = typeof cause === 'object' && cause !== null\n ? (cause as { status?: unknown }).status\n : undefined\n if (typeof status !== 'number' && typeof status !== 'string') return cause\n const wrapped = new Error(error.message, { cause: error })\n wrapped.name = error.name\n\n return Object.assign(wrapped, {\n status,\n origin: 'sandbox-api',\n endpoint: `/v1/sandboxes/${encodeURIComponent(box.id)}/resume`,\n ...(typeof code === 'number' || typeof code === 'string' ? { code } : {}),\n })\n}\n\nasync function resumeStoppedBox(\n box: SandboxInstance,\n timeoutMs: number,\n runtimeEnv: Record<string, string>,\n onProgress?: (event: ProvisionEvent) => void,\n): Promise<Outcome<SandboxInstance>> {\n // A resume is the lifecycle step callers label a turn by, and the waits\n // below report no progress for a stopped box, so report it here.\n const report = (status: ProvisionEvent['status'], message: string) => {\n try {\n onProgress?.({ step: 'container-start', status, message, timestamp: new Date().toISOString() })\n } catch {\n // A progress observer cannot interfere with the resume.\n }\n }\n try {\n livenessVerifiedAt.delete(box.id)\n report('started', 'Resuming the stopped sandbox')\n await resumeWithRequiredRuntimeEnv(box, timeoutMs, runtimeEnv)\n await box.waitFor('running', { timeoutMs, ...(onProgress ? { onProgress } : {}) })\n report('completed', 'The stopped sandbox is running again')\n return ok(box)\n } catch (cause) {\n report('error', 'The stopped sandbox could not be resumed')\n return fail(stoppedBoxResumeError(box, cause))\n }\n}\n\n// Sandbox resume takes `env` only for public keys whose values the platform\n// withholds at rest, and uses them only to rebuild a removed runtime; any\n// other key is refused (400 RESUME_ENV_KEY_NOT_ACCEPTED). A rebuild that lacks\n// values names them (409 RESUME_ENV_REQUIRED, `missingEnvKeys`). So resume\n// without env and supply exactly the named keys from the fresh runtime env.\n// finalizeExistingBox then delivers every fresh value through setRuntimeEnv.\nasync function resumeWithRequiredRuntimeEnv(\n box: SandboxInstance,\n timeoutMs: number,\n runtimeEnv: Record<string, string>,\n): Promise<void> {\n const deadline = Date.now() + timeoutMs\n try {\n await box.resume({ timeoutMs })\n } catch (cause) {\n const missingEnvKeys = resumeEnvRequiredKeys(cause)\n if (!missingEnvKeys?.length || missingEnvKeys.some((key) => runtimeEnv[key] === undefined)) throw cause\n await box.resume({\n timeoutMs: Math.max(1, deadline - Date.now()),\n env: Object.fromEntries(missingEnvKeys.map((key) => [key, runtimeEnv[key]!])),\n })\n }\n}\n\n// Matched by code so SDK versions without ResumeEnvRequiredError still load.\nfunction resumeEnvRequiredKeys(cause: unknown): string[] | undefined {\n if (typeof cause !== 'object' || cause === null) return undefined\n const { code, missingEnvKeys } = cause as { code?: unknown; missingEnvKeys?: unknown }\n if (code !== 'RESUME_ENV_REQUIRED' || !Array.isArray(missingEnvKeys)) return undefined\n return missingEnvKeys.filter((key): key is string => typeof key === 'string')\n}\n\n// How many sessions a stop would end, from the runtime's own session list, or\n// undefined when the runtime does not answer. Listing sessions spawns nothing,\n// so a busy box answers it when it misses the exec probe. A session counts as\n// running on the same evidence the SDK uses to refuse a second dispatch:\n// running, an active execution, or queued with an admitted execution. The SDK\n// owns the request deadline; settlement is awaited so no stop is issued while\n// the answer is still in flight.\nasync function runningSessionCount(box: SandboxInstance): Promise<number | undefined> {\n try {\n const sessions = await box.sessions()\n return sessions.filter(({ info }) =>\n info.status === 'running' ||\n Boolean(info.activeExecutionId) ||\n (info.status === 'queued' && Boolean(info.latestExecutionId)),\n ).length\n } catch {\n return undefined\n }\n}\n\n// State-preserving recovery for a box that failed the reuse gate: stop (keeps\n// the workspace — the platform's suspend path never scrubs storage), resume,\n// then re-probe. `box.delete()` is DEPROVISIONING — it wipes the persistent\n// workspace (sessions, uncommitted files, everything outside the product's own\n// DB) — so it must never be a recovery action (#299: a single slow exec or a\n// crashed harness process used to destroy a user's workspace). This restarts\n// the container, which also reboots a dead sidecar/harness process. Every\n// failure throws SandboxRecoveryFailedError with the workspace intact —\n// including on the `tangle` driver, where stop is unsupported and the throw\n// carries the platform's rejection as its cause.\n//\n// The stop also ends every session on the box, so it is only issued when the\n// runtime reports no running session. A box that misses the probe while busy\n// (a loaded 2-core box can miss it while healthy, #934) is returned as is when\n// it is connectable, and otherwise fails only this request with\n// SandboxBoxBusyError. A runtime that cannot list its sessions gives no such\n// evidence, and the box is restarted as before.\nasync function recoverUnresponsiveBox(\n client: Sandbox,\n box: SandboxInstance,\n probe: LivenessProbeConfig | undefined,\n stage: SandboxExistingBoxStage,\n name: string,\n resumeTimeout: number,\n runtimeEnv: Record<string, string>,\n onProgress?: (event: ProvisionEvent) => void,\n): Promise<SandboxInstance> {\n const running = await runningSessionCount(box)\n if (running) {\n if (sandboxRuntimeUrl(box) && !sandboxEdgeFailed(box)) return box\n throw new SandboxBoxBusyError(\n stage,\n name,\n running,\n sandboxEdgeFailed(box) ? 'runtime edge readiness failed' : 'runtime URL is missing',\n )\n }\n try {\n await box.stop()\n } catch (err) {\n throw new SandboxRecoveryFailedError(\n stage,\n name,\n 'stop',\n 'the platform could not stop the box for a state-preserving restart',\n err,\n )\n }\n const resumed = await resumeStoppedBox(box, resumeTimeout, runtimeEnv, onProgress)\n if (!resumed.succeeded) {\n throw new SandboxRecoveryFailedError(\n stage,\n name,\n 'resume',\n 'the box did not reach running after a state-preserving restart',\n resumed.error,\n )\n }\n const recovered = await refreshRuntimeConnection(client, resumed.value)\n const reusable = await isReusableBox(recovered, probe)\n if (!reusable.succeeded) {\n throw new SandboxRecoveryFailedError(\n stage,\n name,\n 'probe',\n `the box is still unresponsive after a state-preserving restart: ${reusable.error.message}`,\n reusable.error,\n )\n }\n return recovered\n}\n\n/** Scope + the client and box key every workspace-scoped sandbox call needs.\n * One place resolves credentials and derives the box name, so the ensure and\n * peek paths cannot drift on which key a workspace's box lives under. */\nasync function resolveWorkspaceSandboxClient(\n shell: SandboxRuntimeConfig,\n workspaceId: string,\n userId: string | undefined,\n): Promise<{ scope: SandboxScope; client: Sandbox; name: string }> {\n const scope: SandboxScope = { workspaceId, ...(userId ? { userId } : {}) }\n const creds = await shell.credentials(scope)\n if (!creds) throw new Error('sandbox credentials are required (apiKey/baseUrl)')\n return {\n scope,\n client: getClientFromCreds(creds),\n name: shell.boxKey ? shell.boxKey(scope) : shell.name(workspaceId),\n }\n}\n\n/** What a peek can find. `warming` means the control plane is running while\n * the filesystem incarnation is still transitioning. `not-running` carries\n * the platform's own state string (`stopped`, `starting`, `failed`, …) —\n * narrowing it to a union here would drop states the platform adds later,\n * and every caller wants it for a log. */\nexport type PeekWorkspaceSandboxOutcome =\n | { status: 'running'; box: SandboxInstance }\n | { status: 'warming'; readiness: 'transitioning'; box: SandboxInstance }\n | { status: 'not-running'; state: string; box: SandboxInstance }\n | { status: 'absent' }\n\n/**\n * Read-only twin of {@link ensureWorkspaceSandbox}: report whether a\n * workspace's box exists and is fully ready, WITHOUT provisioning, resuming,\n * or bootstrapping anything.\n *\n * This is what a read-mostly path needs — a file-index route's `authorize`\n * seam, a stale-lock reconciliation, a status badge. Calling `ensure` from one\n * of those spins a box up as a side effect of a read (legal-agent #509), and\n * costs the caller a cold start it never asked for.\n *\n * Matching is on BOTH the box key and the display name, IN THAT ORDER.\n * `client.get(id)` keys on the platform's opaque sandbox id, not the\n * deterministic key a product derives from a workspace, and is itself a\n * `list().find` underneath — so a lookup by identity has to list and match.\n * Provisioning here always stamps `name` with the box key, so the key is the\n * authoritative match; the display-name pass exists only to adopt boxes on a\n * host that predates that convention. The order matters: a single unordered\n * `find` returns whichever the platform happens to list first, so a stopped\n * display-name box could shadow a running box-key one and report\n * `not-running` for a live workspace.\n *\n * Unlike `ensure`, this lists ALL statuses in one call: distinguishing \"no box\"\n * from \"box is stopped\" is the whole point, and a status-filtered list cannot.\n *\n * A `client.list()` rejection propagates RAW, unlike the `Outcome`-wrapping\n * helpers `ensure` uses internally. That is deliberate: there is no honest\n * outcome to map a listing failure onto — it is not `absent` and not\n * `not-running`, and inventing one would have callers act on a status the\n * platform never reported. Callers that must tolerate it say so explicitly\n * (the stale-turn-lock policy documents \"a throw is treated as unreachable\").\n */\nexport async function peekWorkspaceSandbox(\n shell: SandboxRuntimeConfig,\n options: { workspaceId: string; userId?: string },\n): Promise<PeekWorkspaceSandboxOutcome> {\n const { client, name } = await resolveWorkspaceSandboxClient(shell, options.workspaceId, options.userId)\n const displayName = shell.name(options.workspaceId)\n const boxes = await client.list()\n const match = boxes.find((box) => box.name === name) ?? boxes.find((box) => box.name === displayName)\n if (!match) return { status: 'absent' }\n if (match.status !== 'running') return { status: 'not-running', state: match.status, box: match }\n if (match.filesystemIncarnationReadiness === 'transitioning') {\n return { status: 'warming', readiness: 'transitioning', box: match }\n }\n if (match.filesystemIncarnationReadiness !== 'ready') {\n throw new Error(`sandbox ${match.id} is running without filesystem incarnation readiness`)\n }\n return { status: 'running', box: match }\n}\n\nasync function resolveWorkspaceRuntimeEnv(\n shell: SandboxRuntimeConfig,\n scope: SandboxScope,\n): Promise<Record<string, string>> {\n const env = await shell.runtimeEnv?.(scope) ?? {}\n assertEnvWithinLimits(env)\n return env\n}\n\n/**\n * Round trips of a reused box that do not depend on its liveness, started with\n * the liveness probe so they overlap it. The egress read and the corpus marker\n * are only reads: the policy is still asserted (and migrated) in finalize, and\n * an unknown marker means the corpus is written as before. The runtime env is\n * sent early only when the egress assertion cannot change where credentials\n * may go (see {@link egressGatesCredentials}); otherwise it waits for it.\n */\ninterface ExistingBoxPrefetch {\n egress?: Promise<Outcome<Awaited<ReturnType<SandboxInstance['egress']['get']>>>>\n /** This isolate verified the box's egress since its last start (see {@link verifiedEgressKey}). */\n egressVerified?: boolean\n corpusMarker?: Promise<string | null>\n /** The renewal already sent to the box; finalize waits for it instead of sending another. */\n runtimeEnv?: Promise<Outcome<void>>\n}\n\ntype ReuseMeasure = <T>(stage: string, operation: () => Promise<T>) => Promise<T>\n\nfunction prefetchExistingBoxReads(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n runtimeEnv: Promise<Record<string, string>>,\n measure: ReuseMeasure,\n): ExistingBoxPrefetch {\n const prefetch: ExistingBoxPrefetch = {}\n if (shell.egressPolicy && hasVerifiedEgress(box, shell.egressPolicy)) {\n prefetch.egressVerified = true\n } else if (shell.egressPolicy) {\n prefetch.egress = measure('egress', async () => {\n try {\n return ok(await box.egress.get())\n } catch (cause) {\n return fail(cause)\n }\n })\n }\n if (shell.deferProfileFiles) prefetch.corpusMarker = readDeferredCorpusMarker(box)\n if (!egressGatesCredentials(shell.egressPolicy)) {\n // A mint failure rejects `runtimeEnv` and the reuse stops before finalize,\n // so nothing was sent; the renewal itself is settled here and never rejects.\n prefetch.runtimeEnv = runtimeEnv.then(\n (env) => Object.keys(env).length === 0\n ? ok(undefined)\n : measure('runtime_env_push', () => box.setRuntimeEnv(env)).then(() => ok(undefined), (cause: unknown) => fail(cause)),\n () => ok(undefined),\n )\n }\n return prefetch\n}\n\n/**\n * Whether the egress assertion must finish before credentials reach a reused\n * box. `open` is the most permissive mode, so no policy the box can hold lets\n * credentials go anywhere `open` would not; asserting it only restores the\n * box's reach (a migration from a narrower policy). `strict` and `blocked`\n * bound where credentials can be sent, so they are asserted first.\n */\nfunction egressGatesCredentials(desired: EgressPolicy | undefined): boolean {\n return desired !== undefined && desired.mode !== 'open'\n}\n\n/** How long a matching egress read stands for a box that has not restarted. */\nconst VERIFIED_EGRESS_TTL_MS = 10 * 60_000\nconst VERIFIED_EGRESS_MAX = 1_000\n\n/**\n * The cache key for a box's verified egress, or null when it must be read.\n * Only an `open` policy is cached: a stale `open` verdict can only cost the\n * box its reach until the entry expires, never widen where credentials go.\n * The key carries the box's start time, so a restarted box is read again.\n */\nfunction verifiedEgressKey(box: SandboxInstance, desired: EgressPolicy): string | null {\n if (desired.mode !== 'open' || !box.id) return null\n const startedAt = box.startedAt instanceof Date ? box.startedAt.getTime() : Number.NaN\n if (!Number.isFinite(startedAt)) return null\n return `${box.id}|${startedAt}|${normalizedEgressPolicy(desired)}`\n}\n\nfunction hasVerifiedEgress(box: SandboxInstance, desired: EgressPolicy, now = Date.now()): boolean {\n const key = verifiedEgressKey(box, desired)\n if (!key) return false\n const verifiedAt = verifiedEgress.get(key)\n if (verifiedAt !== undefined && now - verifiedAt < VERIFIED_EGRESS_TTL_MS) return true\n verifiedEgress.delete(key)\n return false\n}\n\nfunction recordVerifiedEgress(box: SandboxInstance, desired: EgressPolicy): void {\n const key = verifiedEgressKey(box, desired)\n if (!key) return\n verifiedEgress.delete(key)\n verifiedEgress.set(key, Date.now())\n while (verifiedEgress.size > VERIFIED_EGRESS_MAX) {\n const oldest = verifiedEgress.keys().next().value\n if (oldest === undefined) break\n verifiedEgress.delete(oldest)\n }\n}\n\n// All retained-box paths renew credentials before the product bootstrap.\nasync function finalizeExistingBox(\n shell: SandboxRuntimeConfig,\n client: Sandbox,\n box: SandboxInstance,\n stage: SandboxExistingBoxStage,\n name: string,\n workspaceId: string,\n userId: string | undefined,\n harness: Harness,\n scope: SandboxScope,\n runtimeEnv: Record<string, string>,\n prefetch: ExistingBoxPrefetch = {},\n): Promise<SandboxInstance> {\n if (!prefetch.egressVerified) {\n await assertExistingBoxEgress(box, shell.egressPolicy, shell.migrateEgressPolicy, stage, name, prefetch.egress)\n }\n const written = await materializeDeferredFilesForExistingBox(\n shell,\n client,\n box,\n stage,\n name,\n workspaceId,\n userId,\n harness,\n prefetch.corpusMarker,\n )\n if (!written.succeeded) {\n throw deferredProfileWriteFailed(stage, name, written.error)\n }\n const finalBox = written.value\n if (prefetch.runtimeEnv) {\n // The same renewal, sent while the probe ran; its failure fails the reuse\n // exactly as a renewal sent here would.\n const renewed = await prefetch.runtimeEnv\n if (!renewed.succeeded) throw renewed.error\n } else if (Object.keys(runtimeEnv).length > 0) {\n await finalBox.setRuntimeEnv(runtimeEnv)\n }\n if (shell.bootstrap) {\n const boot = await shell.bootstrap(finalBox, scope)\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on ${stage} box ${name}`, { cause: boot.error })\n }\n }\n return finalBox\n}\n\nfunction canonicalizeJson(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalizeJson)\n if (value === null || typeof value !== 'object') return value\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)\n .map(([key, entry]) => [key, canonicalizeJson(entry)]),\n )\n}\n\nfunction normalizedEgressPolicy(policy: EgressPolicy): string {\n const normalized: Record<string, unknown> = { ...policy }\n if (policy.mode === 'strict') {\n normalized.allowDomains = [...new Set(\n (policy.allowDomains ?? [])\n .map((domain) => domain.trim().toLowerCase())\n .filter(Boolean),\n )].sort()\n normalized.includeImplicitDomains = policy.includeImplicitDomains !== false\n } else {\n // `allowDomains` and `includeImplicitDomains` are ignored in open and\n // blocked modes, and the platform keeps a box's old strict list attached\n // after a migration to open. Comparing them refused a box that already had\n // exactly the policy asked for, and every reuse of that box after.\n delete normalized.allowDomains\n delete normalized.includeImplicitDomains\n }\n return JSON.stringify(canonicalizeJson(normalized))\n}\n\nfunction existingBoxEgressError(\n operation: 'read' | 'migration',\n box: SandboxInstance,\n stage: SandboxExistingBoxStage,\n name: string,\n cause: unknown,\n): Error {\n const error = cause instanceof Error ? cause : new Error(String(cause))\n const status = (error as { status?: unknown }).status\n const suffix = operation === 'migration' ? '/egress' : ''\n return Object.assign(\n new Error(`egress policy ${operation} failed on ${stage} box ${name}: ${error.message}`, {\n cause: error,\n }),\n {\n origin: 'sandbox-api',\n endpoint: `/v1/sandboxes/${encodeURIComponent(box.id)}${suffix}`,\n ...(typeof status === 'number' || typeof status === 'string' ? { status } : {}),\n },\n )\n}\n\nasync function assertExistingBoxEgress(\n box: SandboxInstance,\n desired: EgressPolicy | undefined,\n migrate: boolean | undefined,\n stage: SandboxExistingBoxStage,\n name: string,\n prefetched?: Promise<Outcome<Awaited<ReturnType<SandboxInstance['egress']['get']>>>>,\n): Promise<void> {\n if (!desired) return\n let current: Awaited<ReturnType<SandboxInstance['egress']['get']>>\n if (prefetched) {\n const read = await prefetched\n if (!read.succeeded) throw existingBoxEgressError('read', box, stage, name, read.error)\n current = read.value\n } else {\n try {\n current = await box.egress.get()\n } catch (cause) {\n throw existingBoxEgressError('read', box, stage, name, cause)\n }\n }\n const matchingPolicy = normalizedEgressPolicy(current.policy) === normalizedEgressPolicy(desired)\n const explicitSource = current.source !== 'platform'\n if (matchingPolicy && explicitSource) {\n recordVerifiedEgress(box, desired)\n return\n }\n\n if (migrate) {\n try {\n await box.egress.update(desired)\n const migrated = await box.egress.get()\n const migratedPolicy = normalizedEgressPolicy(migrated.policy) === normalizedEgressPolicy(desired)\n if (migratedPolicy && migrated.source !== 'platform') {\n recordVerifiedEgress(box, desired)\n return\n }\n current = migrated\n } catch (cause) {\n throw existingBoxEgressError('migration', box, stage, name, cause)\n }\n }\n\n throw new SandboxEgressPolicyMismatchError(\n stage,\n name,\n current.policy,\n current.source,\n desired,\n )\n}\n\n/** Reuse a workspace sandbox, or remove its previous runtime before provisioning a replacement. */\nexport async function ensureWorkspaceSandbox(\n shell: SandboxRuntimeConfig,\n options: EnsureWorkspaceSandboxOptions,\n): Promise<SandboxInstance> {\n // A budget refusal must land before any box exists, so it runs ahead of both\n // the first attempt and the unbringable-box replacement below.\n await options.spend?.beforeProvision?.({\n workspaceId: options.workspaceId,\n ...(options.userId ? { userId: options.userId } : {}),\n })\n const { trace } = options\n const claim = trace?.start('sandbox.claim', 'sandbox', { 'workspace.harness': options.harness }, options.traceParent)\n // Each ensure step is a child of the claim, and the caller's own `measure` still sees it.\n const traced: EnsureWorkspaceSandboxOptions = trace && claim\n ? {\n ...options,\n measure: <T,>(stage: string, operation: () => Promise<T>): Promise<T> => {\n const run = () => trace.measure(stage, 'sandbox', () => operation(), undefined, claim)\n return options.measure ? options.measure(stage, run) : run()\n },\n }\n : options\n try {\n const box = await bringUpWorkspaceSandbox(shell, traced)\n claim?.end({ 'sandbox.id': box.id })\n await observeProvisionedBox(shell, options, box)\n return box\n } catch (error) {\n claim?.end(undefined, error)\n throw error\n }\n}\n\n/**\n * Report a now-billable box to the spend seam.\n *\n * Awaited rather than fired and forgotten: an expectation ledger with holes\n * reports boxes it simply failed to record as `unknown-box`, and an alert that\n * cries wolf is worse than no alert. The cost is one local write on a path that\n * already makes at least one platform round trip, so it is not the term that\n * decides provisioning latency.\n *\n * Errors are swallowed — the box is up, and failing the caller because\n * bookkeeping failed would trade a real capability for a record of it.\n */\nasync function observeProvisionedBox(\n shell: SandboxRuntimeConfig,\n options: EnsureWorkspaceSandboxOptions,\n box: SandboxInstance,\n): Promise<void> {\n if (!options.spend?.onProvisioned) return\n const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES\n try {\n await options.spend.onProvisioned({\n workspaceId: options.workspaceId,\n ...(options.userId ? { userId: options.userId } : {}),\n sandboxId: box.id,\n boxKey: box.name,\n idleTimeoutSeconds: resources.idleTimeoutSeconds,\n maxLifetimeSeconds: resources.maxLifetimeSeconds,\n at: Date.now(),\n })\n } catch {\n // An observability seam must never take down the provision it reports on.\n }\n}\n\nasync function bringUpWorkspaceSandbox(\n shell: SandboxRuntimeConfig,\n options: EnsureWorkspaceSandboxOptions,\n): Promise<SandboxInstance> {\n try {\n return await provisionWorkspaceSandbox(shell, options)\n } catch (err) {\n // A box the platform cannot bring up is not a transient failure: the box\n // key is derived from the workspace, so every later call resumes the same\n // dead box and fails the same way. Left alone the workspace never runs\n // again. Replacing it is a delete, so it happens only where the shell has\n // declared the box rebuildable — and only once, so a replacement that dies\n // the same way surfaces the error instead of looping.\n if (!shell.replaceUnbringableBox) throw err\n if (options.forceNew) throw err\n if (!isUnbringableBoxError(err)) throw err\n return await provisionWorkspaceSandbox(shell, { ...options, forceNew: true })\n }\n}\n\n/**\n * True when the platform cannot bring this box up where it lives.\n *\n * Two shapes reach here. `SandboxRecoveryFailedError` is the substrate's own\n * verdict after it tried a state-preserving restart and failed. A host-capacity\n * rejection is the same verdict one layer earlier: a box is pinned to a host,\n * and a full host rejects every resume for every box on it until something else\n * there goes away. Neither is transient, and neither is fixed by trying again\n * at the same key.\n */\nfunction isUnbringableBoxError(error: unknown): boolean {\n if (error instanceof SandboxRecoveryFailedError) return true\n const diagnostics = serializeSandboxProvisioningError(error)\n return isSandboxHostCapacityFailure(diagnostics) || isSandboxBoxConfigFailure(diagnostics)\n}\n\nasync function requestSandboxReplacement<TFailure extends StoppedSandboxResumeFailure>(\n recover: ((failure: TFailure) => Promise<Outcome<StoppedSandboxResumeRecovery | null>>) | undefined,\n failure: TFailure,\n label: string,\n): Promise<StoppedSandboxResumeRecovery> {\n if (!recover) throw failure.error\n const recovery = await recover(failure)\n if (!recovery.succeeded) throw recovery.error\n if (!recovery.value) throw failure.error\n\n const replacementBoxKey = recovery.value.replacementBoxKey.trim()\n if (!replacementBoxKey || replacementBoxKey === failure.boxKey) {\n throw new Error(\n `${label} must return a fresh replacement box key for ${failure.boxKey}`,\n { cause: failure.error },\n )\n }\n return { ...recovery.value, replacementBoxKey }\n}\n\nasync function requestMissingSandboxReplacement(\n shell: SandboxRuntimeConfig,\n failure: MissingSandboxFailure,\n): Promise<StoppedSandboxResumeRecovery> {\n // Probe causes diagnose failed liveness; they do not authorize replacement.\n if (failure.error instanceof SandboxRecoveryFailedError && failure.error.phase === 'probe') {\n throw failure.error\n }\n const diagnostics = serializeSandboxProvisioningError(failure.error)\n if (!isSandboxApiSandboxMissingFailure(diagnostics)) throw failure.error\n return requestSandboxReplacement(\n shell.recoverMissingSandbox,\n failure,\n 'missing sandbox recovery',\n )\n}\n\nasync function provisionWorkspaceSandbox(\n shell: SandboxRuntimeConfig,\n options: EnsureWorkspaceSandboxOptions,\n): Promise<SandboxInstance> {\n const execTimeoutMs = shell.livenessProbe?.execTimeoutMs\n // Match the supported SDK command-timeout range before any lifecycle mutation.\n if (execTimeoutMs !== undefined && (\n !Number.isInteger(execTimeoutMs) || execTimeoutMs < 100 || execTimeoutMs > 600_000\n )) {\n throw new Error('livenessProbe.execTimeoutMs must be an integer between 100 and 600000')\n }\n const { workspaceId, userId, harness, forceNew, onProgress, billingOwnerId } = options\n const measure = <T>(stage: string, operation: () => Promise<T>): Promise<T> =>\n options.measure ? options.measure(`sandbox.ensure.${stage}`, operation) : operation()\n const resolved = await measure('credentials', () => resolveWorkspaceSandboxClient(shell, workspaceId, userId))\n const { scope, client } = resolved\n let name = resolved.name\n let recoveryRestore: SandboxRestoreSpec | null | undefined\n let replacementRequested = false\n const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES\n const resumeTimeout = shell.provisionTimeoutMs ?? DEFAULT_PROVISION_TIMEOUT_MS\n\n // Stage 1 — running-box reuse (skipped on forceNew).\n let existing = await measure('list_running', () => listRunning(client, name))\n if (forceNew && existing.succeeded && !existing.value) {\n existing = await listStopped(client, name)\n }\n if (forceNew && !existing.succeeded) throw existing.error\n if (existing.succeeded && existing.value) {\n const found = existing.value\n if (forceNew) {\n const dropped = await deleteBox(found)\n if (!dropped.succeeded) {\n throw new Error(`forceNew: sandbox ${name} could not be deleted`, { cause: dropped.error })\n }\n } else if (found.metadata?.harness === harness) {\n // Resolve app credentials before any restart so a mint failure leaves the\n // existing sandbox running and intact. Reading the runtime connection\n // restarts nothing, so it runs alongside the mint.\n const runtimeEnvMint = measure('runtime_env', () => resolveWorkspaceRuntimeEnv(shell, scope))\n const prefetch = prefetchExistingBoxReads(shell, found, runtimeEnvMint, measure)\n const [envResult, readyResult] = await Promise.allSettled([\n runtimeEnvMint,\n measure('refresh', () => refreshRuntimeConnection(client, found)),\n ])\n if (envResult.status === 'rejected') throw envResult.reason\n const runtimeEnv = envResult.value\n try {\n if (readyResult.status === 'rejected') throw readyResult.reason\n const ready = readyResult.value\n if ((await measure('liveness', () => isReusableBox(ready, shell.livenessProbe))).succeeded) {\n return await measure('finalize', () => finalizeExistingBox(shell, client, ready, 'reused', name, workspaceId, userId, harness, scope, runtimeEnv, prefetch))\n }\n // The prefetched reads never reject; a recovered box is read again in finalize.\n // Unresponsive (or never-connectable) box with the RIGHT harness: recover\n // in place — stop→resume preserves the workspace — and fail loud if the\n // box is still dead. Deleting here wiped user workspaces (#299); delete\n // is reachable only via forceNew now.\n const recovered = await recoverUnresponsiveBox(\n client,\n ready,\n shell.livenessProbe,\n 'reused',\n name,\n resumeTimeout,\n runtimeEnv,\n onProgress,\n )\n return await finalizeExistingBox(shell, client, recovered, 'reused', name, workspaceId, userId, harness, scope, runtimeEnv)\n } catch (cause) {\n const error = cause instanceof Error ? cause : new Error(String(cause))\n const recovery = await requestMissingSandboxReplacement(shell, {\n box: found,\n error,\n scope,\n boxKey: name,\n stage: 'reused',\n })\n name = recovery.replacementBoxKey\n recoveryRestore = recovery.restore\n replacementRequested = true\n }\n } else {\n const dropped = await deleteBox(found)\n if (!dropped.succeeded) {\n throw new Error(\n `sandbox ${name} ` +\n `(was ${String(found.metadata?.harness ?? 'unknown')}, want ${harness}) ` +\n `could not be deleted`,\n { cause: dropped.error },\n )\n }\n }\n }\n\n // Stage 2 — stopped-box resume (skipped on forceNew or resumeStopped===false).\n if (!replacementRequested && !forceNew && shell.resumeStopped !== false) {\n const stopped = await measure('list_stopped', () => listStopped(client, name))\n if (!stopped.succeeded) throw stopped.error\n if (stopped.value) {\n const stoppedBox = stopped.value\n const runtimeEnv = await measure('runtime_env', () => resolveWorkspaceRuntimeEnv(shell, scope))\n const resumed = await measure('resume', () => resumeStoppedBox(stoppedBox, resumeTimeout, runtimeEnv, onProgress))\n if (!resumed.succeeded) {\n const recovery = await requestSandboxReplacement(\n shell.recoverStoppedSandbox,\n { box: stopped.value, error: resumed.error, scope, boxKey: name },\n 'stopped sandbox recovery',\n )\n name = recovery.replacementBoxKey\n recoveryRestore = recovery.restore\n } else {\n try {\n const box = await refreshRuntimeConnection(client, resumed.value)\n if ((await isReusableBox(box, shell.livenessProbe)).succeeded) {\n return await finalizeExistingBox(shell, client, box, 'resumed', name, workspaceId, userId, harness, scope, runtimeEnv)\n }\n // The box resumed but is unresponsive: one full stop→resume cycle is\n // the state-preserving recovery; still-dead fails loud. Never delete —\n // that wipes the workspace (#299).\n const recovered = await recoverUnresponsiveBox(\n client,\n box,\n shell.livenessProbe,\n 'resumed',\n name,\n resumeTimeout,\n runtimeEnv,\n onProgress,\n )\n return await finalizeExistingBox(shell, client, recovered, 'resumed', name, workspaceId, userId, harness, scope, runtimeEnv)\n } catch (cause) {\n const error = cause instanceof Error ? cause : new Error(String(cause))\n const recovery = await requestMissingSandboxReplacement(shell, {\n box: stopped.value,\n error,\n scope,\n boxKey: name,\n stage: 'resumed',\n })\n name = recovery.replacementBoxKey\n recoveryRestore = recovery.restore\n }\n }\n }\n }\n\n // Stage 3 — create fresh.\n const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId)\n const buildCtx: SandboxBuildContext = {\n workspaceId,\n connectedIntegrationIds,\n ...(userId ? { userId } : {}),\n }\n const [secrets, creationEnv, runtimeEnv, files] = await Promise.all([\n shell.secrets(workspaceId),\n shell.env(buildCtx),\n resolveWorkspaceRuntimeEnv(shell, scope),\n shell.files(buildCtx),\n ])\n const env = { ...creationEnv, ...runtimeEnv }\n const fullProfile = shell.profile({ extraFiles: files, harness })\n // When deferring, strip inline files from the create payload and write them\n // into the box after it reaches running. Keeps the provision body under the\n // orchestrator's 256 KiB cap and lands real files on disk.\n const { leanProfile, deferredFiles } = shell.deferProfileFiles\n ? splitDeferredProfileFiles(fullProfile)\n : { leanProfile: fullProfile, deferredFiles: [] as AgentProfileFileMount[] }\n const profile = leanProfile\n\n const role = userId && shell.permissionRole ? shell.permissionRole('developer') : undefined\n\n // Bake the model at create when opted in. childKeyMint overrides the apiKey\n // per-workspace; a typed mint failure falls through to the parent key (logged).\n let model = shell.backendModelAtCreate\n ? requireTransportableModel(resolveModelSelection(shell.provider), `backendModelAtCreate for ${name}`)\n : undefined\n if (model && shell.childKeyMint && model.provider === 'openai-compat') {\n const minted = await shell.childKeyMint(scope)\n if (minted.succeeded) model = { ...model, apiKey: minted.value }\n else {\n console.error(\n `[sandbox] childKeyMint failed for ${workspaceId}; using parent key:`,\n minted.error.message,\n )\n }\n }\n\n const storage = shell.storage?.(buildCtx)\n const restore = recoveryRestore === undefined ? await shell.restore?.(buildCtx) : recoveryRestore\n\n const payload = {\n name,\n image: resources.image,\n // Stamp the deferred-corpus hash so a later REUSE can skip re-writing an\n // unchanged skill corpus (materializeDeferredFilesForExistingBox reads it).\n metadata: {\n ...shell.metadata(harness),\n ...(deferredFiles.length > 0 ? { [DEFERRED_CORPUS_HASH_KEY]: deferredCorpusHash(deferredFiles) } : {}),\n },\n idempotencyKey: name,\n // Passed through untyped (the SDK payload type predates it); the platform\n // authz-gates it server-side and ignores it when unsupported.\n ...(billingOwnerId ? { billingOwnerId } : {}),\n ...(userId ? { permissions: { initialUsers: [{ userId, role }] } } : {}),\n env,\n secrets,\n backend: { type: harness, profile, ...(model ? backendModelFields(model) : {}) },\n ...(storage ? { storage } : {}),\n ...(restore ? restore : {}),\n ...(shell.egressPolicy ? { egressPolicy: shell.egressPolicy } : {}),\n ...(shell.cwd !== undefined ? { cwd: shell.cwd } : {}),\n ...(shell.webTerminalEnabled ? { webTerminalEnabled: true } : {}),\n maxLifetimeSeconds: resources.maxLifetimeSeconds,\n idleTimeoutSeconds: resources.idleTimeoutSeconds,\n resources: {\n cpuCores: resources.cpuCores,\n memoryMB: resources.memoryMB,\n diskGB: resources.diskGB,\n ...(resources.advisory !== undefined ? { advisory: resources.advisory } : {}),\n },\n } as CreatePayload\n\n // S-cost gates: an oversized env entry (E2BIG class), an over-cap provision\n // body, or a system prompt past the degradation cliff — fail loud here,\n // before the POST, with the offending section named. The prompt gate is\n // separate from the payload gate on purpose: the 122,659-byte prompt that\n // produced empty answers is a THIRD of the 240 KB payload cap, so the\n // payload gate never sees it.\n assertEnvWithinLimits(env)\n assertProfilePromptWithinBudget(\n profile,\n shell.promptBudget ?? {},\n `provision profile systemPrompt for ${name}`,\n SHELL_PROMPT_BUDGET_HINT,\n )\n // `?? {}` only narrows the SDK parameter's `| undefined`; the literal above\n // is always defined. The structural sections type needs no cast.\n assertProvisionPayloadWithinCap(payload ?? {})\n\n let box = await measure('create', () => client.create(payload))\n\n await measure('wait_running', () => box.waitFor('running', {\n timeoutMs: shell.provisionTimeoutMs ?? DEFAULT_PROVISION_TIMEOUT_MS,\n ...(onProgress ? { onProgress } : {}),\n }))\n box = await measure('refresh_connection', () => refreshRuntimeConnection(client, box))\n\n if (deferredFiles.length > 0) {\n const written = await writeProfileFilesToBox(box, deferredFiles)\n if (!written.succeeded) {\n throw deferredProfileWriteFailed('new', name, written.error)\n }\n }\n\n if (shell.bootstrap) {\n const bootstrap = shell.bootstrap.bind(shell)\n const boot = await measure('bootstrap', () => bootstrap(box, scope))\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on new box ${name}`, { cause: boot.error })\n }\n }\n return box\n}\n\n// The SDK's SandboxInstance.streamPrompt/.prompt accept `string | PromptInputPart[]`\n// but the published package does not re-export the PromptInputPart type by name from\n// any of its entry points, so it's derived structurally off the method signature\n// itself — this stays in lockstep with the SDK's actual accepted shape.\n/** Extract a single element type from the array parameter of SandboxInstance's streamPrompt method */\nexport type PromptInputPart = Extract<\n Parameters<SandboxInstance['streamPrompt']>[0],\n readonly unknown[]\n>[number]\n\nfunction historyTranscript(\n history: Array<{ role: 'user' | 'assistant'; content: string }>,\n): string {\n return history\n .map((entry) => `${entry.role === 'assistant' ? 'Assistant' : 'User'}: ${entry.content}`)\n .join('\\n\\n')\n}\n\n/** Build a single string combining conversation history and the current user message */\nexport function flattenHistory(\n message: string,\n history?: Array<{ role: 'user' | 'assistant'; content: string }>,\n): string {\n if (!history?.length) return message\n return `${historyTranscript(history)}\\n\\nUser: ${message}`\n}\n\n/**\n * History-aware equivalent of flattenHistory for multimodal prompt parts: the\n * transcript is folded into the first text part (image/file parts carry no\n * text to prepend to) rather than replacing the message wholesale.\n */\nexport function mergeHistoryIntoParts(\n parts: PromptInputPart[],\n history?: Array<{ role: 'user' | 'assistant'; content: string }>,\n): PromptInputPart[] {\n if (!history?.length) return parts\n const textIndex = parts.findIndex((part) => part.type === 'text')\n if (textIndex === -1) {\n throw new Error('mergeHistoryIntoParts requires at least one text part to carry the history')\n }\n const textPart = parts[textIndex] as Extract<PromptInputPart, { type: 'text' }>\n const merged = [...parts]\n merged[textIndex] = { ...textPart, text: `${historyTranscript(history)}\\n\\nUser: ${textPart.text}` }\n return merged\n}\n\n/** Resolve conflicts and merge extra MCP profiles into the app tool MCP without overwriting existing keys */\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\n/** Attach explicit effort through the portable model contract consumed by providers. */\nexport function attachReasoningEffort(\n profile: AgentProfile,\n _harness: Harness,\n effort: 'auto' | ReasoningEffort | undefined,\n): AgentProfile {\n if (!effort || effort === 'auto') return profile\n return {\n ...profile,\n model: {\n ...profile.model,\n reasoningEffort: effort,\n },\n }\n}\n\nexport interface SandboxPromptTokenLimits {\n maxVisibleOutputTokens?: number\n maxReasoningTokens?: number\n maxTotalOutputTokens?: number\n}\n\nfunction positiveSafeInteger(value: number | undefined, field: string): number | undefined {\n if (value === undefined) return undefined\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new Error(`${field} must be a positive safe integer`)\n }\n return value\n}\n\nfunction lowerCeiling(current: number | undefined, requested: number | undefined): number | undefined {\n if (current === undefined) return requested\n if (requested === undefined) return current\n return Math.min(current, requested)\n}\n\n/** Tighten the profile's provider-enforced token ceilings for one prompt. */\nexport function applyPromptTokenLimits(\n profile: AgentProfile,\n limits: SandboxPromptTokenLimits,\n): AgentProfile {\n const requestedVisible = positiveSafeInteger(\n limits.maxVisibleOutputTokens,\n 'maxVisibleOutputTokens',\n )\n const requestedReasoning = positiveSafeInteger(\n limits.maxReasoningTokens,\n 'maxReasoningTokens',\n )\n const requestedTotal = positiveSafeInteger(\n limits.maxTotalOutputTokens,\n 'maxTotalOutputTokens',\n )\n if (\n requestedVisible === undefined\n && requestedReasoning === undefined\n && requestedTotal === undefined\n ) return profile\n\n const maxTotalOutputTokens = lowerCeiling(\n profile.model?.maxTotalOutputTokens,\n requestedTotal,\n )\n let maxVisibleOutputTokens = lowerCeiling(\n profile.model?.maxVisibleOutputTokens,\n requestedVisible,\n )\n let maxReasoningTokens = lowerCeiling(\n profile.model?.maxReasoningTokens,\n requestedReasoning,\n )\n if (maxTotalOutputTokens !== undefined) {\n if (maxVisibleOutputTokens !== undefined) {\n maxVisibleOutputTokens = Math.min(maxVisibleOutputTokens, maxTotalOutputTokens)\n }\n if (maxReasoningTokens !== undefined) {\n maxReasoningTokens = Math.min(maxReasoningTokens, maxTotalOutputTokens)\n }\n }\n\n return {\n ...profile,\n model: {\n ...(profile.model ?? {}),\n ...(maxVisibleOutputTokens !== undefined ? { maxVisibleOutputTokens } : {}),\n ...(maxReasoningTokens !== undefined ? { maxReasoningTokens } : {}),\n ...(maxTotalOutputTokens !== undefined ? { maxTotalOutputTokens } : {}),\n },\n }\n}\n\n/** Define options for configuring and controlling a streaming sandbox prompt session */\nexport interface StreamSandboxPromptOptions {\n /** Complete server-owned profile for this turn. Skips the shell's default composer.\n * Credentials, admission, session identity, and interactions remain execution options.\n * Explicit turn selections override this profile; otherwise its model and harness win\n * over shell defaults. Never populate this field from an untrusted request body. */\n profile?: AgentProfile\n sessionId?: string\n executionId?: string\n /** Stable idempotency key for one logical dispatch. Reuse it with the same\n * `sessionId` when a caller may retry the initial request. */\n turnId?: 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' | ReasoningEffort\n /** Provider-enforced visible answer ceiling for this turn. */\n maxOutputTokens?: number\n /** Provider-enforced hidden reasoning ceiling for this turn. */\n maxReasoningTokens?: number\n /** Provider-enforced combined answer and reasoning ceiling for this turn. */\n maxTotalOutputTokens?: number\n appToolMcp?: Record<string, AgentProfileMcpServer>\n baseProfileMcp?: Record<string, AgentProfileMcpServer>\n extraMcp?: Record<string, AgentProfileMcpServer>\n /** Runtime-owned MCP tools for this turn, outside the authored profile. */\n runtimeAttachments?: { mcp: Record<string, AgentProfileMcpServer> }\n /** Per-turn secret values used by runtime attachments; never stored in the profile or sandbox environment. */\n runtimeSecrets?: Record<string, string>\n /** Mark a backend prepared for a secret-isolated native session. The caller creates\n * that session and prepares its exact backend before dispatch. */\n secretProfileIsolation?: true\n /** SDK-issued digest of the prepared public backend request. */\n expectedPublicProfileRequestDigest?: `sha256:${string}`\n /** SDK-issued receipt for the prepared secret native profile revision. */\n expectedSecretProfileReceipt?: `hmac-sha256:${string}`\n signal?: AbortSignal\n timeoutMs?: number\n /**\n * Execution time limit for this run, in milliseconds. Unset, the runtime\n * falls back to `timeoutMs`, then to its one-hour default, so a turn that\n * must run longer than an hour names it here. The runtime refuses a value\n * above its deployment maximum before the run starts. `timeoutMs` stays the\n * shorter first-output budget.\n */\n ttlMs?: number\n requireVisibleAssistantOutput?: boolean\n // When true, an interactive question event throws instead of yielding.\n // Use this for detached runs whose caller has no consumer to answer it.\n disallowQuestions?: boolean\n // Per-turn question/permission/plan channel toggles, forwarded VERBATIM into the\n // backend config. agent-app does not validate kinds per harness — the sidecar fails\n // session init loudly for unsupported ones; a local matrix would drift. Honored on\n // both streaming and driveTurn paths.\n interactions?: { question?: boolean; permission?: boolean; plan?: boolean }\n // Streaming helper only: detach the run from THIS stream's lifetime. When true, the helper admits the\n // run through `dispatchPrompt`, then reads its exact execution through the\n // SDK replay stream. A Worker restart or browser refresh therefore cannot\n // cancel the server-side run. Reuse `sessionId` + `executionId` + `turnId` on\n // retries; `lastEventId` resumes the same execution instead of dispatching\n // another one.\n // Omit for a run where closing the tab should stop burning tokens.\n detach?: boolean\n // Observe the EXACT profile handed to the sandbox SDK for this turn — after\n // the system-prompt override, the MCP merge, and reasoning-effort attachment\n // — as a ProfileFingerprint. This is the seam an eval/backtest uses to PROVE\n // it executed the shipped profile instead of re-deriving one and asserting\n // nothing. Invoked once, before the first event is yielded.\n onProfileResolved?: (fingerprint: ProfileFingerprint) => void\n // Optional spend-verification activity tap. Omitted, nothing changes. Takes\n // the SAME object `ensureWorkspaceSandbox` does, so a product builds one and\n // wires it in both places; only `onActivity` is read here.\n spend?: SandboxSpendHooks\n /**\n * The turn's trace (`@tangle-network/agent-app/turn-trace`). Its id is sent as `traceId`, the\n * `x-tangle-trace-id` the Sandbox API, orchestrator, sidecar and the Router's dispatch rows all record, and\n * the stream is recorded as a `sandbox.prompt` span: the sidecar's first-text phases, the generation and\n * each tool the box agent ran. Omitted, the SDK mints a trace id the app does not keep.\n */\n trace?: TurnTrace\n /** The span the prompt hangs from. Default: the trace's root. */\n traceParent?: TurnSpan\n}\n\ntype StreamPromptOptions = Parameters<SandboxInstance['streamPrompt']>[1]\ntype DispatchPromptOptions = Parameters<SandboxInstance['dispatchPrompt']>[1]\ntype CompletedTurn = NonNullable<Awaited<ReturnType<SandboxInstance['findCompletedTurn']>>>\n\nfunction cachedSandboxPromptEvents(\n cached: CompletedTurn,\n fallbackExecutionId: string,\n): Array<Record<string, unknown>> {\n const cachedResult = cached.result\n const executionId = typeof cachedResult.executionId === 'string' && cachedResult.executionId.trim()\n ? cachedResult.executionId\n : fallbackExecutionId\n const finalText = typeof cachedResult.finalText === 'string'\n ? cachedResult.finalText\n : typeof cachedResult.response === 'string'\n ? cachedResult.response\n : typeof cachedResult.text === 'string'\n ? cachedResult.text\n : undefined\n\n return [\n {\n type: 'result',\n data: {\n ...cachedResult,\n ...(finalText !== undefined && cachedResult.finalText === undefined ? { finalText } : {}),\n sessionId: cached.sessionId,\n executionId,\n },\n },\n {\n type: 'done',\n data: {\n sessionId: cached.sessionId,\n executionId,\n status: 'completed',\n outcome: { type: 'completed' },\n },\n },\n ]\n}\n\n/**\n * Open the durable event lane for one detached prompt.\n *\n * `dispatchPrompt` is the admission boundary: it returns after the sandbox has\n * accepted the run and keeps executing it after this Worker disappears. The\n * SDK's execution replay stream is then the exact execution-scoped surface.\n * Replaying through `streamPrompt` preserves the direct run-event vocabulary;\n * the session bus wraps message parts under `data.properties`.\n */\nasync function* detachedSandboxPromptEvents(\n box: SandboxInstance,\n prompt: string | PromptInputPart[],\n options: StreamSandboxPromptOptions,\n backend: NonNullable<StreamPromptOptions>['backend'],\n): AsyncGenerator<unknown> {\n const sessionId = options.sessionId?.trim()\n const executionId = options.executionId?.trim()\n if (!sessionId || !executionId) {\n throw new Error('streamSandboxPrompt detach requires stable sessionId and executionId')\n }\n\n const lastEventId = options.lastEventId?.trim() || undefined\n const turnId = options.turnId?.trim() || executionId\n // A cursor is already proof that this execution was admitted. Re-dispatching\n // before replay would turn a failed terminal session into a new prompt.\n const admission = lastEventId\n ? null\n : await box.dispatchPrompt(prompt, {\n sessionId,\n executionId,\n turnId,\n backend,\n ...(options.expectedPublicProfileRequestDigest\n ? { expectedPublicProfileRequestDigest: options.expectedPublicProfileRequestDigest }\n : {}),\n ...(options.expectedSecretProfileReceipt\n ? { expectedSecretProfileReceipt: options.expectedSecretProfileReceipt }\n : {}),\n ...(options.requireVisibleAssistantOutput !== undefined\n ? { requireVisibleAssistantOutput: options.requireVisibleAssistantOutput }\n : {}),\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n ...(options.ttlMs !== undefined ? { ttlMs: options.ttlMs } : {}),\n ...(options.trace ? { traceId: options.trace.traceId } : {}),\n } as DispatchPromptOptions)\n const admittedExecutionId = admission?.executionId ?? executionId\n if (!admittedExecutionId) {\n throw new Error(`detached Sandbox dispatch for ${sessionId} returned no executionId`)\n }\n\n // A completed-turn cache hit deliberately returns `dispatched: false` and\n // emits no new stream events. Yield its public result directly; the replay\n // buffer may already have aged out by the time a retry reaches this helper.\n if (admission?.dispatched === false) {\n const cached = await box.findCompletedTurn(turnId, { sessionId })\n if (cached) {\n yield* cachedSandboxPromptEvents(cached, admittedExecutionId)\n return\n }\n }\n\n // The session bus is a useful observation surface, but its message events\n // use a different envelope (`data.properties.part`). Use the SDK's exact\n // execution replay instead so downstream producers receive the same event\n // vocabulary as a direct prompt stream (`data.part`, terminal `result`, etc.).\n yield* box.streamPrompt('', {\n sessionId: admission?.sessionId ?? sessionId,\n executionId: admittedExecutionId,\n lastEventId: lastEventId || '0',\n ...(options.trace ? { traceId: options.trace.traceId } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n } as StreamPromptOptions)\n}\n\n/**\n * The small event shape consumed by agent-gateway's streaming adapters.\n *\n * Sandbox providers can add fields to their event payloads over time. This\n * adapter deliberately copies only the fields the gateway understands so\n * consumers do not each have to maintain a provider-to-gateway cast.\n */\nexport interface SandboxStreamEvent {\n type?: string\n data?: {\n part?: { type?: string; text?: string }\n delta?: string\n finalText?: string\n code?: string\n message?: string\n details?: Record<string, unknown>\n inputRequired?: { prompt?: string }\n usage?: {\n inputTokens?: number\n outputTokens?: number\n reasoningTokens?: number\n toolTokens?: number\n toolCallCount?: number\n providerCostUsd?: number\n budgetEnforced?: boolean\n }\n tool?: { name?: string; inputTokens?: number; outputTokens?: number }\n reasoning?: { tokens?: number }\n }\n}\n\nfunction optionalNonNegativeNumber(\n value: unknown,\n field: string,\n): number | undefined {\n if (value === undefined) return undefined\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {\n throw new Error(`sandbox gateway event ${field} is invalid`)\n }\n return value\n}\n\nfunction optionalNonNegativeSafeInteger(\n value: unknown,\n field: string,\n): number | undefined {\n const number = optionalNonNegativeNumber(value, field)\n if (number !== undefined && !Number.isSafeInteger(number)) {\n throw new Error(`sandbox gateway event ${field} is invalid`)\n }\n return number\n}\n\nfunction optionalGatewayRecord(\n value: unknown,\n field: string,\n): Record<string, unknown> | undefined {\n if (value === undefined) return undefined\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`sandbox gateway event ${field} is invalid`)\n }\n return value as Record<string, unknown>\n}\n\n/** Normalize raw sandbox events for shared agent-gateway consumers. */\nexport function adaptSandboxStream(\n events: AsyncIterable<unknown>,\n): AsyncGenerator<SandboxStreamEvent> {\n return (async function* () {\n for await (const rawEvent of events) {\n if (!rawEvent || typeof rawEvent !== 'object' || Array.isArray(rawEvent)) continue\n\n const event = rawEvent as Record<string, unknown>\n const rawData = event.data\n const dataRecord =\n rawData && typeof rawData === 'object' && !Array.isArray(rawData)\n ? (rawData as Record<string, unknown>)\n : null\n const data: NonNullable<SandboxStreamEvent['data']> = {}\n\n const rawPart = dataRecord?.part\n if (rawPart && typeof rawPart === 'object' && !Array.isArray(rawPart)) {\n const part = rawPart as Record<string, unknown>\n const normalizedPart: NonNullable<\n NonNullable<SandboxStreamEvent['data']>['part']\n > = {}\n if (typeof part.type === 'string') normalizedPart.type = part.type\n if (typeof part.text === 'string') normalizedPart.text = part.text\n if (Object.keys(normalizedPart).length > 0) data.part = normalizedPart\n }\n\n if (typeof dataRecord?.delta === 'string') data.delta = dataRecord.delta\n if (typeof dataRecord?.finalText === 'string') data.finalText = dataRecord.finalText\n if (typeof dataRecord?.code === 'string') data.code = dataRecord.code\n if (typeof dataRecord?.message === 'string') data.message = dataRecord.message\n const rawDetails = dataRecord?.details\n if (rawDetails && typeof rawDetails === 'object' && !Array.isArray(rawDetails)) {\n data.details = rawDetails as Record<string, unknown>\n }\n\n const usageRecord = optionalGatewayRecord(dataRecord?.usage, 'usage')\n if (usageRecord) {\n const usage: NonNullable<NonNullable<SandboxStreamEvent['data']>['usage']> = {}\n for (const field of [\n 'inputTokens',\n 'outputTokens',\n 'reasoningTokens',\n 'toolTokens',\n 'toolCallCount',\n ] as const) {\n const value = optionalNonNegativeSafeInteger(usageRecord[field], `usage.${field}`)\n if (value !== undefined) usage[field] = value\n }\n const providerCostUsd = optionalNonNegativeNumber(\n usageRecord.providerCostUsd,\n 'usage.providerCostUsd',\n )\n if (providerCostUsd !== undefined) usage.providerCostUsd = providerCostUsd\n if (usageRecord.budgetEnforced !== undefined) {\n if (typeof usageRecord.budgetEnforced !== 'boolean') {\n throw new Error('sandbox gateway event usage.budgetEnforced is invalid')\n }\n usage.budgetEnforced = usageRecord.budgetEnforced\n }\n if (Object.keys(usage).length > 0) data.usage = usage\n }\n\n const toolRecord = optionalGatewayRecord(dataRecord?.tool, 'tool')\n if (toolRecord) {\n const tool: NonNullable<NonNullable<SandboxStreamEvent['data']>['tool']> = {}\n if (typeof toolRecord.name === 'string') tool.name = toolRecord.name\n const inputTokens = optionalNonNegativeSafeInteger(toolRecord.inputTokens, 'tool.inputTokens')\n const outputTokens = optionalNonNegativeSafeInteger(toolRecord.outputTokens, 'tool.outputTokens')\n if (inputTokens !== undefined) tool.inputTokens = inputTokens\n if (outputTokens !== undefined) tool.outputTokens = outputTokens\n if (Object.keys(tool).length > 0) data.tool = tool\n }\n\n const reasoningRecord = optionalGatewayRecord(dataRecord?.reasoning, 'reasoning')\n if (reasoningRecord) {\n const tokens = optionalNonNegativeSafeInteger(\n reasoningRecord.tokens,\n 'reasoning.tokens',\n )\n if (tokens !== undefined) data.reasoning = { tokens }\n }\n\n const rawInputRequired = dataRecord?.inputRequired\n if (\n rawInputRequired &&\n typeof rawInputRequired === 'object' &&\n !Array.isArray(rawInputRequired)\n ) {\n const prompt = (rawInputRequired as Record<string, unknown>).prompt\n data.inputRequired = typeof prompt === 'string' ? { prompt } : {}\n }\n\n yield {\n ...(typeof event.type === 'string' ? { type: event.type } : {}),\n ...(Object.keys(data).length > 0 ? { data } : {}),\n }\n }\n })()\n}\n\n/** Configuration needed to prepare a turn without provisioning a workspace. */\nexport type SandboxPromptConfig = Pick<SandboxRuntimeConfig, 'provider' | 'deferProfileFiles' | 'promptBudget'>\n & Partial<Pick<SandboxRuntimeConfig, 'profile'>>\n\n/** Prepare one effective backend for SDK dispatch or product-specific transport.\n * Supply a server-owned profile, or a shell composer for the default profile.\n * Reuse the returned backend for preflight and dispatch so they inspect identical configuration.\n */\nexport async function resolveSandboxPromptBackend(\n shell: SandboxPromptConfig,\n options: StreamSandboxPromptOptions,\n operation = 'sandbox prompt',\n) {\n const initialHarness = options.harness ?? options.profile?.harness ?? DEFAULT_HARNESS\n if (!isHarness(initialHarness)) throw new Error(`Unsupported sandbox harness: ${initialHarness}`)\n const extraMcp = mergeExtraMcp(\n options.appToolMcp ?? {},\n options.profile?.mcp ?? options.baseProfileMcp ?? {},\n options.extraMcp,\n )\n const compose = (harness: Harness) => {\n if (!shell.profile) throw new Error(`${operation}: supply a profile or a shell profile composer`)\n return shell.profile({ systemPrompt: options.systemPrompt, extraMcp, harness })\n }\n let fullProfile = options.profile\n ? mergeAgentProfiles(options.profile, {\n ...(options.systemPrompt !== undefined ? { prompt: { systemPrompt: options.systemPrompt } } : {}),\n ...(Object.keys(extraMcp).length > 0 ? { mcp: extraMcp } : {}),\n })!\n : compose(initialHarness)\n const harness = options.harness ?? fullProfile.harness ?? DEFAULT_HARNESS\n if (!isHarness(harness)) throw new Error(`Unsupported sandbox harness: ${harness}`)\n // Older composers may place harness-native files. Recompose if their authored\n // preference differs from the default used to discover that preference.\n if (!options.profile && harness !== initialHarness) fullProfile = compose(harness)\n\n const explicitModel = trimOrNull(options.model)\n const profileModel = trimOrNull(fullProfile.model?.default)\n const profileProvider = profileModel && (!explicitModel || explicitModel === profileModel)\n ? trimOrNull(fullProfile.model?.provider)\n : null\n const model = requireTransportableModel(\n resolveModelSelection({\n ...shell.provider,\n providerName: trimOrNull(shell.provider?.providerName) ?? profileProvider ?? undefined,\n }, {\n model: explicitModel ?? profileModel ?? undefined,\n modelApiKey: options.modelApiKey,\n }),\n operation,\n )\n // Profile provider evidence belongs only to its own selected model; the\n // transport provider may instead identify a router serving that vendor.\n if (model) assertHarnessModelCompatible(harness, {\n ...model,\n provider: profileProvider ?? model.provider,\n })\n\n const selectedProfile: AgentProfile = {\n ...fullProfile,\n harness,\n // The materializer compares the profile and transport as provider-qualified\n // identities. Authored provider evidence has already served preflight above.\n ...(model ? { model: { ...fullProfile.model, provider: model.provider, default: model.model } } : {}),\n }\n // The deferred writer owns shell-composed files only. Supplied profiles\n // must retain their resources for the SDK to materialize this turn.\n const executionProfile = shell.deferProfileFiles && !options.profile\n ? splitDeferredProfileFiles(selectedProfile).leanProfile\n : selectedProfile\n const profile = applyPromptTokenLimits(\n attachReasoningEffort(executionProfile, harness, options.effort),\n {\n maxVisibleOutputTokens: options.maxOutputTokens,\n maxReasoningTokens: options.maxReasoningTokens,\n maxTotalOutputTokens: options.maxTotalOutputTokens,\n },\n )\n assertProfilePromptWithinBudget(\n profile, shell.promptBudget ?? {}, `${operation} profile systemPrompt`, SHELL_PROMPT_BUDGET_HINT,\n )\n if (options.onProfileResolved) {\n options.onProfileResolved(await fingerprintAgentProfile(profile, { model: model?.model, harness }))\n }\n return {\n type: harness,\n profile,\n ...(model ? backendModelFields(model) : {}),\n ...(options.runtimeAttachments ? { runtimeAttachments: options.runtimeAttachments } : {}),\n ...(options.runtimeSecrets ? { runtimeSecrets: options.runtimeSecrets } : {}),\n ...(options.secretProfileIsolation ? { metadata: { profileSecretIsolation: true as const } } : {}),\n ...(options.interactions ? { interactions: options.interactions } : {}),\n }\n}\n\n/**\n * How long a refused dispatch is resent. Shorter than the completion\n * Workflow's 10-minute wait for a dispatch to appear, so the request gives up\n * before that Workflow reports the dispatch missing.\n */\nexport const SANDBOX_DISPATCH_TRANSIENT_DEADLINE_MS = 8 * 60_000\n\n/**\n * Resend the same execution while the box refuses it with a transient\n * failure and nothing has been delivered yet. The execution id makes a resend\n * idempotent; after the first event a failure is the run's own.\n */\nasync function* resendRefusedDispatch(\n dispatch: () => AsyncIterable<unknown>,\n signal: AbortSignal | undefined,\n): AsyncGenerator<unknown> {\n let delivered = false\n let firstSeenAt: number | undefined\n for (let attempts = 1; ; attempts += 1) {\n try {\n for await (const event of dispatch()) {\n delivered = true\n yield event\n }\n return\n } catch (error) {\n const failure = delivered ? null : classifySandboxTransientFailure(error)\n if (!failure || failure.code === 'sandbox.control_plane_transient') throw error\n const at = Date.now()\n firstSeenAt ??= at\n const delayMs = sandboxTransientBackoffMs(attempts)\n if (at + delayMs - firstSeenAt > SANDBOX_DISPATCH_TRANSIENT_DEADLINE_MS) {\n throw new SandboxTransientDeadlineError(failure, firstSeenAt, attempts, error)\n }\n console.warn('[sandbox] resending a dispatch the box refused', { code: failure.code, attempt: attempts, delayMs })\n await new Promise<void>((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason)\n const timer = setTimeout(resolve, delayMs)\n signal?.addEventListener('abort', () => { clearTimeout(timer); reject(signal.reason) }, { once: true })\n })\n }\n }\n}\n\n/** Resolve and stream AI-generated responses from a sandboxed environment based on input messages and options */\nexport async function* streamSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string | PromptInputPart[],\n options?: StreamSandboxPromptOptions,\n): AsyncGenerator<unknown> {\n const backend = await resolveSandboxPromptBackend(shell, options ?? {}, 'streamSandboxPrompt')\n const prompt =\n typeof message === 'string'\n ? flattenHistory(message, options?.history)\n : mergeHistoryIntoParts(message, options?.history)\n\n const dispatch = () => options?.detach\n ? detachedSandboxPromptEvents(box, prompt, options, backend)\n : box.streamPrompt(prompt, {\n sessionId: options?.sessionId,\n executionId: options?.executionId,\n turnId: options?.turnId,\n lastEventId: options?.lastEventId,\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n ...(options?.ttlMs !== undefined ? { ttlMs: options.ttlMs } : {}),\n ...(options?.requireVisibleAssistantOutput !== undefined\n ? { requireVisibleAssistantOutput: options.requireVisibleAssistantOutput }\n : {}),\n ...(options?.expectedPublicProfileRequestDigest\n ? { expectedPublicProfileRequestDigest: options.expectedPublicProfileRequestDigest }\n : {}),\n ...(options?.expectedSecretProfileReceipt\n ? { expectedSecretProfileReceipt: options.expectedSecretProfileReceipt }\n : {}),\n ...(options?.trace ? { traceId: options.trace.traceId } : {}),\n backend,\n } as StreamPromptOptions)\n const stream = options?.lastEventId ? dispatch() : resendRefusedDispatch(dispatch, options?.signal)\n\n emitSandboxActivity(options?.spend, box)\n let severedFinishReason: string | null = null\n const promptTrace = options?.trace\n ? createPromptTrace(options.trace, options.traceParent, {\n 'sandbox.id': box.id,\n ...(options.model ? { 'gen_ai.request.model': options.model } : {}),\n ...(options.harness ? { 'sandbox.harness': options.harness } : {}),\n ...(options.detach ? { 'sandbox.detached': true } : {}),\n })\n : undefined\n let promptError: unknown\n try {\n for await (const event of stream) {\n promptTrace?.observe(event)\n const step = classifySeveredStream(event)\n if (step) severedFinishReason = step.kind === 'step-finish' && step.severed ? step.reason : null\n if (severedFinishReason && isTerminalPromptEvent(event)) {\n throw new Error(`sandbox model stream severed mid-turn (reason=\"${severedFinishReason}\")`)\n }\n if (options?.disallowQuestions) {\n const q = detectInteractiveQuestion(event)\n if (q) {\n throw new Error(`sandbox agent asked an interactive question during an autonomous run: ${q}`)\n }\n }\n yield event\n }\n } catch (error) {\n promptError = error\n throw error\n } finally {\n // The box was working right up to here, however this turn ended — a throw,\n // an abandoned generator and a clean finish all bill the same.\n emitSandboxActivity(options?.spend, box)\n promptTrace?.end(promptError)\n }\n // Reconnect-exhausted path: the stream ended on a severed step without a\n // terminal event. A truncated turn must fail loud, not return silently.\n if (severedFinishReason) {\n throw new Error(`sandbox model stream severed mid-turn (reason=\"${severedFinishReason}\")`)\n }\n}\n\n/**\n * Stable identity for a streamed text part, so deltas of one part accumulate\n * together and two concurrent parts never overwrite each other. Harnesses spell\n * the id differently and some snapshot updates carry none at all.\n *\n * Deliberately NOT `/stream`'s `getPartKey`, despite the overlapping property\n * lookup: that one resolves a key for any persisted part across every type and\n * falls back to the CONSTANT `'current'`, which merges all id-less parts into a\n * single lane. Here an id-less part must stay distinct — merging two of them\n * would silently drop one candidate answer, the exact failure class this\n * function was changed to fix. Sharing three lines of lookup would also couple\n * `/sandbox` to `/stream`, which are independent subpaths today.\n */\nfunction textPartId(part: Record<string, unknown> | undefined, fallback: string): string {\n for (const key of ['id', 'partId', 'messagePartId']) {\n const value = part?.[key]\n if (typeof value === 'string' && value.trim()) return value\n }\n return fallback\n}\n\n/**\n * The prompt text a harness may replay back as an assistant text part before it\n * answers. Both spellings are collected because `streamSandboxPrompt` dispatches\n * the HISTORY-FOLDED prompt, not the raw message — an echo replays what was sent.\n */\nfunction dispatchedPromptTexts(\n message: string | PromptInputPart[],\n history: StreamSandboxPromptOptions['history'],\n): string[] {\n const raw =\n typeof message === 'string'\n ? message\n : ((message.find((part) => part.type === 'text') as { text?: string } | undefined)?.text ?? '')\n return [...new Set([raw, flattenHistory(raw, history)].map((text) => text.trim()))].filter(Boolean)\n}\n\n/**\n * The last streamed text part that is not a replay of the prompt. Used only when\n * the turn carried no `result` receipt.\n *\n * Two distinct decisions, and only the first is content-based. WHICH parts are\n * eligible is decided by CONTENT — an echo is excluded because it matches the\n * dispatched prompt, at whatever position it arrived. Choosing among the\n * remaining eligible parts is then ordinal, last-wins, because a harness emits\n * reasoning/preamble parts before the answer. That ordering assumption is safe\n * in a way \"skip the first part\" was not: it can only pick the wrong part when a\n * turn produced several genuine non-echo texts and the final one is not the\n * answer, whereas the positional rule mis-fired on the single-answer case that\n * is overwhelmingly the common one.\n */\nfunction lastNonPromptTextPart(parts: Map<string, string>, promptTexts: string[]): string {\n const values = Array.from(parts.values())\n .map((value) => value.trim())\n .filter((value) => value && !promptTexts.includes(value))\n return values.at(-1) ?? ''\n}\n\n/**\n * Aggregate a sandbox prompt event stream down to the turn's one final answer.\n *\n * Exported SEPARATELY from `runSandboxPrompt` because the aggregation is pure —\n * `AsyncIterable<event> -> string` — while the streaming half is not: a product\n * that mounts per-turn MCP servers or resolves its harness per workspace wraps\n * `streamSandboxPrompt` in its own generator. Binding this logic to one stream\n * function is exactly what pushed three products into forking the whole thing,\n * bug and all. Take this over a local copy no matter whose generator you drive.\n *\n * Two rules earn their keep, and both were learned from the naive version:\n *\n * - Text accumulates PER PART ID, never into one running buffer, so two\n * concurrent text parts cannot overwrite each other.\n * - A prompt echo is identified by CONTENT, never by arrival position. The\n * \"skip whichever text part arrives first\" shortcut is wrong on both sandbox\n * lanes: on the delta lane (`box.streamPrompt`, explicit deltas) the first\n * part is the answer's opening token, so the answer silently loses it; and\n * when the echo arrives AFTER the answer, the function returns the caller's\n * own prompt as the agent's reply. Both failures produce a plausible-looking\n * string, the worst shape for the unattended cron/judge turns this exists for.\n *\n * A blank-but-present `result.finalText` is ignored in favour of the streamed\n * text rather than overwriting a real answer with whitespace.\n *\n * @param events raw sandbox turn events, in order\n * @param message the prompt as handed to the stream, so an echo of it is dropped\n * @param history folded into the dispatched prompt by `streamSandboxPrompt`;\n * pass whatever was passed there, since the echo replays the FOLDED text\n */\nexport async function collectSandboxPromptText(\n events: AsyncIterable<unknown>,\n message: string | PromptInputPart[],\n history?: StreamSandboxPromptOptions['history'],\n): Promise<string> {\n let finalText = ''\n const textParts = new Map<string, string>()\n let anonymousTextPart = 0\n\n for await (const rawEvent of events) {\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 const partId = textPartId(part, delta ? 'delta' : `text-${anonymousTextPart++}`)\n if (delta) textParts.set(partId, `${textParts.get(partId) ?? ''}${delta}`)\n else if (typeof part?.text === 'string') textParts.set(partId, part.text)\n }\n } else if (event.type === 'result') {\n const resultText = typeof event.data?.finalText === 'string' ? event.data.finalText : null\n if (resultText?.trim()) finalText = resultText\n }\n }\n\n return finalText || lastNonPromptTextPart(textParts, dispatchedPromptTexts(message, history))\n}\n\n/**\n * Resolve a sandbox prompt by streaming it and aggregating the turn down to one\n * final string. The shell's profile / model / MCP resolution and severed-stream\n * fail-loud come from `streamSandboxPrompt`; the aggregation is\n * `collectSandboxPromptText`, which products driving their own generator should\n * import directly.\n */\nexport async function runSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string | PromptInputPart[],\n options?: StreamSandboxPromptOptions,\n): Promise<string> {\n return collectSandboxPromptText(\n streamSandboxPrompt(shell, box, message, options),\n message,\n options?.history,\n )\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.\n/** Define permission levels for sandbox access and control */\nexport type SandboxPermissionLevel = 'owner' | 'admin' | 'developer' | 'viewer'\n\n/** Map workspace roles to corresponding sandbox permission levels */\nexport interface MemberSyncSeam {\n roleToSandboxRole: (workspaceRole: string) => SandboxPermissionLevel\n}\n\n/** Resolve adding a user with a specific role to a sandbox and return the operation outcome */\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\n/** Remove a member from the sandbox while preserving their home directory and handle the outcome */\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\n/** Synchronize a sandbox member's role by updating permissions based on the provided role mapping */\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\n/**\n * Write-only secret port: create, replace, and delete a secret by name.\n *\n * There is no read method. The platform's secrets API returns names and\n * timestamps only — a stored value is never served back, it is injected into\n * the sandbox as an environment variable. A `get` here could only ever return\n * a value this process already held, so the port does not offer one.\n */\nexport interface SecretStore {\n create: (name: string, value: string) => Promise<void>\n update: (name: string, value: string) => Promise<void>\n delete: (name: string) => Promise<void>\n}\n\n/** Resolve a SecretStore interface using the provided SandboxRuntimeConfig shell */\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 // The API has no replace route, so a replacement is a delete followed by a\n // create. That pair is NOT atomic: if the create fails, the secret is left\n // deleted rather than at its previous value. `storeSecret` reports that\n // state instead of reporting a generic write failure, because a caller\n // retrying a lost secret needs to know it is now absent.\n update: async (name, value) => {\n await client.secrets.delete(name)\n await client.secrets.create(name, value)\n },\n delete: async (name) => {\n await client.secrets.delete(name)\n },\n }\n}\n\n/** Resolve storing a secret by creating it, or replacing it when it exists */\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(\n new Error(\n `Failed to store sandbox secret ${name}. A replacement deletes before it creates, so ${name} may now be absent rather than holding its previous value.`,\n { cause: err },\n ),\n )\n }\n }\n}\n\n/** Delete a secret by name from the given secret store and return the operation outcome */\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\n/** Represent a token with its expiration date and associated scope */\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: MintScopedTokenOptions,\n): Promise<Outcome<ScopedTokenResult>> {\n try {\n const token = await box.mintScopedToken(options)\n return ok({ token: token.token, expiresAt: token.expiresAt, scope: token.scope })\n } catch (err) {\n return fail(err)\n }\n}\n\n/** Define options to manage deterministic session resumption and turn idempotency in sandboxed drive turns */\nexport interface DriveSandboxTurnOptions extends StreamSandboxPromptOptions {\n /** Deterministic resume key — required. Every tick for the same logical turn\n * MUST reuse it so a crash + re-drive finds the in-flight session instead of\n * starting a second agent run. */\n sessionId: string\n /** Wall-clock cap in ms from the session's start. A still-running session past\n * the cap is cancelled and reported `failed` — bounds an unattended run, such as\n * a turn stalled on an interactive question with no consumer. Omit for no cap. */\n wallCapMs?: number\n}\n\n// One settle → poll → dispatch pass over a detached turn. Delegates to the SDK's\n// `box.driveTurn` (@tangle-network/sandbox ≥ 0.10.5). Sandbox 0.37 admits the\n// turn through the session message lane, so a SessionGateway consumer can observe it.\n// The turn runs fire-and-detached server-side. ONE invocation returns its current\n// state immediately. It never awaits the whole turn in-process, so it does not hold the\n// worker alive for the run's duration (the durability trap the older box.prompt\n// implementation quietly caused).\n//\n// This is the durable path for cron / mission-step / queue callers: re-invoke on\n// your own schedule (Workflow step, DO alarm, queue tick) with the SAME\n// `sessionId` and `turnId`. Dispatch is idempotent on that pair, so a crash +\n// re-drive is a lookup, not a second agent run.\n//\n// The Outcome boundary separates a retryable transport failure from a settled\n// turn: `fail` means the drive call itself threw (network blip — retry the tick);\n// `ok` carries the SDK's discriminated `TurnDriveResult` — inspect `.state`:\n// - `running` → the turn is still executing; re-tick after a delay of your choosing.\n// - `completed` → terminal; `.text` / `.result` hold the payload.\n// - `failed` → terminal and deterministic; re-invoking will not change it (do not retry).\n// - `awaiting_plan_decision`, `blocked_on_approval`, `awaiting_question`,\n// `awaiting_interaction` → the turn settled waiting on a decision. Sandbox\n// 0.45 reports the last three as `failed`.\n/** Resolve a sandbox turn by processing a message with given configuration and options */\nexport async function driveSandboxTurn(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string | PromptInputPart[],\n options: DriveSandboxTurnOptions,\n): Promise<Outcome<TurnDriveResult>> {\n // Configuration failures precede the retryable transport boundary.\n const backend = await resolveSandboxPromptBackend(shell, options, 'driveSandboxTurn')\n const prompt =\n typeof message === 'string'\n ? flattenHistory(message, options.history)\n : mergeHistoryIntoParts(message, options.history)\n try {\n const drive = await box.driveTurn(prompt, {\n sessionId: options.sessionId,\n ...(options.turnId ? { turnId: options.turnId } : {}),\n ...(options.wallCapMs !== undefined ? { wallCapMs: options.wallCapMs } : {}),\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n ...(options.expectedPublicProfileRequestDigest\n ? { expectedPublicProfileRequestDigest: options.expectedPublicProfileRequestDigest }\n : {}),\n ...(options.expectedSecretProfileReceipt\n ? { expectedSecretProfileReceipt: options.expectedSecretProfileReceipt }\n : {}),\n // Sandbox 0.37 drives through the session message lane, so a gateway\n // consumer can handle these events. Callers without one should omit\n // interactions so the run stays unattended.\n backend,\n } as Parameters<SandboxInstance['driveTurn']>[1])\n // The autonomous lane needs this most: a detached turn keeps the box\n // billable with nobody watching, and every tick that reports `running` is\n // fresh evidence it is still working. Without it the expectation ceiling\n // rests on whenever the box was last provisioned.\n emitSandboxActivity(options.spend, box)\n return ok(drive)\n } catch (err) {\n return fail(err)\n }\n}\n\n// Severed-stream classifier. Generic to any router-backed harness: a final step\n// that finished with error/other/unknown is a truncated turn, not a completed one.\nconst SEVERED_FINISH_REASONS = new Set(['error', 'other', 'unknown'])\n\n/** Define transitions marking the start or finish of a sandbox step with associated details */\nexport type SandboxStepTransition =\n | { kind: 'step-start' }\n | { kind: 'step-finish'; reason: string; severed: boolean }\n\nfunction asPlainRecord(v: unknown): Record<string, unknown> | null {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : null\n}\n\n/** Resolve the severed stream event to a corresponding sandbox step transition or null */\nexport function classifySeveredStream(event: unknown): SandboxStepTransition | null {\n const root = asPlainRecord(event)\n if (!root || root.type !== 'message.part.updated') return null\n const body = asPlainRecord(root.properties) ?? asPlainRecord(root.data) ?? root\n const part = asPlainRecord(body.part)\n if (!part) return null\n if (part.type === 'step-start') return { kind: 'step-start' }\n if (part.type !== 'step-finish') return null\n const reason = typeof part.reason === 'string' && part.reason ? part.reason : 'unknown'\n return { kind: 'step-finish', reason, severed: SEVERED_FINISH_REASONS.has(reason) }\n}\n\n/** Determine if an event is a terminal prompt event with type 'result' or 'done */\nexport function isTerminalPromptEvent(event: unknown): boolean {\n const t = asPlainRecord(event)?.type\n return t === 'result' || t === 'done'\n}\n\n// Interactive-question detector. Returns the question text or null. Used by\n// streamSandboxPrompt when disallowQuestions is set.\n/** Resolve the interactive question text from a structured event or return null if none found */\nexport function detectInteractiveQuestion(event: unknown): string | null {\n const root = asPlainRecord(event)\n if (!root) return null\n const type = typeof root.type === 'string' ? root.type : undefined\n const data = asPlainRecord(root.data)\n const props = asPlainRecord(root.properties)\n const body = props ?? data ?? root\n if (type === 'question.asked' || type === 'question') return firstQuestionText(body)\n // Generic structured-interaction event (BackendConfig.interactions kinds surface as\n // `interaction` events with a `kind` discriminator); treat kind:\"question\" as a question.\n if (type === 'interaction' && body.kind === 'question') return firstQuestionText(body)\n const part = asPlainRecord(data?.part) ?? asPlainRecord(body.part)\n const tool =\n (typeof part?.tool === 'string' && part.tool) ||\n (typeof part?.name === 'string' && part.name) ||\n (typeof body.tool === 'string' && body.tool) ||\n undefined\n const isQ =\n type === 'message.part.updated' &&\n (tool === 'question' || asPlainRecord(part)?.type === 'question')\n if (!isQ) return null\n const state = asPlainRecord(asPlainRecord(part)?.state)\n return firstQuestionText(asPlainRecord(state?.input) ?? state ?? part ?? body)\n}\n\nfunction firstQuestionText(value: Record<string, unknown> | null): string {\n const arr = Array.isArray(value?.questions)\n ? value!.questions\n : Array.isArray(asPlainRecord(value?.input)?.questions)\n ? (asPlainRecord(value!.input)!.questions as unknown[])\n : []\n const first = asPlainRecord(arr[0])\n const q =\n (typeof first?.question === 'string' && first.question) ||\n (typeof first?.prompt === 'string' && first.prompt) ||\n undefined\n return q ?? 'interactive question'\n}\n// Generic name-keyed workspace sandbox lifecycle manager.\nexport * from './workspace-sandbox-manager'\n// Browser-direct scoped-token terminal connection route (#341/#349/#350).\nexport * from './terminal-connection'\n// Background box warming on project open: single-flight, non-blocking, and\n// explicit about spend. Imports `ensureWorkspaceSandbox`/`peekWorkspaceSandbox`\n// back out of this module; tsup inlines both files into the one\n// `sandbox/index` chunk, so the cycle exists only in source.\nexport * from './prewarm'\nexport * from './sandbox-run-tool'\nexport * from './sandbox-exec-tool'\n\nexport * from './prewarm-claim-d1'\nexport * from './prewarm-route'\nexport * from './foreground-single-flight'\n// Signal-driven warm leases: resume ahead of need, budget the misses, learn the daily ramp.\nexport * from './warm-lease'\nexport * from './warm-lease-d1'\n// Speculative warm for turns likely to call a sandbox tool (agent turn architecture S8).\nexport * from './escalation-speculator'\n","// Shared Outcome triple for the sandbox modules. Lives in a dependency-free\n// leaf so helpers can use it without importing the substrate-bound index.\n/** Represent success or failure of an operation with corresponding value or error information */\nexport type Outcome<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: Error }\n\nexport const ok = <T>(value: T): Outcome<T> => ({ succeeded: true, value })\nexport const fail = (error: unknown): Outcome<never> => ({\n succeeded: false,\n error: error instanceof Error ? error : new Error(String(error)),\n})\n","/**\n * What a sandbox prompt stream tells the turn's trace: one `sandbox.prompt`\n * span for the whole stream, the sidecar's own first-text phases as child\n * spans, one `sandbox.generation` span from the first visible text, and one\n * `tool.call` span for each tool the box agent ran.\n *\n * Every time here is read on this side of the wire, from when each event\n * arrived. Event arrival is quantized by the stream's chunking, so the tool\n * spans carry `approx: true`. The sidecar's phases are offsets on its own\n * clock; only their durations are used, and the wait that no phase holds (the\n * SDK, the API, the orchestrator and the host, both ways) is `sandbox.transit`.\n */\nimport type { TurnSpan, TurnSpanAttrs, TurnTrace } from '../turn-trace/recorder'\nimport { nextCallIndex } from '../turn-trace/traced-fetch'\n\ntype Rec = Record<string, unknown>\nconst asRec = (value: unknown): Rec | undefined => value && typeof value === 'object' && !Array.isArray(value) ? value as Rec : undefined\nconst asNum = (value: unknown): number | undefined => typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined\n\n/** The sidecar's phase order, and what each one's span is called. */\nconst PHASES = ['agent_run_start', 'harness_spawn', 'harness_ready', 'first_model_request', 'first_upstream_byte', 'first_text'] as const\n\nexport interface PromptTrace {\n /** Read one raw sandbox event. Never throws. */\n observe(event: unknown): void\n /** End the stream's spans. `error` marks the prompt failed. */\n end(error?: unknown): void\n}\n\nexport function createPromptTrace(trace: TurnTrace, parent: TurnSpan | undefined, meta: TurnSpanAttrs): PromptTrace {\n const startedAt = Date.now()\n const prompt = trace.start('sandbox.prompt', 'sandbox', meta, parent)\n let firstEventAt: number | undefined\n let firstTextAt: number | undefined\n let generation: TurnSpan | undefined\n let phases: { offsets: Rec; warm: boolean | null; model?: string } | undefined\n let events = 0\n const tools = new Map<string, TurnSpan>()\n\n const startTool = (id: string, name: string) => {\n if (tools.has(id)) return\n tools.set(id, trace.start('tool.call', 'tool', {\n 'gen_ai.tool.name': name, 'tool.call_id': id, 'call.index': nextCallIndex(trace, 'tool.call'), where: 'sandbox', approx: true,\n }, generation ?? prompt))\n }\n\n const observe = (raw: unknown) => {\n try {\n const event = asRec(raw)\n if (!event) return\n const now = Date.now()\n events++\n firstEventAt ??= now\n const type = typeof event.type === 'string' ? event.type : ''\n const data = asRec(event.data)\n if (type === 'result') {\n const report = asRec(data?.firstTextPhases)\n const offsets = asRec(report?.phasesMs)\n if (offsets) {\n phases = {\n offsets,\n warm: typeof report?.harnessWarm === 'boolean' ? report.harnessWarm : null,\n ...(typeof report?.model === 'string' ? { model: report.model } : {}),\n }\n }\n return\n }\n if (type === 'tool_call' || type === 'tool.call') {\n const id = String(data?.id ?? data?.callId ?? data?.callID ?? data?.name ?? '')\n if (id) startTool(id, String(data?.name ?? data?.tool ?? 'tool'))\n return\n }\n if (type === 'tool_result' || type === 'tool.result') {\n const id = String(data?.id ?? data?.callId ?? data?.callID ?? data?.name ?? '')\n tools.get(id)?.end(undefined, data?.error ?? (data?.status === 'error' ? 'tool_error' : undefined))\n return\n }\n if (type !== 'message.part.updated') return\n const part = asRec(data?.part)\n const partType = String(part?.type ?? '')\n if (partType === 'text' && firstTextAt === undefined && ((typeof data?.delta === 'string' && data.delta) || (typeof part?.text === 'string' && part.text))) {\n firstTextAt = now\n generation = prompt.child('sandbox.generation', 'model')\n } else if (partType === 'tool') {\n const id = String(part?.id ?? part?.callID ?? '')\n if (!id) return\n const state = asRec(part?.state)\n const status = String(state?.status ?? part?.status ?? '')\n startTool(id, String(part?.tool ?? 'tool'))\n if (status === 'completed' || status === 'error') tools.get(id)?.end(undefined, status === 'error' ? 'tool_error' : undefined)\n }\n } catch {\n // Telemetry never fails a turn.\n }\n }\n\n const end = (error?: unknown) => {\n try {\n // A tool the stream never closed ended with the stream.\n for (const span of tools.values()) span.end({ 'tool.unclosed': true })\n generation?.end()\n if (phases && firstTextAt !== undefined) {\n const firstText = asNum(phases.offsets.first_text)\n // The sidecar's clock starts at `turn_received`; its first text frame is the one this side saw at `firstTextAt`.\n if (firstText !== undefined && firstTextAt - firstText >= startedAt) {\n const origin = firstTextAt - firstText\n prompt.record('sandbox.transit', 'sandbox', startedAt, origin, { note: 'sdk, api, orchestrator and host hops, both ways' })\n let previous = 0\n for (const phase of PHASES) {\n const offset = asNum(phases.offsets[phase])\n if (offset === undefined || offset < previous) continue\n // The provider's first byte is model time; the harness steps before it are the box's.\n prompt.record(`sidecar.${phase}`, phase === 'first_upstream_byte' || phase === 'first_text' ? 'model' : 'sandbox', origin + previous, origin + offset)\n previous = offset\n }\n }\n }\n prompt.set({\n events,\n ...(firstEventAt !== undefined ? { first_event_ms: firstEventAt - startedAt } : {}),\n ...(firstTextAt !== undefined ? { first_text_ms: firstTextAt - startedAt } : {}),\n ...(phases?.warm !== null && phases?.warm !== undefined ? { 'sidecar.harness_warm': phases.warm } : {}),\n ...(phases?.model ? { 'sidecar.model': phases.model } : {}),\n ...Object.fromEntries(PHASES.flatMap((phase) => {\n const offset = asNum(phases?.offsets[phase])\n return offset === undefined ? [] : [[`sidecar.${phase}_ms`, Math.round(offset)]]\n })),\n })\n prompt.end(undefined, error)\n } catch {\n // Telemetry never fails a turn.\n }\n }\n\n return { observe, end }\n}\n","import { trimOrNull } from '../runtime/model'\n\n/** Define configuration options for resolving a provider and its model with optional API keys and routing details */\nexport interface ProviderResolutionConfig {\n routerBaseUrl?: string\n apiKey?: string\n providerName?: string\n modelName?: string\n defaultModel?: string\n openaiApiKey?: string\n // Opt-in: a resolvable provider+model WITHOUT an api key still yields model\n // metadata (model/provider/baseUrl, no apiKey) instead of undefined. Keyless\n // metadata makes the sandbox platform mint its OWN per-user router key at\n // create (its requiresRouterKey gate), so turns bill the box's billing owner\n // instead of a product-baked shared key. Requires an explicit providerName —\n // provider inference from key presence cannot fire keyless. Default false:\n // a keyless config resolves to undefined exactly as before.\n allowKeylessModel?: boolean\n // Name of a box environment variable holding the provider key: a stored\n // secret the box is created with. Caller-owned auth by reference, so the\n // platform mints no Router key and the key value never passes through the\n // app. A raw `apiKey` (config or per-turn) takes precedence.\n apiKeyEnv?: string\n}\n\n/** Represent a fully configured model with optional API key and base URL for sandbox platform integration */\n/**\n * Spread a {@link ResolvedModel} onto a sandbox backend config as the nested\n * `model` object — the one spelling every admitted SDK accepts.\n *\n * Do not add the role-named flat fields (`modelId`, `provider`, `apiKey`,\n * `baseUrl`) beside it until the sandbox peer floor reaches the release that\n * folds them (0.60.16). A pre-fold SDK forwards the whole backend unchanged,\n * and the platform's strict backend schema refuses the extra keys:\n * agent-app 0.53.10–0.54.0 emitted both, and every sandbox chat turn on a\n * product resolving sandbox < 0.60.16 failed with \"unrecognized_keys\n * provider, apiKey, baseUrl, modelId at path backend\" (Creative, 2026-10-06).\n */\nexport function backendModelFields(model: ResolvedModel): {\n model: { model: string; provider: string; apiKey?: string; apiKeyEnv?: string; baseUrl?: string };\n} {\n return {\n model: {\n model: model.model,\n provider: model.provider,\n ...(model.apiKey !== undefined ? { apiKey: model.apiKey } : {}),\n ...(model.apiKeyEnv !== undefined ? { apiKeyEnv: model.apiKeyEnv } : {}),\n ...(model.baseUrl !== undefined ? { baseUrl: model.baseUrl } : {}),\n },\n };\n}\n\nexport interface ResolvedModel {\n model: string\n provider: string\n // Omitted only under `allowKeylessModel` — keyless metadata tells the\n // sandbox platform to mint its own per-user router key for the box.\n apiKey?: string\n /** A stored-secret reference standing in for `apiKey`; see {@link ProviderResolutionConfig.apiKeyEnv}. */\n apiKeyEnv?: string\n baseUrl?: string\n}\n\n/**\n * Why a model failed to resolve into something transportable to the sandbox\n * platform. `no_provider` — a model id exists but no provider name could be\n * derived (no explicit `providerName`, and no key present to infer one from).\n * `no_api_key` — a provider AND model both resolved, but no credential is\n * configured and the caller did not opt into `allowKeylessModel`.\n */\nexport type ModelSelectionError = 'no_provider' | 'no_api_key'\n\n/**\n * Which precedence slot supplied the failed/succeeded model id:\n * `override` — the caller's per-turn `{ model }` argument.\n * `config` — `provider.modelName`.\n * `default` — `provider.defaultModel` (only ever consulted for an\n * openai/openai-compat provider shape).\n */\nexport type ModelSelectionSource = 'override' | 'config' | 'default'\n\n/**\n * A model id was named (by override, config, or default) but is not\n * transportable to the sandbox platform. Carries enough to explain WHY\n * without the caller re-deriving the override/config/default precedence\n * chain itself (that re-derivation is how gtm-agent#665 happened — a caller\n * guessed loudness from the wrong slot and dropped a user-selected model).\n */\nexport type ModelSelectionFailure =\n | { succeeded: false; error: 'no_provider'; model: string; source: ModelSelectionSource }\n | {\n succeeded: false\n error: 'no_api_key'\n model: string\n provider: string\n source: ModelSelectionSource\n }\n\n/**\n * The three-state outcome of resolving a model: `{ succeeded: true, value:\n * undefined }` means NOTHING was requested (the legitimate box-default\n * configuration — not an error); `{ succeeded: true, value: ResolvedModel }`\n * means a fully transportable model resolved; anything else is a\n * {@link ModelSelectionFailure} — a model WAS named but can't be sent.\n */\nexport type ModelSelection =\n | { succeeded: true; value: ResolvedModel | undefined }\n | ModelSelectionFailure\n\n/**\n * Resolve a provider + model configuration into a typed three-state outcome\n * that separates \"nothing requested\" from \"something requested but\n * untransportable\" — the distinction {@link resolveModel} collapses and the\n * one that caused gtm-agent#665 (a validated user-selected model silently\n * dropped, box default substituted, durable row still recording the user's\n * choice).\n *\n * Precedence (identical to the legacy `resolveModel`, byte-for-byte):\n * provider is computed first (`providerName`, else inferred `openai-compat`\n * from a present key, else inferred `openai` from a present\n * `openaiApiKey`, else unresolved); the model id is `override.model` else\n * `config.modelName` else — ONLY when the provider is `openai` or\n * `openai-compat` — `config.defaultModel`; the api key is\n * `override.modelApiKey` else `config.apiKey` else — only for provider\n * `openai` — `config.openaiApiKey`.\n *\n * Two behavioral deltas from the legacy function:\n * 1. Every string field (`routerBaseUrl`, `apiKey`, `providerName`,\n * `modelName`, `defaultModel`, `openaiApiKey`, `override.model`,\n * `override.modelApiKey`) is normalized through {@link trimOrNull} first,\n * so `''` (and whitespace-only strings) are treated as absent instead of\n * poisoning the `??` precedence chain — the issue's second stated defect.\n * This also means a value is trimmed (`' gpt-5 '` resolves to `'gpt-5'`).\n * 2. The outcome is three-state instead of collapsing to `undefined`: no\n * model derivable from any slot → `{ succeeded: true, value: undefined }`\n * (still the legitimate \"let the box pick its own default\" case, NOT an\n * error); a model id resolved but no provider could be derived → a\n * `no_provider` failure; a model + provider resolved but no api key (and\n * `allowKeylessModel` was not set) → a `no_api_key` failure. Both failure\n * arms carry `source` so a caller can apply a loudness policy without\n * re-deriving which precedence slot supplied the model.\n */\nexport function resolveModelSelection(\n config: ProviderResolutionConfig | undefined,\n override?: { model?: string; modelApiKey?: string },\n): ModelSelection {\n const c = config ?? {}\n const explicitBaseUrl = trimOrNull(c.routerBaseUrl)\n const explicitApiKey = trimOrNull(override?.modelApiKey) ?? trimOrNull(c.apiKey)\n const providerName = trimOrNull(c.providerName)\n const openaiApiKey = trimOrNull(c.openaiApiKey)\n const provider =\n providerName ?? (explicitApiKey ? 'openai-compat' : openaiApiKey ? 'openai' : undefined)\n\n const overrideModel = trimOrNull(override?.model)\n const configModel = trimOrNull(c.modelName)\n const defaultModel = trimOrNull(c.defaultModel)\n const modelName =\n overrideModel ??\n configModel ??\n (provider === 'openai' || provider === 'openai-compat' ? defaultModel : null)\n\n if (!modelName) return { succeeded: true, value: undefined }\n\n const source: ModelSelectionSource = overrideModel ? 'override' : configModel ? 'config' : 'default'\n\n if (!provider) return { succeeded: false, error: 'no_provider', model: modelName, source }\n\n const apiKey = explicitApiKey ?? (provider === 'openai' ? openaiApiKey : undefined)\n const apiKeyEnv = apiKey ? null : trimOrNull(c.apiKeyEnv)\n if (!apiKey && !apiKeyEnv && !c.allowKeylessModel) {\n return { succeeded: false, error: 'no_api_key', model: modelName, provider, source }\n }\n\n return {\n succeeded: true,\n value: {\n model: modelName,\n provider,\n ...(apiKey ? { apiKey } : apiKeyEnv ? { apiKeyEnv } : {}),\n ...(explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}),\n },\n }\n}\n\n/**\n * Resolve and return the appropriate model configuration based on provider\n * settings and optional overrides.\n *\n * Migration note (intentionally NOT tagged `@deprecated`): this is a thin,\n * source-compatible wrapper over {@link resolveModelSelection} that collapses\n * its three-state outcome back down to `ResolvedModel | undefined`, exactly\n * as before. It stays correct for the common case (no explicit model requested, or a\n * fully-transportable one), but it CANNOT distinguish \"nothing was\n * requested\" from \"a named model could not be transported\" — the ambiguity\n * that caused gtm-agent#665. Prefer {@link resolveModelSelection} directly,\n * or {@link requireTransportableModel} for the fail-loud-on-explicit-model\n * policy the internal sandbox callers use. Not tagged `@deprecated`: it\n * remains the correct call for a caller that never sets an explicit\n * override and only wants \"the box's default is fine\" semantics; a hard\n * deprecation is a later-major decision, not this fix's.\n *\n * The only behavior change on this entry point versus before is the\n * empty-string bugfix that comes free through delegation (issue #302's\n * second defect) — every signature and the `undefined` return semantics are\n * unchanged.\n */\nexport function resolveModel(\n config: ProviderResolutionConfig | undefined,\n override?: { model?: string; modelApiKey?: string },\n): ResolvedModel | undefined {\n const selection = resolveModelSelection(config, override)\n return selection.succeeded ? selection.value : undefined\n}\n\n/**\n * Thrown by {@link requireTransportableModel} when a model that was\n * EXPLICITLY requested via a per-turn `{ model }` override cannot be\n * transported to the sandbox platform. The message names the model, which\n * precedence slot supplied it, what's missing, and the fix, and states\n * plainly that the requested model was NOT sent to the box (the failure mode\n * this error exists to make impossible to miss — gtm-agent#665 silently\n * substituted the box default instead of a user-selected model).\n *\n * The error class itself carries no opinion about *when* it should be\n * thrown — it is constructed from any {@link ModelSelectionFailure},\n * regardless of `source`. A caller wanting a stricter policy (e.g. also\n * fail-loud on an untransportable configured `provider.modelName`) can call\n * {@link resolveModelSelection} directly and throw this itself.\n */\nexport class SandboxModelResolutionError extends Error {\n readonly code: ModelSelectionError\n readonly model: string\n readonly provider?: string\n readonly source: ModelSelectionSource\n\n constructor(failure: ModelSelectionFailure, context: string) {\n const missing =\n failure.error === 'no_provider'\n ? 'no provider could be resolved for it'\n : `provider \"${failure.provider}\" resolved but no API key is configured`\n const fix =\n failure.error === 'no_provider'\n ? 'set providerName explicitly (provider cannot be inferred without one)'\n : 'set apiKey (or openaiApiKey when provider is \"openai\"), or pass allowKeylessModel:true to mint a keyless box'\n super(\n `${context}: model \"${failure.model}\" (from ${failure.source}) is not transportable — ` +\n `${missing}. Fix: ${fix}. The requested model was NOT sent to the box.`,\n )\n this.name = 'SandboxModelResolutionError'\n this.code = failure.error\n this.model = failure.model\n if (failure.error === 'no_api_key') this.provider = failure.provider\n this.source = failure.source\n }\n}\n\n/**\n * Shared fail-loud policy for the sandbox platform's three internal model\n * callers (`ensureWorkspaceSandbox`'s `backendModelAtCreate`,\n * `streamSandboxPrompt`, `driveSandboxTurn`): a `ModelSelection` in, a plain\n * `ResolvedModel | undefined` out, so downstream code is unchanged from\n * before this fix.\n *\n * The policy: success delegates straight through. A failure whose `source`\n * is `'override'` means a PER-TURN model was explicitly selected THIS turn\n * (a live, user-driven choice — passed as `{ model }`) and could not be\n * sent; substituting the box default there is exactly the gtm-agent#665\n * defect, so it throws {@link SandboxModelResolutionError} rather than\n * silently falling back.\n *\n * A failure whose `source` is `'config'` or `'default'` means a\n * *configured* `provider.modelName` / `provider.defaultModel` couldn't\n * resolve — nobody made a choice this turn; the value came from board\n * config that may simply describe \"the platform supplies the credential.\"\n * Shipped consumers rely on exactly that: tax-agent ships a shell with\n * `provider: { providerName: 'openai-compat', modelName, routerBaseUrl }`\n * and no `apiKey`/`allowKeylessModel`, with a contract test asserting\n * `ensureWorkspaceSandbox` creation SUCCEEDS with the model silently\n * dropped so the sandbox platform mints its own in-container credential\n * (`apps/web/tests/sandbox-service-contract.test.ts`). A config-loud policy\n * here would break every fresh tax sandbox provisioning and every tax turn.\n * So both `'config'` and `'default'` keep the pre-#302 logged-skip\n * behavior: `console.error` and drop, letting the box use its own default.\n * A product wanting strict enforcement of a configured `provider.modelName`\n * can call {@link resolveModelSelection} directly and apply its own policy.\n */\nexport function requireTransportableModel(\n selection: ModelSelection,\n context: string,\n): ResolvedModel | undefined {\n if (selection.succeeded) return selection.value\n if (selection.source === 'override') {\n throw new SandboxModelResolutionError(selection, context)\n }\n const reason =\n selection.error === 'no_api_key'\n ? `provider \"${selection.provider}\" has no api key`\n : 'no provider resolved'\n if (selection.source === 'config') {\n console.error(\n `[sandbox] ${context}: dropping configured provider.modelName \"${selection.model}\" (${reason}); ` +\n `the box will use its own default model — set allowKeylessModel:true to bake a keyless model, or configure an api key`,\n )\n } else {\n console.error(\n `[sandbox] ${context}: dropping provider.defaultModel \"${selection.model}\" (${reason}); using the box default`,\n )\n }\n return undefined\n}\n","/**\n * Reading arbitrary bytes out of a sandbox over an exec channel that only\n * speaks text.\n *\n * `box.exec` returns stdout as a string, so a binary file has to be encoded to\n * survive the trip: `wc -c` gives the on-disk length, `base64` gives the\n * payload, and the decoded byte count is checked against the stat. That last\n * check is the point of the module — an exec channel that caps or clips its\n * output still reports `exitCode: 0` with a short buffer, which decodes into a\n * perfectly valid but TRUNCATED file. Verifying the length turns that silent\n * corruption into a loud failure at the boundary.\n *\n * Both helpers return typed outcomes; callers must inspect `succeeded` before\n * touching `value`.\n */\n\n/** The `box.exec` surface these helpers use — structural, so a caller can pass\n * the sandbox SDK's `SandboxInstance` directly or a narrower test double. */\nexport interface SandboxExecChannel {\n exec(\n command: string,\n options?: { sessionId?: string },\n ): Promise<{ stdout: string; stderr: string; exitCode: number }>\n}\n\n/** Define options to execute code within a sandbox environment with optional session control */\nexport interface SandboxExecOptions {\n /** Run inside a named session rather than the box's default one. */\n sessionId?: string\n}\n\n/** Resolve the outcome of a sandbox file size check with success status and value or error message */\nexport type SandboxFileSizeOutcome =\n | { succeeded: true; value: number }\n | { succeeded: false; error: string }\n\n/** Represent the outcome of reading sandbox file bytes with success status and corresponding data or error */\nexport type SandboxFileBytesOutcome =\n | { succeeded: true; value: { bytes: Uint8Array; size: number } }\n | { succeeded: false; error: string }\n\n/** Wraps a value in single quotes for `sh`, closing and reopening the quote\n * around each embedded quote (`'` → `'\"'\"'`). Every path these helpers\n * interpolate into a command goes through this — in-box filenames are\n * arbitrary, so spaces, quotes and `$` are ordinary content, not syntax. */\nexport function shellQuote(value: string): string {\n return `'${value.replaceAll(\"'\", `'\"'\"'`)}'`\n}\n\n/** Decodes with `atob` rather than `Buffer.from(s, 'base64')`: Buffer SKIPS\n * characters outside the alphabet, so a corrupted payload would decode to\n * something plausible instead of throwing. */\nfunction base64ToBytes(base64: string): Uint8Array {\n const binary = atob(base64)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i)\n return bytes\n}\n\nfunction execInSandbox(box: SandboxExecChannel, command: string, options?: SandboxExecOptions) {\n return options?.sessionId ? box.exec(command, { sessionId: options.sessionId }) : box.exec(command)\n}\n\n/** Stats a sandbox file's byte length via `wc -c`. A caller enforcing a size\n * cap must check this BEFORE {@link readSandboxBinaryBytes}, so an oversize\n * file is rejected without paying for a base64 round trip of it. */\nexport async function statSandboxFileSize(\n box: SandboxExecChannel,\n absolutePath: string,\n options?: SandboxExecOptions,\n): Promise<SandboxFileSizeOutcome> {\n const quotedPath = shellQuote(absolutePath)\n let result\n try {\n result = await execInSandbox(box, `wc -c < ${quotedPath}`, options)\n } catch (err) {\n return { succeeded: false, error: err instanceof Error ? err.message : String(err) }\n }\n if (result.exitCode !== 0) {\n return { succeeded: false, error: result.stderr || 'unknown error' }\n }\n const size = Number.parseInt(result.stdout.trim(), 10)\n if (!Number.isFinite(size)) {\n return { succeeded: false, error: `could not parse file size from \"${result.stdout.trim()}\"` }\n }\n return { succeeded: true, value: size }\n}\n\n/** Reads a sandbox file as base64 and decodes it, verifying the decoded byte\n * length against `expectedSize` (from a prior {@link statSandboxFileSize}). A\n * mismatch is reported, never returned as a short buffer. */\nexport async function readSandboxBinaryBytes(\n box: SandboxExecChannel,\n absolutePath: string,\n expectedSize: number,\n options?: SandboxExecOptions,\n): Promise<SandboxFileBytesOutcome> {\n const quotedPath = shellQuote(absolutePath)\n let result\n try {\n result = await execInSandbox(box, `base64 ${quotedPath}`, options)\n } catch (err) {\n return { succeeded: false, error: err instanceof Error ? err.message : String(err) }\n }\n if (result.exitCode !== 0) {\n return { succeeded: false, error: result.stderr || 'unknown error' }\n }\n // GNU coreutils wraps base64 output at 76 columns; BusyBox may not wrap at\n // all. Stripping all whitespace makes both shapes decode identically.\n const cleaned = result.stdout.replace(/\\s+/g, '')\n let bytes: Uint8Array\n try {\n bytes = base64ToBytes(cleaned)\n } catch (err) {\n return {\n succeeded: false,\n error: `could not decode file contents: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\n if (bytes.byteLength !== expectedSize) {\n return {\n succeeded: false,\n error: `read returned ${bytes.byteLength} bytes, expected ${expectedSize} — output truncated in transit`,\n }\n }\n return { succeeded: true, value: { bytes, size: expectedSize } }\n}\n","/** Define the shape of a workspace sandbox instance including its connection details and status. */\nexport interface WorkspaceSandboxInstanceLike {\n id: string\n name?: string\n status?: string\n connection?: {\n runtimeUrl?: string\n sidecarUrl?: string\n authToken?: string\n sidecarToken?: string\n authTokenExpiresAt?: string\n } | null\n}\n\n/** Define the context containing workspace and user identifiers for sandbox environment operations. */\nexport interface WorkspaceSandboxEnsureContext {\n workspaceId: string\n userId: string\n}\n\n/** Define configuration options for managing workspace sandboxes. */\nexport interface WorkspaceSandboxManagerOptions<TClient, TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void> {\n getClient: (ctx: WorkspaceSandboxEnsureContext) => Promise<TClient> | TClient\n nameForWorkspace: (workspaceId: string, ctx: WorkspaceSandboxEnsureContext) => string\n listSandboxes: (client: TClient, ctx: WorkspaceSandboxEnsureContext) => Promise<TBox[]>\n createSandbox: (args: {\n client: TClient\n ctx: WorkspaceSandboxEnsureContext\n name: string\n options: TEnsureOptions\n listError?: unknown\n }) => Promise<TBox>\n waitForRunning?: (box: TBox, ctx: WorkspaceSandboxEnsureContext) => Promise<void>\n prepareExisting?: (box: TBox, ctx: WorkspaceSandboxEnsureContext, options: TEnsureOptions) => Promise<TBox | void>\n prepareCreated?: (box: TBox, ctx: WorkspaceSandboxEnsureContext, options: TEnsureOptions) => Promise<TBox | void>\n onListError?: (error: unknown, ctx: WorkspaceSandboxEnsureContext) => void\n}\n\n/** Manage workspace sandboxes by ensuring their creation and retrieval for specified users. */\nexport interface WorkspaceSandboxManager<TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void> {\n ensureWorkspaceSandbox: (\n workspaceId: string,\n userId: string,\n options?: TEnsureOptions,\n ) => Promise<TBox>\n}\n\n/**\n * Create a generic name-keyed sandbox lifecycle manager for products that\n * drive their own SDK or box types.\n */\nexport function createWorkspaceSandboxManager<TClient, TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void>(\n opts: WorkspaceSandboxManagerOptions<TClient, TBox, TEnsureOptions>,\n): WorkspaceSandboxManager<TBox, TEnsureOptions> {\n return {\n async ensureWorkspaceSandbox(workspaceId, userId, options) {\n if (!workspaceId) throw new Error('workspaceId is required')\n if (!userId) throw new Error('userId is required')\n const ctx = { workspaceId, userId }\n const client = await opts.getClient(ctx)\n const name = opts.nameForWorkspace(workspaceId, ctx)\n let listError: unknown\n let existing: TBox[] = []\n\n try {\n existing = await opts.listSandboxes(client, ctx)\n } catch (err) {\n listError = err\n opts.onListError?.(err, ctx)\n }\n\n const found = existing.find((box) => box.name === name)\n if (found) {\n return (await opts.prepareExisting?.(found, ctx, options as TEnsureOptions)) ?? found\n }\n\n const created = await opts.createSandbox({\n client,\n ctx,\n name,\n options: options as TEnsureOptions,\n listError,\n })\n await opts.waitForRunning?.(created, ctx)\n return (await opts.prepareCreated?.(created, ctx, options as TEnsureOptions)) ?? created\n },\n }\n}\n","/**\n * Browser-direct scoped-token terminal connection route (#341/#349).\n *\n * Epic #343 / decision #341: the fleet's terminal transport is browser-direct\n * — the product's server authenticates the request and provisions/resolves\n * the sandbox exactly once, mints a short-lived SDK scoped token\n * (`box.mintScopedToken`), and hands the browser just enough to connect\n * `TerminalView` straight to the sidecar. No worker relays terminal bytes.\n * The deprecated same-origin relay was removed in #350 after the fleet\n * migrated, leaving this as the package's only terminal transport.\n *\n * VERIFIED PLATFORM CONTRACT (`@tangle-network/sandbox` 0.15.2 + the\n * orchestrator/sidecar enforcement source, verified 2026-07-30):\n *\n * 1. Only a `scope: 'session-runtime'` token carries the `terminal`\n * capability (`cap: [\"read\", \"workspace\", \"terminal\"]`). `'project'` and\n * `'session'` mint SessionGateway READ tokens (HS256, `typ: \"read\"`, no\n * `cap` claim at all — a different token family the sidecar rejects\n * outright); `'read-only'` carries `cap: [\"read\"]` only. **No scope other\n * than `'session-runtime'` can ever open a terminal**, which is why this\n * route no longer takes `scope` as a parameter — it is pinned.\n * 2. The orchestrator's terminal WS gate fails closed unless the token's\n * `sid` claim EQUALS the `<connectionId>` path segment of\n * `/terminals/<connectionId>/ws`\n * (`verifyScopedSidecarCapability(sidecar, token, \"terminal\", connectionId)`).\n * So `mintScopedToken({ scope: 'session-runtime', sessionId })` MUST be\n * called with `sessionId === connectionId` — the exact id `TerminalView`\n * will dial. That is why this route threads a `connectionId` end to end\n * instead of deriving its own session id.\n * 3. The browser-safe terminal base is the mint result's `sidecarProxyUrl`\n * (`/v1/sidecar-proxy/{id}` on the Sandbox API) — **not**\n * `box.connection.runtimeUrl`. The SDK's own `_attachTerminal` is the\n * reference implementation:\n * `mintScopedToken({ scope: 'session-runtime', sessionId: connectionId })`\n * then dial `${scoped.sidecarProxyUrl}/terminals/${connectionId}/ws`.\n * Pointing `TerminalView` at `runtimeUrl` fails auth regardless of scope —\n * only the sidecar-proxy hop decodes the browser's\n * `bearer.<base64url>` WS subprotocol.\n *\n * HISTORICAL NOTE: an earlier shape of this route (and legal-agent's\n * production route it was modeled on, `scope: 'project'` +\n * `connection.runtimeUrl`) predates the platform's terminal-auth hardening —\n * the terminal capability gate (2026-06-19), the scoped-token terminal WS\n * path (2026-07-15), and the `sid`-binding fail-closed check\n * (2026-07-17/18). That shape does not authenticate on the current platform\n * and is not a valid spec for the token path anymore.\n *\n * SECURITY POSTURE: unlike the read-only session-gateway streaming token\n * (`box.mintScopedToken({scope:'session'})` paired with\n * `SessionGatewayClient`), the token this route mints grants **command\n * execution** in the sandbox once handed to `TerminalView`. Its safety rests\n * on a **short TTL** (default 15 minutes, the SDK's own max — still a caller\n * parameter) and, structurally, the narrowest scope the platform offers: one\n * box (`ensureSandbox` resolved it for THIS user), one terminal connection\n * (`session-runtime` bound to a single `sid`). Widening the TTL default\n * without an explicit reason is a security regression, not a convenience.\n *\n * Wire contract: the browser passes the response's `sidecarUrl` as\n * `TerminalView`'s `apiUrl` prop, `token` as its token prop, and the\n * response's echoed `connectionId` as `TerminalView`'s `connectionId` prop —\n * the token's `sid` is bound to exactly that id, so any other value fails the\n * WS upgrade. sandbox-ui sends the token as a `bearer.<base64url>` WebSocket\n * subprotocol (browsers cannot set `Authorization` on a WS handshake).\n * `useSandboxTerminalConnection` (`../web-react/sandbox-terminal`) carries\n * `connectionId` through automatically.\n */\n\n/** The structural surface this route needs from an SDK sandbox box — no `@tangle-network/sandbox` class import (invariant 3). */\nexport interface TerminalConnectionBoxLike {\n id: string\n status?: string\n connection?: { runtimeUrl?: string }\n mintScopedToken(opts: {\n scope: string\n sessionId?: string\n ttlMinutes?: number\n }): Promise<{ token: string; expiresAt: Date; sidecarProxyUrl: string }>\n}\n\n/** Configuration for {@link createSandboxTerminalConnectionRoute}. */\nexport interface SandboxTerminalConnectionRouteOptions<TBox extends TerminalConnectionBoxLike, TUser> {\n /**\n * Authenticate the incoming request. Return the authenticated user, or a\n * `Response` to short-circuit the route (e.g. a 401) — that Response is\n * returned to the caller verbatim.\n */\n requireUser(request: Request): Promise<TUser | Response>\n /**\n * Resolve (provisioning if needed) the sandbox this user's terminal should\n * connect to. Domain-specific provisioning (workspace- vs user-scoped,\n * naming, reuse) stays entirely in the product's implementation of this\n * seam — the route only reacts to success/failure.\n */\n ensureSandbox(user: TUser, request: Request): Promise<TBox>\n /** `box.mintScopedToken` TTL in minutes. Default `15` (the SDK's own max). */\n ttlMinutes?: number\n /**\n * Resolve the terminal connection id the minted token's `sid` is bound to\n * — this MUST be the same id `TerminalView` dials\n * (`tabTerminalConnectionId()`), because the orchestrator's terminal WS\n * gate fails closed unless `sid === <connectionId>` in\n * `/terminals/<connectionId>/ws`.\n *\n * `requested` is `new URL(request.url).searchParams.get('connectionId')`.\n * The default resolver returns `requested` unchanged. A product may\n * validate/namespace the id here (e.g. a per-user prefix in a shared box)\n * — if it rewrites the id, the client MUST use the response's echoed\n * `connectionId`, since the sid binding makes any other id fail the WS\n * upgrade.\n *\n * A resolved falsy/empty value fails the request with a 400 before any\n * sandbox work happens.\n */\n resolveConnectionId?: (ctx: {\n request: Request\n user: TUser\n box: TBox\n requested: string | null\n }) => string | null | undefined | Promise<string | null | undefined>\n}\n\nconst DEFAULT_TTL_MINUTES = 15\nconst TERMINAL_SCOPE = 'session-runtime'\n\nfunction defaultResolveConnectionId(ctx: { requested: string | null }): string | null {\n return ctx.requested\n}\n\n/**\n * Build the browser-direct terminal connection route: `GET` handler that\n * authenticates, resolves the sandbox, mints a scoped token pinned to\n * `scope: 'session-runtime'` (the ONLY scope the platform grants the\n * `terminal` capability to), and returns exactly what the browser needs to\n * connect `TerminalView` directly to the sidecar — no worker in the data\n * path once the terminal is open.\n *\n * Response shapes:\n * - `requireUser` returns a `Response` → that `Response`, verbatim.\n * - `ensureSandbox` throws → `500 {error}` (the thrown message surfaced).\n * - `box.connection?.runtimeUrl` missing → `503 {error, status: box.status}`\n * — this is a READINESS gate only; the URL returned to the client on\n * success is always the mint's `sidecarProxyUrl`, never `runtimeUrl`.\n * - resolved connection id is falsy/empty → `400 {error}`.\n * - `box.mintScopedToken` rejects → `503 {error}`.\n * - success → `200 {sidecarUrl, token, expiresAt, status, sandboxId, connectionId}`.\n * `connectionId` is the id the token's `sid` is bound to — the client MUST\n * hand this (not its own) to `TerminalView`.\n */\nexport function createSandboxTerminalConnectionRoute<TBox extends TerminalConnectionBoxLike, TUser>(\n opts: SandboxTerminalConnectionRouteOptions<TBox, TUser>,\n): (request: Request) => Promise<Response> {\n const resolveConnectionId = opts.resolveConnectionId ?? defaultResolveConnectionId\n\n return async function handleSandboxTerminalConnection(request: Request): Promise<Response> {\n const user = await opts.requireUser(request)\n if (user instanceof Response) return user\n\n let box: TBox\n try {\n box = await opts.ensureSandbox(user, request)\n } catch (err) {\n return Response.json(\n { error: err instanceof Error ? err.message : 'Failed to provision sandbox' },\n { status: 500 },\n )\n }\n\n const runtimeUrl = box.connection?.runtimeUrl\n if (!runtimeUrl) {\n return Response.json(\n {\n error: 'Sandbox runtime not ready. The sandbox is still initializing -- retry in a few seconds.',\n status: box.status,\n },\n { status: 503 },\n )\n }\n\n const requested = new URL(request.url).searchParams.get('connectionId')\n const connectionId = await resolveConnectionId({ request, user, box, requested })\n if (!connectionId) {\n return Response.json(\n {\n error:\n \"connectionId is required — pass the same id TerminalView dials (tabTerminalConnectionId()) as the 'connectionId' query parameter\",\n },\n { status: 400 },\n )\n }\n\n let scoped: { token: string; expiresAt: Date; sidecarProxyUrl: string }\n try {\n scoped = await box.mintScopedToken({\n scope: TERMINAL_SCOPE,\n ttlMinutes: opts.ttlMinutes ?? DEFAULT_TTL_MINUTES,\n sessionId: connectionId,\n })\n } catch (err) {\n return Response.json(\n { error: err instanceof Error ? err.message : 'Failed to mint sandbox token' },\n { status: 503 },\n )\n }\n\n return Response.json({\n sidecarUrl: scoped.sidecarProxyUrl,\n token: scoped.token,\n expiresAt: scoped.expiresAt.toISOString(),\n status: box.status,\n sandboxId: box.id,\n connectionId,\n })\n }\n}\n","/**\n * `createSandboxPrewarmer` — \"this user just opened this project; start warming\n * their box\" as a shell primitive, so every agent-app product gets the same\n * answer instead of forking one.\n *\n * WHY THIS IS SHELL, NOT ENGINE. The engine rule asks whether the capability\n * makes sense without a specific app's side channel. \"Warm a box\" does — but\n * `@tangle-network/sandbox` has no notion of a WORKSPACE. It keys boxes by an\n * opaque sandbox id; the workspace→box mapping, the harness match, and the\n * profile materialisation all live in `ensureWorkspaceSandbox` here. A\n * prewarmer is that mapping plus a scheduling policy, so it belongs beside it.\n * It is deliberately NOT a new subpath: it composes `peekWorkspaceSandbox` and\n * `ensureWorkspaceSandbox` directly and needs exactly the peers `/sandbox`\n * already needs, so a separate entry would add a second place to look for \"how\n * do I get a box\" and buy no peer isolation (the reason `/work-product-react`\n * is split out).\n *\n * WHAT IT IS NOT. It does not make cold starts fast — they already are.\n * Measured on the real platform (staging-sandbox, n=5, 2026-07-28): a box goes\n * from nothing to terminal-ready in 2.34–3.19 s (median 2.73 s), and an\n * already-running box answers in 1.16–2.29 s (median 1.35 s). Prewarming buys\n * ~1.4 s. The reason it matters is not latency: it is that a product which\n * only ever provisions lazily, on a path whose guard never passes, never\n * provisions AT ALL — and the UI then shows a spinner over a box that does not\n * exist and is not being created. That is the failure this primitive removes.\n *\n * ── COST POSTURE (read before adopting) ────────────────────────────────────\n * A warmed box is a REAL charge. It bills from creation until the platform's\n * idle timeout reclaims it — `SandboxRuntimeConfig`'s create-time\n * `idleTimeoutSeconds`, not anything this module sets. A product warming on\n * every project open pays that timeout for every user who opens and bounces.\n * With a 3600 s idle timeout against a ~131 s mean session life, a bounce\n * costs an hour of box time to save ~1.4 s. THAT TRADE IS USUALLY WRONG.\n *\n * So the levers are explicit and the defaults are the cheap ones:\n * - `mode: 'resume-only'` (DEFAULT) never creates a box that does not exist.\n * It only revives one the user already has, so the spend is bounded by\n * boxes the user already caused. This is the safe fleet default.\n * - `mode: 'create-or-resume'` is the owner-requested behaviour — warm on\n * open even for a first-time user. Opt in per product, and lower the\n * shell's `idleTimeoutSeconds` when you do.\n * - `shouldPrewarm(scope)` is the product's own policy hook (paid tier only,\n * returning user only, has-documents only …). Returning false costs nothing.\n * - `failureCooldownMs` stops a hard-failing workspace from retry-storming;\n * every retry is another create attempt, which is more spend.\n * Warm with the SAME harness the next turn will use. `ensureWorkspaceSandbox`\n * DELETES and recreates a name-matched box whose harness differs, so warming\n * `opencode` and then turning `claude-code` pays for two boxes and is slower\n * than not warming at all. The prewarm key includes the harness so the two are\n * never deduped into one.\n *\n * ── SINGLE-FLIGHT (measured, not assumed) ──────────────────────────────────\n * The sandbox platform does NOT dedupe by box name. Two concurrent\n * `POST /v1/sandboxes` with an identical name both returned HTTP 201 and left\n * two running boxes (verified against staging-sandbox, 2026-07-28). So two\n * tabs, or two isolates, racing a warm genuinely leak a box — a prewarm that\n * races is worse than no prewarm. Hence two layers:\n * 1. an in-process map, which is free and catches same-isolate races\n * (double-mount, two requests on one isolate);\n * 2. a `claim` store the product supplies, which is the only thing that can\n * make this correct ACROSS isolates — the usual deployment target here is\n * Cloudflare Workers, where \"same isolate\" guarantees nothing.\n * `claim` is REQUIRED, with `'single-isolate-only'` as the explicit opt-out,\n * so nobody gets the unsafe behaviour by forgetting a field. Say it out loud\n * or supply a store.\n *\n * ── FAILURE IS LOUD, NEVER FATAL ───────────────────────────────────────────\n * A failed warm degrades to exactly today's lazy path: the next real request\n * calls `ensureWorkspaceSandbox` itself. It never throws into the caller's\n * render path — `completion` RESOLVES with `{ ok: false }` rather than\n * rejecting, because an unhandled rejection handed to `waitUntil` can fail the\n * request it rode in on. But it is never silent: every failure fires\n * `onEvent({ type: 'failed' })` and is readable afterwards through\n * `readiness()` as `{ status: 'failed' }`. The bug class this whole module\n * exists to kill is a soft failure that surfaces as an unusable panel ten\n * minutes later, so a warm that dies must leave a trace a product can render.\n */\n\nimport type { SandboxInstance } from '@tangle-network/sandbox/core'\nimport type { Harness } from '../harness/index'\nimport {\n ensureWorkspaceSandbox,\n peekWorkspaceSandbox,\n type SandboxRuntimeConfig,\n} from './index'\n\n/** The workspace a warm targets. Mirrors `EnsureWorkspaceSandboxOptions`'\n * identity fields — the prewarmer forwards them verbatim so a warmed box is\n * byte-identical to the one the lazy path would have built. */\nexport interface SandboxPrewarmScope {\n workspaceId: string\n userId?: string\n /** Must match the harness the next turn will use — see the cost note above. */\n harness: Harness\n billingOwnerId?: string\n}\n\n/**\n * Cross-isolate claim. `acquire` must be atomic (a D1 conditional insert, a DO,\n * a KV `put` with `onlyIf`) — a read-then-write is exactly the race this exists\n * to close. `ttlSeconds` bounds a claim leaked by an isolate that died\n * mid-warm; without expiry a single crash wedges a workspace forever.\n */\nexport interface PrewarmClaimStore {\n /** True when THIS caller now owns the right to warm `key`. */\n acquire(key: string, ttlSeconds: number): Promise<boolean>\n /** Best-effort release. A throw here is swallowed — the TTL is the backstop. */\n release(key: string): Promise<void>\n /** Optional: lets `readiness()` report `warming` for a warm running in\n * ANOTHER isolate. Without it, `warming` is only visible in the isolate\n * that started it, and every other one reports `absent`. */\n isHeld?(key: string): Promise<boolean>\n}\n\n/**\n * The ownership proof for one foreground provisioning attempt.\n *\n * `expiresAt` is both the lease deadline and its fencing value. The D1 store\n * advances it when a takeover succeeds, so an expired owner cannot release a\n * successor's lease. Keep this object and pass it back unchanged to\n * `FencedPrewarmClaimStore.releaseLease`.\n */\nexport interface PrewarmClaimLease {\n readonly key: string\n readonly expiresAt: number\n}\n\n/** State needed by a foreground caller that waits for another isolate. */\nexport type PrewarmClaimState =\n | { status: 'held'; expiresAt: number }\n | { status: 'expired'; expiresAt: number }\n | { status: 'absent' }\n\n/** A claim store that can distinguish a completed owner from a crashed owner. */\nexport interface InspectablePrewarmClaimStore extends PrewarmClaimStore {\n isHeld(key: string): Promise<boolean>\n inspect(key: string): Promise<PrewarmClaimState>\n}\n\n/**\n * Fenced claim operations for foreground provisioning.\n *\n * This is separate from `PrewarmClaimStore` so the published boolean\n * `acquire` and key-only `release` methods remain source-compatible. A\n * foreground caller must use the lease returned here and release that lease,\n * not the legacy key-only method.\n */\nexport interface FencedPrewarmClaimStore extends InspectablePrewarmClaimStore {\n /** Atomically acquire a lease or return null when another live lease wins. */\n acquireLease(key: string, ttlSeconds: number): Promise<PrewarmClaimLease | null>\n /** Conditionally release only this lease. A stale lease is a no-op. */\n releaseLease(lease: PrewarmClaimLease): Promise<void>\n}\n\n/** What `prewarm()` decided. Every value except `started` means no box was\n * created and nothing was spent on this call. */\nexport type PrewarmOutcome =\n | 'started'\n | 'already-running'\n | 'already-warming'\n | 'warming-elsewhere'\n | 'declined-by-policy'\n | 'cooling-down'\n | 'absent-and-resume-only'\n\n/** Terminal result of a warm this caller owns. Never a rejection. */\nexport interface PrewarmResult {\n ok: boolean\n boxId?: string\n error?: string\n /** Wall time of the warm itself, for the product's own timing trace. */\n ms: number\n}\n\nexport interface PrewarmDecision {\n outcome: PrewarmOutcome\n /** Present ONLY when `outcome === 'started'`. Hand it to `ctx.waitUntil` so a\n * client disconnect cannot kill the warm. Never rejects. */\n completion?: Promise<PrewarmResult>\n}\n\n/** Readiness for the UI. `ready`/`warming` reuse the vocabulary\n * `createSandboxFileIndexRoute` (`/chat-routes`) and `useFileMentions`\n * (`/web-react`) already speak, so a product renders ONE warming state rather\n * than inventing a second spinner for boxes. */\nexport type SandboxReadiness =\n | { status: 'ready'; boxId: string }\n | { status: 'warming' }\n | { status: 'absent' }\n | { status: 'failed'; error: string; retryAfterMs: number }\n\nexport type PrewarmEvent =\n | { type: 'started'; key: string; workspaceId: string }\n | { type: 'succeeded'; key: string; workspaceId: string; boxId: string; ms: number }\n | { type: 'failed'; key: string; workspaceId: string; error: string; ms: number }\n | { type: 'skipped'; key: string; workspaceId: string; outcome: PrewarmOutcome }\n\nexport interface SandboxPrewarmerOptions {\n /** Cross-isolate single-flight, or the explicit acknowledgement that you are\n * accepting per-isolate dedupe only. No default — see the header. */\n claim: PrewarmClaimStore | 'single-isolate-only'\n /** `'resume-only'` (default) never creates a box that does not exist.\n * `'create-or-resume'` warms from nothing — the expensive one. */\n mode?: 'resume-only' | 'create-or-resume'\n /** Product policy gate. Not called when a box is already running. */\n shouldPrewarm?(scope: SandboxPrewarmScope): boolean | Promise<boolean>\n /** Observability seam. A failed warm MUST be visible somewhere. */\n onEvent?(event: PrewarmEvent): void\n /** Claim lifetime. Default 180 s — comfortably over a cold create. */\n claimTtlSeconds?: number\n /** Suppress re-warming a workspace that just failed. Default 60_000 ms. */\n failureCooldownMs?: number\n /** Clock seam for tests. */\n now?(): number\n}\n\nexport interface SandboxPrewarmer {\n /**\n * Non-blocking warm. The returned promise settles as soon as the DECISION is\n * known (at most one `list()` against the platform, plus a claim `acquire`);\n * the provisioning itself rides on `completion`. On a render path either\n * ignore the returned promise or run the whole call inside `waitUntil` — do\n * not await `completion` before responding.\n */\n prewarm(scope: SandboxPrewarmScope): Promise<PrewarmDecision>\n /** Zero-provisioning status read for a UI. Never creates or resumes. */\n readiness(scope: SandboxPrewarmScope): Promise<SandboxReadiness>\n /** Clear a recorded failure so the next `prewarm` retries immediately. */\n clearFailure(scope: SandboxPrewarmScope): void\n}\n\n/** Identity of a warm. Harness is part of it because `ensureWorkspaceSandbox`\n * destroys and rebuilds a box whose harness does not match. */\nexport function sandboxPrewarmClaimKey(\n scope: Pick<SandboxPrewarmScope, 'workspaceId' | 'harness'>,\n): string {\n return `${scope.workspaceId}::${scope.harness}`\n}\n\nfunction errText(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nexport function createSandboxPrewarmer(\n shell: SandboxRuntimeConfig,\n options: SandboxPrewarmerOptions,\n): SandboxPrewarmer {\n const mode = options.mode ?? 'resume-only'\n const claimTtlSeconds = options.claimTtlSeconds ?? 180\n const failureCooldownMs = options.failureCooldownMs ?? 60_000\n const now = options.now ?? (() => Date.now())\n const claim = options.claim === 'single-isolate-only' ? null : options.claim\n\n const inFlight = new Map<string, Promise<PrewarmResult>>()\n const failures = new Map<string, { error: string; until: number }>()\n\n const emit = (event: PrewarmEvent): void => {\n try {\n options.onEvent?.(event)\n } catch {\n // An observability seam must never take down the warm it is reporting on.\n }\n }\n\n async function releaseClaim(key: string): Promise<void> {\n if (!claim) return\n try {\n await claim.release(key)\n } catch {\n // Best effort by contract — the TTL is what actually guarantees release.\n }\n }\n\n /**\n * Owns the box work for one warm. Resolves; never rejects.\n *\n * Clears `inFlight` in its own `finally`, BEFORE the returned promise\n * settles, so the invariant a caller can rely on is: once `completion`\n * resolves, the key is free. Deferring the delete to a `.finally()` chained\n * outside would leave it queued one microtask later, and a caller that\n * awaits `completion` and immediately re-warms would get a stale\n * `already-warming` instead of a real decision.\n */\n async function runWarm(\n key: string,\n scope: SandboxPrewarmScope,\n holdsClaim: boolean,\n ): Promise<PrewarmResult> {\n const startedAt = now()\n emit({ type: 'started', key, workspaceId: scope.workspaceId })\n try {\n const box: SandboxInstance = await ensureWorkspaceSandbox(shell, {\n workspaceId: scope.workspaceId,\n userId: scope.userId,\n harness: scope.harness,\n billingOwnerId: scope.billingOwnerId,\n })\n const ms = now() - startedAt\n failures.delete(key)\n emit({ type: 'succeeded', key, workspaceId: scope.workspaceId, boxId: box.id, ms })\n return { ok: true, boxId: box.id, ms }\n } catch (err) {\n const ms = now() - startedAt\n const error = errText(err)\n // Recorded, not thrown: the next real request still takes the lazy path,\n // and `readiness()` can now tell the UI the warm failed instead of\n // leaving it to spin over a box that is never coming.\n failures.set(key, { error, until: now() + failureCooldownMs })\n emit({ type: 'failed', key, workspaceId: scope.workspaceId, error, ms })\n return { ok: false, error, ms }\n } finally {\n inFlight.delete(key)\n if (holdsClaim) await releaseClaim(key)\n }\n }\n\n return {\n async prewarm(scope: SandboxPrewarmScope): Promise<PrewarmDecision> {\n const key = sandboxPrewarmClaimKey(scope)\n\n // Synchronous guards first — these run before any `await`, so two calls\n // in one isolate cannot both get past this point.\n if (inFlight.has(key)) {\n emit({ type: 'skipped', key, workspaceId: scope.workspaceId, outcome: 'already-warming' })\n return { outcome: 'already-warming' }\n }\n const failure = failures.get(key)\n if (failure && now() < failure.until) {\n emit({ type: 'skipped', key, workspaceId: scope.workspaceId, outcome: 'cooling-down' })\n return { outcome: 'cooling-down' }\n }\n\n // Reserve the key for THIS isolate before the first await. The reservation\n // is a placeholder the real warm replaces; without it, two concurrent\n // callers would both suspend on `peek` and both proceed.\n let settle: (result: PrewarmResult) => void = () => {}\n const reservation = new Promise<PrewarmResult>((resolve) => {\n settle = resolve\n })\n inFlight.set(key, reservation)\n\n const abandon = (outcome: PrewarmOutcome): PrewarmDecision => {\n inFlight.delete(key)\n settle({ ok: false, error: outcome, ms: 0 })\n emit({ type: 'skipped', key, workspaceId: scope.workspaceId, outcome })\n return { outcome }\n }\n\n try {\n // Cheapest question first: is it already running? Costs one list() and\n // no claim, so the common \"user reopens a warm project\" path spends\n // nothing.\n const peek = await peekWorkspaceSandbox(shell, {\n workspaceId: scope.workspaceId,\n userId: scope.userId,\n })\n if (peek.status === 'running') return abandon('already-running')\n if (peek.status === 'warming') return abandon('already-warming')\n if (peek.status === 'absent' && mode === 'resume-only') {\n return abandon('absent-and-resume-only')\n }\n\n if (options.shouldPrewarm) {\n const allowed = await options.shouldPrewarm(scope)\n if (!allowed) return abandon('declined-by-policy')\n }\n\n let holdsClaim = false\n if (claim) {\n holdsClaim = await claim.acquire(key, claimTtlSeconds)\n if (!holdsClaim) return abandon('warming-elsewhere')\n }\n\n // The key is already reserved above; `runWarm` owns clearing it.\n const warm = runWarm(key, scope, holdsClaim)\n void warm.then(settle)\n return { outcome: 'started', completion: warm }\n } catch (err) {\n // A peek/policy/claim failure is a failed warm like any other: recorded,\n // surfaced, and degraded to the lazy path.\n const error = errText(err)\n inFlight.delete(key)\n failures.set(key, { error, until: now() + failureCooldownMs })\n settle({ ok: false, error, ms: 0 })\n emit({ type: 'failed', key, workspaceId: scope.workspaceId, error, ms: 0 })\n return { outcome: 'cooling-down' }\n }\n },\n\n async readiness(scope: SandboxPrewarmScope): Promise<SandboxReadiness> {\n const key = sandboxPrewarmClaimKey(scope)\n // A running box outranks a recorded failure: the failure may be stale\n // (a later warm, or the lazy path, may have succeeded since).\n const peek = await peekWorkspaceSandbox(shell, {\n workspaceId: scope.workspaceId,\n userId: scope.userId,\n })\n if (peek.status === 'running') return { status: 'ready', boxId: peek.box.id }\n if (peek.status === 'warming') return { status: 'warming' }\n\n if (inFlight.has(key)) return { status: 'warming' }\n if (claim?.isHeld) {\n try {\n if (await claim.isHeld(key)) return { status: 'warming' }\n } catch {\n // An unreadable claim store must not turn a status read into a 500.\n }\n }\n\n const failure = failures.get(key)\n if (failure && now() < failure.until) {\n return { status: 'failed', error: failure.error, retryAfterMs: failure.until - now() }\n }\n\n // A stopped box is not 'absent' to the platform, but to a user staring at\n // a dead terminal the distinction is meaningless: neither can serve them\n // until something warms it.\n return { status: 'absent' }\n },\n\n clearFailure(scope: SandboxPrewarmScope): void {\n failures.delete(sandboxPrewarmClaimKey(scope))\n },\n }\n}\n","/**\n * `createSandboxRunTool`: the `sandbox_run` tool a Router turn calls when the\n * work needs a computer — run code, read a PDF or a sheet, fill a form with a\n * Python toolkit. The conversational turn stays on the Router engine\n * (`./router-turn`); only this call enters the box, and its final answer comes\n * back to the model as the tool result.\n *\n * NEVER SILENT. A box that cannot start, a run that fails and a run that ends\n * with no answer each come back as a typed failure (`sandbox_unavailable`,\n * `sandbox_failed`, `sandbox_empty`) that the model reads and must report. A\n * product that leaves this tool out when it cannot place a box drops the\n * capability without the model or the user knowing; mount the tool and let it\n * fail instead.\n *\n * WARM LEASES. When the product passes `warm`, the call counts as a turn on the\n * box's lease (`leases.turn(key)`), so an `escalation-likely` warm from\n * `createEscalationSpeculator` is recorded as used. The default name is the\n * one the speculator listens for (`DEFAULT_ESCALATION_TOOLS`).\n */\nimport type { SandboxInstance } from '@tangle-network/sandbox'\nimport type { TurnSpan, TurnTrace } from '../turn-trace/recorder'\nimport { runSandboxPrompt, type SandboxRuntimeConfig, type StreamSandboxPromptOptions } from './index'\n\nexport type SandboxRunFailureCode = 'sandbox_unavailable' | 'sandbox_failed' | 'sandbox_empty' | 'invalid_arguments'\n\n/** A typed `sandbox_run` failure. `code` and `message` are what the model reads. */\nexport class SandboxRunError extends Error {\n constructor(readonly code: SandboxRunFailureCode, message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = 'SandboxRunError'\n }\n}\n\n/** The engine's per-call tool context (`RouterTurnToolContext`), kept structural so this module does not import the engine. */\nexport interface SandboxToolContext {\n emit(kind: string, data?: unknown): void\n /** The turn's trace and this call's `tool.call` span (`runRouterTurn` supplies both). The box claim, the box run and the\n * trace id sent to the Sandbox API follow from them; without them nothing is recorded. */\n trace?: TurnTrace\n span?: TurnSpan\n}\n\nexport interface SandboxTaskOptions {\n signal: AbortSignal\n timeoutMs: number\n /** Streams a typed side event from the box run (a progress step, a file written) as the turn's `tool_event`. */\n emit(kind: string, data?: unknown): void\n /** The turn's trace and this call's span, for a runner that streams a prompt (`sandboxPromptRunner` does). */\n trace?: TurnTrace\n span?: TurnSpan\n}\n\nexport interface SandboxRunToolOptions {\n /** The box this call runs in. The product provisions, binds and bills it; this module never\n * creates one. A throw is reported to the model as `sandbox_unavailable`, unless it is a\n * `SandboxRunError`, whose own code and message are kept (an unpaid account, for example). */\n box(signal: AbortSignal): Promise<SandboxInstance>\n /** Runs the task on the box and returns the box agent's final answer: {@link sandboxPromptRunner}\n * for the shell's own prompt path, or the product's runner (skill placement, app-tool MCP, a spend tap). */\n runTask(box: SandboxInstance, task: string, options: SandboxTaskOptions): Promise<string>\n /** Wall-clock cap for one call, box start included. Default 5 minutes. */\n timeoutMs?: number\n /** Cancels a call in flight, for example the turn's own signal. */\n signal?: AbortSignal\n /** The box's warm lease, so the call is recorded as a turn on it. */\n warm?: { leases: { turn(key: string): Promise<unknown> }; key: string }\n /** Every failure with its cause, for the product's logs. The model only reads the typed message. */\n onFailure?(error: SandboxRunError): void\n name?: string\n description?: string\n}\n\n/** The tool shape `runRouterTurn` takes (`RouterTurnTool`), kept structural so this module does not import the engine. */\nexport interface SandboxRunTool {\n name: string\n description: string\n inputSchema: Record<string, unknown>\n run(args: Record<string, unknown>, context?: SandboxToolContext): Promise<{ answer: string; ms: number }>\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60_000\nconst TASK_LIMIT = 20_000\n\nexport const SANDBOX_RUN_DESCRIPTION =\n 'Run work that needs a computer in this workspace\\'s sandbox: executing code or scripts, reading or converting ' +\n 'PDFs, spreadsheets and archives, filling forms with the installed toolkits, or editing many files. Describe the ' +\n 'whole task and the result you need; the sandbox agent does it and returns its answer. Takes seconds to minutes, ' +\n 'so use it only when the answer needs the computer.'\n\n/** The default `runTask`: the shell's own `runSandboxPrompt`, unattended (questions refused). */\nexport function sandboxPromptRunner(shell: SandboxRuntimeConfig, prompt: Omit<StreamSandboxPromptOptions, 'signal' | 'history'> = {}): SandboxRunToolOptions['runTask'] {\n return (box, task, { signal, timeoutMs, trace, span }) => runSandboxPrompt(shell, box, task, {\n ...prompt, signal, timeoutMs, disallowQuestions: true,\n ...(trace ? { trace } : {}), ...(span ? { traceParent: span } : {}),\n })\n}\n\nexport function createSandboxRunTool(options: SandboxRunToolOptions): SandboxRunTool {\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n const runTask = options.runTask\n const fail = (code: SandboxRunFailureCode, message: string, cause?: unknown): never => {\n const error = new SandboxRunError(code, message, cause === undefined ? undefined : { cause })\n options.onFailure?.(error)\n throw error\n }\n return {\n name: options.name ?? 'sandbox_run',\n description: options.description ?? SANDBOX_RUN_DESCRIPTION,\n inputSchema: {\n type: 'object',\n properties: { task: { type: 'string', description: 'The complete task for the sandbox agent, with the result you need back.' } },\n required: ['task'],\n additionalProperties: false,\n },\n async run(args, context) {\n const emit = (kind: string, data?: unknown) => { try { context?.emit(kind, data) } catch { /* a view never fails the call */ } }\n const task = typeof args.task === 'string' ? args.task.trim() : ''\n if (!task || task.length > TASK_LIMIT) {\n return fail('invalid_arguments', `task must be 1 to ${TASK_LIMIT} characters`)\n }\n const started = Date.now()\n const signal = AbortSignal.any([AbortSignal.timeout(timeoutMs), ...(options.signal ? [options.signal] : [])])\n if (options.warm) await options.warm.leases.turn(options.warm.key).catch(() => {})\n // A product's box() may not honour the signal either (a hung provision); the cap still holds.\n const capped = <T,>(work: Promise<T>) => Promise.race([work, new Promise<never>((_, reject) => {\n if (signal.aborted) reject(signal.reason)\n signal.addEventListener('abort', () => reject(signal.reason), { once: true })\n })])\n let box: SandboxInstance\n const claim = context?.span?.child('sandbox.claim', 'sandbox')\n try {\n box = await capped(options.box(signal))\n claim?.end()\n } catch (error) {\n claim?.end(undefined, error instanceof SandboxRunError ? error.code : 'sandbox_unavailable')\n if (error instanceof SandboxRunError) return fail(error.code, error.message, error.cause)\n return fail('sandbox_unavailable', 'The sandbox for this workspace could not start, so this work was not done.', error)\n }\n emit('box_ready', { ms: Date.now() - started })\n let answer: string\n try {\n // A product runner may not honour the signal; the call still ends at the cap.\n answer = await capped(runTask(box, task, {\n signal, timeoutMs: Math.max(1, timeoutMs - (Date.now() - started)), emit,\n ...(context?.trace ? { trace: context.trace } : {}), ...(context?.span ? { span: context.span } : {}),\n }))\n } catch (error) {\n const timedOut = signal.aborted && !options.signal?.aborted\n return fail('sandbox_failed', timedOut\n ? `The sandbox did not finish within ${Math.round(timeoutMs / 1000)} s, so this work was not done.`\n : 'The sandbox run failed, so this work was not done.', error)\n }\n if (!answer.trim()) return fail('sandbox_empty', 'The sandbox finished without an answer.')\n return { answer, ms: Date.now() - started }\n },\n }\n}\n","/**\n * `createSandboxExecTool`: the `sandbox_exec` tool a Router turn calls to run\n * one command in the product's box — a toolkit script, a converter, a check —\n * and read its exit code and output. Unlike `sandbox_run` it starts no box\n * agent: the Router model stays in charge and the box only executes.\n *\n * WHY. Tax's Router default lost its Python form toolkit because the lane had\n * no way to reach a box: 685 tool calls, 0 form fills (2026-10). A toolkit\n * the product mounts in the box is reachable from the Router lane only\n * through a command tool.\n *\n * NEVER SILENT. A box that cannot start or be prepared, and a command that\n * cannot run or outruns its cap, come back as a typed `SandboxRunError`\n * (`sandbox_unavailable`, `sandbox_failed`) the model must report. A command\n * that runs and exits non-zero is a result, not a failure: the model reads\n * its exit code and stderr and can correct itself.\n *\n * `prepare` runs once per tool, before the first command (install a runtime,\n * copy the session's documents in). `allow` is the product's command policy.\n */\nimport type { SandboxInstance } from '@tangle-network/sandbox'\nimport { SandboxRunError, type SandboxToolContext } from './sandbox-run-tool'\n\n/** `ExecOptions` from SDK 0.62.2, which sends `traceId` as `x-tangle-trace-id`; spelled here so the tool builds against the pinned older SDK too. */\ntype ExecOptionsWithTrace = NonNullable<Parameters<SandboxInstance['exec']>[1]> & { traceId?: string }\n\nexport interface SandboxExecToolOptions {\n /** The box commands run in. The product provisions, binds and bills it. A throw is\n * `sandbox_unavailable`, unless it is a `SandboxRunError`, which is kept as it is. */\n box(signal: AbortSignal): Promise<SandboxInstance>\n /** Once per tool, before the first command: install a runtime, sync files in. */\n prepare?(box: SandboxInstance, signal: AbortSignal): Promise<void>\n /** Default working directory. */\n cwd?: string\n env?: Record<string, string>\n /** Cap for one command, box start and prepare included. Default 2 minutes. */\n timeoutMs?: number\n /** Characters of stdout and of stderr returned to the model, each; the tail is kept. Default 4 000, so\n * one result stays inside `runRouterTurn`'s default 12 000-character tool-result limit, which keeps the\n * head and would otherwise cut the tail, where errors are. Raise both together. */\n maxOutputChars?: number\n /** The product's command policy: a string refuses the command with that reason. */\n allow?(command: string): string | null\n /** After each command, the files the product wants the model to know about (e.g. its output folder). */\n listFiles?(box: SandboxInstance, signal: AbortSignal): Promise<string[]>\n signal?: AbortSignal\n /** The box's warm lease, so a call is recorded as a turn on it. */\n warm?: { leases: { turn(key: string): Promise<unknown> }; key: string }\n onFailure?(error: SandboxRunError): void\n name?: string\n description?: string\n}\n\nexport interface SandboxExecResult {\n exitCode: number\n stdout: string\n stderr: string\n /** True when stdout or stderr was cut to `maxOutputChars`. */\n truncated: boolean\n ms: number\n files?: string[]\n}\n\nexport interface SandboxExecTool {\n name: string\n description: string\n inputSchema: Record<string, unknown>\n run(args: Record<string, unknown>, context?: SandboxToolContext): Promise<SandboxExecResult>\n}\n\nconst DEFAULT_TIMEOUT_MS = 2 * 60_000\nconst DEFAULT_OUTPUT_CHARS = 4_000\nconst COMMAND_LIMIT = 10_000\n\nexport const SANDBOX_EXEC_DESCRIPTION =\n \"Run one shell command in this workspace's sandbox and get its exit code, stdout and stderr. Use it for the \" +\n 'installed toolkits and scripts, file conversion and checks. A non-zero exit code is a result to read and fix, ' +\n 'not a reason to stop.'\n\nfunction tail(text: string, limit: number): { text: string; cut: boolean } {\n return text.length > limit ? { text: `…${text.slice(-limit)}`, cut: true } : { text, cut: false }\n}\n\nfunction raceAbort<T>(work: Promise<T>, signal: AbortSignal): Promise<T> {\n return Promise.race([work, new Promise<never>((_, reject) => {\n if (signal.aborted) reject(signal.reason)\n signal.addEventListener('abort', () => reject(signal.reason), { once: true })\n })])\n}\n\nexport function createSandboxExecTool(options: SandboxExecToolOptions): SandboxExecTool {\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n const outputChars = options.maxOutputChars ?? DEFAULT_OUTPUT_CHARS\n const fail = (code: 'sandbox_unavailable' | 'sandbox_failed' | 'invalid_arguments', message: string, cause?: unknown): never => {\n const error = new SandboxRunError(code, message, cause === undefined ? undefined : { cause })\n options.onFailure?.(error)\n throw error\n }\n let ready: Promise<SandboxInstance> | null = null\n const place = (signal: AbortSignal) => {\n ready ??= (async () => {\n let box: SandboxInstance\n try {\n box = await options.box(signal)\n } catch (error) {\n if (error instanceof SandboxRunError) throw error\n throw new SandboxRunError('sandbox_unavailable', 'The sandbox for this workspace could not start, so the command did not run.', { cause: error })\n }\n try {\n await options.prepare?.(box, signal)\n } catch (error) {\n throw new SandboxRunError('sandbox_unavailable', 'The sandbox could not be prepared for commands, so the command did not run.', { cause: error })\n }\n return box\n })()\n // A failed start is not cached: the next call tries again.\n ready.catch(() => { ready = null })\n return ready\n }\n return {\n name: options.name ?? 'sandbox_exec',\n description: options.description ?? SANDBOX_EXEC_DESCRIPTION,\n inputSchema: {\n type: 'object',\n properties: {\n command: { type: 'string', description: 'One shell command, e.g. `tax-python fill_form.py --form 1040`.' },\n cwd: { type: 'string', description: 'Working directory; defaults to the workspace directory.' },\n },\n required: ['command'],\n additionalProperties: false,\n },\n async run(args, context) {\n const emit = (kind: string, data?: unknown) => { try { context?.emit(kind, data) } catch { /* a view never fails the call */ } }\n const command = typeof args.command === 'string' ? args.command.trim() : ''\n if (!command || command.length > COMMAND_LIMIT) return fail('invalid_arguments', `command must be 1 to ${COMMAND_LIMIT} characters`)\n const refusal = options.allow?.(command)\n if (refusal) return fail('invalid_arguments', refusal)\n const cwd = typeof args.cwd === 'string' && args.cwd.trim() ? args.cwd.trim() : options.cwd\n const started = Date.now()\n const signal = AbortSignal.any([AbortSignal.timeout(timeoutMs), ...(options.signal ? [options.signal] : [])])\n if (options.warm) await options.warm.leases.turn(options.warm.key).catch(() => {})\n let box: SandboxInstance\n // A box this tool already placed answers at once; the span says which kind of claim this was.\n const reused = ready !== null\n const claim = context?.span?.child('sandbox.claim', 'sandbox')\n const starting = place(signal)\n try {\n box = await raceAbort(starting, signal)\n } catch (error) {\n claim?.end(undefined, error instanceof SandboxRunError ? error.code : 'sandbox_unavailable')\n // A start that outlived this call's cap may never settle; the next call starts again.\n if (ready === starting) ready = null\n if (error instanceof SandboxRunError) {\n options.onFailure?.(error)\n throw error\n }\n return fail('sandbox_unavailable', 'The sandbox did not start in time, so the command did not run.', error)\n }\n claim?.end({ 'claim.reused': reused })\n emit('box_ready', { ms: Date.now() - started })\n let result: { exitCode: number; stdout: string; stderr: string }\n const execSpan = context?.span?.child('sandbox.exec', 'sandbox')\n try {\n result = await raceAbort(box.exec(command, {\n ...(cwd ? { cwd } : {}),\n ...(options.env ? { env: options.env } : {}),\n timeoutMs: Math.max(1, timeoutMs - (Date.now() - started)),\n // The same id the Router turn sends, so this command's Sandbox API and host records join the turn.\n // SDK 0.62.2 added `traceId` to ExecOptions; an older SDK ignores the field.\n ...(context?.trace ? { traceId: context.trace.traceId } : {}),\n } as ExecOptionsWithTrace), signal)\n execSpan?.end({ 'exec.exit_code': result.exitCode })\n } catch (error) {\n execSpan?.end(undefined, 'exec_failed')\n const timedOut = signal.aborted && !options.signal?.aborted\n return fail('sandbox_failed', timedOut\n ? `The command did not finish within ${Math.round(timeoutMs / 1000)} s.`\n : 'The command could not run in the sandbox.', error)\n }\n const stdout = tail(result.stdout ?? '', outputChars)\n const stderr = tail(result.stderr ?? '', outputChars)\n const files = options.listFiles ? await options.listFiles(box, signal).catch(() => undefined) : undefined\n return { exitCode: result.exitCode, stdout: stdout.text, stderr: stderr.text, truncated: stdout.cut || stderr.cut,\n ms: Date.now() - started, ...(files ? { files } : {}) }\n },\n }\n}\n","import type {\n FencedPrewarmClaimStore,\n PrewarmClaimLease,\n PrewarmClaimState,\n} from './prewarm'\n\n/**\n * `createD1PrewarmClaimStore` — the cross-isolate half of\n * `createSandboxPrewarmer`'s single-flight, implemented once.\n *\n * WHY THIS SHIPS HERE. `SandboxPrewarmerOptions.claim` is REQUIRED and has no\n * default, which is correct — the unsafe behaviour must be said out loud. But\n * \"required with no implementation\" is how five products end up hand-rolling\n * five subtly different atomic leases, and a lease that is subtly wrong is\n * indistinguishable from one that works until two tabs leak a box. Every\n * agent-app product deploys to Cloudflare Workers with a D1 binding, so the\n * store is the same code in all of them: it is mechanism, not domain, and it\n * belongs beside the prewarmer.\n *\n * The measured stake (staging-sandbox, 2026-07-28): two concurrent\n * `POST /v1/sandboxes` with an identical name BOTH returned HTTP 201 and left\n * two running boxes. The platform does not dedupe by name, so nothing below\n * this line is defensive programming — an unclaimed race genuinely doubles\n * spend.\n *\n * ── ATOMICITY IS THE WHOLE POINT ───────────────────────────────────────────\n * `acquire` is ONE statement. A `SELECT` followed by an `INSERT` is exactly the\n * race this exists to close: both isolates read \"free\", both write, both warm.\n * The upsert's `DO UPDATE ... WHERE expires_at <= now` means an unexpired claim\n * makes the conflict path a no-op, and `RETURNING` then yields no row — so the\n * loser learns it lost from the same statement that would have made it the\n * winner. `RETURNING` is used rather than `meta.changes` because a no-op upsert\n * reporting `changes: 0` is a SQLite detail, whereas \"no row came back\" is the\n * statement telling you directly.\n *\n * Foreground provisioning uses `acquireLease`/`releaseLease`. The lease's\n * returned `expiresAt` is a fencing value: takeover writes a value strictly\n * greater than the expired value, and release changes only the matching value\n * into a signed tombstone. A later acquire advances the absolute value, so a\n * stale release cannot collide even after a same-clock release and reacquire.\n * `inspect` hides the tombstone as `absent`. This uses the published two-column\n * table without changing the legacy `PrewarmClaimStore` methods or requiring a\n * migration.\n *\n * ── STRUCTURAL, NOT A DEPENDENCY ───────────────────────────────────────────\n * The binding is taken as the narrow shape actually used (`prepare().bind()`,\n * `.first()`, `.run()`), per the package's structural-over-hard-dep rule. No\n * `@cloudflare/workers-types` import, so `/sandbox` stays importable in a plain\n * node test. A real `D1Database` satisfies it.\n *\n * ── THE TABLE IS THE PRODUCT'S MIGRATION, NOT A LAZY CREATE ────────────────\n * The store never runs DDL. A `CREATE TABLE IF NOT EXISTS` on every project\n * open costs a round trip on the exact path this feature exists to keep fast,\n * and it hides schema drift instead of failing on it. `PREWARM_CLAIM_TABLE_DDL`\n * is exported so a product pastes it into a real migration. If the table is\n * missing, `acquire` throws — and the prewarmer treats a throwing claim as a\n * failed warm: it records the failure, emits `onEvent({type:'failed'})`, and\n * degrades to the lazy path. Fail-closed and loud, never a silent double-warm.\n */\n\n/** The columns and statements this store uses, and nothing else. A real\n * `D1Database` structurally satisfies it. */\nexport interface PrewarmClaimD1Like {\n prepare(query: string): {\n bind(...values: unknown[]): {\n first<T = Record<string, unknown>>(): Promise<T | null>\n run(): Promise<unknown>\n }\n }\n}\n\nexport interface D1PrewarmClaimStoreOptions {\n /** Defaults to `sandbox_prewarm_claims`. Must be a bare SQL identifier — it\n * is interpolated, because a table name cannot be a bound parameter. */\n table?: string\n /** Clock seam for tests. */\n now?(): number\n}\n\nexport const DEFAULT_PREWARM_CLAIM_TABLE = 'sandbox_prewarm_claims'\n\n/** Paste into a migration. Positive `expires_at` values are epoch MILLISECONDS,\n * matching `Date.now()`. A released fenced claim keeps a negative tombstone so\n * a later lease can advance its fencing value without adding a column. */\nexport const PREWARM_CLAIM_TABLE_DDL = `CREATE TABLE IF NOT EXISTS ${DEFAULT_PREWARM_CLAIM_TABLE} (\n key TEXT PRIMARY KEY,\n expires_at INTEGER NOT NULL\n)`\n\nconst SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/\n\n/**\n * A fenced `PrewarmClaimStore` backed by one D1 table.\n *\n * ```ts\n * const prewarmer = createSandboxPrewarmer(shell, {\n * claim: createD1PrewarmClaimStore(env.DB),\n * mode: 'create-or-resume',\n * })\n * ```\n */\nexport function createD1PrewarmClaimStore(\n db: PrewarmClaimD1Like,\n options: D1PrewarmClaimStoreOptions = {},\n): FencedPrewarmClaimStore {\n const table = options.table ?? DEFAULT_PREWARM_CLAIM_TABLE\n // A table name cannot be bound, so it is interpolated — which makes it the\n // one injection surface here. Reject anything that is not a bare identifier\n // at construction time, where the stack still points at the caller.\n if (!SAFE_IDENTIFIER.test(table)) {\n throw new Error(`Invalid prewarm claim table name: ${JSON.stringify(table)}`)\n }\n const now = options.now ?? (() => Date.now())\n\n const acquireSql = `INSERT INTO ${table} (key, expires_at) VALUES (?1, ?2)\nON CONFLICT(key) DO UPDATE SET expires_at = ?2 WHERE ${table}.expires_at <= ?3\nRETURNING key`\n const acquireLeaseSql = `INSERT INTO ${table} (key, expires_at) VALUES (?1, ?2)\nON CONFLICT(key) DO UPDATE SET expires_at = MAX(?2, ABS(${table}.expires_at) + 1)\nWHERE ${table}.expires_at <= ?3\nRETURNING key, expires_at`\n const releaseSql = `DELETE FROM ${table} WHERE key = ?1`\n const releaseLeaseSql = `UPDATE ${table}\nSET expires_at = CASE WHEN expires_at = 0 THEN -1 ELSE -expires_at END\nWHERE key = ?1 AND expires_at = ?2`\n const inspectSql = `SELECT expires_at FROM ${table} WHERE key = ?1`\n\n async function inspect(key: string): Promise<PrewarmClaimState> {\n const row = await db\n .prepare(inspectSql)\n .bind(key)\n .first<{ expires_at: number }>()\n if (!row || row.expires_at < 0) return { status: 'absent' }\n return row.expires_at > now()\n ? { status: 'held', expiresAt: row.expires_at }\n : { status: 'expired', expiresAt: row.expires_at }\n }\n\n return {\n async acquire(key: string, ttlSeconds: number): Promise<boolean> {\n const at = now()\n const row = await db\n .prepare(acquireSql)\n .bind(key, at + ttlSeconds * 1000, at)\n .first<{ key: string }>()\n return row != null\n },\n\n async acquireLease(key: string, ttlSeconds: number): Promise<PrewarmClaimLease | null> {\n const at = now()\n const requestedExpiry = Math.max(1, at + ttlSeconds * 1000)\n const row = await db\n .prepare(acquireLeaseSql)\n .bind(key, requestedExpiry, at)\n .first<{ key: string; expires_at: number }>()\n if (!row) return null\n return Object.freeze({ key: row.key, expiresAt: row.expires_at })\n },\n\n async release(key: string): Promise<void> {\n // Best effort by the `PrewarmClaimStore` contract: the prewarmer swallows\n // a throw here because the TTL is what actually guarantees release.\n await db.prepare(releaseSql).bind(key).run()\n },\n\n async releaseLease(lease: PrewarmClaimLease): Promise<void> {\n await db.prepare(releaseLeaseSql).bind(lease.key, lease.expiresAt).run()\n },\n\n async isHeld(key: string): Promise<boolean> {\n return (await inspect(key)).status === 'held'\n },\n\n inspect,\n }\n}\n","/**\n * `createWorkspacePrewarmRoute`: the HTTP face of prewarm-on-open, so every\n * agent-app product warms the same way. The browser half is\n * `useWorkspacePrewarm` in `/web-react`: it POSTs here when a member opens a\n * workspace page in a visible tab, and again when they focus the composer.\n *\n * WHAT THE PRODUCT SUPPLIES. Only `authorize`. It authenticates the member\n * from the request exactly as the product's other routes do and returns the\n * warm to run: a box resume, a profile preparation, or `createSandboxPrewarmer`\n * from this subpath. The route owns everything shared: bot and prefetch\n * refusal, per-key single-flight, a short success memory, timing, and the rule\n * that a warm never reaches the member as an error.\n *\n * WHY THE WARM RUNS INSIDE THE REQUEST. A suspended box takes ~31 s to resume\n * (Hospitality production, 2026-10-10), past the 30 s that Cloudflare's\n * `waitUntil` grants after a response. Awaiting the warm keeps the request\n * open for as long as the member's tab is, which is exactly as long as a warm\n * is useful. The browser never awaits it for UI.\n *\n * IDEMPOTENCE. The in-process record only collapses concurrent calls within\n * one isolate, and a second call answers `joined` at once instead of awaiting\n * the first: on Workers a warm's I/O belongs to the request that started it, so\n * when that request is cancelled (the member navigates) its promise never\n * settles, and requests awaiting it hung 43-45 s (Hospitality production,\n * 2026-10-11). A record older than `staleMs` no longer counts. Two isolates can\n * both run the warm, so the product's warm must be safe to repeat: a resume of\n * a running box is a no-op, and a creation needs a claim store (see\n * `createSandboxPrewarmer`).\n *\n * FAILURE. A thrown warm answers 200 `{ outcome: 'failed' }` without the error\n * text, which can name internal hosts. `onEvent` receives the error so the\n * product can log it. The next real turn takes its normal placement path.\n */\n\n/** What the product decided for this request. */\nexport type WorkspacePrewarmAuthorization =\n /** Not signed in, not a member, or a foreign origin: return this response. */\n | { status: 'denied'; response: Response }\n /** A signed-in member the product does not warm for (a role that cannot\n * chat, a box mid-upgrade). Answers 200 so the browser stays quiet. */\n | { status: 'declined'; reason: string }\n /**\n * Run `warm` once per `key` at a time. `key` names what is warmed, such as\n * the box; members who share a box share a key. `warm` may return a small\n * JSON-safe report for the response and `onEvent`.\n */\n | { status: 'allowed'; key: string; warm: () => Promise<WorkspacePrewarmReport | void> }\n\n/** Why the browser asked: `useWorkspacePrewarm` sends `page-open` or `composer-focus`. */\nexport type WorkspacePrewarmReason = 'page-open' | 'composer-focus'\n\nexport type WorkspacePrewarmReport = Record<string, string | number | boolean | null>\n\nexport type WorkspacePrewarmOutcome =\n /** This request ran the warm to completion. */\n | 'warmed'\n /** Another request in this isolate is already running it; this one answered at once. */\n | 'joined'\n /** The same key warmed successfully within `recentMs`; nothing ran. */\n | 'recent'\n | 'declined'\n /** A crawler, link preview, or speculative prefetch; nothing ran. */\n | 'automated'\n | 'failed'\n\nexport interface WorkspacePrewarmResponse {\n outcome: WorkspacePrewarmOutcome\n /** Time this request spent, including any warm it ran. A `joined` answer never waits. */\n ms: number\n reason?: string\n report?: WorkspacePrewarmReport\n}\n\nexport type WorkspacePrewarmEvent =\n | { type: 'warmed'; key: string; ms: number; report?: WorkspacePrewarmReport }\n | { type: 'failed'; key: string; ms: number; error: string }\n\nexport interface CreateWorkspacePrewarmRouteOptions<Context = void> {\n /** `context` is whatever the caller passed beside the request, such as a\n * Hono context carrying the Worker's bindings. */\n authorize(input: { request: Request; context: Context; reason: WorkspacePrewarmReason }): Promise<WorkspacePrewarmAuthorization>\n /** After a successful warm, answer `recent` for this long. Default 30 000 ms. */\n recentMs?: number\n /** A warm started longer ago than this no longer blocks the key: its request\n * may have been cancelled, taking the warm with it. A longer warm still\n * running is repeated, which is safe because warms must be idempotent.\n * Default 45 000 ms (a suspended box resumes in ~31 s). */\n staleMs?: number\n /** Observability for warms this route ran. Errors thrown here are ignored. */\n onEvent?(event: WorkspacePrewarmEvent): void\n /** Clock seam for tests. */\n now?(): number\n}\n\n// Crawlers and link-preview fetchers. Headless browsers are deliberately absent:\n// signed-in QA drives a headless browser through this same path.\nconst AUTOMATED_AGENT =\n /bot\\b|crawler|spider|slurp|facebookexternalhit|embedly|preview|whatsapp|curl\\/|wget\\/|python-requests|go-http-client/i\n\n/** True for crawler user agents and browser speculative prefetch or prerender. */\nexport function isAutomatedPrewarmRequest(request: Request): boolean {\n const purpose = `${request.headers.get('sec-purpose') ?? ''} ${request.headers.get('purpose') ?? ''}`\n if (/prefetch|prerender/i.test(purpose)) return true\n return AUTOMATED_AGENT.test(request.headers.get('user-agent') ?? '')\n}\n\nconst RECENT_LIMIT = 1_000\n\nasync function requestReason(request: Request): Promise<WorkspacePrewarmReason> {\n if (Number(request.headers.get('content-length') ?? 0) > 1_024) return 'page-open'\n try {\n // A clone, so a product's authorize can still read the body.\n const body = (await request.clone().json()) as { reason?: unknown } | null\n return body?.reason === 'composer-focus' ? 'composer-focus' : 'page-open'\n } catch {\n return 'page-open'\n }\n}\n\nfunction reply(body: WorkspacePrewarmResponse, status = 200): Response {\n return Response.json(body, { status, headers: { 'Cache-Control': 'private, no-store' } })\n}\n\n/**\n * Build the handler once per isolate, not per request: its single-flight and\n * success memory live in the returned closure.\n */\nexport function createWorkspacePrewarmRoute<Context = void>(\n options: CreateWorkspacePrewarmRouteOptions<Context>,\n): (request: Request, context: Context) => Promise<Response> {\n const recentMs = options.recentMs ?? 30_000\n const now = options.now ?? (() => Date.now())\n const staleMs = options.staleMs ?? 45_000\n // Start times, never promises: no request may await I/O another request owns.\n const inFlight = new Map<string, { at: number }>()\n const recent = new Map<string, number>()\n\n const emit = (event: WorkspacePrewarmEvent): void => {\n try {\n options.onEvent?.(event)\n } catch {\n // Logging must not change the warm's outcome.\n }\n }\n\n const remember = (key: string, at: number): void => {\n recent.delete(key)\n recent.set(key, at)\n // Insertion order is age order, so the oldest entries go first.\n for (const old of recent.keys()) {\n if (recent.size <= RECENT_LIMIT) break\n recent.delete(old)\n }\n }\n\n async function run(key: string, warm: () => Promise<WorkspacePrewarmReport | void>): Promise<WorkspacePrewarmResponse> {\n const started = now()\n try {\n const report = (await warm()) ?? undefined\n const ms = now() - started\n remember(key, now())\n emit({ type: 'warmed', key, ms, ...(report ? { report } : {}) })\n return { outcome: 'warmed', ms, ...(report ? { report } : {}) }\n } catch (err) {\n const ms = now() - started\n emit({ type: 'failed', key, ms, error: err instanceof Error ? err.message : String(err) })\n return { outcome: 'failed', ms }\n }\n }\n\n return async function prewarm(request: Request, context: Context): Promise<Response> {\n const started = now()\n if (request.method !== 'POST') {\n return new Response(null, { status: 405, headers: { Allow: 'POST' } })\n }\n if (isAutomatedPrewarmRequest(request)) return reply({ outcome: 'automated', ms: 0 })\n\n let auth: WorkspacePrewarmAuthorization\n try {\n auth = await options.authorize({ request, context, reason: await requestReason(request) })\n } catch (err) {\n // An authorization that cannot decide refuses; it never warms.\n emit({ type: 'failed', key: '', ms: now() - started, error: err instanceof Error ? err.message : String(err) })\n return reply({ outcome: 'failed', ms: now() - started })\n }\n if (auth.status === 'denied') return auth.response\n if (auth.status === 'declined') return reply({ outcome: 'declined', ms: now() - started, reason: auth.reason })\n\n const { key } = auth\n const running = inFlight.get(key)\n if (running && now() - running.at < staleMs) {\n return reply({ outcome: 'joined', ms: now() - started })\n }\n const warmedAt = recent.get(key)\n if (warmedAt !== undefined && now() - warmedAt < recentMs) {\n return reply({ outcome: 'recent', ms: now() - started })\n }\n const mark = { at: now() }\n inFlight.set(key, mark)\n try {\n return reply({ ...(await run(key, auth.warm)), ms: now() - started })\n } finally {\n if (inFlight.get(key) === mark) inFlight.delete(key)\n }\n }\n}\n","/**\n * Serialize request-time sandbox provisioning across Worker isolates.\n *\n * Background prewarming can lose a race without delaying a request. A real\n * user turn cannot: its losing request must wait for the owner, adopt the box\n * that became ready, or report why the owner did not leave a usable box.\n */\n\nimport type { Harness } from '../harness/index'\nimport type { PeekWorkspaceSandboxOutcome } from './index'\nimport {\n sandboxPrewarmClaimKey,\n type FencedPrewarmClaimStore,\n type PrewarmClaimLease,\n} from './prewarm'\n\nexport const DEFAULT_FOREGROUND_PROVISION_CLAIM_TTL_SECONDS = 180\nexport const DEFAULT_FOREGROUND_PROVISION_POLL_INTERVAL_MS = 5_000\n\nexport type ReadyRunningSandboxOutcome = Extract<\n PeekWorkspaceSandboxOutcome,\n { status: 'running' }\n> & {\n box: Extract<PeekWorkspaceSandboxOutcome, { status: 'running' }>['box'] & {\n filesystemIncarnationReadiness: 'ready'\n }\n}\n\nexport class SandboxProvisioningFailedElsewhereError extends Error {\n readonly code = 'sandbox.provisioning_failed_elsewhere'\n\n constructor(\n readonly workspaceId: string,\n readonly state: string,\n ) {\n super(\n `Sandbox provisioning for workspace ${workspaceId} failed in another request ` +\n `(state=${state})`,\n )\n this.name = 'SandboxProvisioningFailedElsewhereError'\n }\n}\n\nexport class SandboxFilesystemNotReadyError extends Error {\n readonly code = 'sandbox.filesystem_not_ready'\n readonly retryable = true\n\n constructor(\n readonly workspaceId: string,\n readonly readiness: 'transitioning' | 'missing',\n ) {\n super(`Sandbox filesystem for workspace ${workspaceId} is ${readiness}`)\n this.name = 'SandboxFilesystemNotReadyError'\n }\n}\n\nexport type ForegroundSandboxSingleFlightEvent =\n | { type: 'waiting'; key: string; workspaceId: string }\n | { type: 'release-failed'; key: string; workspaceId: string; error: string }\n\nexport interface ForegroundSandboxSingleFlightOptions<T> {\n claim: FencedPrewarmClaimStore\n workspaceId: string\n harness: Harness\n provision(): Promise<T>\n peek(): Promise<PeekWorkspaceSandboxOutcome>\n adopt(box: ReadyRunningSandboxOutcome): T | Promise<T>\n onEvent?(event: ForegroundSandboxSingleFlightEvent): void\n wait?(ms: number): Promise<void>\n claimTtlSeconds?: number\n pollIntervalMs?: number\n}\n\nfunction failedState(peek: PeekWorkspaceSandboxOutcome): string {\n return peek.status === 'not-running' ? peek.state : 'absent'\n}\n\nfunction isReadyRunningSandbox(\n peek: PeekWorkspaceSandboxOutcome,\n): peek is ReadyRunningSandboxOutcome {\n return (\n peek.status === 'running' &&\n peek.box.filesystemIncarnationReadiness === 'ready'\n )\n}\n\nfunction positiveNumber(value: number, name: string): number {\n if (!Number.isFinite(value) || value <= 0) {\n throw new RangeError(`${name} must be a positive finite number`)\n }\n return value\n}\n\nfunction safeErrorText(error: unknown): string {\n try {\n if (error instanceof Error) {\n const message = error.message\n if (typeof message === 'string' && message) return message\n }\n } catch {\n // Error values can be proxies or custom subclasses with hostile getters.\n }\n\n try {\n if (error !== null && (typeof error === 'object' || typeof error === 'function')) {\n const message = Reflect.get(error, 'message')\n if (typeof message === 'string' && message) return message\n }\n } catch {\n // A hostile proxy must not replace the successful provision result.\n }\n\n try {\n const text = typeof error === 'string' ? error : String(error)\n return text || 'unknown error'\n } catch {\n return 'unknown error'\n }\n}\n\n/**\n * Run one foreground provision or adopt the ready result from its current\n * owner. An expired retained claim permits takeover. A released claim without\n * a usable box reports the prior attempt instead of starting a retry storm.\n */\nexport async function runForegroundSandboxSingleFlight<T>(\n options: ForegroundSandboxSingleFlightOptions<T>,\n): Promise<T> {\n const key = sandboxPrewarmClaimKey(options)\n const ttlSeconds = positiveNumber(\n options.claimTtlSeconds ?? DEFAULT_FOREGROUND_PROVISION_CLAIM_TTL_SECONDS,\n 'claimTtlSeconds',\n )\n const pollIntervalMs = positiveNumber(\n options.pollIntervalMs ?? DEFAULT_FOREGROUND_PROVISION_POLL_INTERVAL_MS,\n 'pollIntervalMs',\n )\n const wait =\n options.wait ??\n ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)))\n\n const emit = (event: ForegroundSandboxSingleFlightEvent): void => {\n try {\n options.onEvent?.(event)\n } catch {\n // Observability cannot decide whether provisioning succeeds.\n }\n }\n\n const provisionAsOwner = async (lease: PrewarmClaimLease): Promise<T> => {\n try {\n return await options.provision()\n } finally {\n try {\n await options.claim.releaseLease(lease)\n } catch (error) {\n emit({\n type: 'release-failed',\n key,\n workspaceId: options.workspaceId,\n error: safeErrorText(error),\n })\n }\n }\n }\n\n const initialLease = await options.claim.acquireLease(key, ttlSeconds)\n if (initialLease) return provisionAsOwner(initialLease)\n\n emit({ type: 'waiting', key, workspaceId: options.workspaceId })\n while (true) {\n await wait(pollIntervalMs)\n const [peek, claim] = await Promise.all([\n options.peek(),\n options.claim.inspect(key),\n ])\n\n if (claim.status === 'held') continue\n if (peek.status === 'warming') {\n throw new SandboxFilesystemNotReadyError(options.workspaceId, 'transitioning')\n }\n if (isReadyRunningSandbox(peek)) return options.adopt(peek)\n if (peek.status === 'running') {\n throw new SandboxFilesystemNotReadyError(\n options.workspaceId,\n peek.box.filesystemIncarnationReadiness === 'transitioning'\n ? 'transitioning'\n : 'missing',\n )\n }\n\n if (claim.status === 'absent') {\n throw new SandboxProvisioningFailedElsewhereError(\n options.workspaceId,\n failedState(peek),\n )\n }\n const takeoverLease = await options.claim.acquireLease(key, ttlSeconds)\n if (takeoverLease) return provisionAsOwner(takeoverLease)\n }\n}\n","/**\n * `createWarmLeases`: warm a workspace's box shortly before a member needs it,\n * hold it while the conversation continues, and let the platform suspend it\n * afterwards. One primitive for every warm signal, so a page open, a composer\n * focus, an inbound line message and a learned weekly pattern share one\n * dedupe, one budget and one event stream.\n *\n * WHY A LEASE. Drew cancelled always-on keep-warm (2026-10-11): a warm box must\n * be earned by a signal and must cost a bounded amount when the signal was\n * wrong. Measured on Hospitality (2026-10-04..10-11, timestamps only): every\n * human first message after 30 min of quiet landed on a suspended box, and the\n * cold first reply took 68 s on the web and 76 s on a line.\n *\n * WHO SUSPENDS. Not this module. `POST /v1/sandboxes/:id/stop` suspends a box\n * even while a turn runs in it (agent-container\n * `routes/projects/lifecycle.ts`), whereas the platform's idle reaper re-checks\n * the sidecar for live work before it suspends. So a lease only ever resumes\n * and, during a burst hold, pings. An unused warm ends when the box's own idle\n * timeout passes; create boxes with `idleTimeoutSeconds` near the warm hold\n * (600 s) to make a wrong warm cost about ten minutes, and tell this module that\n * value through `boxIdleMs` so its accounting matches the platform.\n *\n * WHAT IT COSTS. Each lease that ends without a turn charges the box time it\n * caused (until the box's idle timeout after its last warm activity) to that\n * key's UTC day. Signals listed in `budgetedReasons` are refused once the day's\n * charge reaches `dailyBudgetMs`. A box that was already running when a signal\n * arrived is charged nothing: the warm did not cause that time.\n *\n * PREDICTION. Every turn that arrives after `boxIdleMs` of quiet (a cold\n * arrival) adds to a decayed count for its ten-minute bin of the day and its\n * weekday. Hour-of-week bins were too coarse: one arrival a day in an hour is\n * a 15% chance for any ten-minute warm, so a shift-start ramp never crossed a\n * useful threshold. `sweep()` warms a key when the predicted chance of a cold\n * arrival in the next `holdMs` reaches that key's threshold, at most once per\n * hour, within the budget. The threshold tunes itself: a predicted warm that is used lowers it,\n * one that is wasted raises it.\n *\n * EVENTS. `warm_started`, `warm_hit`, `warm_wasted`, `warm_declined`,\n * `warm_failed` and `warm_abandoned` each carry the key and the reason, so a product can compute hit\n * rate and wasted minutes per workspace from its logs alone.\n */\n\n/** Why a warm was requested. Products may add their own reasons. */\nexport type WarmReason =\n | 'page-open'\n | 'composer-focus'\n | 'line-ingress'\n | 'member-activity'\n | 'predicted'\n | 'scheduled'\n /** A turn is likely to call a sandbox tool (deterministic input rules, or a\n * `sandbox_run` call starting to stream). See `createEscalationSpeculator`. */\n | 'escalation-likely'\n | (string & {})\n\n/** What the product's `warm` did to the box. */\nexport type WarmBoxOutcome =\n /** The box was stopped and is now running: this warm caused its up-time. */\n | 'resumed'\n /** The box was already running: nothing to warm, nothing charged. */\n | 'running'\n /** No box exists for this key. Leases never create boxes. */\n | 'absent'\n /** The platform refused the resume for capacity (HTTP 429: the org is at its\n * concurrent-box limit). A speculative warm must not compete with real work\n * for the last slots, so the key cools down instead of retrying. */\n | 'capacity'\n\nexport type WarmLeaseEvent =\n | { type: 'warm_started'; key: string; reason: WarmReason; outcome: WarmBoxOutcome; ms: number }\n | { type: 'warm_hit'; key: string; reason: WarmReason; leadMs: number }\n | { type: 'warm_wasted'; key: string; reason: WarmReason; minutes: number }\n | { type: 'warm_declined'; key: string; reason: WarmReason; why: 'budget' | 'absent' | 'capacity' }\n | { type: 'warm_failed'; key: string; reason: WarmReason; error: string }\n /** The lease ended without its warm ever reporting: the request running it was\n * cancelled or the isolate died. Whether the box resumed is unknown, so it is\n * counted here rather than charged or dropped. */\n | { type: 'warm_abandoned'; key: string; reason: WarmReason }\n\nexport type WarmSignalOutcome =\n /** This call started a lease and ran the product's warm. */\n | 'started'\n /** A lease was already live (here or in another isolate); its hold was extended. */\n | 'extended'\n | 'declined'\n | 'failed'\n\nexport interface WarmSignalResult {\n outcome: WarmSignalOutcome\n box?: WarmBoxOutcome\n}\n\nexport interface WarmTurnResult {\n /** The turn landed on a box a lease had already warmed. */\n hit: boolean\n /** The turn arrived after `boxIdleMs` of quiet on this key. */\n coldArrival: boolean\n}\n\nexport interface WarmSweepReport {\n ended: number\n wasted: number\n /** Expired leases whose warm never reported an outcome. */\n abandoned: number\n pinged: number\n predicted: number\n /** Keys whose ping or predicted warm threw; the rest of the batch still ran. */\n errors: number\n}\n\n/** One key's row. Times are epoch milliseconds; 0 means never. */\nexport interface WarmLeaseRow {\n key: string\n leaseId: string | null\n reason: string | null\n startedAt: number\n holdUntil: number\n warmAt: number\n usedAt: number\n resumed: boolean\n pingAt: number\n lastTurnAt: number\n day: string\n dayWarmMs: number\n threshold: number\n slots: number[]\n slotsAt: number\n firstSeenAt: number\n predictedAt: number\n /** Signals are refused without calling the product's warm until this time:\n * set after an 'absent' or 'capacity' outcome, cleared by a turn. */\n declinedUntil: number\n /** An ended, unused warm whose box may still be up: settled at the span no\n * turn used, when a turn arrives or its idle window closes. 0 when none. */\n pendingWarmAt: number\n /** The most the pending warm can be charged: until the box's idle timeout. */\n pendingMs: number\n pendingReason: string | null\n}\n\n/** Persistence for leases. `begin` and `markUsed` must be atomic across isolates. */\nexport interface WarmLeaseStore {\n read(key: string): Promise<WarmLeaseRow | null>\n /**\n * Start a lease with `leaseId` when none is live, otherwise extend the live\n * one's hold to at least `holdUntil`. A lease whose warm has not reported by\n * `staleBefore` counts as not live and is taken over, so a warm killed with\n * its request is retried instead of blocking every later signal. Returns the\n * live lease id after the write; the caller started the lease exactly when\n * it equals `leaseId`.\n */\n begin(key: string, leaseId: string, reason: string, now: number, holdUntil: number, staleBefore: number): Promise<string>\n /** Record the result of this lease's warm. No-op for a superseded lease. */\n markWarm(key: string, leaseId: string, warmAt: number, resumed: boolean): Promise<void>\n /**\n * Record a turn: mark the live lease used (first turn only), extend its hold\n * to `holdUntil`, and store `lastTurnAt`. Returns the row as it was BEFORE\n * the write, so the caller can tell a hit and a cold arrival apart.\n */\n markUsed(key: string, now: number, holdUntil: number): Promise<WarmLeaseRow | null>\n /**\n * End `leaseId`, charging `chargeMs` to `day` and setting the predicted-warm\n * threshold when one is given. No-op for a superseded lease.\n */\n end(key: string, leaseId: string, day: string, chargeMs: number, threshold?: number): Promise<void>\n /** Overwrite the prediction fields. Lossy under races by design: it is a statistic. */\n writeProfile(key: string, slots: number[], slotsAt: number, firstSeenAt: number): Promise<void>\n markPinged(key: string, at: number): Promise<void>\n markPredicted(key: string, at: number): Promise<void>\n /** Refuse signals for `key` until `until` (cleared by the next turn). */\n markDeclined(key: string, until: number): Promise<void>\n /** Record an ended, unused warm whose charge is settled later. */\n markPending(key: string, warmAt: number, maxMs: number, reason: string): Promise<void>\n /**\n * Charge the pending warm that started at `warmAt` `chargeMs` to `day` and\n * clear it. Only the first settler of a given warm succeeds (a turn and a\n * sweep may race); returns whether this call settled it.\n */\n settlePending(key: string, warmAt: number, day: string, chargeMs: number): Promise<boolean>\n /** Pending warms whose idle window has closed by `now`. */\n listPendingDue(now: number, limit: number): Promise<WarmLeaseRow[]>\n /** Bounded batches for `sweep`. */\n listExpired(now: number, limit: number): Promise<WarmLeaseRow[]>\n listHeld(now: number, limit: number): Promise<WarmLeaseRow[]>\n listPredictable(now: number, limit: number): Promise<WarmLeaseRow[]>\n}\n\nexport interface WarmLeasesOptions {\n store: WarmLeaseStore\n /** Resume the key's box if it is stopped. Never create one. */\n warm(key: string, reason: WarmReason): Promise<WarmBoxOutcome>\n /**\n * Optional: touch the running box through a path the platform counts as\n * activity (an exec of `true`). Needed only when `burstHoldMs` exceeds\n * `boxIdleMs`; without it a burst hold is just the box's own idle timeout.\n */\n keepAlive?(key: string): Promise<void>\n /** The idle timeout the key's boxes were created with. Default 30 min, the platform default. */\n boxIdleMs?: number\n /** How long a warm waits for its first turn. Default 10 min. */\n holdMs?: number\n /** How long the box stays held after a turn. Default `boxIdleMs` (no pings). */\n burstHoldMs?: number\n /** Unused-warm box time allowed per key per UTC day. Default 30 min. */\n dailyBudgetMs?: number\n /**\n * How long a started warm may go without reporting before the next signal\n * takes the lease over and warms again. Default 2 min, past a slow resume.\n */\n warmDeadlineMs?: number\n /** After a warm finds no box, refuse that key's signals this long. Default 10 min. */\n absentCooldownMs?: number\n /** After a capacity refusal, refuse that key's signals this long. Default 5 min. */\n capacityCooldownMs?: number\n /** Reasons subject to the budget. Default page-open, member-activity, predicted, scheduled, escalation-likely. */\n budgetedReasons?: readonly string[]\n /** Starting predicted-warm threshold, a probability. Default 0.25. */\n initialThreshold?: number\n onEvent?(event: WarmLeaseEvent): void\n now?(): number\n newId?(): string\n}\n\nexport interface WarmLeases {\n /** A signal that a member may need `key`'s box soon. Awaits the warm when it starts one. */\n signal(key: string, reason: WarmReason): Promise<WarmSignalResult>\n /** Call when a turn is admitted for `key`, before its box is placed. */\n turn(key: string): Promise<WarmTurnResult>\n /** End expired leases, ping held boxes, and start predicted warms. Run from a cron. */\n sweep(options?: { limit?: number }): Promise<WarmSweepReport>\n}\n\n/** 144 ten-minute bins of the UTC day, then 7 weekday counts (Monday first). */\nexport const WARM_SLOTS = 151\nconst DAY_BINS = 144\nconst BIN_MS = 10 * 60_000\nconst HOUR_MS = 3_600_000\nconst DAY_MS = 24 * HOUR_MS\nconst SLOT_HALF_LIFE_MS = 14 * DAY_MS\nconst PING_MARGIN_MS = 2 * 60_000\nconst THRESHOLD_FLOOR = 0.05\nconst THRESHOLD_CEILING = 0.95\nconst DEFAULT_BUDGETED = ['page-open', 'member-activity', 'predicted', 'scheduled', 'escalation-likely'] as const\n\n/** UTC ten-minute bin of the day, 0..143. */\nexport function warmBinOf(at: number): number {\n return Math.floor((((at % DAY_MS) + DAY_MS) % DAY_MS) / BIN_MS)\n}\n\n/** UTC weekday, Monday = 0. */\nexport function warmWeekdayOf(at: number): number {\n return (new Date(at).getUTCDay() + 6) % 7\n}\n\nexport function utcDay(at: number): string {\n return new Date(at).toISOString().slice(0, 10)\n}\n\n/** Decay every slot to `at` with a 14-day half-life. */\nexport function decaySlots(slots: readonly number[], from: number, at: number): number[] {\n const factor = from > 0 && at > from ? 0.5 ** ((at - from) / SLOT_HALF_LIFE_MS) : 1\n return Array.from({ length: WARM_SLOTS }, (_, i) => (slots[i] ?? 0) * factor)\n}\n\n/** Record one cold arrival at `at`. */\nexport function addColdArrival(slots: readonly number[], slotsAt: number, at: number): number[] {\n const next = decaySlots(slots, slotsAt, at)\n next[warmBinOf(at)] = (next[warmBinOf(at)] ?? 0) + 1\n next[DAY_BINS + warmWeekdayOf(at)] = (next[DAY_BINS + warmWeekdayOf(at)] ?? 0) + 1\n return next\n}\n\n/**\n * Chance of at least one cold arrival in `[at, at + windowMs)`.\n *\n * Each ten-minute bin's rate is its decayed count over the effective days\n * observed, smoothed over its neighbours (a shift that starts at 07:00 sends\n * its first message anywhere from 06:55 to 07:15), and scaled by how busy the\n * window's weekday is against the average weekday. The weekday factor is\n * smoothed toward 1 because two weeks hold only two of each weekday.\n */\nexport function predictColdArrival(\n row: Pick<WarmLeaseRow, 'slots' | 'slotsAt' | 'firstSeenAt'>,\n at: number,\n windowMs: number,\n): number {\n if (row.firstSeenAt <= 0 || row.slots.length !== WARM_SLOTS) return 0\n const slots = decaySlots(row.slots, row.slotsAt, at)\n const decay = Math.LN2 / SLOT_HALF_LIFE_MS\n const observedMs = Math.max(DAY_MS, at - row.firstSeenAt)\n const days = (1 - Math.exp(-decay * observedMs)) / decay / DAY_MS\n const weekdays = slots.slice(DAY_BINS)\n const meanWeekday = weekdays.reduce((sum, v) => sum + v, 0) / 7\n const bin = (i: number) => slots[((i % DAY_BINS) + DAY_BINS) % DAY_BINS] ?? 0\n let expected = 0\n for (let start = at; start < at + windowMs; ) {\n const index = warmBinOf(start)\n const binEnd = start - (((start % BIN_MS) + BIN_MS) % BIN_MS) + BIN_MS\n const end = Math.min(binEnd, at + windowMs)\n const smoothed = 0.25 * bin(index - 1) + 0.5 * bin(index) + 0.25 * bin(index + 1)\n const weekday = ((weekdays[warmWeekdayOf(start)] ?? 0) + 1) / (meanWeekday + 1)\n expected += (smoothed / days) * weekday * ((end - start) / BIN_MS)\n start = end\n }\n return 1 - Math.exp(-expected)\n}\n\nfunction errText(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nexport function createWarmLeases(options: WarmLeasesOptions): WarmLeases {\n const { store } = options\n const boxIdleMs = options.boxIdleMs ?? 30 * 60_000\n const holdMs = options.holdMs ?? 10 * 60_000\n const warmDeadlineMs = options.warmDeadlineMs ?? 2 * 60_000\n const absentCooldownMs = options.absentCooldownMs ?? 10 * 60_000\n const capacityCooldownMs = options.capacityCooldownMs ?? 5 * 60_000\n const burstHoldMs = options.burstHoldMs ?? boxIdleMs\n const dailyBudgetMs = options.dailyBudgetMs ?? 30 * 60_000\n const budgeted = new Set<string>(options.budgetedReasons ?? DEFAULT_BUDGETED)\n const initialThreshold = options.initialThreshold ?? 0.25\n const now = options.now ?? (() => Date.now())\n const newId = options.newId ?? (() => crypto.randomUUID())\n\n const emit = (event: WarmLeaseEvent): void => {\n try {\n options.onEvent?.(event)\n } catch {\n // Observability must not change a warm's outcome.\n }\n }\n\n // A pending warm counts in full until it settles: conservative, and while it\n // is pending its box is still up, so another warm would buy nothing.\n const spentToday = (row: WarmLeaseRow | null, at: number): number =>\n (row && row.day === utcDay(at) ? row.dayWarmMs : 0) +\n (row && row.pendingWarmAt > 0 && utcDay(row.pendingWarmAt) === utcDay(at) ? row.pendingMs : 0)\n\n /**\n * The most box time an unused lease can have caused: until the box's idle\n * timeout after its last warm activity (the resume, or a keep-alive ping).\n * Not the hold: later signals extend the hold, but the hold keeps no box up,\n * so a page polled every few minutes once inflated one warm to 50 min.\n */\n function chargeOf(row: WarmLeaseRow): number {\n if (!row.resumed || row.usedAt > 0 || row.warmAt <= 0) return 0\n return Math.max(row.warmAt, row.pingAt) + boxIdleMs - row.warmAt\n }\n\n async function signal(key: string, reason: WarmReason): Promise<WarmSignalResult> {\n const at = now()\n const row = await store.read(key)\n // A recent 'absent' or 'capacity' answer stands until it expires or a turn\n // clears it. Refused silently: on a busy page this fires every few seconds,\n // and each event would be a duplicate of the decline that set it.\n if (row && row.declinedUntil > at && !row.leaseId) return { outcome: 'declined' }\n if (budgeted.has(reason)) {\n if (!(row?.leaseId) && spentToday(row, at) >= dailyBudgetMs) {\n emit({ type: 'warm_declined', key, reason, why: 'budget' })\n return { outcome: 'declined' }\n }\n }\n const leaseId = newId()\n const live = await store.begin(key, leaseId, reason, at, at + holdMs, at - warmDeadlineMs)\n if (live !== leaseId) return { outcome: 'extended' }\n\n let box: WarmBoxOutcome\n try {\n box = await options.warm(key, reason)\n } catch (err) {\n await store.end(key, leaseId, utcDay(at), 0)\n emit({ type: 'warm_failed', key, reason, error: errText(err) })\n return { outcome: 'failed' }\n }\n const warmAt = now()\n if (box === 'absent' || box === 'capacity') {\n await store.end(key, leaseId, utcDay(at), 0)\n await store.markDeclined(key, warmAt + (box === 'absent' ? absentCooldownMs : capacityCooldownMs))\n emit({ type: 'warm_declined', key, reason, why: box })\n return { outcome: 'declined', box }\n }\n await store.markWarm(key, leaseId, warmAt, box === 'resumed')\n emit({ type: 'warm_started', key, reason, outcome: box, ms: warmAt - at })\n return { outcome: 'started', box }\n }\n\n async function turn(key: string): Promise<WarmTurnResult> {\n const at = now()\n const before = await store.markUsed(key, at, at + burstHoldMs)\n const coldArrival = !before || before.lastTurnAt <= 0 || at - before.lastTurnAt > boxIdleMs\n const hit = Boolean(\n before?.leaseId && before.usedAt <= 0 && before.resumed && before.warmAt > 0 && before.warmAt <= at,\n )\n if (hit && before) {\n emit({ type: 'warm_hit', key, reason: before.reason ?? 'unknown', leadMs: at - before.startedAt })\n }\n // A turn inside an ended warm's idle window landed on the box that warm\n // resumed: a hit, and only the span before it was unused.\n let lateHit = false\n if (before && before.pendingWarmAt > 0 && at < before.pendingWarmAt + before.pendingMs) {\n const unused = Math.max(0, at - before.pendingWarmAt)\n if (await store.settlePending(key, before.pendingWarmAt, utcDay(before.pendingWarmAt), unused)) {\n lateHit = true\n const reason = before.pendingReason ?? 'unknown'\n emit({ type: 'warm_hit', key, reason, leadMs: unused })\n if (unused >= 60_000) emit({ type: 'warm_wasted', key, reason, minutes: Math.round(unused / 60_000) })\n }\n }\n if (coldArrival) {\n const slots = addColdArrival(before?.slots ?? [], before?.slotsAt ?? 0, at)\n await store.writeProfile(key, slots, at, before?.firstSeenAt || at)\n }\n return { hit: hit || lateHit, coldArrival }\n }\n\n async function sweep(sweepOptions: { limit?: number } = {}): Promise<WarmSweepReport> {\n const limit = sweepOptions.limit ?? 50\n const at = now()\n const report: WarmSweepReport = { ended: 0, wasted: 0, abandoned: 0, pinged: 0, predicted: 0, errors: 0 }\n\n for (const row of await store.listExpired(at, limit)) {\n if (!row.leaseId) continue\n const charge = chargeOf(row)\n let threshold: number | undefined\n if (row.reason === 'predicted' && row.resumed) {\n const current = row.threshold > 0 ? row.threshold : initialThreshold\n threshold = Math.min(THRESHOLD_CEILING, Math.max(THRESHOLD_FLOOR, current * (row.usedAt > 0 ? 0.85 : 1.3)))\n }\n // An unused warm is not charged here: its box stays up until the idle\n // timeout, and a turn in that window means only part of it was unused.\n await store.end(row.key, row.leaseId, utcDay(row.warmAt || row.startedAt), 0, threshold)\n if (charge > 0) await store.markPending(row.key, row.warmAt, charge, row.reason ?? 'unknown')\n report.ended += 1\n if (row.warmAt <= 0) {\n report.abandoned += 1\n emit({ type: 'warm_abandoned', key: row.key, reason: row.reason ?? 'unknown' })\n }\n }\n\n for (const row of await store.listPendingDue(at, limit)) {\n if (await store.settlePending(row.key, row.pendingWarmAt, utcDay(row.pendingWarmAt), row.pendingMs)) {\n report.wasted += 1\n emit({ type: 'warm_wasted', key: row.key, reason: row.pendingReason ?? 'unknown', minutes: Math.round(row.pendingMs / 60_000) })\n }\n }\n\n if (options.keepAlive && burstHoldMs > boxIdleMs) {\n for (const row of await store.listHeld(at, limit)) {\n const lastActivity = Math.max(row.pingAt, row.lastTurnAt, row.warmAt)\n if (lastActivity + boxIdleMs - PING_MARGIN_MS > at) continue\n if (row.holdUntil <= lastActivity + boxIdleMs) continue\n try {\n await options.keepAlive(row.key)\n await store.markPinged(row.key, at)\n report.pinged += 1\n } catch {\n report.errors += 1\n }\n }\n }\n\n for (const row of await store.listPredictable(at, limit)) {\n if (row.leaseId || at - row.predictedAt < HOUR_MS) continue\n if (row.lastTurnAt > 0 && at - row.lastTurnAt < boxIdleMs) continue\n const threshold = row.threshold > 0 ? row.threshold : initialThreshold\n if (predictColdArrival(row, at, holdMs) < threshold) continue\n await store.markPredicted(row.key, at)\n try {\n const result = await signal(row.key, 'predicted')\n if (result.outcome === 'started') report.predicted += 1\n if (result.outcome === 'failed') report.errors += 1\n } catch {\n report.errors += 1\n }\n }\n return report\n }\n\n return { signal, turn, sweep }\n}\n","import { WARM_SLOTS, type WarmLeaseRow, type WarmLeaseStore } from './warm-lease'\n\n/**\n * `createD1WarmLeaseStore`: the `WarmLeaseStore` every Workers product uses,\n * one row per key in one table.\n *\n * Race-sensitive steps are single statements. `begin` is an upsert whose SET\n * expressions read the old row, so two isolates that signal at once agree on\n * one lease id and only its owner runs the warm. `markUsed` claims the first\n * use with a conditional UPDATE … RETURNING, so two turns cannot both count as\n * the hit. The prediction slots are a decayed statistic and are written\n * without a fence: a lost increment under a race costs nothing.\n *\n * The table is the product's migration (`WARM_LEASE_TABLE_DDL`); the store\n * never runs DDL, for the same reason as `createD1PrewarmClaimStore`.\n */\n\nexport const DEFAULT_WARM_LEASE_TABLE = 'sandbox_warm_lease'\n\n/** Paste into a migration. Times are epoch milliseconds; 0 means never. */\nexport const WARM_LEASE_TABLE_DDL = `CREATE TABLE IF NOT EXISTS ${DEFAULT_WARM_LEASE_TABLE} (\n key TEXT PRIMARY KEY,\n lease_id TEXT,\n reason TEXT,\n started_at INTEGER NOT NULL DEFAULT 0,\n hold_until INTEGER NOT NULL DEFAULT 0,\n warm_at INTEGER NOT NULL DEFAULT 0,\n used_at INTEGER NOT NULL DEFAULT 0,\n resumed INTEGER NOT NULL DEFAULT 0,\n ping_at INTEGER NOT NULL DEFAULT 0,\n last_turn_at INTEGER NOT NULL DEFAULT 0,\n day TEXT NOT NULL DEFAULT '',\n day_warm_ms INTEGER NOT NULL DEFAULT 0,\n threshold REAL NOT NULL DEFAULT 0,\n slots TEXT NOT NULL DEFAULT '',\n slots_at INTEGER NOT NULL DEFAULT 0,\n first_seen_at INTEGER NOT NULL DEFAULT 0,\n predicted_at INTEGER NOT NULL DEFAULT 0,\n declined_until INTEGER NOT NULL DEFAULT 0,\n pending_warm_at INTEGER NOT NULL DEFAULT 0,\n pending_ms INTEGER NOT NULL DEFAULT 0,\n pending_reason TEXT\n)`\n\n/** For a table created from an earlier \\`WARM_LEASE_TABLE_DDL\\`: paste into a migration. */\nexport const WARM_LEASE_DECLINED_UNTIL_DDL =\n `ALTER TABLE ${DEFAULT_WARM_LEASE_TABLE} ADD COLUMN declined_until INTEGER NOT NULL DEFAULT 0`\n\n/** For a table created before pending charges: paste each into a migration. */\nexport const WARM_LEASE_PENDING_DDL = [\n `ALTER TABLE ${DEFAULT_WARM_LEASE_TABLE} ADD COLUMN pending_warm_at INTEGER NOT NULL DEFAULT 0`,\n `ALTER TABLE ${DEFAULT_WARM_LEASE_TABLE} ADD COLUMN pending_ms INTEGER NOT NULL DEFAULT 0`,\n `ALTER TABLE ${DEFAULT_WARM_LEASE_TABLE} ADD COLUMN pending_reason TEXT`,\n] as const\n\nconst SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/\n\ninterface Row {\n key: string\n lease_id: string | null\n reason: string | null\n started_at: number\n hold_until: number\n warm_at: number\n used_at: number\n resumed: number\n ping_at: number\n last_turn_at: number\n day: string\n day_warm_ms: number\n threshold: number\n slots: string\n slots_at: number\n first_seen_at: number\n predicted_at: number\n declined_until: number\n pending_warm_at: number\n pending_ms: number\n pending_reason: string | null\n}\n\n/** The D1 surface this store uses: `prepare().bind()` with `first`, `run` and `all`. A real `D1Database` satisfies it. */\nexport interface WarmLeaseD1Like {\n prepare(query: string): {\n bind(...values: unknown[]): {\n first<T = Record<string, unknown>>(): Promise<T | null>\n run(): Promise<unknown>\n all<T = Record<string, unknown>>(): Promise<{ results: T[] }>\n }\n }\n}\n\nfunction parseSlots(text: string): number[] {\n if (!text) return []\n try {\n const parsed: unknown = JSON.parse(text)\n if (Array.isArray(parsed) && parsed.length === WARM_SLOTS) return parsed.map((v) => Number(v) || 0)\n } catch {\n // A corrupt profile restarts learning; it must not break a turn.\n }\n return []\n}\n\nfunction toRow(row: Row): WarmLeaseRow {\n return {\n key: row.key,\n leaseId: row.lease_id,\n reason: row.reason,\n startedAt: row.started_at,\n holdUntil: row.hold_until,\n warmAt: row.warm_at,\n usedAt: row.used_at,\n resumed: row.resumed === 1,\n pingAt: row.ping_at,\n lastTurnAt: row.last_turn_at,\n day: row.day,\n dayWarmMs: row.day_warm_ms,\n threshold: row.threshold,\n slots: parseSlots(row.slots),\n slotsAt: row.slots_at,\n firstSeenAt: row.first_seen_at,\n predictedAt: row.predicted_at,\n declinedUntil: row.declined_until ?? 0,\n pendingWarmAt: row.pending_warm_at ?? 0,\n pendingMs: row.pending_ms ?? 0,\n pendingReason: row.pending_reason ?? null,\n }\n}\n\nexport function createD1WarmLeaseStore(\n db: WarmLeaseD1Like,\n options: { table?: string } = {},\n): WarmLeaseStore {\n const t = options.table ?? DEFAULT_WARM_LEASE_TABLE\n if (!SAFE_IDENTIFIER.test(t)) throw new Error(`Invalid warm lease table name: ${JSON.stringify(t)}`)\n\n // Every SET expression reads the old row. A lease is free when there is none,\n // or when its warm has not reported by ?6 (the request running it was cancelled).\n const free = `(${t}.lease_id IS NULL OR (${t}.warm_at = 0 AND ${t}.started_at <= ?6))`\n const beginSql = `INSERT INTO ${t} (key, lease_id, reason, started_at, hold_until) VALUES (?1, ?2, ?3, ?4, ?5)\nON CONFLICT(key) DO UPDATE SET\n lease_id = CASE WHEN ${free} THEN ?2 ELSE ${t}.lease_id END,\n reason = CASE WHEN ${free} THEN ?3 ELSE ${t}.reason END,\n started_at = CASE WHEN ${free} THEN ?4 ELSE ${t}.started_at END,\n warm_at = CASE WHEN ${free} THEN 0 ELSE ${t}.warm_at END,\n used_at = CASE WHEN ${free} THEN 0 ELSE ${t}.used_at END,\n resumed = CASE WHEN ${free} THEN 0 ELSE ${t}.resumed END,\n ping_at = CASE WHEN ${free} THEN 0 ELSE ${t}.ping_at END,\n hold_until = MAX(${t}.hold_until, ?5)\nRETURNING lease_id`\n const markWarmSql = `UPDATE ${t} SET warm_at = ?3, resumed = ?4 WHERE key = ?1 AND lease_id = ?2`\n const firstUseSql = `UPDATE ${t} SET used_at = ?2 WHERE key = ?1 AND lease_id IS NOT NULL AND used_at = 0 RETURNING key`\n const turnSql = `INSERT INTO ${t} (key, last_turn_at, hold_until) VALUES (?1, ?2, ?3)\nON CONFLICT(key) DO UPDATE SET last_turn_at = ?2, hold_until = MAX(${t}.hold_until, ?3), declined_until = 0`\n // A charge for an older day than the row holds is dropped: that day's budget is already spent.\n const endSql = `UPDATE ${t} SET\n lease_id = NULL, reason = NULL, started_at = 0, warm_at = 0, used_at = 0, resumed = 0, ping_at = 0,\n day_warm_ms = CASE WHEN day = ?3 THEN day_warm_ms + ?4 WHEN day < ?3 THEN ?4 ELSE day_warm_ms END,\n day = CASE WHEN day < ?3 THEN ?3 ELSE day END,\n threshold = COALESCE(?5, threshold)\nWHERE key = ?1 AND lease_id = ?2`\n const profileSql = `UPDATE ${t} SET slots = ?2, slots_at = ?3, first_seen_at = ?4 WHERE key = ?1`\n const readSql = `SELECT * FROM ${t} WHERE key = ?1`\n\n // D1 accepts numbered `?NNN` placeholders; better-sqlite3, which product test\n // harnesses commonly wrap as D1, rejects them. Statements stay numbered for\n // readability and are expanded to plain `?` with their values in order.\n const q = (sql: string, ...values: unknown[]) => {\n const ordered: unknown[] = []\n const text = sql.replace(/\\?(\\d+)/g, (_, n: string) => {\n ordered.push(values[Number(n) - 1])\n return '?'\n })\n return db.prepare(text).bind(...ordered)\n }\n\n const read = async (key: string): Promise<WarmLeaseRow | null> => {\n const row = await q(readSql, key).first<Row>()\n return row ? toRow(row) : null\n }\n const list = async (sql: string, ...values: unknown[]): Promise<WarmLeaseRow[]> =>\n ((await q(sql, ...values).all<Row>()).results ?? []).map(toRow)\n\n return {\n read,\n\n async begin(key, leaseId, reason, now, holdUntil, staleBefore) {\n const row = await q(beginSql, key, leaseId, reason, now, holdUntil, staleBefore).first<{ lease_id: string }>()\n if (!row) throw new Error('warm lease begin returned no row')\n return row.lease_id\n },\n\n async markWarm(key, leaseId, warmAt, resumed) {\n await q(markWarmSql, key, leaseId, warmAt, resumed ? 1 : 0).run()\n },\n\n async markUsed(key, now, holdUntil) {\n const before = await read(key)\n const claimed = await q(firstUseSql, key, now).first<{ key: string }>()\n await q(turnSql, key, now, holdUntil).run()\n // Another turn claimed the first use between the read and the claim: this one is not the hit.\n if (before && !claimed && before.usedAt <= 0) return { ...before, usedAt: now }\n return before\n },\n\n async end(key, leaseId, day, chargeMs, threshold) {\n await q(endSql, key, leaseId, day, Math.max(0, Math.round(chargeMs)), threshold ?? null).run()\n },\n\n async writeProfile(key, slots, slotsAt, firstSeenAt) {\n const rounded = slots.map((v) => Math.round(v * 1000) / 1000)\n await q(profileSql, key, JSON.stringify(rounded), slotsAt, firstSeenAt).run()\n },\n\n async markPinged(key, at) {\n await q(`UPDATE ${t} SET ping_at = ?2 WHERE key = ?1`, key, at).run()\n },\n\n async markPending(key, warmAt, maxMs, reason) {\n await q(`UPDATE ${t} SET pending_warm_at = ?2, pending_ms = ?3, pending_reason = ?4 WHERE key = ?1`,\n key, warmAt, Math.max(0, Math.round(maxMs)), reason).run()\n },\n\n async settlePending(key, warmAt, day, chargeMs) {\n // Fenced by the warm's start time, so a turn and a sweep cannot both settle it.\n const settled = await q(`UPDATE ${t} SET\n day_warm_ms = CASE WHEN day = ?3 THEN day_warm_ms + ?4 WHEN day < ?3 THEN ?4 ELSE day_warm_ms END,\n day = CASE WHEN day < ?3 THEN ?3 ELSE day END,\n pending_warm_at = 0, pending_ms = 0, pending_reason = NULL\nWHERE key = ?1 AND pending_warm_at = ?2 RETURNING key`, key, warmAt, day, Math.max(0, Math.round(chargeMs))).first<{ key: string }>()\n return settled != null\n },\n\n listPendingDue: (now, limit) =>\n list(`SELECT * FROM ${t} WHERE pending_warm_at > 0 AND pending_warm_at + pending_ms <= ?1 ORDER BY pending_warm_at LIMIT ?2`, now, limit),\n\n async markDeclined(key, until) {\n await q(`UPDATE ${t} SET declined_until = ?2 WHERE key = ?1`, key, until).run()\n },\n\n async markPredicted(key, at) {\n await q(`UPDATE ${t} SET predicted_at = ?2 WHERE key = ?1`, key, at).run()\n },\n\n listExpired: (now, limit) =>\n list(`SELECT * FROM ${t} WHERE lease_id IS NOT NULL AND hold_until <= ?1 ORDER BY hold_until LIMIT ?2`, now, limit),\n\n listHeld: (now, limit) =>\n list(`SELECT * FROM ${t} WHERE hold_until > ?1 ORDER BY ping_at LIMIT ?2`, now, limit),\n\n // Random order so a large fleet is covered across sweeps instead of always checking the same rows.\n listPredictable: (now, limit) =>\n list(\n `SELECT * FROM ${t} WHERE lease_id IS NULL AND first_seen_at > 0 AND predicted_at <= ?1 ORDER BY random() LIMIT ?2`,\n now - 3_600_000,\n limit,\n ),\n }\n}\n","/**\n * `createEscalationSpeculator`: warm a turn's sandbox box when the turn is\n * likely to escalate to it, so `sandbox_run` finds the box running instead of\n * paying the resume (p50 6.4 s on escalated turns, agent turn architecture S8).\n *\n * TWO SIGNALS, CHEAPEST FIRST. Deterministic rules on the turn's input fire\n * before the model is called: an attachment a process must read (PDF, sheet,\n * archive, code), a fenced code block, or words that ask for execution. Then,\n * while the reply streams, `tool_call_start` for an escalation tool fires as\n * soon as the model names it, seconds before its arguments finish. Either one\n * signals the box's warm lease with reason `escalation-likely`, at most once\n * per turn.\n *\n * NEVER GATES. Signals are fire-and-forget: the lease dedupes across isolates,\n * charges unused warms to the key's daily budget (`escalation-likely` is a\n * budgeted reason), and backs off on capacity. A speculation that is wrong\n * costs box time within that budget; it never delays or fails the turn.\n *\n * MEASURING IT. The `sandbox_run` binding calls `leases.turn(boxKey)` when the\n * tool runs. A `warm_hit` with reason `escalation-likely` is a box the\n * speculation made ready in time. The S8 number is that count over all\n * escalated turns.\n *\n * Off unless the app passes `mode: 'deterministic'` (from `SANDBOX_PREWARM_HINT`).\n */\n\n/** `SANDBOX_PREWARM_HINT`: `off` (default) or `deterministic`. */\nexport type PrewarmHintMode = 'off' | 'deterministic'\n\nexport function parsePrewarmHint(value: string | undefined | null): PrewarmHintMode {\n return value?.trim().toLowerCase() === 'deterministic' ? 'deterministic' : 'off'\n}\n\n/** Why a turn was judged likely to escalate. */\nexport type EscalationHint = 'attachment' | 'code-block' | 'execution-words' | 'tool-call-start'\n\nexport interface EscalationInput {\n text?: string\n attachments?: ReadonlyArray<{ mediaType?: string; name?: string }>\n}\n\n/** The tools that run in the box. A `tool_call_start` for one of these warms it. */\nexport const DEFAULT_ESCALATION_TOOLS = ['sandbox_run', 'sandbox_exec'] as const\n\nconst PROCESS_MEDIA = /^(application\\/(pdf|zip|x-zip|gzip|x-tar|vnd\\.openxmlformats|vnd\\.ms-excel|vnd\\.oasis)|text\\/(csv|x-python|x-script))/i\nconst PROCESS_EXTENSIONS = /\\.(pdf|xlsx?|csv|tsv|ods|zip|tar|gz|py|ipynb|js|ts|sh|sql|parquet|json)$/i\nconst EXECUTION_WORDS =\n /\\b(run|execute|compile|convert|parse|extract|install|script|python|notebook|spreadsheet|csv|xlsx|regex|calculate|plot|chart|test suite|build the)\\b/i\n\n/** Pure: the reasons this input suggests the turn will need the box, if any. */\nexport function escalationHints(input: EscalationInput): EscalationHint[] {\n const hints: EscalationHint[] = []\n if ((input.attachments ?? []).some((a) => PROCESS_MEDIA.test(a.mediaType ?? '') || PROCESS_EXTENSIONS.test(a.name ?? ''))) {\n hints.push('attachment')\n }\n const text = input.text ?? ''\n if (/```/.test(text)) hints.push('code-block')\n if (EXECUTION_WORDS.test(text)) hints.push('execution-words')\n return hints\n}\n\nexport interface EscalationSpeculatorOptions {\n mode: PrewarmHintMode\n /** The box's warm lease; only `signal` is used. */\n leases: { signal(key: string, reason: 'escalation-likely'): Promise<unknown> }\n /** The warm-lease key of the box `sandbox_run` would use for this turn. */\n boxKey: string\n escalationTools?: readonly string[]\n /** Observability: called once, when the turn's warm is signalled. */\n onSpeculate?(hint: EscalationHint): void\n}\n\nexport interface EscalationSpeculator {\n /** Call with the turn's input before the model call. */\n onInput(input: EscalationInput): void\n /** Call with each event the model stream yields. Non-tool events are ignored. */\n onEvent(event: { type: string; toolName?: string }): void\n /** The hint that fired for this turn, if any. */\n readonly fired: EscalationHint | null\n}\n\n/** One speculator per turn. */\nexport function createEscalationSpeculator(options: EscalationSpeculatorOptions): EscalationSpeculator {\n const tools = new Set<string>(options.escalationTools ?? DEFAULT_ESCALATION_TOOLS)\n let fired: EscalationHint | null = null\n\n const speculate = (hint: EscalationHint): void => {\n if (options.mode === 'off' || fired) return\n fired = hint\n try {\n options.onSpeculate?.(hint)\n } catch {\n // Observability must not change the turn.\n }\n // Fire and forget: a warm never gates or fails the turn.\n void options.leases.signal(options.boxKey, 'escalation-likely').catch(() => undefined)\n }\n\n return {\n onInput(input) {\n const hint = escalationHints(input)[0]\n if (hint) speculate(hint)\n },\n onEvent(event) {\n if (event.type === 'tool_call_start' && event.toolName && tools.has(event.toolName)) speculate('tool-call-start')\n },\n get fired() {\n return fired\n },\n }\n}\n"],"mappings":"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","names":["fail","DEFAULT_TIMEOUT_MS","fail","errText","SAFE_IDENTIFIER","value","credentials","retryAfterMs","res","refreshed","runtimeEnv","box","harness"]}