From 0b62c736a0ca097469e215739e61aa7832f1d3da Mon Sep 17 00:00:00 2001 From: Devin Foley Date: Thu, 15 Oct 2026 14:05:26 -0700 Subject: [PATCH] feat(connections): add generic Daytona API and Toolbox access (#16483) ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Apps connections give agents controlled access to external services. > - Daytona provides sandbox, file, command, Git, and account APIs. > - Operators need to assign this access without exposing a server credential. > - A small task-specific tool list cannot serve general Daytona work. > - This pull request adds the published HTTP actions through the existing connection gateway. > - Operators keep control of identity, agent access, and each action. ## Linked Issues or Issue Description **Problem or motivation** Paperclip has a Daytona sandbox provider for its own execution infrastructure. It lacks a normal Apps connection for agents to manage an operator's Daytona account. Reusing the server's provider credential would bypass normal connection ownership and action permissions. **Proposed solution** Add a Daytona connection with personal or shared vault credentials. Generate its action catalog from the official platform and Toolbox API specifications. Use the existing run-bound gateway, grants, action policies, approvals, revocation, and audit paths. Sandbox IDs come from Daytona; tools need no Paperclip task or lease ID. **Alternatives considered** A four-action diagnostic subset cannot support general provider work. Launching the provider CLI would expose host filesystem behavior. Native OAuth is not included because a supported third-party registration path was not verified. The native method uses an organization API key. Existing Composio setup is a separate possible OAuth route and is not qualified by this change. **Roadmap alignment** This extends the existing Apps and Connections provider coverage in `ROADMAP.md`. It uses that system's credential and permission model. GitHub searches found no existing Daytona Apps connector PR or issue. ## What Changed - Add the Daytona catalog entry, provider source override, official theme logos, permission review, and setup documentation. - Generate 274 HTTP actions: 169 platform and 105 Toolbox operations. Record two WebSocket upgrades separately; do not advertise them as HTTP tools. Record source URLs and hashes. - Add provider-focused execution for sandboxes, snapshots, volumes, files, Git, commands, computer use, and account resources. Provider authority still limits which endpoints accept an organization key. - Validate action arguments. Resolve Toolbox targets through the fixed platform API. Check sandbox identity and organization before using an approved Daytona proxy. Keep normal guarded network requests and vault resolution. - Transfer file bytes without reading or writing host files. Share one caller deadline across prerequisite reads, dispatch, and response reading. Bound requests and responses. Do not automatically retry writes with unknown outcomes. Redact the selected credential from results and errors. - Classify credential access, access changes, interactive input, command execution, file permissions, and deletion (including TTL and auto-delete) as destructive actions. Keep new and changed actions under catalog review. - Upgrade saved catalogs and retire the earlier diagnostic names. Hide retired actions from the UI and agent discovery even when provider refresh fails. Preserve existing action choices and historical records. Reject stale same-name contracts during agent discovery and dispatch before a board refresh. - Add database-backed gateway and catalog-upgrade regressions, schema generator tests, a browser setup check, and both capability map updates. ## Verification - Passed on the review-fix head: 57 focused Vitest cases (18 Daytona database/client cases, five HTTP boundary cases, and 34 shared catalog cases), four generator tests, `pnpm -r typecheck`, and `pnpm build`. The five HTTP cases use a real local server through the pinned production transport. The normal browser setup check and 17 generator/artwork cases passed on the initial PR head; those UI and artwork paths are unchanged. - Passed on this branch: brand asset validation, token gates, map structure checks, and `git diff --check`. All latest-head GitHub checks pass on `ea979ccb3a64dc9508807823540f935c4316ea35`. Apex is 5/5, with all five findings addressed and zero unresolved threads. The branch has no merge conflicts. - The initial catalog-generation command could not find the external research corpus. The supported `--definitions-only` mode regenerated the definitions successfully. Unrelated generated drift was excluded. - An earlier full local Vitest attempt on the preview branch failed when bundled PostgreSQL could not start on macOS. After replay onto current master, all three unchanged event-sequencing cases pass with bundled PostgreSQL; the earlier startup cause remains uncertain. - The first full-suite command on this branch used my external test database override. Chat fixtures require a current migrated schema and failed because `agents.lifecycle_state` was absent in that disposable database. A focused comparison reproduces failure with the override and passes with normal setup. That attempt was stopped, and the full suite restarted without the override. Focused Daytona cases use their own migrated PostgreSQL 16 databases. - The clean local full-suite attempt recorded embedded PostgreSQL startup failures in two unchanged native-runtime cases and two failures in unchanged Git fixtures. It was stopped after these failures were isolated; no full local suite pass is claimed. The 15 matching native-runtime cases pass separately. The Git cases fail with the local `init.defaultBranch=main` setting and pass with `GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=init.defaultBranch GIT_CONFIG_VALUE_0=master` limited to the test command. No global Git setting was changed. Full Linux CI is green. - Fixtures use real database persistence and run-bound gateway sessions with provider responses replaced by fixtures. They cover personal/shared vault ownership, reads and writes, file bytes, Off policies, revocation, organization mismatch, untrusted proxy rejection, output bounds, saved catalog upgrades, failed refresh, and permission preservation. - The first Apex review found five valid issues: multipart transport compatibility, destructive classification, caller deadlines, audit filters, and stale saved contracts. All five were fixed with regressions before the second review. A typecheck then found the nullable saved schema hash; admission now accepts that stored type and rejects null as stale. - The browser check covers setup controls without submitting a provider key. No real Daytona account, provider write, native OAuth flow, or agent model run is qualified. Live provider read/write proof remains pending a test account. ## Risks - Daytona keys have broad Toolbox authority, including keys with no selected resource scopes. Only assign this connection to trusted agents and review its action permissions. - Remote writes or commands can continue after a timeout. Calls do not automatically retry an uncertain outcome. - The bridge targets Daytona Cloud. Proxy hosts are restricted; an unrecognized future regional host fails closed. - Files and responses have an 8 MiB bound. Each action has one caller deadline, capped at 30 seconds across all provider requests and response reading. Interactive WebSocket sessions are not exposed as HTTP actions. - The generated JSON snapshot exceeds 1,000 lines because it holds the provider input contracts. Generator logic and execution code remain in separate small modules. Updates require explicit regeneration and catalog review. - No database migration or lockfile change is required. ## Model Used OpenAI Codex, GPT-6. The runtime identifies the model family but does not expose the exact backend model ID or context window. Used reasoning, repository inspection, code editing, shell tools, database verification, and browser tests. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip --- doc/connections/DAYTONA.md | 146 + .../tool-method-permission-reviews.json | 18 + maps/agent-access-map/app-permissions.md | 9 + maps/agent-access-map/connection-setup.md | 7 + maps/feature-map/app-permissions.md | 7 + maps/feature-map/connection-setup.md | 7 + .../shared/src/app-definitions.generated.ts | 7 +- packages/shared/src/app-definitions.test.ts | 2 +- packages/shared/src/app-definitions.ts | 1 + .../shared/src/app-definitions/daytona.json | 75 + scripts/app-definition-overrides/daytona.json | 75 + scripts/generate-daytona-tools.mjs | 142 + scripts/generate-daytona-tools.test.mjs | 53 + .../src/__tests__/daytona-connection.test.ts | 269 + .../__tests__/daytona-http-boundary.test.ts | 110 + server/src/routes/tool-access.ts | 2 +- server/src/services/daytona.ts | 258 + .../daytona/operations.generated.json | 15822 ++++++++++++++++ server/src/services/tool-access.ts | 92 +- server/src/services/tool-catalog-hash.ts | 37 + server/src/services/tool-gateway.ts | 22 +- tests/e2e/daytona-connector.spec.ts | 25 + ui/public/brands/apps/daytona-dark.svg | 1 + ui/public/brands/apps/daytona.svg | 1 + ui/public/brands/apps/manifest.json | 7 + 25 files changed, 17140 insertions(+), 55 deletions(-) create mode 100644 doc/connections/DAYTONA.md create mode 100644 packages/shared/src/app-definitions/daytona.json create mode 100644 scripts/app-definition-overrides/daytona.json create mode 100644 scripts/generate-daytona-tools.mjs create mode 100644 scripts/generate-daytona-tools.test.mjs create mode 100644 server/src/__tests__/daytona-connection.test.ts create mode 100644 server/src/__tests__/daytona-http-boundary.test.ts create mode 100644 server/src/services/daytona.ts create mode 100644 server/src/services/daytona/operations.generated.json create mode 100644 server/src/services/tool-catalog-hash.ts create mode 100644 tests/e2e/daytona-connector.spec.ts create mode 100644 ui/public/brands/apps/daytona-dark.svg create mode 100644 ui/public/brands/apps/daytona.svg diff --git a/doc/connections/DAYTONA.md b/doc/connections/DAYTONA.md new file mode 100644 index 00000000000..d8cdd65cea0 --- /dev/null +++ b/doc/connections/DAYTONA.md @@ -0,0 +1,146 @@ +# Daytona connection + +Daytona uses the normal Apps connection, selected personal/company credential, +agent installation, action policy, gateway, revocation and audit paths. The API +key stays in the instance vault. The connector does not borrow sandbox-provider +environment credentials or another connection's credential. + +Sign-in tokens are never reused as resource tokens; id.paperclip.ing never +stores resource tokens; no connections hub on the ID service. + +## Connect and test + +Choose **Connectors โ†’ Daytona โ†’ Add key**, select access, and enter a Daytona +organization API key. Give that key the read, write, and delete permissions for +the resources you intend to manage. An optional organization ID under Advanced +pins the credential to its organization. Setup verifies `GET /api-keys/current`. +Use the saved connection's ordinary Permissions screen to choose agents and set +actions to Allowed, Ask first, or Off. + +This is a provider-focused connector. Sandbox IDs and names come from Daytona; +no Paperclip task, run, or environment lease is required. Granting access to this +connection grants access to the provider resources its credential can reach. +Some user/account and administrator operations require extra provider authority +or user authentication and will reject an API key. Paperclip does not fall back +to another identity when Daytona denies access. + +## Complete published HTTP action catalog + +The catalog contains **274 actions** from Daytona's published specifications: +169 platform API operations and 105 Toolbox operations. It includes sandbox +creation, start/stop/recovery/deletion, snapshots, volumes, files and transfers, +Git, commands and sessions, computer use, organization/account administration, +and provider telemetry queries. These provider telemetry tools do not emit +Paperclip first-party telemetry. + +Actions have provider names such as `daytona_api_list_sandboxes`, +`daytona_api_create_sandbox`, `daytona_toolbox_execute_command`, and +`daytona_toolbox_download_file`. The generated schemas retain the provider's +path/query/body arguments and required fields. Toolbox actions also take a +`sandboxId`. Returned provider objects are not reduced to Paperclip task data. +The selected connection credential is redacted from results and errors. + +| Action group | Permission classification | +| --- | --- | +| Ordinary reads, file downloads, and read-only lookups | Read | +| Resource creation, file/Git changes, lifecycle and configuration changes | Write | +| Deletion (including TTL/auto-delete), command/code/interactive input, reset/restore, secret/credential access, signed access links and file/account access changes | Destructive | + +The source inventory also records **two WebSocket upgrade endpoints**: +interactive interpreter execution and PTY connection. These are streaming +protocol connections, not ordinary HTTP/MCP request-response tools. They are +not advertised as nonfunctional actions. The command/code and session tools +provide the corresponding request-response execution paths. + +The API and Toolbox specification sources and SHA-256 hashes are recorded in +`server/src/services/daytona/operations.generated.json`. Regenerate with: + +```sh +node scripts/generate-daytona-tools.mjs +node --test scripts/generate-daytona-tools.test.mjs +``` + +The large generated JSON file is one provider contract snapshot. Its generator +and invocation implementation stay separate from it; no runtime network discovery +or unbounded schema copying occurs on the server's startup path. + +## Credential and transport boundary + +The platform API endpoint is fixed to `https://app.daytona.io/api`. Toolbox +calls resolve the sandbox through that API, verify its exact ID/name and +organization, and accept only reviewed Daytona cloud proxy hostnames and the +`/toolbox` path. Every request still uses the normal DNS-pinned egress guard. +Redirects are rejected. Action arguments cannot replace Authorization or the +organization header. Generic credential export rejects Daytona. + +File uploads take base64 bytes; downloads return bytes with content type and +length. The connector never reads a local host file path, writes host files, +launches the Daytona CLI, or executes commands on the Paperclip server. Provider +commands execute inside the selected Daytona sandbox. Reads and transfers have +an 8 MiB bound. An action shares one deadline across identity, target lookup, +dispatch, and response reading: the caller's budget, capped at 30 seconds. +Expiry blocks later dispatches and cancels active requests. Mutations are never +retried automatically. A timed-out command or write can still be running at the +provider; inspect it before retrying. + +Daytona does not provide a diagnostic-only runtime key: every valid organization +key can access running sandboxes through the Toolbox, even with no selected +resource scopes. Treat this as broad provider access. Agent assignment and action +permissions enforce the capability boundary; a read grant is not permission to +run a command or delete a sandbox. + +## OAuth research + +The native connection currently uses an API key. Daytona's CLI supports browser +sign-in, but its published configuration uses Daytona's own first-party AuthKit +clients. The public issuer metadata does not advertise client registration, and +a supported third-party OAuth app registration path was not verified. The +connector does not borrow those client IDs, copy CLI sign-in tokens, or invent a +native OAuth consent flow. + +Composio advertises managed OAuth for its Daytona toolkit. That is a separate +existing provider route: connect Composio through its ordinary connection flow, +then configure its Daytona app. Its auth configuration and account entitlements +must be verified through that provider's live setup. This native connector does +not require Composio or forward its credential to Composio. A marketing listing +is not proof that this instance completed Daytona OAuth. + +## Validation and limits + +Database-backed tests exercise company and personal vault ownership, real +run-scoped gateway reads and writes, file bytes, action denial, revocation, +foreign-account rejection, untrusted proxy rejection, all generated argument +schemas, and bounded/sanitized errors. Generator tests account for HTTP operations +and protocol upgrades and preserve recursive input definitions. + +These fixtures do not qualify a real Daytona account. Live provider proof is +pending an operator connecting a key and trying an allowed read and write. No +platform key or live provider credential is installed by this change. Existing +saved connections must review the expanded catalog through normal Permissions; +new actions do not inherit approval from the previous four diagnostic actions. +Opening a saved Daytona connection upgrades an outdated catalog. The earlier +Paperclip-specific actions are retired and hidden from both Permissions and +agent discovery, even if a provider outage prevents refresh. Historical rows +remain for audit, and newly discovered actions require review. +Agent discovery and dispatch also check same-name saved contracts against the +deployed schema and risk classification. An outdated action cannot execute +while it waits for a human to open Permissions and review the change. + +The HTTP boundary tests use a real local server and the pinned transport to +check multipart uploads, audit filter encoding, response cancellation, and +unrelated request responsiveness. The provider network/TLS leg is simulated; +these checks do not replace live account proof. + +Provider research verified 2026-10-15: + +- https://www.daytona.io/docs/en/api-keys/ +- https://www.daytona.io/docs/en/tools/api/ +- https://www.daytona.io/docs/openapi.json +- https://www.daytona.io/docs/toolbox-openapi.json +- https://github.com/daytona/clients/tree/main/cli/mcp +- https://composio.dev/toolkits/daytona +- https://www.daytona.io/brand + +Official square logo assets are copied unchanged from +`https://framerusercontent.com/images/k2z1jCEWqymEd7reVoRseEVMFHU.svg` and +`https://framerusercontent.com/images/JjrFl7J2k84ANwYg3pD9Hwilc.svg`. diff --git a/doc/connections/tool-method-permission-reviews.json b/doc/connections/tool-method-permission-reviews.json index eb07d0400df..eaa8114a565 100644 --- a/doc/connections/tool-method-permission-reviews.json +++ b/doc/connections/tool-method-permission-reviews.json @@ -2668,6 +2668,24 @@ "reviewedAt": "2026-10-09", "liveProof": "Paperclip Apps qualification passed: connected the public-mcp method from the natural Connectors catalog; initialization/discovery showed exactly 4 Read actions and 0 Write actions. Restricted agent access to Just agents I pick with 0 selected; the public method requires no identity. A bounded hf_fs search of hf://docs for MCP with limit 3 succeeded (3 public doc entries; UI preview reported one successful result row) in 0.7s. After reload, the page still showed Connected, 4 actions, Read 4, Write 0, and no agents can use this connection; the same query succeeded again in 0.8s. The Test dialog reported the direct call ran as Connector Tester; no heartbeat/agent execution or other provider tool call occurred.", "evidenceLimit": "Qualification used only public documentation and did not use a Hugging Face account, OAuth, API key, private repo, write, inference, Space execution, or job. Anonymous endpoint was directly probed separately and returned 4 read tools, matching Paperclip discovery. The setup flow says no identity required; a one-member human audience was saved before reload, but human identity controls were not shown after reload. A root browser inspection confirmed four read actions and zero agents selected; a privacy-safe permissions screenshot was saved. Rate limits and later provider catalog changes remain outside this proof." + }, + { + "app": "daytona", + "method": "workspace-diagnostics", + "auth": "api_key", + "policy": "provider-key", + "requestedScopes": [], + "capability": "write", + "supportedActions": "All published Daytona HTTP API and Toolbox operations: account and organization resources, sandbox lifecycle, files, Git, commands, sessions, snapshots, volumes, computer use, and telemetry reads. Provider permissions still apply.", + "evidence": [ + "https://www.daytona.io/docs/en/api-keys/", + "https://www.daytona.io/docs/openapi.json", + "https://www.daytona.io/docs/toolbox-openapi.json", + "https://github.com/daytona/clients/tree/main/cli/mcp" + ], + "reviewedAt": "2026-10-15", + "liveProof": "not-run", + "keyPermissions": "Create an organization key with the read, write, and delete permissions for the resources you intend to manage. Daytona toolbox access is available to every valid organization key, even without selected scopes. Some user or administration endpoints require provider user authentication and will reject an API key." } ] } diff --git a/maps/agent-access-map/app-permissions.md b/maps/agent-access-map/app-permissions.md index e6d7f106a87..1b9e3ebdfcd 100644 --- a/maps/agent-access-map/app-permissions.md +++ b/maps/agent-access-map/app-permissions.md @@ -82,6 +82,15 @@ own policy and access review. Gaps: Catalog refresh/review and quarantined-action enablement are management operations. +Daytona also checks its deployed native contract on the board's +`GET /api/tool-connections/{connectionId}/catalog`. A changed saved catalog +refreshes under the viewing human's credential context. Retired tools are +hidden even if refresh fails. Agent discovery and dispatch reject retired names +and stale same-name contracts before refresh; new/changed tools stay quarantined until reviewed. The +[database-backed Daytona fixtures](../../server/src/__tests__/daytona-connection.test.ts) +exercise this boundary through real run-bound gateway sessions with fixture +provider responses. They do not qualify a live Daytona account or agent model. + ## `test-action` Review: `baseline`. diff --git a/maps/agent-access-map/connection-setup.md b/maps/agent-access-map/connection-setup.md index dc93187f5d0..db544eca52f 100644 --- a/maps/agent-access-map/connection-setup.md +++ b/maps/agent-access-map/connection-setup.md @@ -83,6 +83,13 @@ remaining operations before qualifying the whole capability. Gaps: An initiation endpoint exists; it is not authorization to complete the person's credential flow. +Daytona native setup uses an organization API key in the selected personal or +company vault grant. It does not borrow sandbox-provider credentials or CLI +login tokens. Agents use assigned provider tools through the normal run-bound +gateway; they cannot export the key. [Database-backed fixtures](../../server/src/__tests__/daytona-connection.test.ts) +cover selected vault ownership and gateway reads/writes with provider responses +replaced by fixtures. Real provider authentication remains unqualified. + ## `handoff` Review: `baseline`. diff --git a/maps/feature-map/app-permissions.md b/maps/feature-map/app-permissions.md index 521ca22fec0..291d2b0bcb1 100644 --- a/maps/feature-map/app-permissions.md +++ b/maps/feature-map/app-permissions.md @@ -44,6 +44,13 @@ Automated: [app detail tests](../../ui/src/pages/apps/AppDetail.test.tsx) cover Manual: Run a read-only action with explicit inputs and inspect returned data and activity. Refresh discovery and review new actions. Revoke or disconnect only the disposable credential, then verify subsequent use fails with an actionable reconnect state. +For Daytona, opening an older saved catalog discovers the current native +contract. Removed diagnostic actions disappear from Permissions and agent +discovery; new or changed actions require review. Existing Off/Allowed choices +remain in place. [Daytona regressions](../../server/src/__tests__/daytona-connection.test.ts) +cover shared/personal catalog upgrades, failed refresh, permission preservation, +run-bound file transfers, and revocation with fixture provider responses. + ## Gotchas - Connected does not imply an agent has access or an action is allowed. diff --git a/maps/feature-map/connection-setup.md b/maps/feature-map/connection-setup.md index f818fded54c..ffe815d8fd7 100644 --- a/maps/feature-map/connection-setup.md +++ b/maps/feature-map/connection-setup.md @@ -92,6 +92,13 @@ saved connection. Run a permitted read-only action with an eligible agent and verify its useful result. Try an ineligible agent and confirm denial. Repeat with a user who cannot install company-wide; the UI must not imply broad access. +Daytona follows this same key/access wizard. Its native method exposes the +published platform and Toolbox HTTP actions using provider sandbox IDs, without +a Paperclip task or lease requirement. [Daytona browser setup](../../tests/e2e/daytona-connector.spec.ts) +checks the catalog, password field, access controls, and optional organization +pin. It does not submit a key or qualify a real provider account. See +[Daytona](../../doc/connections/DAYTONA.md) for API-key authority and OAuth limits. + ### `mcp-link` Automated: AppsConnect's generic MCP cases cover probe-driven auth, private or diff --git a/packages/shared/src/app-definitions.generated.ts b/packages/shared/src/app-definitions.generated.ts index d1a5d262491..1666fb5c280 100644 --- a/packages/shared/src/app-definitions.generated.ts +++ b/packages/shared/src/app-definitions.generated.ts @@ -99,7 +99,8 @@ import a97 from "./app-definitions/responses-api.json" with { type: "json" }; import a98 from "./app-definitions/messages-api.json" with { type: "json" }; import a99 from "./app-definitions/chat-completions-api.json" with { type: "json" }; import a100 from "./app-definitions/local.json" with { type: "json" }; -import a101 from "./app-definitions/monday.json" with { type: "json" }; -import a102 from "./app-definitions/speko.json" with { type: "json" }; +import a101 from "./app-definitions/daytona.json" with { type: "json" }; +import a102 from "./app-definitions/monday.json" with { type: "json" }; +import a103 from "./app-definitions/speko.json" with { type: "json" }; import type { AppDefinition } from "./types/app-definition.js"; -export const APP_DEFINITIONS=[a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31,a32,a33,a34,a35,a36,a37,a38,a39,a40,a41,a42,a43,a44,a45,a46,a47,a48,a49,a50,a51,a52,a53,a54,a55,a56,a57,a58,a59,a60,a61,a62,a63,a64,a65,a66,a67,a68,a69,a70,a71,a72,a73,a74,a75,a76,a77,a78,a79,a80,a81,a82,a83,a84,a85,a86,a87,a88,a89,a90,a91,a92,a93,a94,a95,a96,a97,a98,a99,a100,a101,a102] as AppDefinition[]; +export const APP_DEFINITIONS=[a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31,a32,a33,a34,a35,a36,a37,a38,a39,a40,a41,a42,a43,a44,a45,a46,a47,a48,a49,a50,a51,a52,a53,a54,a55,a56,a57,a58,a59,a60,a61,a62,a63,a64,a65,a66,a67,a68,a69,a70,a71,a72,a73,a74,a75,a76,a77,a78,a79,a80,a81,a82,a83,a84,a85,a86,a87,a88,a89,a90,a91,a92,a93,a94,a95,a96,a97,a98,a99,a100,a101,a102,a103] as AppDefinition[]; diff --git a/packages/shared/src/app-definitions.test.ts b/packages/shared/src/app-definitions.test.ts index bbe8d1cf8ee..6cc868cf6ce 100644 --- a/packages/shared/src/app-definitions.test.ts +++ b/packages/shared/src/app-definitions.test.ts @@ -884,7 +884,7 @@ describe("AppDefinition catalog", () => { "ticktick", "xero", ]); - expect(APP_STORE_DEFINITIONS).toHaveLength(80); + expect(APP_STORE_DEFINITIONS).toHaveLength(81); const connectableSlugs = new Set( CONNECTABLE_APP_DEFINITIONS.map((entry) => entry.slug), ); diff --git a/packages/shared/src/app-definitions.ts b/packages/shared/src/app-definitions.ts index e1f56841a94..40d56a9453a 100644 --- a/packages/shared/src/app-definitions.ts +++ b/packages/shared/src/app-definitions.ts @@ -8,6 +8,7 @@ export const CONNECTABLE_APP_SLUGS = new Set([ "responses-api", "messages-api", "chat-completions-api", "local", "agentmail", "browser-use-cloud", + "daytona", "cognee", ...SELF_SERVE_MCP_CANDIDATES.map((entry) => entry.slug), "monday", diff --git a/packages/shared/src/app-definitions/daytona.json b/packages/shared/src/app-definitions/daytona.json new file mode 100644 index 00000000000..5ee359cd655 --- /dev/null +++ b/packages/shared/src/app-definitions/daytona.json @@ -0,0 +1,75 @@ +{ + "schemaVersion": 1, + "slug": "daytona", + "name": "Daytona", + "description": "Manage Daytona sandboxes, files, commands, Git, snapshots, volumes, and account resources.", + "categories": [ + "developer" + ], + "featured": false, + "branding": { + "logoUrl": "/brands/apps/daytona.svg", + "darkLogoUrl": "/brands/apps/daytona-dark.svg" + }, + "urlPatterns": [ + "https://app.daytona.io/*" + ], + "methods": [ + { + "key": "workspace-diagnostics", + "transport": "rest_api", + "auth": "api_key", + "ownershipModes": [ + "customer" + ], + "whenToUse": "Manage resources and run tools in your Daytona account.", + "defaults": { + "serverUrl": "https://app.daytona.io/api" + }, + "guidanceMd": "Connect a Daytona organization API key. All published HTTP API and Toolbox actions are available; the key's provider permissions and your action policies control access. Sandbox IDs come directly from Daytona.", + "riskTier": "S4", + "label": "Connect Daytona", + "credentialFields": [ + { + "key": "authorization", + "label": "Daytona API key", + "type": "password", + "required": true, + "placeholder": "Enter Daytona API key", + "secret": true, + "helperMd": "Create an organization key with the read, write, and delete permissions for the resources you intend to manage. Daytona toolbox access is available to every valid organization key, even without selected scopes. Some user or administration endpoints require provider user authentication and will reject an API key." + } + ], + "keyPlacement": { + "location": "header", + "name": "Authorization", + "prefix": "Bearer " + }, + "tenantFields": [ + { + "key": "organizationId", + "label": "Pin to organization ID", + "type": "text", + "advanced": true, + "helperMd": "Optional. Reject a key or sandbox from a different Daytona organization.", + "validation": { + "pattern": "^[a-fA-F0-9-]{36}$", + "maxLength": 36 + } + } + ], + "requiredResourceFilters": [ + "organization", + "sandbox" + ], + "consoleLinks": { + "keys": "https://app.daytona.io/dashboard/keys", + "docs": "https://www.daytona.io/docs/en/api-keys/" + }, + "warnings": [ + "This connection can run commands, access sandbox files and secrets, create resources, and delete data. Select trusted agents and set action permissions before use. Your Daytona API key stays in the vault." + ] + } + ], + "docsUrl": "https://www.daytona.io/docs/en/sandboxes/" +} diff --git a/scripts/app-definition-overrides/daytona.json b/scripts/app-definition-overrides/daytona.json new file mode 100644 index 00000000000..5ee359cd655 --- /dev/null +++ b/scripts/app-definition-overrides/daytona.json @@ -0,0 +1,75 @@ +{ + "schemaVersion": 1, + "slug": "daytona", + "name": "Daytona", + "description": "Manage Daytona sandboxes, files, commands, Git, snapshots, volumes, and account resources.", + "categories": [ + "developer" + ], + "featured": false, + "branding": { + "logoUrl": "/brands/apps/daytona.svg", + "darkLogoUrl": "/brands/apps/daytona-dark.svg" + }, + "urlPatterns": [ + "https://app.daytona.io/*" + ], + "methods": [ + { + "key": "workspace-diagnostics", + "transport": "rest_api", + "auth": "api_key", + "ownershipModes": [ + "customer" + ], + "whenToUse": "Manage resources and run tools in your Daytona account.", + "defaults": { + "serverUrl": "https://app.daytona.io/api" + }, + "guidanceMd": "Connect a Daytona organization API key. All published HTTP API and Toolbox actions are available; the key's provider permissions and your action policies control access. Sandbox IDs come directly from Daytona.", + "riskTier": "S4", + "label": "Connect Daytona", + "credentialFields": [ + { + "key": "authorization", + "label": "Daytona API key", + "type": "password", + "required": true, + "placeholder": "Enter Daytona API key", + "secret": true, + "helperMd": "Create an organization key with the read, write, and delete permissions for the resources you intend to manage. Daytona toolbox access is available to every valid organization key, even without selected scopes. Some user or administration endpoints require provider user authentication and will reject an API key." + } + ], + "keyPlacement": { + "location": "header", + "name": "Authorization", + "prefix": "Bearer " + }, + "tenantFields": [ + { + "key": "organizationId", + "label": "Pin to organization ID", + "type": "text", + "advanced": true, + "helperMd": "Optional. Reject a key or sandbox from a different Daytona organization.", + "validation": { + "pattern": "^[a-fA-F0-9-]{36}$", + "maxLength": 36 + } + } + ], + "requiredResourceFilters": [ + "organization", + "sandbox" + ], + "consoleLinks": { + "keys": "https://app.daytona.io/dashboard/keys", + "docs": "https://www.daytona.io/docs/en/api-keys/" + }, + "warnings": [ + "This connection can run commands, access sandbox files and secrets, create resources, and delete data. Select trusted agents and set action permissions before use. Your Daytona API key stays in the vault." + ] + } + ], + "docsUrl": "https://www.daytona.io/docs/en/sandboxes/" +} diff --git a/scripts/generate-daytona-tools.mjs b/scripts/generate-daytona-tools.mjs new file mode 100644 index 00000000000..3a0fc13ddb4 --- /dev/null +++ b/scripts/generate-daytona-tools.mjs @@ -0,0 +1,142 @@ +import { createHash } from "node:crypto"; +import { readFile, writeFile, mkdir } from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; + +const sources = { + api: "https://www.daytona.io/docs/openapi.json", + toolbox: "https://www.daytona.io/docs/toolbox-openapi.json", +}; +const verbs = new Set(["get", "post", "put", "patch", "delete", "head", "options"]); +const snake = value => value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toLowerCase(); + +/** Retain only reachable input definitions, rather than copying the whole API + * schema into every action. Provider response schemas are not tool inputs. */ +function inputSchema(value, schemas) { + const definitions = {}; + function visit(node) { + if (Array.isArray(node)) return node.map(visit); + if (!node || typeof node !== "object") return node; + if (node.$ref) { + const prefix = "#/components/schemas/"; + if (!node.$ref.startsWith(prefix)) throw new Error(`Unsupported schema reference: ${node.$ref}`); + const key = node.$ref.slice(prefix.length); + if (!Object.hasOwn(schemas, key)) throw new Error(`Missing schema: ${key}`); + if (!Object.hasOwn(definitions, key)) { + definitions[key] = {}; + definitions[key] = visit(schemas[key]); + } + return { $ref: `#/definitions/${key}`, ...Object.fromEntries(Object.entries(node).filter(([k]) => k !== "$ref").map(([k,v]) => [k,visit(v)])) }; + } + const result = Object.fromEntries(Object.entries(node).filter(([key]) => !["nullable", "example", "xml", "discriminator"].includes(key)).map(([key,child]) => [key,visit(child)])); + if (result.format === "binary") { + delete result.format; + result.contentEncoding = "base64"; + result.description = `${result.description ?? "File bytes"} (base64; never a host file path)`; + } + // OpenAPI formats that Ajv does not define do not constrain JSON values. + if (["int32", "int64", "float", "double", "byte"].includes(result.format)) delete result.format; + return node.nullable ? { anyOf: [result, { type: "null" }] } : result; + } + const root = visit(value); + if (Object.keys(definitions).length) root.definitions = definitions; + return root; +} + +export function generateDaytonaCatalog(specs) { + const tools = []; + const streaming = []; + for (const [kind, spec] of Object.entries(specs)) { + for (const [route, item] of Object.entries(spec.paths)) { + for (const [method, operation] of Object.entries(item)) { + if (!verbs.has(method)) continue; + if (!operation.operationId) throw new Error(`Missing operationId: ${kind} ${method} ${route}`); + const name = `daytona_${kind}_${snake(operation.operationId)}`; + // These are protocol upgrades, not request/response MCP actions. Keep + // them in the inventory so an update cannot silently lose an operation. + if (operation.responses?.["101"]) { + streaming.push({ name, kind, path: route, method: method.toUpperCase(), transport: "websocket" }); + continue; + } + const properties = {}, required = [], parameters = []; + const groups = { path: { type: "object", properties: {}, required: [], additionalProperties: false }, + query: { type: "object", properties: {}, required: [], additionalProperties: false }, + headers: { type: "object", properties: {}, required: [], additionalProperties: false } }; + for (const parameter of [...(item.parameters ?? []), ...(operation.parameters ?? [])]) { + const group = parameter.in === "header" ? "headers" : parameter.in; + if (!groups[group]) throw new Error(`Unsupported parameter: ${name} ${parameter.in}`); + // Organization and invocation authorization come from the selected + // connection, never an action argument. + if (group === "headers" && /^(authorization|cookie|host|x-daytona-organization-id)$/i.test(parameter.name)) continue; + groups[group].properties[parameter.name] = { ...(parameter.schema ?? parameter.content?.["application/json"]?.schema ?? {}), + ...(parameter.description ? { description: parameter.description } : {}) }; + if (parameter.required) groups[group].required.push(parameter.name); + // The audit API documents bracket-key filters despite declaring form + // style for its referenced filter objects in the OpenAPI document. + const auditFilter = kind === "api" && operation.operationId === "getOrganizationAuditLogs" + && group === "query" && /Filter$/.test(parameter.schema?.$ref ?? ""); + parameters.push({ name: parameter.name, group, style: auditFilter ? "deepObject" : parameter.style ?? "form", explode: parameter.explode ?? true, + json: Boolean(parameter.content?.["application/json"]) }); + } + for (const [group, schema] of Object.entries(groups)) { + if (!Object.keys(schema.properties).length) continue; + properties[group] = schema; + if (schema.required.length) required.push(group); + } + if (kind === "toolbox") { properties.sandboxId = { type: "string", minLength: 1, maxLength: 200 }; required.push("sandboxId"); } + const content = operation.requestBody?.content ?? {}; + let bodyContentType = Object.hasOwn(content, "application/json") ? "application/json" : Object.keys(content)[0]; + if (bodyContentType) { + properties.body = content[bodyContentType].schema ?? {}; + if (operation.requestBody.required) required.push("body"); + } + // Daytona's bulk upload endpoint omits its multipart body from the + // OpenAPI input. Its published SDK supplies repeated file parts whose + // filename is the destination path. No host filesystem is exposed. + if (kind === "toolbox" && operation.operationId === "UploadFiles") { + bodyContentType = "multipart/form-data"; + properties.files = { type: "array", minItems: 1, maxItems: 100, items: { type: "object", additionalProperties: false, + properties: { path: { type: "string", minLength: 1 }, contentBase64: { type: "string", contentEncoding: "base64" } }, + required: ["path", "contentBase64"] } }; + required.push("files"); + } + const sensitive = /signing.?key|secrets?|push.?access|api.?key|credentials|ssh.?access|signed.?port.?preview|admin.?portal|app.?portal/i.test(operation.operationId) + || /\/(secret|docker-registry)(\/|$)/.test(route); + const readOnly = (method === "get" || method === "head" || ["DownloadFiles", "FindAccessibilityNodes", "Completions"].includes(operation.operationId)) && !sensitive; + const accessChange = !readOnly && /\/(roles|invitations|identity-providers|linked-accounts|pending-sso-links)(\/|$)|\/users\/[^/]+\/access$/.test(route); + const interactiveInput = kind === "toolbox" && !readOnly + && (/^\/computeruse\//.test(route) || route === "/process/pty" || /\/command\/[^/]+\/input$/.test(route)); + const destructive = method === "delete" || sensitive || accessChange || interactiveInput + || /execute|code.?run|push.?changes|reset.?changes|restore.?files|initialize|update.?env|public.?status|network.?settings|authenticate|set.?ttl|auto.?delete|file.?permissions/i.test(operation.operationId); + tools.push({ name, kind, path: route, method: method.toUpperCase(), parameters, + ...(bodyContentType ? { bodyContentType } : {}), + title: operation.summary || operation.operationId, + description: operation.description || operation.summary || operation.operationId, + inputSchema: inputSchema({ type: "object", additionalProperties: false, properties, required }, spec.components?.schemas ?? {}), + annotations: { readOnlyHint: readOnly, destructiveHint: destructive, idempotentHint: readOnly, openWorldHint: true } }); + } + } + } + const names = tools.map(tool => tool.name); + if (new Set(names).size !== names.length) throw new Error("Duplicate Daytona action name"); + return { tools, streaming }; +} + +async function main() { + const inputIndex = process.argv.indexOf("--input-dir"); + const inputDir = inputIndex < 0 ? undefined : process.argv[inputIndex + 1]; + const specs = {}, provenance = {}; + for (const [kind, url] of Object.entries(sources)) { + const raw = inputDir ? await readFile(path.join(inputDir, `daytona-${kind}-openapi.json`)) + : Buffer.from(await (await fetch(url)).arrayBuffer()); + specs[kind] = JSON.parse(raw.toString("utf8")); + provenance[kind] = { url, sha256: createHash("sha256").update(raw).digest("hex") }; + } + const output = { schemaVersion: 1, sources: provenance, ...generateDaytonaCatalog(specs) }; + const target = fileURLToPath(new URL("../server/src/services/daytona/operations.generated.json", import.meta.url)); + await mkdir(path.dirname(target), { recursive: true }); + await writeFile(target, JSON.stringify(output, null, 2) + "\n"); + console.log(`Generated ${output.tools.length} Daytona actions; recorded ${output.streaming.length} protocol upgrade endpoints.`); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) await main(); diff --git a/scripts/generate-daytona-tools.test.mjs b/scripts/generate-daytona-tools.test.mjs new file mode 100644 index 00000000000..d0715820049 --- /dev/null +++ b/scripts/generate-daytona-tools.test.mjs @@ -0,0 +1,53 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { generateDaytonaCatalog } from "./generate-daytona-tools.mjs"; + +test("accounts for every HTTP operation and protocol upgrade without dropping methods", () => { + const result = generateDaytonaCatalog({ api: { paths: { + "/sandbox": { get: { operationId: "listSandboxes" }, post: { operationId: "createSandbox" } }, + "/stream": { get: { operationId: "stream", responses: { 101: {} } } }, + } } }); + assert.deepEqual(result.tools.map(t => t.name), ["daytona_api_list_sandboxes", "daytona_api_create_sandbox"]); + assert.equal(result.tools[0].annotations.readOnlyHint, true); + assert.equal(result.tools[1].annotations.readOnlyHint, false); + assert.equal(result.streaming.length, 1); +}); + +test("retains reachable recursive input definitions and replaces file paths with bytes", () => { + const result = generateDaytonaCatalog({ toolbox: { paths: { "/files": { post: { operationId: "UploadFile", + requestBody: { required: true, content: { "multipart/form-data": { schema: { $ref: "#/components/schemas/File" } } } } } } }, + components: { schemas: { File: { type: "object", properties: { file: { type: "string", format: "binary" }, + next: { $ref: "#/components/schemas/File" } } }, Unused: { type: "string" } } } } }); + const schema = result.tools[0].inputSchema; + assert.equal(schema.definitions.File.properties.file.contentEncoding, "base64"); + assert.equal(schema.definitions.File.properties.next.$ref, "#/definitions/File"); + assert.equal(schema.definitions.Unused, undefined); + assert.ok(schema.required.includes("sandboxId")); +}); + +test("never lets action arguments override selected connection authorization", () => { + const result = generateDaytonaCatalog({ api: { paths: { "/sandbox": { get: { operationId: "listSandboxes", + parameters: [{ name: "Authorization", in: "header", schema: { type: "string" } }, + { name: "X-Daytona-Organization-ID", in: "header", schema: { type: "string" } }] } } } } }); + assert.equal(result.tools[0].parameters.length, 0); + assert.equal(result.tools[0].inputSchema.properties.headers, undefined); +}); + +test("requires destructive permission for credentials, access changes, and interactive execution", () => { + const result = generateDaytonaCatalog({ api: { paths: { + "/secret/{id}": { get: { operationId: "getSecret" } }, + "/organizations/{id}/roles": { post: { operationId: "createRole" } }, + "/sandbox/{id}/ports/{port}/signed-preview-url": { get: { operationId: "getSignedPortPreviewUrl" } }, + "/sandbox/{id}/ttl/{minutes}": { post: { operationId: "setTtl" } }, + "/sandbox/{id}/autodelete/{interval}": { post: { operationId: "setAutoDeleteInterval" } }, + } }, toolbox: { paths: { + "/computeruse/keyboard/type": { post: { operationId: "TypeText" } }, + "/process/session/{sessionId}/command/{commandId}/input": { post: { operationId: "SendInput" } }, + "/process/pty": { post: { operationId: "CreatePtySession" } }, + "/files/permissions": { post: { operationId: "SetFilePermissions" } }, + } } }); + for (const tool of result.tools) { + assert.equal(tool.annotations.readOnlyHint, false, tool.name); + assert.equal(tool.annotations.destructiveHint, true, tool.name); + } +}); diff --git a/server/src/__tests__/daytona-connection.test.ts b/server/src/__tests__/daytona-connection.test.ts new file mode 100644 index 00000000000..b4e2b90c40e --- /dev/null +++ b/server/src/__tests__/daytona-connection.test.ts @@ -0,0 +1,269 @@ +import { randomUUID } from "node:crypto"; +import { and, eq } from "drizzle-orm"; +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; +import { agents, companies, companyMemberships, companySecrets, connectionGrants, createDb, + ensurePostgresDatabase, applyPendingMigrations, heartbeatRuns, issues, toolCatalogEntries, toolConnections } from "@paperclipai/db"; +import { toolAccessService } from "../services/tool-access.js"; +import { createToolGatewayService } from "../services/tool-gateway.js"; +import { DAYTONA_API_URL, DAYTONA_TOOLS, daytonaClient, executeDaytonaTool } from "../services/daytona.js"; +import { getEmbeddedPostgresTestSupport, startEmbeddedPostgresTestDatabase } from "./helpers/embedded-postgres.js"; + +const external = process.env.PAPERCLIP_TEST_DATABASE_URL; +const support = external ? { supported: true } : await getEmbeddedPostgresTestSupport(); +const actor = { actorType: "user" as const, actorId: "daytona-reviewer" }; +const credential = "daytona-fixture-secret"; +(support.supported ? describe : describe.skip)("Daytona governed provider actions", () => { + let db: ReturnType; + let temp: Awaited> | undefined; + beforeAll(async () => { + if (external) { + const url = new URL(external); url.pathname = "/daytona_" + randomUUID().replaceAll("-", ""); + await ensurePostgresDatabase(external, url.pathname.slice(1)); + await applyPendingMigrations(url.toString()); db = createDb(url.toString()); + } else { temp = await startEmbeddedPostgresTestDatabase("daytona-connector-"); db = createDb(temp.connectionString); } + }, 30000); + afterAll(async () => { await db?.$client.end(); await temp?.cleanup(); }); + + async function fixture(personal = false) { + const [company] = await db.insert(companies).values({ name: "Daytona fixture", issuePrefix: `D${randomUUID().slice(0, 6)}` }).returning(); + await db.insert(companyMemberships).values({ companyId: company.id, principalType: "user", principalId: actor.actorId, membershipRole: "admin", status: "active" }); + const organizationId = randomUUID(), sandboxId = randomUUID(); + let sandboxOrganization = organizationId, proxy = "https://proxy.app.daytona.io/toolbox"; + const request = vi.fn(async (url: string, init: RequestInit) => { + expect(new Headers(init.headers).get("Authorization")).toBe(`Bearer ${credential}`); + expect(["error", "manual"]).toContain(init.redirect); + const parsed = new URL(url); + if (url === `${DAYTONA_API_URL}/api-keys/current`) return Response.json({ organizationId, key: credential }); + if (parsed.pathname === "/api/sandbox" && init.method === "GET") return Response.json([{ id: sandboxId, name: "External sandbox", organizationId }]); + if (parsed.pathname === "/api/sandbox" && init.method === "POST") return Response.json({ id: sandboxId, organizationId, ...JSON.parse(init.body as string) }); + if (url === `${DAYTONA_API_URL}/sandbox/${sandboxId}`) return init.method === "DELETE" ? new Response(null, { status: 204 }) + : Response.json({ id: sandboxId, name: "External sandbox", organizationId: sandboxOrganization, state: "started", toolboxProxyUrl: proxy }); + if (parsed.pathname === `/toolbox/${sandboxId}/process/execute`) return Response.json({ exitCode: 0, result: `done ${credential}` }); + if (parsed.pathname === `/toolbox/${sandboxId}/files/download`) return new Response("file bytes", { headers: { "Content-Type": "application/octet-stream" } }); + if (parsed.pathname === `/toolbox/${sandboxId}/files/upload-v2`) { + expect(Buffer.isBuffer(init.body)).toBe(true); + const form = await new Response(init.body, { headers: init.headers }).formData(); + expect(await (form.get("file") as Blob).text()).toBe("uploaded bytes"); + return Response.json({ path: parsed.searchParams.get("path") }); + } + throw new Error("Unexpected provider request"); + }); + const service = toolAccessService(db, { remoteHttpRequest: request, remoteHttpEndpointLookup: async () => [{ address: "8.8.8.8", family: 4 }] }); + const connected = await service.connectGalleryApp(company.id, { galleryKey: "daytona", methodKey: "workspace-diagnostics", + ...(personal ? { grantKind: "user" as const } : {}), credentialValues: { "credentials.authorization": credential } }, actor); + const [agent] = await db.insert(agents).values({ companyId: company.id, name: "Maintainer", role: "engineer", adapterType: "process" }).returning(); + await service.finishGalleryAppConnection(company.id, connected.connectionId, { enabledCatalogEntryIds: connected.catalog.map(c => c.id), + askFirstCatalogEntryIds: [], access: { agentIds: [agent.id] } }, actor); + const [issue] = await db.insert(issues).values({ companyId: company.id, title: "Provider work", assigneeAgentId: agent.id }).returning(); + const [run] = await db.insert(heartbeatRuns).values({ companyId: company.id, agentId: agent.id, issueId: issue.id, + scopeKind: "issue", invocationSource: "on_demand", status: "running", responsibleUserId: actor.actorId, contextSnapshot: { issueId: issue.id } }).returning(); + const gateway = createToolGatewayService(db, { remoteHttpRequest: request }); + const session = await gateway.createSession({ companyId: company.id, agentId: agent.id, runId: run.id, issueId: issue.id }); + const tools = await gateway.listToolsForSession(session.token); + const call = (name: string, parameters: unknown, timeoutMs?: number) => { + const tool = tools.find(t => t.upstreamToolName === name); + expect(tool, name).toBeTruthy(); + return gateway.executeTool({ sessionToken: session.token, tool: tool!.name, parameters, timeoutMs, idempotencyKey: randomUUID() }); + }; + return { company, service, connected, agent, request, call, gateway, session, organizationId, sandboxId, + foreignOrganization: () => { sandboxOrganization = randomUUID(); }, foreignProxy: () => { proxy = "https://attacker.example/toolbox"; } }; + } + + it.each([false, true])("uses the selected vault identity for real gateway reads and writes (personal=%s)", async personal => { + const f = await fixture(personal); + const [grant] = await db.select().from(connectionGrants).where(eq(connectionGrants.connectionId, f.connected.connectionId)); + const [secret] = await db.select().from(companySecrets).where(eq(companySecrets.id, grant.credentialSecretRefs[0].secretId)); + expect(grant.kind).toBe(personal ? "user" : "organization"); + expect(secret.scope).toBe(personal ? "user" : "company"); + expect(secret.ownerUserId).toBe(personal ? actor.actorId : null); + expect(f.connected.catalog).toHaveLength(DAYTONA_TOOLS.length); + expect(f.connected.catalog.find(c => c.toolName === "daytona_api_list_sandboxes")).toMatchObject({ isReadOnly: true }); + expect(f.connected.catalog.find(c => c.toolName === "daytona_toolbox_execute_command")).toMatchObject({ isDestructive: true, isReadOnly: false }); + for (const name of ["daytona_api_set_ttl", "daytona_api_set_auto_delete_interval", "daytona_toolbox_set_file_permissions"]) { + expect(f.connected.catalog.find(c => c.toolName === name), name).toMatchObject({ isDestructive: true, isReadOnly: false }); + } + expect(JSON.stringify(await f.service.getConnection(f.connected.connectionId))).not.toContain(credential); + // The sandbox has no Paperclip environment lease or task ownership record. + expect(JSON.stringify(await f.call("daytona_api_list_sandboxes", {}))).toContain(f.sandboxId); + expect(JSON.stringify(await f.call("daytona_api_create_sandbox", { body: { name: "Created through gateway" } }))).toContain("Created through gateway"); + const result = JSON.stringify(await f.call("daytona_toolbox_execute_command", { sandboxId: f.sandboxId, body: { command: "echo done" } })); + expect(result).toContain("done"); expect(result).not.toContain(credential); + expect(JSON.stringify(await f.call("daytona_api_get_current_api_key", {}))).not.toContain(credential); + }, 30000); + + it("transfers file bytes without reading or writing the server filesystem", async () => { + const f = await fixture(); + const download = JSON.stringify(await f.call("daytona_toolbox_download_file", { sandboxId: f.sandboxId, query: { path: "/workspace/file.txt" } })); + expect(download).toContain(Buffer.from("file bytes").toString("base64")); + const upload = await f.call("daytona_toolbox_upload_file", { sandboxId: f.sandboxId, query: { path: "/workspace/file.txt" }, + body: { file: Buffer.from("uploaded bytes").toString("base64") } }); + expect(JSON.stringify(upload)).toContain("/workspace/file.txt"); + }); + + it("rejects a mismatched organization or untrusted toolbox URL before forwarding the key", async () => { + const f = await fixture(); + f.foreignOrganization(); f.request.mockClear(); + await expect(f.call("daytona_toolbox_execute_command", { sandboxId: f.sandboxId, body: { command: "true" } })).rejects.toThrow("outside the selected account"); + expect(f.request).toHaveBeenCalledTimes(2); + const g = await fixture(); g.foreignProxy(); g.request.mockClear(); + await expect(g.call("daytona_toolbox_execute_command", { sandboxId: g.sandboxId, body: { command: "true" } })).rejects.toThrow("unrecognized toolbox"); + expect(g.request.mock.calls.every(([url]) => url.startsWith(DAYTONA_API_URL))).toBe(true); + }); + + it("rejects foreign connection bindings, unknown arguments and path traversal", async () => { + const f = await fixture(); f.request.mockClear(); + await expect(executeDaytonaTool({ binding: { companyId: randomUUID(), agentId: f.agent.id }, + connection: { companyId: f.company.id, config: {} }, headers: { Authorization: `Bearer ${credential}` }, request: f.request, + toolName: "daytona_api_list_sandboxes", parameters: {} })).rejects.toThrow("Connection not found"); + await expect(f.call("daytona_api_list_sandboxes", { command: "printenv" })).rejects.toThrow(); + await expect(f.call("daytona_api_get_sandbox", { path: { sandboxIdOrName: "../api-keys" } })).rejects.toThrow("Invalid Daytona path"); + }); + + it("rechecks revocation for a previously created gateway session", async () => { + const f = await fixture(); + await db.update(toolConnections).set({ enabled: false }).where(and(eq(toolConnections.id, f.connected.connectionId), eq(toolConnections.companyId, f.company.id))); + f.request.mockClear(); + await expect(f.call("daytona_api_list_sandboxes", {})).rejects.toThrow(); + expect(f.request).not.toHaveBeenCalled(); + }); + it("applies an Off action policy to writes through an existing session", async () => { + const f = await fixture(); + await f.service.finishGalleryAppConnection(f.company.id, f.connected.connectionId, { + enabledCatalogEntryIds: f.connected.catalog.filter(c => c.toolName !== "daytona_toolbox_execute_command").map(c => c.id), + askFirstCatalogEntryIds: [], access: { agentIds: [f.agent.id] }, + }, actor); + f.request.mockClear(); + await expect(f.call("daytona_toolbox_execute_command", { sandboxId: f.sandboxId, body: { command: "true" } })).rejects.toThrow(); + expect(f.request).not.toHaveBeenCalled(); + }); + it("quarantines added and changed actions even when a refresh requests all tools", async () => { + const f = await fixture(); + const changed = f.connected.catalog.find(c => c.toolName === "daytona_toolbox_execute_command")!; + const removed = f.connected.catalog.find(c => c.toolName === "daytona_api_create_sandbox")!; + await db.update(toolCatalogEntries).set({ schemaHash: "earlier-schema", versionHash: "earlier-version" }).where(eq(toolCatalogEntries.id, changed.id)); + await db.delete(toolCatalogEntries).where(eq(toolCatalogEntries.id, removed.id)); + const refresh = await f.service.refreshCatalog(f.connected.connectionId, actor, { enableAllByDefault: true }); + expect(refresh.catalog.find(c => c.toolName === changed.toolName)?.status).toBe("quarantined"); + expect(refresh.catalog.find(c => c.toolName === removed.toolName)?.status).toBe("quarantined"); + f.request.mockClear(); + await expect(f.call("daytona_toolbox_execute_command", { sandboxId: f.sandboxId, body: { command: "true" } })).rejects.toThrow(); + expect(f.request).not.toHaveBeenCalled(); + }); + + async function installLegacyCatalog(f: Awaited>) { + await db.delete(toolCatalogEntries).where(eq(toolCatalogEntries.connectionId, f.connected.connectionId)); + const legacyNames = ["daytona_get_account", "daytona_list_workspaces", "daytona_get_workspace", "daytona_get_workspace_recovery"]; + const legacy = await db.insert(toolCatalogEntries).values(legacyNames.map(toolName => ({ + companyId: f.company.id, applicationId: f.connected.connection.applicationId, connectionId: f.connected.connectionId, + name: toolName, toolName, title: toolName === "daytona_get_workspace_recovery" ? "Get workspace recovery" : toolName, + entryKind: "tool", status: "active", riskLevel: "read", isReadOnly: true, + inputSchema: { type: "object" }, versionHash: "legacy", schemaHash: "legacy", + }))).returning(); + await f.service.finishGalleryAppConnection(f.company.id, f.connected.connectionId, { + enabledCatalogEntryIds: legacy.map(entry => entry.id), askFirstCatalogEntryIds: [], access: { agentIds: [f.agent.id] }, + }, actor); + // Earlier read-only defaults must not authorize the expanded native catalog. + const [row] = await db.select().from(toolConnections).where(eq(toolConnections.id, f.connected.connectionId)); + await db.update(toolConnections).set({ config: { ...row.config, safeDefault: true } }).where(eq(toolConnections.id, row.id)); + return legacyNames; + } + + it.each([false, true])("upgrades a saved four-action catalog without exposing or authorizing retired tools (personal=%s)", async personal => { + const f = await fixture(personal); + const legacyNames = await installLegacyCatalog(f); + expect((await f.gateway.listToolsForSession(f.session.token)).some(tool => legacyNames.includes(tool.upstreamToolName ?? ""))).toBe(false); + f.request.mockClear(); + const catalog = await f.service.listCatalog(f.connected.connectionId, f.company.id, actor); + expect(catalog).toHaveLength(274); + expect(catalog.every(entry => entry.status === "quarantined")).toBe(true); + expect(catalog.some(entry => legacyNames.includes(entry.toolName))).toBe(false); + const stored = await db.select().from(toolCatalogEntries).where(eq(toolCatalogEntries.connectionId, f.connected.connectionId)); + expect(stored.filter(entry => legacyNames.includes(entry.toolName))).toHaveLength(4); + expect(stored.filter(entry => legacyNames.includes(entry.toolName)).every(entry => entry.status === "removed")).toBe(true); + expect(f.request).toHaveBeenCalledTimes(1); + f.request.mockClear(); + expect(await f.service.listCatalog(f.connected.connectionId, f.company.id, actor)).toHaveLength(274); + expect(f.request).not.toHaveBeenCalled(); + expect((await f.gateway.listToolsForSession(f.session.token)).some(tool => tool.upstreamToolName?.startsWith("daytona_"))).toBe(false); + }, 30000); + + it("hides retired native actions even when the saved key cannot refresh its catalog", async () => { + const f = await fixture(); + await installLegacyCatalog(f); + f.request.mockRejectedValue(new Error("Provider unavailable")); + expect(await f.service.listCatalog(f.connected.connectionId, f.company.id, actor)).toEqual([]); + expect((await f.gateway.listToolsForSession(f.session.token)).some(tool => tool.upstreamToolName?.startsWith("daytona_get_"))).toBe(false); + }); + + it("preserves existing Off and Allowed choices while retiring leftover actions", async () => { + const f = await fixture(); + await f.service.finishGalleryAppConnection(f.company.id, f.connected.connectionId, { + enabledCatalogEntryIds: f.connected.catalog.filter(entry => entry.toolName !== "daytona_toolbox_execute_command").map(entry => entry.id), + askFirstCatalogEntryIds: [], access: { agentIds: [f.agent.id] }, + }, actor); + await db.insert(toolCatalogEntries).values({ + companyId: f.company.id, applicationId: f.connected.connection.applicationId, connectionId: f.connected.connectionId, + name: "daytona_get_workspace_recovery", toolName: "daytona_get_workspace_recovery", title: "Get workspace recovery", + entryKind: "tool", status: "active", riskLevel: "read", isReadOnly: true, + inputSchema: { type: "object" }, versionHash: "legacy", schemaHash: "legacy", + }); + expect(await f.service.listCatalog(f.connected.connectionId, f.company.id, actor)).toHaveLength(274); + f.request.mockClear(); + await expect(f.call("daytona_toolbox_execute_command", { sandboxId: f.sandboxId, body: { command: "true" } })).rejects.toThrow(); + expect(f.request).not.toHaveBeenCalled(); + expect(JSON.stringify(await f.call("daytona_api_list_sandboxes", {}))).toContain(f.sandboxId); + }); + + it("blocks a stale same-name contract before board refresh, including an existing session", async () => { + const f = await fixture(); + const changed = f.connected.catalog.find(entry => entry.toolName === "daytona_toolbox_execute_command")!; + await db.update(toolCatalogEntries).set({ versionHash: "earlier-provider-contract", schemaHash: "earlier-schema", riskLevel: "read" }) + .where(eq(toolCatalogEntries.id, changed.id)); + f.request.mockClear(); + expect((await f.gateway.listToolsForSession(f.session.token)).some(tool => tool.upstreamToolName === changed.toolName)).toBe(false); + await expect(f.call(changed.toolName, { sandboxId: f.sandboxId, body: { command: "true" } })).rejects.toThrow(); + expect(f.request).not.toHaveBeenCalled(); + const refreshed = await f.service.refreshCatalog(f.connected.connectionId, actor); + expect(refreshed.catalog.find(entry => entry.toolName === changed.toolName)?.status).toBe("quarantined"); + }); + + it("carries a caller deadline across prerequisite reads and never starts a late write", async () => { + const f = await fixture(); + const original = f.request.getMockImplementation()!; + f.request.mockImplementation(async (url, init) => { + if (url.endsWith("/api-keys/current")) await new Promise(resolve => setTimeout(resolve, 80)); + return original(url, init); + }); + f.request.mockClear(); + await expect(f.call("daytona_toolbox_execute_command", { sandboxId: f.sandboxId, body: { command: "true" } }, 20)).rejects.toThrow("deadline expired"); + await new Promise(resolve => setTimeout(resolve, 100)); + expect(f.request.mock.calls.every(([url]) => url.endsWith("/api-keys/current"))).toBe(true); + }); +}); + +describe("Daytona provider client", () => { + it("validates every published action schema before provider dispatch", async () => { + const request = vi.fn(async () => { throw new Error("Unexpected provider request"); }); + expect(DAYTONA_TOOLS).toHaveLength(274); + for (const tool of DAYTONA_TOOLS) { + await expect(executeDaytonaTool({ binding: { companyId: "company", agentId: "agent" }, + connection: { companyId: "company", config: {} }, headers: { Authorization: `Bearer ${credential}` }, + request, toolName: tool.name, parameters: null }), tool.name).rejects.toThrow("Invalid Daytona action arguments"); + } + expect(request).not.toHaveBeenCalled(); + }); + it("fails closed on organization mismatch and sanitizes provider errors", async () => { + await expect(daytonaClient({ Authorization: `Bearer ${credential}` }, async () => Response.json({ organizationId: randomUUID() }), randomUUID()).probe()) + .rejects.toThrow("configured organization"); + await expect(daytonaClient({ Authorization: `Bearer ${credential}` }, async () => new Response(credential, { status: 403 })).probe()) + .rejects.toThrow("Daytona denied access"); + }); + it("bounds response bytes", async () => { + await expect(daytonaClient({ Authorization: `Bearer ${credential}` }, async () => new Response("x".repeat(8 * 1024 * 1024 + 1))).probe()) + .rejects.toThrow("exceeded the limit"); + }); + it("does not expose transport stream errors", async () => { + const request = async () => new Response(new ReadableStream({ start(controller) { controller.error(new Error(credential)); } })); + await expect(daytonaClient({ Authorization: `Bearer ${credential}` }, request).probe()).rejects.toThrow("response was interrupted"); + }); +}); diff --git a/server/src/__tests__/daytona-http-boundary.test.ts b/server/src/__tests__/daytona-http-boundary.test.ts new file mode 100644 index 00000000000..29f9513aca8 --- /dev/null +++ b/server/src/__tests__/daytona-http-boundary.test.ts @@ -0,0 +1,110 @@ +import { randomUUID } from "node:crypto"; +import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http"; +import { connect, type AddressInfo, type Socket } from "node:net"; +import { afterEach, describe, expect, it } from "vitest"; +import { executeDaytonaTool } from "../services/daytona.js"; +import { guardedRemoteHttpFetch } from "../services/remote-http-fetch.js"; + +const organizationId = randomUUID(), sandboxId = randomUUID(); +const credential = "daytona-http-fixture-key"; +const servers: Server[] = [], sockets: Socket[] = []; +afterEach(async () => { + sockets.splice(0).forEach(socket => socket.destroy()); + await Promise.all(servers.splice(0).map(server => new Promise(resolve => server.close(() => resolve())))); +}); + +async function provider(handler: (req: IncomingMessage, res: ServerResponse) => Promise | void, + stallIdentity = false) { + const calls: string[] = [], errors: unknown[] = []; + const server = createServer((req, res) => { + calls.push(req.url!); + if (req.url === "/health") { res.end("ok"); return; } + const json = (value: unknown) => { res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify(value)); }; + if (req.url === "/api/api-keys/current" && !stallIdentity) { json({ organizationId }); return; } + if (req.url === `/api/sandbox/${sandboxId}`) { + json({ id: sandboxId, organizationId, toolboxProxyUrl: "https://proxy.app.daytona.io/toolbox" }); return; + } + Promise.resolve(handler(req, res)).catch(error => { errors.push(error); res.statusCode = 500; res.end(); }); + }); + servers.push(server); + server.on("connection", socket => sockets.push(socket)); + await new Promise(resolve => server.listen(0, "127.0.0.1", resolve)); + const port = (server.address() as AddressInfo).port; + // Preserve the real pinned node:http path, including its body serializer and + // abort handling. Only the network/TLS leg is a controlled local stand-in. + const request = (url: string, init: RequestInit) => { + const endpoint = new URL(url); + endpoint.protocol = "http:"; endpoint.hostname = "daytona-boundary.test"; endpoint.port = String(port); + return guardedRemoteHttpFetch(endpoint, init, { + allowPrivateNetwork: false, lookup: async () => [{ address: "93.184.216.34", family: 4 }], + socketFactory: target => { + const socket = connect({ host: "127.0.0.1", port }); + sockets.push(socket); + Object.defineProperty(socket, "remoteAddress", { get: () => target.address, configurable: true }); + return socket; + }, + responseTimeoutMs: 5000, error: (message, code) => Object.assign(new Error(message), { code }), + }); + }; + const call = (toolName: string, parameters: unknown, budgetMs = 3000) => executeDaytonaTool({ + binding: { companyId: "company", agentId: "agent" }, connection: { companyId: "company", config: {} }, + headers: { Authorization: `Bearer ${credential}` }, request, toolName, parameters, + signal: AbortSignal.timeout(budgetMs), deadlineAt: Date.now() + budgetMs, + }); + return { call, calls, errors, health: () => fetch(`http://127.0.0.1:${port}/health`) }; +} + +describe("Daytona production HTTP boundary", () => { + it.each([false, true])("sends valid multipart bytes through the pinned transport (bulk=%s)", async bulk => { + const bytes = Buffer.from([0, 255, 1, 13, 10]); + const p = await provider(async (req, res) => { + expect(req.headers.authorization).toBe(`Bearer ${credential}`); + expect(req.headers["content-type"]).toMatch(/^multipart\/form-data; boundary=/); + const chunks: Buffer[] = []; + for await (const chunk of req) chunks.push(Buffer.from(chunk)); + const body = Buffer.concat(chunks); + const form = await new Response(body, { headers: { "Content-Type": req.headers["content-type"]! } }).formData(); + expect(Buffer.from(await (form.get(bulk ? "files" : "file") as Blob).arrayBuffer())).toEqual(bytes); + if (bulk) expect(body.toString("latin1")).toContain('filename="/workspace/binary.bin"'); + res.setHeader("Content-Type", "application/json"); res.end('{"uploaded":true}'); + }); + await expect(p.call(bulk ? "daytona_toolbox_upload_files" : "daytona_toolbox_upload_file", { + sandboxId, + ...(bulk ? { files: [{ path: "/workspace/binary.bin", contentBase64: bytes.toString("base64") }] } + : { query: { path: "/workspace/binary.bin" }, body: { file: bytes.toString("base64") } }), + })).resolves.toEqual({ uploaded: true }); + expect(p.errors).toEqual([]); + }); + + it("encodes audit filter objects using the documented bracket keys", async () => { + const p = await provider((req, res) => { + const url = new URL(req.url!, "http://provider.test"); + expect(url.searchParams.get("createdAt[gte]")).toBe("2026-10-01T00:00:00Z"); + expect(url.searchParams.get("actorId[eq]")).toBe("actor"); + expect(url.searchParams.get("statusCode[gte]")).toBe("400"); + expect(url.searchParams.has("createdAt")).toBe(false); + res.setHeader("Content-Type", "application/json"); res.end("[]"); + }); + await expect(p.call("daytona_api_get_organization_audit_logs", { path: { organizationId }, + query: { createdAt: { gte: "2026-10-01T00:00:00Z" }, actorId: { eq: "actor" }, statusCode: { gte: 400 } }, + })).resolves.toEqual([]); + expect(p.errors).toEqual([]); + }); + + it.each(["identity", "body"])("honors a total deadline during %s without blocking unrelated requests", async phase => { + const p = await provider((_req, res) => { + if (phase === "body") { + res.setHeader("Content-Type", "application/json"); res.write('{"pending":'); + // A dribbling body defeats idle timeouts but must not renew the action budget. + const timer = setInterval(() => res.write(" "), 10); + res.on("close", () => clearInterval(timer)); + } + }, phase === "identity"); + const pending = expect(p.call("daytona_api_create_sandbox", { body: { name: "deadline" } }, 300)) + .rejects.toMatchObject({ status: 504, details: { code: "daytona_deadline_exceeded" } }); + expect(await (await p.health()).text()).toBe("ok"); + await pending; + expect(p.calls.filter(url => url === "/api/sandbox")).toHaveLength(phase === "identity" ? 0 : 1); + expect(p.errors).toEqual([]); + }); +}); diff --git a/server/src/routes/tool-access.ts b/server/src/routes/tool-access.ts index a6c77e19fef..51b4425e60e 100644 --- a/server/src/routes/tool-access.ts +++ b/server/src/routes/tool-access.ts @@ -2281,7 +2281,7 @@ function connectorEnrollmentPrincipal(req: Request): string { assertBoard(req); const existing = await getAccessibleResource(req, res, svc.getConnection(req.params.connectionId as string), "Tool connection not found"); if (!existing) return; - res.json({ catalog: await svc.listCatalog(existing.id, existing.companyId) }); + res.json({ catalog: await svc.listCatalog(existing.id, existing.companyId, getActorInfo(req)) }); }); router.get("/tool-connections/:connectionId/activity", async (req, res) => { diff --git a/server/src/services/daytona.ts b/server/src/services/daytona.ts new file mode 100644 index 00000000000..81529e5b867 --- /dev/null +++ b/server/src/services/daytona.ts @@ -0,0 +1,258 @@ +import Ajv, { type ValidateFunction } from "ajv"; +import addFormats from "ajv-formats"; +import { z } from "zod"; +import { HttpError } from "../errors.js"; +import { redactSensitiveText } from "../redaction.js"; +import { descriptorHash, stableHash } from "./tool-catalog-hash.js"; +import catalog from "./daytona/operations.generated.json" with { type: "json" }; + +export const DAYTONA_API_URL = "https://app.daytona.io/api"; +// Preserve the saved method identity when upgrading the earlier small catalog. +export const DAYTONA_METHOD = "workspace-diagnostics"; +const MAX_BYTES = 8 * 1024 * 1024; +const record = (value: unknown): Record => + value && typeof value === "object" && !Array.isArray(value) ? value as Record : {}; +const failure = (status: number, code: string, message: string) => new HttpError(status, message, { code }); +export type DaytonaRequest = (url: string, init: RequestInit) => Promise; +type Operation = typeof catalog.tools[number]; +const operations = new Map(catalog.tools.map(operation => [operation.name, operation])); +const validators = new Map(); +// Match the interop used by the existing plugin configuration validator. +const AjvCtor = (Ajv as any).default ?? Ajv; +const ajv = new AjvCtor({ strict: false, allErrors: true, validateFormats: true }); +((addFormats as any).default ?? addFormats)(ajv); + +export const DAYTONA_TOOLS = catalog.tools.map(({ name, title, description, inputSchema, annotations }) => ({ + name, title, description, inputSchema: inputSchema as Record, annotations, +})); + +export function isDaytonaToolName(name: string): boolean { + return operations.has(name); +} + +const currentContracts = new Map(DAYTONA_TOOLS.map(tool => [tool.name, { + versionHash: descriptorHash(tool, daytonaRisk(tool.name)), schemaHash: stableHash(tool.inputSchema), riskLevel: daytonaRisk(tool.name), +}])); + +export function isCurrentDaytonaCatalogEntry(entry: { toolName: string; versionHash: string; schemaHash: string | null; riskLevel: string }): boolean { + const current = currentContracts.get(entry.toolName); + return Boolean(current && current.versionHash === entry.versionHash && current.schemaHash === entry.schemaHash && current.riskLevel === entry.riskLevel); +} + +export function isDaytonaConnection(connection: { transport: string; config?: Record }) { + return connection.transport === "rest_api" && connection.config?.sourceTemplateKey === "daytona" + && connection.config.connectionMethodKey === DAYTONA_METHOD && connection.config.url === DAYTONA_API_URL; +} + +export function daytonaRisk(name: string): "read" | "write" | "destructive" { + const operation = operations.get(name); + if (!operation || operation.annotations.destructiveHint) return "destructive"; + return operation.annotations.readOnlyHint ? "read" : "write"; +} + +function pathValue(value: unknown) { + const text = String(value); + if (!text || text.length > 8192 || /[\u0000-\u001f\\]/.test(text) + || text.split("/").some(segment => segment === "." || segment === "..")) { + throw failure(422, "daytona_arguments_invalid", "Invalid Daytona path argument."); + } + return encodeURIComponent(text); +} + +function decodeFile(value: unknown) { + if (typeof value !== "string" || value.length > Math.ceil(MAX_BYTES / 3) * 4 + || value.length % 4 !== 0 || /[^A-Za-z0-9+/=]/.test(value)) { + throw failure(422, "daytona_file_invalid", "File contents must be bounded base64 bytes."); + } + const bytes = Buffer.from(value, "base64"); + if (bytes.toString("base64") !== value) throw failure(422, "daytona_file_invalid", "File contents must be canonical base64 bytes."); + return bytes; +} + +/** A provider-focused REST bridge. It never reads host files, calls host shell + * commands, borrows provider-plugin credentials, or looks up Paperclip tasks. */ +export function daytonaClient(headers: Record, request: DaytonaRequest, pinnedOrganizationId?: unknown, + signal: AbortSignal = AbortSignal.timeout(30_000), deadlineAt: number = Date.now() + 30_000) { + const authorization = headers.Authorization; + if (!authorization || !/^Bearer [^\r\n]+$/.test(authorization)) { + throw failure(422, "daytona_credential_missing", "Reconnect Daytona to restore its API key."); + } + const secret = authorization.slice(7); + const expired = () => failure(504, "daytona_deadline_exceeded", "The Daytona action deadline expired. An operation already sent may still be running; inspect it before retrying."); + // Bound the caller even if a transport or body reader is slow to acknowledge + // cancellation. A late prerequisite result never advances to the next call. + async function withinDeadline(work: () => Promise): Promise { + if (signal.aborted || Date.now() >= deadlineAt) throw expired(); + let abort!: () => void; + try { + return await Promise.race([ + Promise.resolve().then(() => { if (signal.aborted || Date.now() >= deadlineAt) throw expired(); return work(); }), + new Promise((_resolve, reject) => { + abort = () => reject(expired()); + signal.addEventListener("abort", abort, { once: true }); + }), + ]); + } finally { signal.removeEventListener("abort", abort); } + } + function sanitize(value: unknown): unknown { + if (typeof value === "string") return redactSensitiveText(value.split(secret).join("[REDACTED]")); + if (Array.isArray(value)) return value.map(sanitize); + if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, sanitize(item)])); + return value; + } + + async function send(url: string, init: RequestInit, organizationId?: string): Promise { + const projected = new Headers(init.headers); + projected.set("Authorization", authorization!); + projected.set("X-Daytona-Source", "paperclip-connector"); + if (organizationId) projected.set("X-Daytona-Organization-ID", organizationId); + let response: Response; + try { + response = await withinDeadline(() => request(url, { ...init, redirect: "error", headers: Object.fromEntries(projected), signal })); + } catch { + if (signal.aborted || Date.now() >= deadlineAt) throw expired(); + throw failure(502, "daytona_outcome_unknown", init.method === "GET" + ? "Daytona could not complete the request." + : "Daytona did not return a result. The operation may have started; inspect its state before retrying."); + } + if (!response.ok) { + void response.body?.cancel().catch(() => {}); + const status = [400, 401, 403, 404, 409, 422, 429].includes(response.status) ? response.status : 502; + throw failure(status, "daytona_request_failed", status === 401 || status === 403 + ? "Daytona denied access. Check this key's organization and permissions. Some account operations require provider user authentication." + : status === 404 ? "Daytona could not find this resource." : "Daytona could not complete this operation."); + } + if (response.status === 204 || !response.body) return null; + const reader = response.body.getReader(); + const chunks: Uint8Array[] = []; + let length = 0; + try { + for (;;) { + const part = await withinDeadline(() => reader.read()); + if (part.done) break; + length += part.value.byteLength; + if (length > MAX_BYTES) throw failure(502, "daytona_output_limit", "Daytona's response exceeded the limit. Request a smaller page or file range."); + chunks.push(part.value); + } + } catch (error) { + if (error instanceof HttpError) throw error; + throw failure(502, "daytona_outcome_unknown", "Daytona's response was interrupted. Inspect the operation before retrying."); + } finally { void reader.cancel().catch(() => {}); } + const bytes = Buffer.concat(chunks); + if (!bytes.length) return null; + const contentType = response.headers.get("Content-Type") ?? "application/octet-stream"; + if (contentType.includes("json")) { + try { return sanitize(JSON.parse(bytes.toString("utf8"))); } + catch { throw failure(502, "daytona_invalid_response", "Daytona returned an invalid response."); } + } + if (contentType.startsWith("text/")) return sanitize(bytes.toString("utf8")); + if (bytes.includes(Buffer.from(secret))) throw failure(403, "daytona_credential_export_denied", "The response contains connection credential material."); + return { contentType, contentBase64: bytes.toString("base64"), byteLength: bytes.length }; + } + + async function identity() { + const value = record(await send(`${DAYTONA_API_URL}/api-keys/current`, { method: "GET" })); + const organizationId = value.organizationId; + if (!z.string().uuid().safeParse(organizationId).success || (pinnedOrganizationId && organizationId !== pinnedOrganizationId)) { + throw failure(403, "daytona_organization_mismatch", "The Daytona key does not identify the configured organization."); + } + return { organizationId: organizationId as string }; + } + + async function execute(operation: Operation, parameters: Record) { + const account = await identity(); + let base = DAYTONA_API_URL; + if (operation.kind === "toolbox") { + const sandbox = record(await send(`${DAYTONA_API_URL}/sandbox/${pathValue(parameters.sandboxId)}`, { method: "GET" }, account.organizationId)); + if (!z.string().uuid().safeParse(sandbox.id).success || sandbox.organizationId !== account.organizationId + || (sandbox.id !== parameters.sandboxId && sandbox.name !== parameters.sandboxId)) { + throw failure(403, "daytona_workspace_mismatch", "Daytona returned a sandbox outside the selected account or target."); + } + let proxyValue = sandbox.toolboxProxyUrl; + if (!proxyValue) proxyValue = record(await send(`${DAYTONA_API_URL}/sandbox/${pathValue(sandbox.id)}/toolbox-proxy-url`, { method: "GET" }, account.organizationId)).url; + let proxy: URL; + try { proxy = new URL(String(proxyValue)); } + catch { throw failure(502, "daytona_proxy_invalid", "Daytona returned an invalid toolbox address."); } + if (proxy.protocol !== "https:" || !/^proxy(?:-[a-z0-9-]+)?\.app\.daytona\.io$/.test(proxy.hostname) + || proxy.username || proxy.password || (proxy.port && proxy.port !== "443") + || !/^\/toolbox\/?$/.test(proxy.pathname) || proxy.search || proxy.hash) { + throw failure(502, "daytona_proxy_invalid", "Daytona returned an unrecognized toolbox address. No credentials were forwarded."); + } + base = `${proxy.origin}/toolbox/${pathValue(sandbox.id)}`; + } + const route = operation.path.replace(/\{([^}]+)\}/g, (_match, key: string) => pathValue(record(parameters.path)[key])); + const url = new URL(base + route); + const projectedHeaders: Record = {}; + for (const parameter of operation.parameters) { + if (parameter.group === "path") continue; + const value = record(parameters[parameter.group])[parameter.name]; + if (value === undefined || value === null) continue; + if (parameter.group === "headers") { + const text = String(value); + if (/[\r\n]/.test(text)) throw failure(422, "daytona_arguments_invalid", "Invalid Daytona header argument."); + projectedHeaders[parameter.name] = text; + } else if (parameter.json || (value && typeof value === "object" && !Array.isArray(value))) { + if (parameter.style === "deepObject") { + for (const [key, child] of Object.entries(record(value))) { + if (Array.isArray(child)) child.forEach(item => url.searchParams.append(`${parameter.name}[${key}]`, String(item))); + else url.searchParams.append(`${parameter.name}[${key}]`, String(child)); + } + } else url.searchParams.append(parameter.name, JSON.stringify(value)); + } else if (Array.isArray(value)) { + if (parameter.explode) value.forEach(item => url.searchParams.append(parameter.name, String(item))); + else url.searchParams.append(parameter.name, value.join(parameter.style === "spaceDelimited" ? " " : parameter.style === "pipeDelimited" ? "|" : ",")); + } else url.searchParams.append(parameter.name, String(value)); + } + let body: BodyInit | undefined; + if (operation.bodyContentType === "multipart/form-data") { + const form = new FormData(); + if (Array.isArray(parameters.files)) { + let total = 0; + for (const item of parameters.files) { + const file = record(item), bytes = decodeFile(file.contentBase64); + total += bytes.length; + if (total > MAX_BYTES) throw failure(422, "daytona_input_limit", "The total upload exceeds the limit."); + form.append("files", new Blob([bytes]), String(file.path)); + } + } else { + for (const [key, value] of Object.entries(record(parameters.body))) { + if (key === "file") form.append(key, new Blob([decodeFile(value)]), "upload"); + else form.append(key, String(value)); + } + } + // The guarded, DNS-pinned transport accepts bytes, not FormData. Use the + // platform encoder to serialize parts and its matching boundary header. + const encoded = new Request(DAYTONA_API_URL, { method: "POST", body: form }); + body = Buffer.from(await withinDeadline(() => encoded.arrayBuffer())); + if (body.byteLength > MAX_BYTES) throw failure(422, "daytona_input_limit", "The multipart upload exceeds the limit."); + projectedHeaders["Content-Type"] = encoded.headers.get("Content-Type")!; + } else if (parameters.body !== undefined) { + body = JSON.stringify(parameters.body); + if (Buffer.byteLength(body) > MAX_BYTES) throw failure(422, "daytona_input_limit", "The request body exceeds the limit."); + projectedHeaders["Content-Type"] = operation.bodyContentType === "*/*" ? "application/json" : operation.bodyContentType ?? "application/json"; + } + // No automatic retry. A transport failure cannot prove a write did not run. + return send(url.toString(), { method: operation.method, headers: projectedHeaders, body }, account.organizationId); + } + return { probe: identity, execute }; +} + +type Binding = { companyId: string; agentId: string | null; runId?: string | null; responsibleUserId?: string | null }; +type Connection = { companyId: string; config: Record }; +export async function executeDaytonaTool(input: { + binding: Binding; connection: Connection; headers: Record; + request: DaytonaRequest; toolName: string; parameters: unknown; + signal?: AbortSignal; + deadlineAt?: number; +}) { + if (!input.binding.agentId || input.connection.companyId !== input.binding.companyId) { + throw failure(404, "daytona_connection_not_found", "Connection not found."); + } + const operation = operations.get(input.toolName); + if (!operation) throw failure(404, "daytona_tool_not_found", "Daytona action not found."); + let validate = validators.get(operation.name); + if (!validate) { validate = ajv.compile(operation.inputSchema); validators.set(operation.name, validate!); } + if (!validate!(input.parameters)) throw failure(422, "daytona_arguments_invalid", "Invalid Daytona action arguments."); + const config = record(input.connection.config.methodConfig); + return daytonaClient(input.headers, input.request, config.organizationId, input.signal, input.deadlineAt).execute(operation, record(input.parameters)); +} diff --git a/server/src/services/daytona/operations.generated.json b/server/src/services/daytona/operations.generated.json new file mode 100644 index 00000000000..b68366e2bd3 --- /dev/null +++ b/server/src/services/daytona/operations.generated.json @@ -0,0 +1,15822 @@ +{ + "schemaVersion": 1, + "sources": { + "api": { + "url": "https://www.daytona.io/docs/openapi.json", + "sha256": "345f667a51f6ef8beceff152a07bafd032cdc16bebb94bc65e02e693141d41e1" + }, + "toolbox": { + "url": "https://www.daytona.io/docs/toolbox-openapi.json", + "sha256": "cf6e0f84d1a95c4ed8e15c170255bce3b3b5a508d6514cc4bdde9bd36456c6f5" + } + }, + "tools": [ + { + "name": "daytona_api_config_controller_get_config", + "kind": "api", + "path": "/config", + "method": "GET", + "parameters": [], + "title": "Get config", + "description": "Get config", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_api_keys", + "kind": "api", + "path": "/api-keys", + "method": "GET", + "parameters": [], + "title": "List API keys", + "description": "List API keys", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_api_key", + "kind": "api", + "path": "/api-keys", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create API key", + "description": "Create API key", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateApiKey" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateApiKey": { + "properties": { + "name": { + "description": "The name of the API key", + "type": "string" + }, + "permissions": { + "description": "The list of organization resource permissions explicitly assigned to the API key", + "items": { + "enum": [ + "write:registries", + "delete:registries", + "write:snapshots", + "delete:snapshots", + "write:sandboxes", + "delete:sandboxes", + "read:volumes", + "write:volumes", + "delete:volumes", + "write:regions", + "delete:regions", + "read:runners", + "write:runners", + "delete:runners", + "read:audit_logs", + "manage:api_keys", + "manage:secrets", + "read:limits", + "manage:sso", + "read:billing", + "manage:billing" + ], + "type": "string", + "x-enum-varnames": [ + "WRITE_REGISTRIES", + "DELETE_REGISTRIES", + "WRITE_SNAPSHOTS", + "DELETE_SNAPSHOTS", + "WRITE_SANDBOXES", + "DELETE_SANDBOXES", + "READ_VOLUMES", + "WRITE_VOLUMES", + "DELETE_VOLUMES", + "WRITE_REGIONS", + "DELETE_REGIONS", + "READ_RUNNERS", + "WRITE_RUNNERS", + "DELETE_RUNNERS", + "READ_AUDIT_LOGS", + "MANAGE_API_KEYS", + "MANAGE_SECRETS", + "READ_LIMITS", + "MANAGE_SSO", + "READ_BILLING", + "MANAGE_BILLING" + ] + }, + "type": "array" + }, + "expiresAt": { + "anyOf": [ + { + "description": "When the API key expires", + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "name", + "permissions" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_current_api_key", + "kind": "api", + "path": "/api-keys/current", + "method": "GET", + "parameters": [], + "title": "Get current API key's details", + "description": "Get current API key's details", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_api_key", + "kind": "api", + "path": "/api-keys/{name}", + "method": "DELETE", + "parameters": [ + { + "name": "name", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete API key", + "description": "Delete API key", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_api_key", + "kind": "api", + "path": "/api-keys/{name}", + "method": "GET", + "parameters": [ + { + "name": "name", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get API key", + "description": "Get API key", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_api_key_for_user", + "kind": "api", + "path": "/api-keys/{userId}/{name}", + "method": "DELETE", + "parameters": [ + { + "name": "userId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "name", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete API key for user", + "description": "Delete API key for user", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_organization_invitations_for_authenticated_user", + "kind": "api", + "path": "/organizations/invitations", + "method": "GET", + "parameters": [], + "title": "List organization invitations for authenticated user", + "description": "List organization invitations for authenticated user", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_organization_invitations_count_for_authenticated_user", + "kind": "api", + "path": "/organizations/invitations/count", + "method": "GET", + "parameters": [], + "title": "Get count of organization invitations for authenticated user", + "description": "Get count of organization invitations for authenticated user", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_accept_organization_invitation", + "kind": "api", + "path": "/organizations/invitations/{invitationId}/accept", + "method": "POST", + "parameters": [ + { + "name": "invitationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Accept organization invitation", + "description": "Accept organization invitation", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "invitationId": { + "type": "string", + "description": "Invitation ID" + } + }, + "required": [ + "invitationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_decline_organization_invitation", + "kind": "api", + "path": "/organizations/invitations/{invitationId}/decline", + "method": "POST", + "parameters": [ + { + "name": "invitationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Decline organization invitation", + "description": "Decline organization invitation", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "invitationId": { + "type": "string", + "description": "Invitation ID" + } + }, + "required": [ + "invitationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_organizations", + "kind": "api", + "path": "/organizations", + "method": "GET", + "parameters": [], + "title": "List organizations", + "description": "List organizations", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_organization", + "kind": "api", + "path": "/organizations", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create organization", + "description": "Create organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateOrganization" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateOrganization": { + "properties": { + "name": { + "description": "The name of organization", + "type": "string" + }, + "defaultRegionId": { + "description": "The ID of the default region for the organization", + "type": "string" + } + }, + "required": [ + "defaultRegionId", + "name" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_set_organization_default_region", + "kind": "api", + "path": "/organizations/{organizationId}/default-region", + "method": "PATCH", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Set default region for organization", + "description": "Set default region for organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateOrganizationDefaultRegion" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateOrganizationDefaultRegion": { + "properties": { + "defaultRegionId": { + "description": "The ID of the default region for the organization", + "type": "string" + } + }, + "required": [ + "defaultRegionId" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_organization_default_queue_timeout", + "kind": "api", + "path": "/organizations/{organizationId}/default-queue-timeout", + "method": "PATCH", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Set organization default queue timeout", + "description": "Set organization default queue timeout", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateOrganizationDefaultQueueTimeout" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateOrganizationDefaultQueueTimeout": { + "properties": { + "defaultQueueTimeout": { + "anyOf": [ + { + "description": "Default minutes to wait for runner assignment before cancelling sandbox creation. Null disables the default. A number must be a positive integer.", + "type": "integer" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "defaultQueueTimeout" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_organization", + "kind": "api", + "path": "/organizations/{organizationId}", + "method": "DELETE", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete organization", + "description": "Delete organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_organization", + "kind": "api", + "path": "/organizations/{organizationId}", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get organization by ID", + "description": "Get organization by ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_organization_usage_overview", + "kind": "api", + "path": "/organizations/{organizationId}/usage", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get organization current usage overview", + "description": "Get organization current usage overview", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_available_sandbox_classes", + "kind": "api", + "path": "/organizations/{organizationId}/available-sandbox-classes", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "List available sandbox classes for organization", + "description": "List available sandbox classes for organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_leave_organization", + "kind": "api", + "path": "/organizations/{organizationId}/leave", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Leave organization", + "description": "Leave organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_organization_otel_config_by_sandbox_auth_token", + "kind": "api", + "path": "/organizations/otel-config/by-sandbox-auth-token/{authToken}", + "method": "GET", + "parameters": [ + { + "name": "authToken", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get organization OTEL config by sandbox auth token", + "description": "Get organization OTEL config by sandbox auth token", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "authToken": { + "type": "string", + "description": "Sandbox Auth Token" + } + }, + "required": [ + "authToken" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox_identity_by_sandbox_auth_token", + "kind": "api", + "path": "/organizations/sandbox-identity/by-sandbox-auth-token/{authToken}", + "method": "GET", + "parameters": [ + { + "name": "authToken", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get sandbox identity by sandbox auth token", + "description": "Get sandbox identity by sandbox auth token", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "authToken": { + "type": "string", + "description": "Sandbox Auth Token" + } + }, + "required": [ + "authToken" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_organization_otel_config", + "kind": "api", + "path": "/organizations/{organizationId}/otel-config", + "method": "DELETE", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete organization OpenTelemetry configuration", + "description": "Delete organization OpenTelemetry configuration", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_organization_otel_config", + "kind": "api", + "path": "/organizations/{organizationId}/otel-config", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get organization OTEL config by organization ID", + "description": "Get organization OTEL config by organization ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_organization_otel_config", + "kind": "api", + "path": "/organizations/{organizationId}/otel-config", + "method": "PUT", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update organization OpenTelemetry configuration", + "description": "Update organization OpenTelemetry configuration", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/OtelConfig" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "OtelConfig": { + "properties": { + "endpoint": { + "description": "Endpoint", + "type": "string" + }, + "headers": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "description": "Headers", + "type": "object" + }, + { + "type": "null" + } + ] + }, + "organizationId": { + "description": "Organization ID the config belongs to", + "type": "string" + } + }, + "required": [ + "endpoint" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_experimental_config", + "kind": "api", + "path": "/organizations/{organizationId}/experimental-config", + "method": "PUT", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update experimental configuration", + "description": "Update experimental configuration", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + }, + "body": { + "additionalProperties": true, + "type": "object" + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_organization_roles", + "kind": "api", + "path": "/organizations/{organizationId}/roles", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "List organization roles", + "description": "List organization roles", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_organization_role", + "kind": "api", + "path": "/organizations/{organizationId}/roles", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Create organization role", + "description": "Create organization role", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/CreateOrganizationRole" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "CreateOrganizationRole": { + "properties": { + "name": { + "description": "The name of the role", + "type": "string" + }, + "description": { + "description": "The description of the role", + "type": "string" + }, + "permissions": { + "description": "The list of permissions assigned to the role", + "items": { + "enum": [ + "write:registries", + "delete:registries", + "write:snapshots", + "delete:snapshots", + "write:sandboxes", + "delete:sandboxes", + "read:volumes", + "write:volumes", + "delete:volumes", + "write:regions", + "delete:regions", + "read:runners", + "write:runners", + "delete:runners", + "read:audit_logs", + "manage:api_keys", + "manage:secrets", + "read:limits", + "manage:sso", + "read:billing", + "manage:billing" + ], + "type": "string", + "x-enum-varnames": [ + "WRITE_REGISTRIES", + "DELETE_REGISTRIES", + "WRITE_SNAPSHOTS", + "DELETE_SNAPSHOTS", + "WRITE_SANDBOXES", + "DELETE_SANDBOXES", + "READ_VOLUMES", + "WRITE_VOLUMES", + "DELETE_VOLUMES", + "WRITE_REGIONS", + "DELETE_REGIONS", + "READ_RUNNERS", + "WRITE_RUNNERS", + "DELETE_RUNNERS", + "READ_AUDIT_LOGS", + "MANAGE_API_KEYS", + "MANAGE_SECRETS", + "READ_LIMITS", + "MANAGE_SSO", + "READ_BILLING", + "MANAGE_BILLING" + ] + }, + "type": "array" + } + }, + "required": [ + "description", + "name", + "permissions" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_organization_role", + "kind": "api", + "path": "/organizations/{organizationId}/roles/{roleId}", + "method": "DELETE", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "roleId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete organization role", + "description": "Delete organization role", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + }, + "roleId": { + "type": "string", + "description": "Role ID" + } + }, + "required": [ + "organizationId", + "roleId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_organization_role", + "kind": "api", + "path": "/organizations/{organizationId}/roles/{roleId}", + "method": "PUT", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "roleId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update organization role", + "description": "Update organization role", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + }, + "roleId": { + "type": "string", + "description": "Role ID" + } + }, + "required": [ + "organizationId", + "roleId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateOrganizationRole" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateOrganizationRole": { + "properties": { + "name": { + "description": "The name of the role", + "type": "string" + }, + "description": { + "description": "The description of the role", + "type": "string" + }, + "permissions": { + "description": "The list of permissions assigned to the role", + "items": { + "enum": [ + "write:registries", + "delete:registries", + "write:snapshots", + "delete:snapshots", + "write:sandboxes", + "delete:sandboxes", + "read:volumes", + "write:volumes", + "delete:volumes", + "write:regions", + "delete:regions", + "read:runners", + "write:runners", + "delete:runners", + "read:audit_logs", + "manage:api_keys", + "manage:secrets", + "read:limits", + "manage:sso", + "read:billing", + "manage:billing" + ], + "type": "string", + "x-enum-varnames": [ + "WRITE_REGISTRIES", + "DELETE_REGISTRIES", + "WRITE_SNAPSHOTS", + "DELETE_SNAPSHOTS", + "WRITE_SANDBOXES", + "DELETE_SANDBOXES", + "READ_VOLUMES", + "WRITE_VOLUMES", + "DELETE_VOLUMES", + "WRITE_REGIONS", + "DELETE_REGIONS", + "READ_RUNNERS", + "WRITE_RUNNERS", + "DELETE_RUNNERS", + "READ_AUDIT_LOGS", + "MANAGE_API_KEYS", + "MANAGE_SECRETS", + "READ_LIMITS", + "MANAGE_SSO", + "READ_BILLING", + "MANAGE_BILLING" + ] + }, + "type": "array" + } + }, + "required": [ + "description", + "name", + "permissions" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_organization_members", + "kind": "api", + "path": "/organizations/{organizationId}/users", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "List organization members", + "description": "List organization members", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_access_for_organization_member", + "kind": "api", + "path": "/organizations/{organizationId}/users/{userId}/access", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "userId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update access for organization member", + "description": "Update access for organization member", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + }, + "userId": { + "type": "string", + "description": "User ID" + } + }, + "required": [ + "organizationId", + "userId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateOrganizationMemberAccess" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateOrganizationMemberAccess": { + "properties": { + "role": { + "default": "member", + "description": "Organization member role", + "enum": [ + "owner", + "member" + ], + "type": "string" + }, + "assignedRoleIds": { + "default": [ + "00000000-0000-0000-0000-000000000001" + ], + "description": "Array of assigned role IDs", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "assignedRoleIds", + "role" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_organization_member", + "kind": "api", + "path": "/organizations/{organizationId}/users/{userId}", + "method": "DELETE", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "userId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete organization member", + "description": "Delete organization member", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + }, + "userId": { + "type": "string", + "description": "User ID" + } + }, + "required": [ + "organizationId", + "userId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_organization_invitations", + "kind": "api", + "path": "/organizations/{organizationId}/invitations", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "List pending organization invitations", + "description": "List pending organization invitations", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_organization_invitation", + "kind": "api", + "path": "/organizations/{organizationId}/invitations", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Create organization invitation", + "description": "Create organization invitation", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/CreateOrganizationInvitation" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "CreateOrganizationInvitation": { + "properties": { + "email": { + "description": "Email address of the invitee", + "type": "string" + }, + "role": { + "default": "member", + "description": "Organization member role for the invitee", + "enum": [ + "owner", + "member" + ], + "type": "string" + }, + "assignedRoleIds": { + "default": [ + "00000000-0000-0000-0000-000000000001" + ], + "description": "Array of assigned role IDs for the invitee", + "items": { + "type": "string" + }, + "type": "array" + }, + "expiresAt": { + "description": "Expiration date of the invitation", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "assignedRoleIds", + "email", + "role" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_organization_invitation", + "kind": "api", + "path": "/organizations/{organizationId}/invitations/{invitationId}", + "method": "PUT", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "invitationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update organization invitation", + "description": "Update organization invitation", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + }, + "invitationId": { + "type": "string", + "description": "Invitation ID" + } + }, + "required": [ + "organizationId", + "invitationId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateOrganizationInvitation" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateOrganizationInvitation": { + "properties": { + "role": { + "description": "Organization member role", + "enum": [ + "owner", + "member" + ], + "type": "string" + }, + "assignedRoleIds": { + "description": "Array of role IDs", + "items": { + "type": "string" + }, + "type": "array" + }, + "expiresAt": { + "description": "Expiration date of the invitation", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "assignedRoleIds", + "role" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_cancel_organization_invitation", + "kind": "api", + "path": "/organizations/{organizationId}/invitations/{invitationId}/cancel", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "invitationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Cancel organization invitation", + "description": "Cancel organization invitation", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + }, + "invitationId": { + "type": "string", + "description": "Invitation ID" + } + }, + "required": [ + "organizationId", + "invitationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_available_regions", + "kind": "api", + "path": "/regions", + "method": "GET", + "parameters": [], + "title": "List all available regions for the organization", + "description": "List all available regions for the organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_region", + "kind": "api", + "path": "/regions", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create a new region", + "description": "Create a new region", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateRegion" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateRegion": { + "properties": { + "name": { + "description": "Region name", + "type": "string" + }, + "proxyUrl": { + "anyOf": [ + { + "description": "Proxy URL for the region", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "sshGatewayUrl": { + "anyOf": [ + { + "description": "SSH Gateway URL for the region", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "snapshotManagerUrl": { + "anyOf": [ + { + "description": "Snapshot Manager URL for the region", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "otelEndpoint": { + "anyOf": [ + { + "description": "OTel collector endpoint for sandboxes created in this region. When set, sandbox OTel data is sent to this endpoint instead of the Daytona-hosted collector and will not be available in the Daytona analytics API or dashboard.", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "name" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_region", + "kind": "api", + "path": "/regions/{id}", + "method": "DELETE", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete a region", + "description": "Delete a region", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Region ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_region_by_id", + "kind": "api", + "path": "/regions/{id}", + "method": "GET", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get region by ID", + "description": "Get region by ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Region ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_region", + "kind": "api", + "path": "/regions/{id}", + "method": "PATCH", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update region configuration", + "description": "Update region configuration", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Region ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateRegion" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateRegion": { + "properties": { + "proxyUrl": { + "anyOf": [ + { + "description": "Proxy URL for the region", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "sshGatewayUrl": { + "anyOf": [ + { + "description": "SSH Gateway URL for the region", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "snapshotManagerUrl": { + "anyOf": [ + { + "description": "Snapshot Manager URL for the region", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "otelEndpoint": { + "anyOf": [ + { + "description": "OTel collector endpoint for sandboxes created in this region. When set, sandbox OTel data is sent to this endpoint instead of the Daytona-hosted collector and will not be available in the Daytona analytics API or dashboard.", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_regenerate_proxy_api_key", + "kind": "api", + "path": "/regions/{id}/regenerate-proxy-api-key", + "method": "POST", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Regenerate proxy API key for a region", + "description": "Regenerate proxy API key for a region", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Region ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_regenerate_ssh_gateway_api_key", + "kind": "api", + "path": "/regions/{id}/regenerate-ssh-gateway-api-key", + "method": "POST", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Regenerate SSH gateway API key for a region", + "description": "Regenerate SSH gateway API key for a region", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Region ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_regenerate_snapshot_manager_credentials", + "kind": "api", + "path": "/regions/{id}/regenerate-snapshot-manager-credentials", + "method": "POST", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Regenerate snapshot manager credentials for a region", + "description": "Regenerate snapshot manager credentials for a region", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Region ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_generate_workos_admin_portal_link", + "kind": "api", + "path": "/organizations/{organizationId}/identity-providers/workos-admin-portal-link", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Generate a WorkOS Admin Portal link for configuring SSO or SCIM directory sync", + "description": "Generate a WorkOS Admin Portal link for configuring SSO or SCIM directory sync", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/GenerateWorkosAdminPortalLink" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "GenerateWorkosAdminPortalLink": { + "properties": { + "intent": { + "allOf": [ + { + "$ref": "#/definitions/WorkosAdminPortalIntent" + } + ], + "description": "Which setup flow to open: sso for a single sign-on connection, dsync for SCIM directory sync" + } + }, + "required": [ + "intent" + ], + "type": "object" + }, + "WorkosAdminPortalIntent": { + "description": "Which setup flow to open: sso for a single sign-on connection, dsync for SCIM directory sync", + "enum": [ + "sso", + "dsync" + ], + "type": "string" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_workos_sso_connections", + "kind": "api", + "path": "/organizations/{organizationId}/identity-providers/workos-sso-connections", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "List the SSO connections configured for the organization in WorkOS", + "description": "List the SSO connections configured for the organization in WorkOS", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_organization_identity_providers", + "kind": "api", + "path": "/organizations/{organizationId}/identity-providers", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "List organization identity providers", + "description": "List organization identity providers", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_organization_identity_provider", + "kind": "api", + "path": "/organizations/{organizationId}/identity-providers", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Create organization identity provider", + "description": "Create organization identity provider", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/CreateIdentityProvider" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "CreateIdentityProvider": { + "properties": { + "name": { + "description": "Display name for the identity provider", + "type": "string" + }, + "oidcConfig": { + "allOf": [ + { + "$ref": "#/definitions/OidcIdPConfig" + } + ], + "description": "OIDC configuration" + }, + "emailDomains": { + "default": [], + "description": "Email domains used for IdP discovery on the login form and to validate the user identity returned by the IdP. Required and must be non-empty unless `allowAnyDomain` is true.", + "items": { + "type": "string" + }, + "type": "array" + }, + "allowAnyDomain": { + "default": false, + "description": "When true, the IdP accepts any email domain returned by the external provider. Disables the post-callback domain check and allows `emailDomains` to be empty. Only enable for trusted IdPs that strictly control which users can authenticate.", + "type": "boolean" + }, + "trustEmailVerified": { + "default": false, + "description": "When true, skip the `email_verified` claim check on SSO logins through this identity provider. Only intended for providers that never emit the claim (e.g. Microsoft Entra ID). Risky: only enable if the IdP strictly controls its users' email addresses.", + "type": "boolean" + }, + "defaultAssignedRoleIds": { + "default": [], + "description": "Organization role IDs assigned to users who join the organization via SSO through this identity provider. Roles must be global or belong to this organization. Empty (default) grants the lowest access: membership with no resource permissions.", + "items": { + "type": "string" + }, + "type": "array" + }, + "enabled": { + "default": true, + "description": "Whether the identity provider is enabled", + "type": "boolean" + } + }, + "required": [ + "emailDomains", + "name", + "oidcConfig" + ], + "type": "object" + }, + "OidcIdPConfig": { + "properties": { + "issuerUrl": { + "description": "OIDC Issuer URL", + "type": "string" + }, + "clientId": { + "description": "OAuth Client ID", + "type": "string" + }, + "clientSecret": { + "description": "OAuth Client Secret", + "type": "string" + }, + "scope": { + "description": "OAuth scopes", + "type": "string" + } + }, + "required": [ + "clientId", + "clientSecret", + "issuerUrl" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_organization_identity_provider", + "kind": "api", + "path": "/organizations/{organizationId}/identity-providers/{id}", + "method": "DELETE", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete organization identity provider", + "description": "Delete organization identity provider", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + }, + "id": { + "type": "string", + "description": "Identity provider ID" + } + }, + "required": [ + "organizationId", + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_organization_identity_provider", + "kind": "api", + "path": "/organizations/{organizationId}/identity-providers/{id}", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get organization identity provider", + "description": "Get organization identity provider", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + }, + "id": { + "type": "string", + "description": "Identity provider ID" + } + }, + "required": [ + "organizationId", + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_organization_identity_provider", + "kind": "api", + "path": "/organizations/{organizationId}/identity-providers/{id}", + "method": "PATCH", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update organization identity provider", + "description": "Update organization identity provider", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + }, + "id": { + "type": "string", + "description": "Identity provider ID" + } + }, + "required": [ + "organizationId", + "id" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateIdentityProvider" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateIdentityProvider": { + "properties": { + "name": { + "description": "Display name for the identity provider", + "type": "string" + }, + "oidcConfig": { + "allOf": [ + { + "$ref": "#/definitions/UpdateOidcIdPConfig" + } + ], + "description": "OIDC configuration" + }, + "emailDomains": { + "description": "Email domains used for IdP discovery on the login form and to validate the user identity returned by the IdP. If provided and `allowAnyDomain` is not being set to true, must contain at least one domain. To clear domains in the same request, set `allowAnyDomain: true` and `emailDomains: []`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "allowAnyDomain": { + "description": "When true, the IdP accepts any email domain returned by the external provider. Disables the post-callback domain check and allows `emailDomains` to be empty. Only enable for trusted IdPs that strictly control which users can authenticate.", + "type": "boolean" + }, + "trustEmailVerified": { + "description": "When true, skip the `email_verified` claim check on SSO logins through this identity provider. Only intended for providers that never emit the claim (e.g. Microsoft Entra ID). Risky: only enable if the IdP strictly controls its users' email addresses.", + "type": "boolean" + }, + "defaultAssignedRoleIds": { + "description": "Organization role IDs assigned to users who join the organization via SSO through this identity provider. Roles must be global or belong to this organization. Empty grants the lowest access: membership with no resource permissions.", + "items": { + "type": "string" + }, + "type": "array" + }, + "enabled": { + "description": "Whether the identity provider is enabled", + "type": "boolean" + } + }, + "type": "object" + }, + "UpdateOidcIdPConfig": { + "properties": { + "issuerUrl": { + "description": "OIDC Issuer URL", + "type": "string" + }, + "clientId": { + "description": "OAuth Client ID", + "type": "string" + }, + "clientSecret": { + "description": "OAuth Client Secret", + "type": "string" + }, + "scope": { + "description": "OAuth scopes", + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_test_organization_identity_provider_connection", + "kind": "api", + "path": "/organizations/{organizationId}/identity-providers/test-connection", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Test OIDC identity provider connection", + "description": "Test OIDC identity provider connection", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/TestIdentityProviderConnection" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "TestIdentityProviderConnection": { + "properties": { + "issuerUrl": { + "description": "OIDC Issuer URL to test", + "type": "string" + } + }, + "required": [ + "issuerUrl" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_authenticated_user", + "kind": "api", + "path": "/users/me", + "method": "GET", + "parameters": [], + "title": "Get authenticated user", + "description": "Get authenticated user", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_record_login", + "kind": "api", + "path": "/users/me/logins", + "method": "POST", + "parameters": [], + "title": "Record a completed login", + "description": "Called by the dashboard once per completed sign-in. The email access gate evaluates the user and reports the login to analytics; a refused user receives 403 with code EMAIL_ACCESS_DENIED.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_accept_privacy_policies", + "kind": "api", + "path": "/users/privacy-policies/accept", + "method": "POST", + "parameters": [], + "title": "Accept the current privacy policies", + "description": "Accept the current privacy policies", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_account_providers", + "kind": "api", + "path": "/users/account-providers", + "method": "GET", + "parameters": [], + "title": "Get account providers", + "description": "Social sign-in providers (Google, GitHub, ...) enabled for this environment, each flagged with whether the authenticated user has an identity linked through it.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_link_account", + "kind": "api", + "path": "/users/linked-accounts", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Link account (withdrawn)", + "description": "Withdrawn. This operation is no longer supported and always responds 410.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateLinkedAccount" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateLinkedAccount": { + "properties": { + "provider": { + "description": "The authentication provider of the secondary account", + "type": "string" + }, + "userId": { + "description": "The user ID of the secondary account", + "type": "string" + } + }, + "required": [ + "provider", + "userId" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_shared_regions", + "kind": "api", + "path": "/shared-regions", + "method": "GET", + "parameters": [], + "title": "List all shared regions", + "description": "List all shared regions", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_sandboxes", + "kind": "api", + "path": "/sandbox", + "method": "GET", + "parameters": [ + { + "name": "cursor", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "limit", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "id", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "name", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "labels", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "includeErroredDeleted", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "includeWarm", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "states", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "snapshots", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "regionIds", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "sandboxClasses", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "minCpu", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "maxCpu", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "minMemoryGiB", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "maxMemoryGiB", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "minDiskGiB", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "maxDiskGiB", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "minGpu", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "maxGpu", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "isPublic", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "isRecoverable", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "createdAtAfter", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "createdAtBefore", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "lastEventAfter", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "lastEventBefore", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "autoDestroyAtAfter", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "autoDestroyAtBefore", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "sort", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "order", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "List sandboxes", + "description": "Advanced filtering and ordering. Eventually consistent.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "cursor": { + "type": "string", + "description": "Pagination cursor from a previous response" + }, + "limit": { + "default": 100, + "maximum": 200, + "minimum": 1, + "type": "integer", + "description": "Number of results per page" + }, + "id": { + "type": "string", + "description": "Filter by ID prefix (case-insensitive)" + }, + "name": { + "type": "string", + "description": "Filter by name prefix (case-insensitive)" + }, + "labels": { + "type": "string", + "description": "JSON encoded labels to filter by" + }, + "includeErroredDeleted": { + "default": false, + "type": "boolean", + "description": "Include results with errored state and deleted desired state" + }, + "includeWarm": { + "default": false, + "type": "boolean", + "description": "Include unclaimed warm pool sandboxes (excluded by default)" + }, + "states": { + "items": { + "$ref": "#/definitions/SandboxState" + }, + "type": "array", + "description": "List of states to filter by." + }, + "snapshots": { + "items": { + "type": "string" + }, + "type": "array", + "description": "List of snapshot names to filter by" + }, + "regionIds": { + "items": { + "type": "string" + }, + "type": "array", + "description": "List of regions IDs to filter by" + }, + "sandboxClasses": { + "items": { + "$ref": "#/definitions/SandboxClass" + }, + "type": "array", + "description": "List of sandbox classes to filter by" + }, + "minCpu": { + "minimum": 1, + "type": "number", + "description": "Minimum CPU" + }, + "maxCpu": { + "minimum": 1, + "type": "number", + "description": "Maximum CPU" + }, + "minMemoryGiB": { + "minimum": 1, + "type": "number", + "description": "Minimum memory in GiB" + }, + "maxMemoryGiB": { + "minimum": 1, + "type": "number", + "description": "Maximum memory in GiB" + }, + "minDiskGiB": { + "minimum": 1, + "type": "number", + "description": "Minimum disk space in GiB" + }, + "maxDiskGiB": { + "minimum": 1, + "type": "number", + "description": "Maximum disk space in GiB" + }, + "minGpu": { + "minimum": 0, + "type": "number", + "description": "Minimum GPU" + }, + "maxGpu": { + "minimum": 0, + "type": "number", + "description": "Maximum GPU" + }, + "isPublic": { + "type": "boolean", + "description": "Filter by public status" + }, + "isRecoverable": { + "type": "boolean", + "description": "Filter by recoverable status" + }, + "createdAtAfter": { + "format": "date-time", + "type": "string", + "description": "Include items created after this timestamp" + }, + "createdAtBefore": { + "format": "date-time", + "type": "string", + "description": "Include items created before this timestamp" + }, + "lastEventAfter": { + "format": "date-time", + "type": "string", + "description": "Include items with last event after this timestamp" + }, + "lastEventBefore": { + "format": "date-time", + "type": "string", + "description": "Include items with last event before this timestamp" + }, + "autoDestroyAtAfter": { + "format": "date-time", + "type": "string", + "description": "Include items scheduled for auto destroy after this timestamp" + }, + "autoDestroyAtBefore": { + "format": "date-time", + "type": "string", + "description": "Include items scheduled for auto destroy before this timestamp" + }, + "sort": { + "$ref": "#/definitions/SandboxListSortField", + "description": "Field to sort by" + }, + "order": { + "$ref": "#/definitions/SandboxListSortDirection", + "description": "Direction to sort by" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [], + "definitions": { + "SandboxState": { + "enum": [ + "creating", + "restoring", + "destroyed", + "destroying", + "started", + "stopped", + "starting", + "stopping", + "error", + "build_failed", + "pending_build", + "building_snapshot", + "unknown", + "pulling_snapshot", + "archived", + "archiving", + "resizing", + "snapshotting", + "forking", + "pausing", + "paused", + "resuming" + ], + "type": "string" + }, + "SandboxClass": { + "enum": [ + "linux-vm", + "container", + "windows" + ], + "type": "string", + "x-enum-varnames": [ + "LINUX_VM", + "CONTAINER", + "WINDOWS" + ] + }, + "SandboxListSortField": { + "enum": [ + "name", + "cpu", + "memoryGib", + "diskGib", + "lastActivityAt", + "createdAt" + ], + "type": "string" + }, + "SandboxListSortDirection": { + "enum": [ + "asc", + "desc" + ], + "type": "string" + } + } + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_sandbox", + "kind": "api", + "path": "/sandbox", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create a new sandbox", + "description": "Create a new sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateSandbox" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateSandbox": { + "properties": { + "name": { + "description": "The name of the sandbox. If not provided, the sandbox ID will be used as the name", + "type": "string" + }, + "snapshot": { + "description": "The ID or name of the snapshot used for the sandbox", + "type": "string" + }, + "user": { + "description": "The user associated with the project", + "type": "string" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "description": "Environment variables for the sandbox", + "type": "object" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "Labels for the sandbox", + "type": "object" + }, + "public": { + "description": "Whether the sandbox http preview is publicly accessible", + "type": "boolean" + }, + "networkBlockAll": { + "description": "Whether to block all network access for the sandbox", + "type": "boolean" + }, + "kvm": { + "default": false, + "description": "Expose KVM (/dev/kvm) inside the sandbox via nested virtualization. linux-vm snapshots only. Requires the sandbox_kvm feature for the organization.", + "type": "boolean" + }, + "networkAllowList": { + "description": "Comma-separated list of allowed CIDR network addresses for the sandbox", + "type": "string" + }, + "domainAllowList": { + "description": "Comma-separated list of allowed domains for the sandbox", + "type": "string" + }, + "outboundProxyUrl": { + "description": "Outbound proxy URL to route the sandbox HTTP(S) traffic through (http or https; credentials may be included in the URL). On its own this is convenience routing, not a security boundary: it is applied by injecting the standard HTTP(S)_PROXY environment variables at creation, so a process that clears those variables egresses directly. Combine with domainAllowList to have web-port (80/443) egress transparently redirected through the proxy chain at the network layer, which cannot be bypassed from inside the sandbox.", + "type": "string" + }, + "otelEndpointOverride": { + "description": "OTel collector endpoint override for this sandbox. When set, sandbox OTel data is sent to this endpoint instead of the default collector (the Daytona-hosted collector or the region-configured endpoint) and will not be available in the Daytona analytics API or dashboard.", + "type": "string" + }, + "target": { + "description": "The target (region) where the sandbox will be created", + "type": "string" + }, + "cpu": { + "description": "CPU cores allocated to the sandbox", + "type": "integer" + }, + "gpu": { + "description": "GPU units allocated to the sandbox", + "type": "integer" + }, + "gpuType": { + "description": "Preferred GPU type for the sandbox. Accepts a single value or an ordered preference list โ€” the scheduler tries each in order and pins the sandbox to the first that has capacity.", + "items": { + "$ref": "#/definitions/GpuType" + }, + "type": "array" + }, + "spot": { + "default": false, + "description": "GPU-only. When true, the sandbox may be instantly terminated without notice to free GPU capacity for an on-demand (non-spot) GPU sandbox. Ignored / rejected when the sandbox requests no GPUs.", + "type": "boolean" + }, + "memory": { + "description": "Memory allocated to the sandbox in GB", + "type": "integer" + }, + "disk": { + "description": "Disk space allocated to the sandbox in GB", + "type": "integer" + }, + "autoStopInterval": { + "description": "Auto-stop interval in minutes (0 means disabled)", + "type": "integer" + }, + "autoPauseInterval": { + "description": "Auto-pause interval in minutes (0 means disabled). Only supported for sandbox classes that support pausing. Not allowed for ephemeral sandboxes. At most one of autoStopInterval and autoPauseInterval may be non-zero. For non-ephemeral sandbox classes that support pausing, defaults to 60 minutes (with auto-stop disabled) when neither interval is provided.", + "type": "integer" + }, + "autoArchiveInterval": { + "description": "Auto-archive interval in minutes (0 means the maximum interval will be used)", + "type": "integer" + }, + "autoDeleteInterval": { + "description": "Auto-delete interval in minutes (negative value means disabled, 0 means delete immediately upon stopping)", + "type": "integer" + }, + "ttlMinutes": { + "description": "Maximum time to live in minutes, counted as wall-clock time since creation regardless of sandbox state (0 means disabled). When it elapses the sandbox is destroyed, even if it is stopped, paused, or archived. Subject to the maximum sandbox lifespan configured for the organization region and sandbox class, in which case it also defaults to that maximum and cannot be disabled.", + "type": "integer" + }, + "queueTimeout": { + "description": "Minutes to wait for runner assignment before cancelling sandbox creation. Applies only while the sandbox is unassigned in pending_build or pulling_snapshot. Only honored when default queue timeout is enabled for the organization. Omit to use the organization default; null/omit with no organization default leaves the wait unlimited. Must be a positive integer.", + "type": "integer" + }, + "volumes": { + "description": "Array of volumes to attach to the sandbox", + "items": { + "$ref": "#/definitions/SandboxVolume" + }, + "type": "array" + }, + "buildInfo": { + "allOf": [ + { + "$ref": "#/definitions/CreateBuildInfo" + } + ], + "description": "Build information for the sandbox" + }, + "linkedSandbox": { + "description": "ID or name of an existing sandbox to link the new sandbox to. The new sandbox will be scheduled on the same runner as the linked sandbox so a local network can be established between them. Linked sandboxes must be ephemeral (autoDeleteInterval=0) and cannot themselves be linked to another sandbox. GPU sandboxes cannot participate in links in either direction: a GPU sandbox cannot specify linkedSandbox, and cannot be the link target of another sandbox.", + "type": "string" + }, + "secrets": { + "description": "Secrets to mount in this sandbox. Each entry maps an env var name to a vault secret name.", + "items": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "GpuType": { + "enum": [ + "H100", + "H200", + "B300", + "RTX-PRO-6000", + "RTX-4090", + "RTX-5090", + "MI355X" + ], + "type": "string", + "x-enum-varnames": [ + "H100", + "H200", + "B300", + "RTX_PRO_6000", + "RTX_4090", + "RTX_5090", + "MI355X" + ] + }, + "SandboxVolume": { + "properties": { + "volumeId": { + "description": "The ID or name of the volume. Resolved to the volume ID on sandbox create.", + "type": "string" + }, + "mountPath": { + "description": "The mount path for the volume", + "type": "string" + }, + "subpath": { + "description": "Optional subpath within the volume to mount. When specified, only this S3 prefix will be accessible. When omitted, the entire volume is mounted.", + "type": "string" + } + }, + "required": [ + "mountPath", + "volumeId" + ], + "type": "object" + }, + "CreateBuildInfo": { + "properties": { + "dockerfileContent": { + "description": "The Dockerfile content used for the build", + "type": "string" + }, + "contextHashes": { + "description": "The context hashes used for the build", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "dockerfileContent" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandboxes_for_runner", + "kind": "api", + "path": "/sandbox/for-runner", + "method": "GET", + "parameters": [ + { + "name": "states", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "skipReconcilingSandboxes", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get sandboxes for the authenticated runner", + "description": "Get sandboxes for the authenticated runner", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "states": { + "type": "string", + "description": "Comma-separated list of sandbox states to filter by" + }, + "skipReconcilingSandboxes": { + "type": "boolean", + "description": "Skip sandboxes where state differs from desired state" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_sandbox", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}", + "method": "DELETE", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete sandbox", + "description": "Delete sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}", + "method": "GET", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "verbose", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get sandbox details", + "description": "Sandboxes destroyed by spot preemption remain retrievable for 24 hours so `spotEvictedAt` can be read. Sandboxes destroyed by queue timeout remain retrievable for 24 hours so `queueTimedOutAt` can be read.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "verbose": { + "type": "boolean", + "description": "Include verbose output" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_recover_sandbox", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/recover", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "skipStart", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Recover sandbox from error state", + "description": "Recover sandbox from error state", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "skipStart": { + "type": "boolean", + "description": "If true, the sandbox is left in STOPPED after recovery instead of being started." + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_start_sandbox", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/start", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Start or resume sandbox", + "description": "Starts a stopped or archived sandbox, or resumes a paused sandbox. The transition taken depends on the current sandbox state.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_stop_sandbox", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/stop", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "force", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Stop sandbox", + "description": "Stop sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "force": { + "type": "boolean", + "description": "Force stop the sandbox using SIGKILL instead of SIGTERM" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_pause_sandbox", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/pause", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Pause sandbox", + "description": "Pause sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_resize_sandbox", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/resize", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Resize sandbox resources", + "description": "Resize sandbox resources", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/ResizeSandbox" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "ResizeSandbox": { + "properties": { + "cpu": { + "description": "CPU cores to allocate to the sandbox (minimum: 1)", + "minimum": 1, + "type": "integer" + }, + "memory": { + "description": "Memory in GB to allocate to the sandbox (minimum: 1)", + "minimum": 1, + "type": "integer" + }, + "disk": { + "description": "Disk space in GB to allocate to the sandbox (can only be increased)", + "minimum": 1, + "type": "integer" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_replace_labels", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/labels", + "method": "PUT", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Replace sandbox labels", + "description": "Replace sandbox labels", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/SandboxLabels" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "SandboxLabels": { + "properties": { + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "Key-value pairs of labels", + "type": "object" + } + }, + "required": [ + "labels" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_sandbox_state", + "kind": "api", + "path": "/sandbox/{sandboxId}/state", + "method": "PUT", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update sandbox state", + "description": "Update sandbox state", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateSandboxStateDto" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateSandboxStateDto": { + "properties": { + "state": { + "description": "The new state for the sandbox", + "enum": [ + "creating", + "restoring", + "destroyed", + "destroying", + "started", + "stopped", + "starting", + "stopping", + "error", + "build_failed", + "pending_build", + "building_snapshot", + "unknown", + "pulling_snapshot", + "archived", + "archiving", + "resizing", + "snapshotting", + "forking", + "pausing", + "paused", + "resuming" + ], + "type": "string" + }, + "errorReason": { + "description": "Optional error message when reporting an error state", + "type": "string" + }, + "recoverable": { + "description": "Whether the sandbox is recoverable", + "type": "boolean" + } + }, + "required": [ + "state" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_backup", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/backup", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Create sandbox backup", + "description": "Deprecated: backups are managed automatically. This endpoint is a no-op kept for compatibility.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_sandbox_snapshot", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/snapshot", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Create a snapshot from a sandbox", + "description": "Create a snapshot from a sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/CreateSandboxSnapshot" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "CreateSandboxSnapshot": { + "properties": { + "name": { + "description": "Name for the new snapshot", + "type": "string" + }, + "includeMemory": { + "default": false, + "description": "Include the VM's memory in the snapshot. VM sandboxes only. When true the sandbox must be STARTED; when false (default) VM sandboxes must be STOPPED. Container sandboxes do not support memory snapshots.", + "type": "boolean" + } + }, + "required": [ + "name" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_fork_sandbox", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/fork", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Fork a sandbox", + "description": "Fork a sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/ForkSandbox" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "ForkSandbox": { + "properties": { + "name": { + "description": "The name for the forked sandbox. If not provided, a unique name will be generated.", + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox_forks", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/forks", + "method": "GET", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "includeDestroyed", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get sandbox fork children", + "description": "Get sandbox fork children", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "includeDestroyed": { + "type": "boolean" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox_parent", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/parent", + "method": "GET", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get sandbox fork parent", + "description": "Get sandbox fork parent", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox_ancestors", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/ancestors", + "method": "GET", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get sandbox fork ancestor chain", + "description": "Get sandbox fork ancestor chain", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_public_status", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/public/{isPublic}", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "isPublic", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Update public status", + "description": "Update public status", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + }, + "isPublic": { + "type": "boolean", + "description": "Public status to set" + } + }, + "required": [ + "sandboxIdOrName", + "isPublic" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox_signing_key", + "kind": "api", + "path": "/sandbox/{sandboxId}/signing-key", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get the signing key for a sandbox", + "description": "Get the signing key for a sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_rotate_signing_key", + "kind": "api", + "path": "/sandbox/{sandboxId}/signing-key/rotate", + "method": "POST", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Rotate the signing key, invalidating all previously signed URLs", + "description": "Rotate the signing key, invalidating all previously signed URLs", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_last_activity", + "kind": "api", + "path": "/sandbox/{sandboxId}/last-activity", + "method": "POST", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update sandbox last activity", + "description": "Update sandbox last activity", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateLastActivity" + } + }, + "required": [ + "path" + ], + "definitions": { + "UpdateLastActivity": { + "properties": { + "activityType": { + "description": "Optional type of interaction that reset the activity timer.", + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_set_autostop_interval", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/autostop/{interval}", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "interval", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Set sandbox auto-stop interval", + "description": "Set sandbox auto-stop interval", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + }, + "interval": { + "type": "number", + "description": "Auto-stop interval in minutes (0 to disable)" + } + }, + "required": [ + "sandboxIdOrName", + "interval" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_set_auto_pause_interval", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/autopause/{interval}", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "interval", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Set sandbox auto-pause interval", + "description": "Set sandbox auto-pause interval", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + }, + "interval": { + "type": "number", + "description": "Auto-pause interval in minutes (0 to disable)" + } + }, + "required": [ + "sandboxIdOrName", + "interval" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_set_ttl", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/ttl/{ttlMinutes}", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "ttlMinutes", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Set sandbox TTL", + "description": "Set sandbox TTL", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + }, + "ttlMinutes": { + "type": "number", + "description": "Maximum time to live in minutes, re-anchored from the current time (0 to disable). When it elapses the sandbox is destroyed, even if it is stopped, paused, or archived" + } + }, + "required": [ + "sandboxIdOrName", + "ttlMinutes" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_set_auto_archive_interval", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/autoarchive/{interval}", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "interval", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Set sandbox auto-archive interval", + "description": "Set sandbox auto-archive interval", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + }, + "interval": { + "type": "number", + "description": "Auto-archive interval in minutes (0 means the maximum interval will be used)" + } + }, + "required": [ + "sandboxIdOrName", + "interval" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_set_auto_delete_interval", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/autodelete/{interval}", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "interval", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Set sandbox auto-delete interval", + "description": "Set sandbox auto-delete interval", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + }, + "interval": { + "type": "number", + "description": "Auto-delete interval in minutes (negative value means disabled, 0 means delete immediately upon stopping)" + } + }, + "required": [ + "sandboxIdOrName", + "interval" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_network_settings", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/network-settings", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update sandbox network settings", + "description": "Changes outbound network policy on the runner for a running sandbox (for example block all traffic, restore access, or set a CIDR allow list).", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateSandboxNetworkSettings" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateSandboxNetworkSettings": { + "properties": { + "networkBlockAll": { + "description": "Whether to block all network access for the sandbox", + "type": "boolean" + }, + "networkAllowList": { + "description": "Comma-separated list of allowed CIDR network addresses for the sandbox", + "type": "string" + }, + "domainAllowList": { + "description": "Comma-separated list of allowed domains for the sandbox", + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_sandbox_secrets", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/secrets", + "method": "PUT", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update sandbox secrets", + "description": "Replaces the set of vault secrets mounted in the sandbox. Attached, detached and rotated secrets take effect for outbound requests within seconds. New env vars become visible to processes spawned after the update; a sandbox created without any secrets must be restarted for newly attached secrets to work.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateSandboxSecrets" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateSandboxSecrets": { + "properties": { + "secrets": { + "description": "Secrets to mount in this sandbox, replacing the previously mounted set. Each entry maps an env var name to a vault secret name. Pass an empty array to detach all secrets.", + "items": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "secrets" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_archive_sandbox", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/archive", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Archive sandbox", + "description": "Archive sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_port_preview_url", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/ports/{port}/preview-url", + "method": "GET", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "port", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get preview URL for a sandbox port", + "description": "Get preview URL for a sandbox port", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + }, + "port": { + "type": "number", + "description": "Port number to get preview URL for" + } + }, + "required": [ + "sandboxIdOrName", + "port" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_signed_port_preview_url", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/ports/{port}/signed-preview-url", + "method": "GET", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "port", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "expiresInSeconds", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get signed preview URL for a sandbox port", + "description": "Get signed preview URL for a sandbox port", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + }, + "port": { + "type": "integer", + "description": "Port number to get signed preview URL for" + } + }, + "required": [ + "sandboxIdOrName", + "port" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "expiresInSeconds": { + "type": "integer", + "description": "Expiration time in seconds (default: 60 seconds)" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_expire_signed_port_preview_url", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/ports/{port}/signed-preview-url/{token}/expire", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "port", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "token", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Expire signed preview URL for a sandbox port", + "description": "Expire signed preview URL for a sandbox port", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + }, + "port": { + "type": "integer", + "description": "Port number to expire signed preview URL for" + }, + "token": { + "type": "string", + "description": "Token to expire signed preview URL for" + } + }, + "required": [ + "sandboxIdOrName", + "port", + "token" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_build_logs", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/build-logs", + "method": "GET", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "follow", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get build logs", + "description": "This endpoint is deprecated. Use `getBuildLogsUrl` instead.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "follow": { + "type": "boolean", + "description": "Whether to follow the logs stream" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_build_logs_url", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/build-logs-url", + "method": "GET", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get build logs URL", + "description": "Get build logs URL", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_revoke_ssh_access", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/ssh-access", + "method": "DELETE", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "token", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Revoke SSH access for sandbox", + "description": "Revoke SSH access for sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "SSH access token to revoke. If not provided, all SSH access for the sandbox will be revoked." + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_ssh_access", + "kind": "api", + "path": "/sandbox/{sandboxIdOrName}/ssh-access", + "method": "POST", + "parameters": [ + { + "name": "sandboxIdOrName", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "expiresInMinutes", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Create SSH access for sandbox", + "description": "Create SSH access for sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxIdOrName": { + "type": "string", + "description": "ID or name of the sandbox" + } + }, + "required": [ + "sandboxIdOrName" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "expiresInMinutes": { + "type": "number", + "description": "Expiration time in minutes (default: 60)" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_validate_ssh_access", + "kind": "api", + "path": "/sandbox/ssh-access/validate", + "method": "GET", + "parameters": [ + { + "name": "token", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Validate SSH access for sandbox", + "description": "Validate SSH access for sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "SSH access token to validate" + } + }, + "required": [ + "token" + ], + "additionalProperties": false + } + }, + "required": [ + "query" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_toolbox_proxy_url", + "kind": "api", + "path": "/sandbox/{sandboxId}/toolbox-proxy-url", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get toolbox proxy URL for a sandbox", + "description": "Get toolbox proxy URL for a sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_organization_by_sandbox_id", + "kind": "api", + "path": "/sandbox/{sandboxId}/organization", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get organization by sandbox ID", + "description": "Get organization by sandbox ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_region_quota_by_sandbox_id", + "kind": "api", + "path": "/sandbox/{sandboxId}/region-quota", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get region quota by sandbox ID", + "description": "Get region quota by sandbox ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_resolve_sandbox_secrets", + "kind": "api", + "path": "/sandbox/{sandboxId}/secrets", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Resolve sandbox secrets", + "description": "Resolve sandbox secrets", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "Sandbox ID" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_runners", + "kind": "api", + "path": "/runners", + "method": "GET", + "parameters": [ + { + "name": "regionId", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "List all runners", + "description": "List all runners", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "regionId": { + "type": "string", + "description": "Filter runners by region ID" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_runner", + "kind": "api", + "path": "/runners", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create runner", + "description": "Create runner", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateRunner" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateRunner": { + "properties": { + "regionId": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tags": { + "description": "Tags to associate with the runner", + "items": { + "type": "string" + }, + "type": "array" + }, + "sandboxClass": { + "allOf": [ + { + "$ref": "#/definitions/CreateRunnerSandboxClass" + } + ], + "default": "container", + "description": "The sandbox class supported by the runner. Defaults to container when omitted or null." + } + }, + "required": [ + "name", + "regionId" + ], + "type": "object" + }, + "CreateRunnerSandboxClass": { + "anyOf": [ + { + "description": "The sandbox class supported by the runner. Defaults to container when omitted or null.", + "enum": [ + "container", + "linux-vm", + "windows", + null + ], + "type": "string" + }, + { + "type": "null" + } + ] + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_info_for_authenticated_runner", + "kind": "api", + "path": "/runners/me", + "method": "GET", + "parameters": [], + "title": "Get info for authenticated runner", + "description": "Get info for authenticated runner", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_snapshot_refs_for_authenticated_runner", + "kind": "api", + "path": "/runners/me/snapshots", + "method": "GET", + "parameters": [], + "title": "Get snapshot refs for authenticated runner", + "description": "Get snapshot refs for authenticated runner", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_runner_by_sandbox_id", + "kind": "api", + "path": "/runners/by-sandbox/{sandboxId}", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get runner by sandbox ID", + "description": "Get runner by sandbox ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_runners_by_snapshot_ref", + "kind": "api", + "path": "/runners/by-snapshot-ref", + "method": "GET", + "parameters": [ + { + "name": "ref", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get runners by snapshot ref", + "description": "Get runners by snapshot ref", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "ref": { + "type": "string", + "description": "Snapshot ref" + } + }, + "required": [ + "ref" + ], + "additionalProperties": false + } + }, + "required": [ + "query" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_runner", + "kind": "api", + "path": "/runners/{id}", + "method": "DELETE", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "force", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Delete runner", + "description": "Delete runner", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Runner ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "force": { + "type": "boolean", + "description": "Delete the runner without waiting for sandboxes already marked for destruction. Requires the runner to have stopped reporting as ready." + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_runner_by_id", + "kind": "api", + "path": "/runners/{id}", + "method": "GET", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get runner by ID", + "description": "Get runner by ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Runner ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_runner_full_by_id", + "kind": "api", + "path": "/runners/{id}/full", + "method": "GET", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get runner by ID", + "description": "Get runner by ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Runner ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_runner_scheduling", + "kind": "api", + "path": "/runners/{id}/scheduling", + "method": "PATCH", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Update runner scheduling status", + "description": "Update runner scheduling status", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Runner ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_runner_draining", + "kind": "api", + "path": "/runners/{id}/draining", + "method": "PATCH", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Update runner draining status", + "description": "Update runner draining status", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Runner ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_runner_healthcheck", + "kind": "api", + "path": "/runners/healthcheck", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Runner healthcheck", + "description": "Endpoint for version 2 runners to send healthcheck and metrics. Updates lastChecked timestamp and runner metrics.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/RunnerHealthcheck" + } + }, + "required": [ + "body" + ], + "definitions": { + "RunnerHealthcheck": { + "properties": { + "metrics": { + "allOf": [ + { + "$ref": "#/definitions/RunnerHealthMetrics" + } + ], + "description": "Runner metrics" + }, + "serviceHealth": { + "description": "Health status of individual services on the runner", + "items": { + "$ref": "#/definitions/RunnerServiceHealth" + }, + "type": "array" + }, + "domain": { + "description": "Runner domain", + "type": "string" + }, + "proxyUrl": { + "description": "Runner proxy URL", + "type": "string" + }, + "apiUrl": { + "description": "Runner API URL", + "type": "string" + }, + "appVersion": { + "description": "Runner app version", + "type": "string" + } + }, + "required": [ + "appVersion" + ], + "type": "object" + }, + "RunnerHealthMetrics": { + "properties": { + "currentCpuLoadAverage": { + "description": "Current CPU load average", + "type": "number" + }, + "currentCpuUsagePercentage": { + "description": "Current CPU usage percentage", + "type": "number" + }, + "currentMemoryUsagePercentage": { + "description": "Current memory usage percentage", + "type": "number" + }, + "currentDiskUsagePercentage": { + "description": "Current disk usage percentage", + "type": "number" + }, + "currentAllocatedCpu": { + "description": "Currently allocated CPU cores", + "type": "number" + }, + "currentAllocatedMemoryGiB": { + "description": "Currently allocated memory in GiB", + "type": "number" + }, + "currentAllocatedDiskGiB": { + "description": "Currently allocated disk in GiB", + "type": "number" + }, + "currentSnapshotCount": { + "description": "Number of snapshots currently stored", + "type": "number" + }, + "currentStartedSandboxes": { + "description": "Number of started sandboxes", + "type": "number" + }, + "cpu": { + "description": "Total CPU cores on the runner", + "type": "number" + }, + "memoryGiB": { + "description": "Total RAM in GiB on the runner", + "type": "number" + }, + "diskGiB": { + "description": "Total disk space in GiB on the runner", + "type": "number" + }, + "gpu": { + "description": "Total number of GPUs on the runner", + "type": "number" + }, + "gpuType": { + "description": "GPU model name", + "type": "string" + } + }, + "required": [ + "cpu", + "currentAllocatedCpu", + "currentAllocatedDiskGiB", + "currentAllocatedMemoryGiB", + "currentCpuLoadAverage", + "currentCpuUsagePercentage", + "currentDiskUsagePercentage", + "currentMemoryUsagePercentage", + "currentSnapshotCount", + "currentStartedSandboxes", + "diskGiB", + "memoryGiB" + ], + "type": "object" + }, + "RunnerServiceHealth": { + "properties": { + "serviceName": { + "description": "Name of the service being checked", + "type": "string" + }, + "healthy": { + "description": "Whether the service is healthy", + "type": "boolean" + }, + "errorReason": { + "description": "Error reason if the service is unhealthy", + "type": "string" + } + }, + "required": [ + "healthy", + "serviceName" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_all_snapshots", + "kind": "api", + "path": "/snapshots", + "method": "GET", + "parameters": [ + { + "name": "page", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "limit", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "name", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "sourceSandboxId", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "sort", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "order", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "List all snapshots", + "description": "List all snapshots", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "page": { + "default": 1, + "minimum": 1, + "type": "integer", + "description": "Page number of the results" + }, + "limit": { + "default": 100, + "maximum": 200, + "minimum": 1, + "type": "integer", + "description": "Number of results per page" + }, + "name": { + "type": "string", + "description": "Filter by partial name match" + }, + "sourceSandboxId": { + "type": "string", + "description": "Filter by the ID of the sandbox the snapshot was created from" + }, + "sort": { + "default": "lastUsedAt", + "enum": [ + "name", + "state", + "lastUsedAt", + "createdAt" + ], + "type": "string", + "description": "Field to sort by" + }, + "order": { + "default": "desc", + "enum": [ + "asc", + "desc" + ], + "type": "string", + "description": "Direction to sort by" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_snapshot", + "kind": "api", + "path": "/snapshots", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create a new snapshot", + "description": "Create a new snapshot", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateSnapshot" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateSnapshot": { + "properties": { + "name": { + "description": "The name of the snapshot", + "type": "string" + }, + "imageName": { + "description": "The image name of the snapshot", + "type": "string" + }, + "entrypoint": { + "description": "The entrypoint command for the snapshot", + "items": { + "type": "string" + }, + "type": "array" + }, + "cpu": { + "description": "CPU cores allocated to the resulting sandbox", + "type": "integer" + }, + "gpu": { + "description": "GPU units allocated to the resulting sandbox", + "type": "integer" + }, + "gpuType": { + "description": "Preferred GPU type for the resulting sandbox.", + "items": { + "$ref": "#/definitions/GpuType" + }, + "type": "array" + }, + "memory": { + "description": "Memory allocated to the resulting sandbox in GB", + "type": "integer" + }, + "disk": { + "description": "Disk space allocated to the sandbox in GB", + "type": "integer" + }, + "buildInfo": { + "allOf": [ + { + "$ref": "#/definitions/CreateBuildInfo" + } + ], + "description": "Build information for the snapshot" + }, + "regionId": { + "description": "ID of the region where the snapshot will be available. Defaults to organization default region if not specified.", + "type": "string" + }, + "sandboxClass": { + "allOf": [ + { + "$ref": "#/definitions/SandboxClass" + } + ], + "description": "Target sandbox class. Determines which runners can host sandboxes created from this snapshot." + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "GpuType": { + "enum": [ + "H100", + "H200", + "B300", + "RTX-PRO-6000", + "RTX-4090", + "RTX-5090", + "MI355X" + ], + "type": "string", + "x-enum-varnames": [ + "H100", + "H200", + "B300", + "RTX_PRO_6000", + "RTX_4090", + "RTX_5090", + "MI355X" + ] + }, + "CreateBuildInfo": { + "properties": { + "dockerfileContent": { + "description": "The Dockerfile content used for the build", + "type": "string" + }, + "contextHashes": { + "description": "The context hashes used for the build", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "dockerfileContent" + ], + "type": "object" + }, + "SandboxClass": { + "enum": [ + "linux-vm", + "container", + "windows" + ], + "type": "string", + "x-enum-varnames": [ + "LINUX_VM", + "CONTAINER", + "WINDOWS" + ] + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_remove_snapshot", + "kind": "api", + "path": "/snapshots/{id}", + "method": "DELETE", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete snapshot", + "description": "Delete snapshot", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Snapshot ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_snapshot", + "kind": "api", + "path": "/snapshots/{id}", + "method": "GET", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get snapshot by ID or name", + "description": "Get snapshot by ID or name", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Snapshot ID or name" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_snapshot_build_logs", + "kind": "api", + "path": "/snapshots/{id}/build-logs", + "method": "GET", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "follow", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get snapshot build logs", + "description": "This endpoint is deprecated. Use `getSnapshotBuildLogsUrl` instead.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Snapshot ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "follow": { + "type": "boolean", + "description": "Whether to follow the logs stream" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_snapshot_build_logs_url", + "kind": "api", + "path": "/snapshots/{id}/build-logs-url", + "method": "GET", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get snapshot build logs URL", + "description": "Get snapshot build logs URL", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Snapshot ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_activate_snapshot", + "kind": "api", + "path": "/snapshots/{id}/activate", + "method": "POST", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Activate a snapshot", + "description": "Activate a snapshot", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Snapshot ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_deactivate_snapshot", + "kind": "api", + "path": "/snapshots/{id}/deactivate", + "method": "POST", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Deactivate a snapshot", + "description": "Deactivate a snapshot", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Snapshot ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_is_sandbox_public", + "kind": "api", + "path": "/preview/{sandboxId}/public", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Check if sandbox is public", + "description": "Check if sandbox is public", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_is_preview_warning_enabled", + "kind": "api", + "path": "/preview/{sandboxId}/preview-warning", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "port", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Check if the preview warning page is enabled for the sandbox", + "description": "Check if the preview warning page is enabled for the sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox, or a signed preview URL token (requires the port query param)" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "port": { + "type": "number", + "description": "Port the signed preview URL token was issued for. Required when sandboxId is a signed token." + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_is_valid_auth_token", + "kind": "api", + "path": "/preview/{sandboxId}/validate/{authToken}", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "authToken", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Check if sandbox auth token is valid", + "description": "Check if sandbox auth token is valid", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + }, + "authToken": { + "type": "string", + "description": "Auth token of the sandbox" + } + }, + "required": [ + "sandboxId", + "authToken" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_signing_key", + "kind": "api", + "path": "/preview/{sandboxId}/signing-key", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get the signing key for a sandbox", + "description": "Get the signing key for a sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_has_sandbox_access", + "kind": "api", + "path": "/preview/{sandboxId}/access", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Check if user has access to the sandbox", + "description": "Check if user has access to the sandbox", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox_id_from_signed_preview_url_token", + "kind": "api", + "path": "/preview/{signedPreviewToken}/{port}/sandbox-id", + "method": "GET", + "parameters": [ + { + "name": "signedPreviewToken", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "port", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get sandbox ID from signed preview URL token", + "description": "Get sandbox ID from signed preview URL token", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "signedPreviewToken": { + "type": "string", + "description": "Signed preview URL token" + }, + "port": { + "type": "number", + "description": "Port number to get sandbox ID from signed preview URL token" + } + }, + "required": [ + "signedPreviewToken", + "port" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_volumes", + "kind": "api", + "path": "/volumes", + "method": "GET", + "parameters": [ + { + "name": "includeDeleted", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "List all volumes", + "description": "List all volumes", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "includeDeleted": { + "type": "boolean", + "description": "Include deleted volumes in the response" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_volume", + "kind": "api", + "path": "/volumes", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create a new volume", + "description": "Create a new volume", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateVolume" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateVolume": { + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_volume", + "kind": "api", + "path": "/volumes/{volumeId}", + "method": "DELETE", + "parameters": [ + { + "name": "volumeId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete volume", + "description": "Delete volume", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "volumeId": { + "type": "string", + "description": "ID of the volume" + } + }, + "required": [ + "volumeId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_volume", + "kind": "api", + "path": "/volumes/{volumeId}", + "method": "GET", + "parameters": [ + { + "name": "volumeId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get volume details", + "description": "Get volume details", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "volumeId": { + "type": "string", + "description": "ID of the volume" + } + }, + "required": [ + "volumeId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_volume_by_name", + "kind": "api", + "path": "/volumes/by-name/{name}", + "method": "GET", + "parameters": [ + { + "name": "name", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get volume details by name", + "description": "Get volume details by name", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the volume" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_jobs", + "kind": "api", + "path": "/jobs", + "method": "GET", + "parameters": [ + { + "name": "page", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "limit", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "status", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "offset", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "List jobs for the runner", + "description": "Returns a paginated list of jobs for the runner, optionally filtered by status.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "page": { + "default": 1, + "minimum": 1, + "type": "integer", + "description": "Page number of the results" + }, + "limit": { + "default": 100, + "maximum": 200, + "minimum": 1, + "type": "integer", + "description": "Maximum number of jobs to return (default: 100, max: 500)" + }, + "status": { + "$ref": "#/definitions/JobStatus", + "description": "Filter jobs by status" + }, + "offset": { + "type": "integer", + "description": "Number of jobs to skip for pagination (default: 0)" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [], + "definitions": { + "JobStatus": { + "enum": [ + "PENDING", + "IN_PROGRESS", + "COMPLETED", + "FAILED" + ], + "type": "string" + } + } + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_poll_jobs", + "kind": "api", + "path": "/jobs/poll", + "method": "GET", + "parameters": [ + { + "name": "timeout", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "limit", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Long poll for jobs", + "description": "Long poll endpoint for runners to fetch pending jobs. Returns immediately if jobs are available, otherwise waits up to timeout seconds.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "timeout": { + "type": "integer", + "description": "Timeout in seconds for long polling (default: 30, max: 60)" + }, + "limit": { + "type": "integer", + "description": "Maximum number of jobs to return (default: 10, max: 100)" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_job", + "kind": "api", + "path": "/jobs/{jobId}", + "method": "GET", + "parameters": [ + { + "name": "jobId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get job details", + "description": "Get job details", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "description": "ID of the job" + } + }, + "required": [ + "jobId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_job_status", + "kind": "api", + "path": "/jobs/{jobId}/status", + "method": "POST", + "parameters": [ + { + "name": "jobId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update job status", + "description": "Update job status", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "description": "ID of the job" + } + }, + "required": [ + "jobId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateJobStatus" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateJobStatus": { + "properties": { + "status": { + "allOf": [ + { + "$ref": "#/definitions/JobStatus" + } + ], + "description": "The new status of the job" + }, + "errorMessage": { + "description": "Error message if the job failed", + "type": "string" + }, + "resultMetadata": { + "description": "Result metadata for the job", + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "JobStatus": { + "enum": [ + "PENDING", + "IN_PROGRESS", + "COMPLETED", + "FAILED" + ], + "type": "string" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_warm_pools", + "kind": "api", + "path": "/warm-pools", + "method": "GET", + "parameters": [], + "title": "List warm pools for the organization", + "description": "List warm pools for the organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_warm_pool", + "kind": "api", + "path": "/warm-pools", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create a warm pool", + "description": "Create a warm pool", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateWarmPool" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateWarmPool": { + "properties": { + "snapshot": { + "description": "The snapshot (id or name) to keep warm sandboxes for. A pool only serves sandbox creates that use this snapshot with the default OS user and no custom env, volumes or secrets.", + "type": "string" + }, + "pool": { + "description": "Number of warm sandboxes to keep ready (capped by the organization quota)", + "minimum": 1, + "type": "number" + }, + "target": { + "description": "Target region for the warm pool. Defaults to the organization default region.", + "type": "string" + } + }, + "required": [ + "pool", + "snapshot" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_warm_pool", + "kind": "api", + "path": "/warm-pools/{id}", + "method": "DELETE", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete a warm pool", + "description": "Delete a warm pool", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Warm pool ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_warm_pool", + "kind": "api", + "path": "/warm-pools/{id}", + "method": "PATCH", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update a warm pool size", + "description": "Update a warm pool size", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Warm pool ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateWarmPool" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateWarmPool": { + "properties": { + "pool": { + "description": "New desired number of warm sandboxes (0 drains the pool)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "pool" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_gpu_capacity", + "kind": "api", + "path": "/organizations/{organizationId}/gpu-capacity", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get shared GPU capacity", + "description": "Returns a short-lived observation of the shared GPU fleet. Organization quotas and entitlements are not applied. Capacity can change immediately and sandbox creation remains authoritative.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_registries", + "kind": "api", + "path": "/docker-registry", + "method": "GET", + "parameters": [], + "title": "List registries", + "description": "List registries", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_registry", + "kind": "api", + "path": "/docker-registry", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create registry", + "description": "Create registry", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateDockerRegistry" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateDockerRegistry": { + "properties": { + "name": { + "description": "Registry name", + "type": "string" + }, + "url": { + "description": "Registry URL", + "type": "string" + }, + "username": { + "description": "Registry username", + "type": "string" + }, + "password": { + "description": "Registry password", + "type": "string" + }, + "project": { + "description": "Registry project", + "type": "string" + } + }, + "required": [ + "name", + "password", + "url", + "username" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_transient_push_access", + "kind": "api", + "path": "/docker-registry/registry-push-access", + "method": "GET", + "parameters": [ + { + "name": "regionId", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get temporary registry access for pushing snapshots", + "description": "Get temporary registry access for pushing snapshots", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "regionId": { + "type": "string", + "description": "ID of the region where the snapshot will be available (defaults to organization default region)" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_registry", + "kind": "api", + "path": "/docker-registry/{id}", + "method": "DELETE", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete registry", + "description": "Delete registry", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "ID of the docker registry" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_registry", + "kind": "api", + "path": "/docker-registry/{id}", + "method": "GET", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get registry", + "description": "Get registry", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "ID of the docker registry" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_registry", + "kind": "api", + "path": "/docker-registry/{id}", + "method": "PATCH", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update registry", + "description": "Update registry", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "ID of the docker registry" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateDockerRegistry" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateDockerRegistry": { + "properties": { + "name": { + "description": "Registry name", + "type": "string" + }, + "url": { + "description": "Registry URL", + "type": "string" + }, + "username": { + "description": "Registry username", + "type": "string" + }, + "password": { + "description": "Registry password", + "type": "string" + }, + "project": { + "description": "Registry project", + "type": "string" + } + }, + "required": [ + "name", + "url", + "username" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_secrets", + "kind": "api", + "path": "/secret", + "method": "GET", + "parameters": [], + "title": "List secrets", + "description": "This endpoint is deprecated and fails for organizations with more than 1500 secrets. Use `listSecretsPaginated` instead.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_create_secret", + "kind": "api", + "path": "/secret", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create secret", + "description": "Create secret", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "body": { + "$ref": "#/definitions/CreateSecret" + } + }, + "required": [ + "body" + ], + "definitions": { + "CreateSecret": { + "properties": { + "name": { + "description": "Secret name (alphanumeric, hyphens, underscores)", + "type": "string" + }, + "value": { + "description": "Secret value", + "type": "string" + }, + "description": { + "description": "Optional description of the secret", + "type": "string" + }, + "hosts": { + "description": "Allowed hosts this secret may be sent to", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_secrets_paginated", + "kind": "api", + "path": "/secret/paginated", + "method": "GET", + "parameters": [ + { + "name": "cursor", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "limit", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "name", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "sort", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "order", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "List secrets with pagination", + "description": "List secrets with pagination", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "cursor": { + "type": "string", + "description": "Pagination cursor from a previous response" + }, + "limit": { + "default": 100, + "maximum": 200, + "minimum": 1, + "type": "integer", + "description": "Number of results per page" + }, + "name": { + "type": "string", + "description": "Filter by partial name match" + }, + "sort": { + "default": "createdAt", + "enum": [ + "name", + "createdAt", + "updatedAt" + ], + "type": "string", + "description": "Field to sort by" + }, + "order": { + "default": "desc", + "enum": [ + "asc", + "desc" + ], + "type": "string", + "description": "Direction to sort by" + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_delete_secret", + "kind": "api", + "path": "/secret/{secretId}", + "method": "DELETE", + "parameters": [ + { + "name": "secretId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Delete secret", + "description": "Delete secret", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "secretId": { + "type": "string", + "description": "ID of the secret" + } + }, + "required": [ + "secretId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_secret", + "kind": "api", + "path": "/secret/{secretId}", + "method": "GET", + "parameters": [ + { + "name": "secretId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get secret", + "description": "Get secret", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "secretId": { + "type": "string", + "description": "ID of the secret" + } + }, + "required": [ + "secretId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_update_secret", + "kind": "api", + "path": "/secret/{secretId}", + "method": "PATCH", + "parameters": [ + { + "name": "secretId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Update secret", + "description": "Update secret", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "secretId": { + "type": "string", + "description": "ID of the secret" + } + }, + "required": [ + "secretId" + ], + "additionalProperties": false + }, + "body": { + "$ref": "#/definitions/UpdateSecret" + } + }, + "required": [ + "path", + "body" + ], + "definitions": { + "UpdateSecret": { + "properties": { + "value": { + "description": "New secret value", + "type": "string" + }, + "description": { + "description": "Optional description of the secret", + "type": "string" + }, + "hosts": { + "description": "Allowed hosts this secret may be sent to", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_list_pending_sso_links", + "kind": "api", + "path": "/users/me/pending-sso-links", + "method": "GET", + "parameters": [], + "title": "List pending SSO account links for the authenticated user", + "description": "List pending SSO account links for the authenticated user", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_confirm_pending_sso_link", + "kind": "api", + "path": "/users/me/pending-sso-links/{id}/confirm", + "method": "POST", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Confirm (link) a pending SSO account link", + "description": "Confirm (link) a pending SSO account link", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_dismiss_pending_sso_link", + "kind": "api", + "path": "/users/me/pending-sso-links/{id}", + "method": "DELETE", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Dismiss a pending SSO account link", + "description": "Dismiss a pending SSO account link", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_webhook_controller_get_app_portal_access", + "kind": "api", + "path": "/webhooks/organizations/{organizationId}/app-portal-access", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get Svix Consumer App Portal access for an organization", + "description": "Get Svix Consumer App Portal access for an organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_webhook_controller_get_initialization_status", + "kind": "api", + "path": "/webhooks/organizations/{organizationId}/initialization-status", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get webhook initialization status for an organization", + "description": "Get webhook initialization status for an organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_webhook_controller_initialize_webhooks", + "kind": "api", + "path": "/webhooks/organizations/{organizationId}/initialize", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Initialize webhooks for an organization", + "description": "Initialize webhooks for an organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_webhook_controller_refresh_endpoints", + "kind": "api", + "path": "/webhooks/organizations/{organizationId}/refresh-endpoints", + "method": "POST", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Refresh cached endpoint presence flag for an organization", + "description": "Refresh cached endpoint presence flag for an organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_organization_audit_logs", + "kind": "api", + "path": "/audit/organizations/{organizationId}", + "method": "GET", + "parameters": [ + { + "name": "organizationId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "page", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "limit", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "from", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "to", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "nextToken", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "id", + "group": "query", + "style": "deepObject", + "explode": true, + "json": false + }, + { + "name": "actorId", + "group": "query", + "style": "deepObject", + "explode": true, + "json": false + }, + { + "name": "actorEmail", + "group": "query", + "style": "deepObject", + "explode": true, + "json": false + }, + { + "name": "actorApiKeyPrefix", + "group": "query", + "style": "deepObject", + "explode": true, + "json": false + }, + { + "name": "actorApiKeySuffix", + "group": "query", + "style": "deepObject", + "explode": true, + "json": false + }, + { + "name": "action", + "group": "query", + "style": "deepObject", + "explode": true, + "json": false + }, + { + "name": "targetType", + "group": "query", + "style": "deepObject", + "explode": true, + "json": false + }, + { + "name": "targetId", + "group": "query", + "style": "deepObject", + "explode": true, + "json": false + }, + { + "name": "statusCode", + "group": "query", + "style": "deepObject", + "explode": true, + "json": false + }, + { + "name": "createdAt", + "group": "query", + "style": "deepObject", + "explode": true, + "json": false + } + ], + "title": "Get audit logs for organization", + "description": "Get audit logs for organization", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID" + } + }, + "required": [ + "organizationId" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "page": { + "default": 1, + "minimum": 1, + "type": "integer", + "description": "Page number of the results" + }, + "limit": { + "default": 100, + "maximum": 200, + "minimum": 1, + "type": "integer", + "description": "Number of results per page" + }, + "from": { + "format": "date-time", + "type": "string", + "description": "Deprecated alias for `createdAt[gte]`. From date (ISO 8601 format)." + }, + "to": { + "format": "date-time", + "type": "string", + "description": "Deprecated alias for `createdAt[lte]`. To date (ISO 8601 format)." + }, + "nextToken": { + "type": "string", + "description": "Token for cursor-based pagination. When provided, takes precedence over page parameter." + }, + "id": { + "$ref": "#/definitions/StringFilter", + "description": "Filter by audit log ID." + }, + "actorId": { + "$ref": "#/definitions/StringFilter", + "description": "Filter by actor user ID." + }, + "actorEmail": { + "$ref": "#/definitions/StringFilter", + "description": "Filter by actor email." + }, + "actorApiKeyPrefix": { + "$ref": "#/definitions/StringFilter", + "description": "Filter by actor API key prefix." + }, + "actorApiKeySuffix": { + "$ref": "#/definitions/StringFilter", + "description": "Filter by actor API key suffix." + }, + "action": { + "$ref": "#/definitions/StringFilter", + "description": "Filter by action." + }, + "targetType": { + "$ref": "#/definitions/StringFilter", + "description": "Filter by target type." + }, + "targetId": { + "$ref": "#/definitions/StringFilter", + "description": "Filter by target ID." + }, + "statusCode": { + "$ref": "#/definitions/IntFilter", + "description": "Filter by HTTP status code." + }, + "createdAt": { + "$ref": "#/definitions/DateFilter", + "description": "Filter by creation timestamp." + } + }, + "required": [], + "additionalProperties": false + } + }, + "required": [ + "path" + ], + "definitions": { + "StringFilter": { + "properties": { + "eq": { + "description": "Match values equal to this value.", + "type": "string" + }, + "not": { + "description": "Match values not equal to this value.", + "type": "string" + }, + "in": { + "description": "Match values present in this list. Accepts comma-separated values or repeated query parameters. Maximum 100 entries.", + "items": { + "type": "string" + }, + "type": "array" + }, + "notIn": { + "description": "Match values not present in this list. Accepts comma-separated values or repeated query parameters. Maximum 100 entries.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "IntFilter": { + "properties": { + "eq": { + "description": "Match values equal to this value.", + "type": "number" + }, + "not": { + "description": "Match values not equal to this value.", + "type": "number" + }, + "in": { + "description": "Match values present in this list. Accepts comma-separated values or repeated query parameters. Maximum 100 entries.", + "items": { + "type": "number" + }, + "type": "array" + }, + "notIn": { + "description": "Match values not present in this list. Accepts comma-separated values or repeated query parameters. Maximum 100 entries.", + "items": { + "type": "number" + }, + "type": "array" + }, + "gte": { + "description": "Match values greater than or equal to this value.", + "type": "number" + }, + "lte": { + "description": "Match values less than or equal to this value.", + "type": "number" + }, + "gt": { + "description": "Match values strictly greater than this value.", + "type": "number" + }, + "lt": { + "description": "Match values strictly less than this value.", + "type": "number" + } + }, + "type": "object" + }, + "DateFilter": { + "properties": { + "gte": { + "description": "Match values greater than or equal to this timestamp (ISO 8601).", + "format": "date-time", + "type": "string" + }, + "lte": { + "description": "Match values less than or equal to this timestamp (ISO 8601).", + "format": "date-time", + "type": "string" + }, + "gt": { + "description": "Match values strictly greater than this timestamp (ISO 8601).", + "format": "date-time", + "type": "string" + }, + "lt": { + "description": "Match values strictly less than this timestamp (ISO 8601).", + "format": "date-time", + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_audit_scenarios", + "kind": "api", + "path": "/audit/scenarios", + "method": "GET", + "parameters": [], + "title": "Get supported audit log scenarios", + "description": "Returns the supported audit log actions grouped by target type. The list is derived at runtime from the audited routes and system events, so it always reflects what can actually appear in the audit log.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_push_access", + "kind": "api", + "path": "/object-storage/push-access", + "method": "GET", + "parameters": [], + "title": "Get temporary storage access for pushing objects", + "description": "Get temporary storage access for pushing objects", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_api_health_controller_live", + "kind": "api", + "path": "/health", + "method": "GET", + "parameters": [], + "title": "HealthController_live", + "description": "HealthController_live", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_health_controller_check", + "kind": "api", + "path": "/health/ready", + "method": "GET", + "parameters": [], + "title": "HealthController_check", + "description": "HealthController_check", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": {}, + "required": [] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox_logs", + "kind": "api", + "path": "/sandbox/{sandboxId}/telemetry/logs", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "from", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "to", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "page", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "limit", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "severities", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "search", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get sandbox logs", + "description": "Retrieve OTEL logs for a sandbox within a time range", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "from": { + "format": "date-time", + "type": "string", + "description": "Start of time range (ISO 8601)" + }, + "to": { + "format": "date-time", + "type": "string", + "description": "End of time range (ISO 8601)" + }, + "page": { + "default": 1, + "type": "integer", + "description": "Page number (1-indexed)" + }, + "limit": { + "default": 100, + "type": "integer", + "description": "Number of items per page" + }, + "severities": { + "items": { + "type": "string" + }, + "type": "array", + "description": "Filter by severity levels (DEBUG, INFO, WARN, ERROR)" + }, + "search": { + "type": "string", + "description": "Search in log body" + } + }, + "required": [ + "from", + "to" + ], + "additionalProperties": false + } + }, + "required": [ + "path", + "query" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox_traces", + "kind": "api", + "path": "/sandbox/{sandboxId}/telemetry/traces", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "from", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "to", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "page", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "limit", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get sandbox traces", + "description": "Retrieve OTEL traces for a sandbox within a time range", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "from": { + "format": "date-time", + "type": "string", + "description": "Start of time range (ISO 8601)" + }, + "to": { + "format": "date-time", + "type": "string", + "description": "End of time range (ISO 8601)" + }, + "page": { + "default": 1, + "type": "integer", + "description": "Page number (1-indexed)" + }, + "limit": { + "default": 100, + "type": "integer", + "description": "Number of items per page" + } + }, + "required": [ + "from", + "to" + ], + "additionalProperties": false + } + }, + "required": [ + "path", + "query" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox_trace_spans", + "kind": "api", + "path": "/sandbox/{sandboxId}/telemetry/traces/{traceId}", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "traceId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + } + ], + "title": "Get trace spans", + "description": "Retrieve all spans for a specific trace", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + }, + "traceId": { + "type": "string", + "description": "ID of the trace" + } + }, + "required": [ + "sandboxId", + "traceId" + ], + "additionalProperties": false + } + }, + "required": [ + "path" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_api_get_sandbox_metrics", + "kind": "api", + "path": "/sandbox/{sandboxId}/telemetry/metrics", + "method": "GET", + "parameters": [ + { + "name": "sandboxId", + "group": "path", + "style": "simple", + "explode": false, + "json": false + }, + { + "name": "from", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "to", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "metricNames", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get sandbox metrics", + "description": "Retrieve OTEL metrics for a sandbox within a time range", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the sandbox" + } + }, + "required": [ + "sandboxId" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "from": { + "format": "date-time", + "type": "string", + "description": "Start of time range (ISO 8601)" + }, + "to": { + "format": "date-time", + "type": "string", + "description": "End of time range (ISO 8601)" + }, + "metricNames": { + "items": { + "type": "string" + }, + "type": "array", + "description": "Filter by metric names" + } + }, + "required": [ + "from", + "to" + ], + "additionalProperties": false + } + }, + "required": [ + "path", + "query" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_find_accessibility_nodes", + "kind": "toolbox", + "path": "/computeruse/a11y/find", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Find accessibility nodes", + "description": "Search the AT-SPI tree for nodes matching a role/name/state filter and return a flat list.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/FindAccessibilityNodesRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "FindAccessibilityNodesRequest": { + "properties": { + "limit": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "nameMatch": { + "description": "\"exact\" | \"substring\" | \"regex\"", + "type": "string" + }, + "pid": { + "type": "integer" + }, + "role": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "states": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_focus_accessibility_node", + "kind": "toolbox", + "path": "/computeruse/a11y/node/focus", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Focus an accessibility node", + "description": "Move keyboard focus to the AT-SPI node identified by id (bus-name:object-path).", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/AccessibilityNodeRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "AccessibilityNodeRequest": { + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_invoke_accessibility_node", + "kind": "toolbox", + "path": "/computeruse/a11y/node/invoke", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Invoke an action on an accessibility node", + "description": "Call an AT-SPI Action on the node. Leave action empty to invoke the node's primary (first) action.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/AccessibilityInvokeRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "AccessibilityInvokeRequest": { + "properties": { + "action": { + "type": "string" + }, + "id": { + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_set_accessibility_node_value", + "kind": "toolbox", + "path": "/computeruse/a11y/node/value", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Set the value of an accessibility node", + "description": "Write the given value to the node via EditableText.SetTextContents or, for numeric controls, Value.CurrentValue.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/AccessibilitySetValueRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "AccessibilitySetValueRequest": { + "properties": { + "id": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_accessibility_tree", + "kind": "toolbox", + "path": "/computeruse/a11y/tree", + "method": "GET", + "parameters": [ + { + "name": "scope", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "pid", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "maxDepth", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get accessibility tree", + "description": "Fetch the AT-SPI accessibility tree for the focused application, a specific PID, or all registered applications.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "scope": { + "type": "string", + "description": "Scope: focused | pid | all (default: focused)" + }, + "pid": { + "type": "integer", + "description": "Process ID when scope=pid" + }, + "maxDepth": { + "type": "integer", + "description": "Max tree depth (-1 unbounded, 0 root only; default -1)" + } + }, + "required": [], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_display_info", + "kind": "toolbox", + "path": "/computeruse/display/info", + "method": "GET", + "parameters": [], + "title": "Get display information", + "description": "Get information about all available displays", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_windows", + "kind": "toolbox", + "path": "/computeruse/display/windows", + "method": "GET", + "parameters": [], + "title": "Get windows information", + "description": "Get information about all open windows", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_key_down", + "kind": "toolbox", + "path": "/computeruse/keyboard/down", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Press and hold a keyboard key", + "description": "Press a key or modifier and hold it down until a matching key up call", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/KeyboardKeyDownRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "KeyboardKeyDownRequest": { + "properties": { + "key": { + "description": "e.g., \"ctrl\", \"shift\", \"a\"", + "type": "string" + } + }, + "required": [ + "key" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_press_hotkey", + "kind": "toolbox", + "path": "/computeruse/keyboard/hotkey", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Press hotkey", + "description": "Press a hotkey combination (e.g., ctrl+c, cmd+v)", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/KeyboardHotkeyRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "KeyboardHotkeyRequest": { + "properties": { + "keys": { + "description": "e.g., \"ctrl+c\", \"cmd+v\"", + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_press_key", + "kind": "toolbox", + "path": "/computeruse/keyboard/key", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Press key", + "description": "Press a key with optional modifiers", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/KeyboardPressRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "KeyboardPressRequest": { + "properties": { + "key": { + "type": "string" + }, + "modifiers": { + "description": "ctrl, alt, shift, cmd", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_type_text", + "kind": "toolbox", + "path": "/computeruse/keyboard/type", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Type text", + "description": "Type text with optional delay between keystrokes", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/KeyboardTypeRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "KeyboardTypeRequest": { + "properties": { + "delay": { + "description": "milliseconds between keystrokes", + "type": "integer" + }, + "text": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_key_up", + "kind": "toolbox", + "path": "/computeruse/keyboard/up", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Release a held keyboard key", + "description": "Release a key or modifier that is currently held down", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/KeyboardKeyUpRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "KeyboardKeyUpRequest": { + "properties": { + "key": { + "description": "e.g., \"ctrl\", \"shift\", \"a\"", + "type": "string" + } + }, + "required": [ + "key" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_click", + "kind": "toolbox", + "path": "/computeruse/mouse/click", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Click mouse button", + "description": "Click the mouse button at the specified coordinates", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/MouseClickRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "MouseClickRequest": { + "properties": { + "button": { + "description": "left, right, middle", + "type": "string" + }, + "clicks": { + "description": "Clicks is a pointer so an omitted value is distinguishable from an\nexplicit 0, which must be rejected rather than silently defaulted.", + "type": "integer" + }, + "double": { + "type": "boolean" + }, + "modifiers": { + "items": { + "type": "string" + }, + "type": "array" + }, + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_mouse_down", + "kind": "toolbox", + "path": "/computeruse/mouse/down", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Press mouse button", + "description": "Press and hold a mouse button, optionally moving to the specified coordinates first", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/MouseDownRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "MouseDownRequest": { + "properties": { + "button": { + "description": "left, right, middle", + "type": "string" + }, + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_drag", + "kind": "toolbox", + "path": "/computeruse/mouse/drag", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Drag mouse", + "description": "Drag the mouse from start to end coordinates", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/MouseDragRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "MouseDragRequest": { + "properties": { + "button": { + "type": "string" + }, + "endX": { + "type": "integer" + }, + "endY": { + "type": "integer" + }, + "modifiers": { + "items": { + "type": "string" + }, + "type": "array" + }, + "startX": { + "type": "integer" + }, + "startY": { + "type": "integer" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_move_mouse", + "kind": "toolbox", + "path": "/computeruse/mouse/move", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Move mouse cursor", + "description": "Move the mouse cursor to the specified coordinates", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/MouseMoveRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "MouseMoveRequest": { + "properties": { + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_mouse_position", + "kind": "toolbox", + "path": "/computeruse/mouse/position", + "method": "GET", + "parameters": [], + "title": "Get mouse position", + "description": "Get the current mouse cursor position", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_scroll", + "kind": "toolbox", + "path": "/computeruse/mouse/scroll", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Scroll mouse wheel", + "description": "Scroll the mouse wheel at the specified coordinates", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/MouseScrollRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "MouseScrollRequest": { + "properties": { + "amount": { + "minimum": 0, + "type": "integer" + }, + "direction": { + "description": "up, down, left, right", + "type": "string" + }, + "modifiers": { + "items": { + "type": "string" + }, + "type": "array" + }, + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_mouse_up", + "kind": "toolbox", + "path": "/computeruse/mouse/up", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Release mouse button", + "description": "Release a held mouse button, optionally moving to the specified coordinates first", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/MouseUpRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "MouseUpRequest": { + "properties": { + "button": { + "description": "left, right, middle", + "type": "string" + }, + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_computer_use_status", + "kind": "toolbox", + "path": "/computeruse/process-status", + "method": "GET", + "parameters": [], + "title": "Get computer use process status", + "description": "Get the status of all computer use processes", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_process_errors", + "kind": "toolbox", + "path": "/computeruse/process/{processName}/errors", + "method": "GET", + "parameters": [ + { + "name": "processName", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get process errors", + "description": "Get errors for a specific computer use process", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "processName": { + "type": "string", + "description": "Process name to get errors for" + } + }, + "required": [ + "processName" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_process_logs", + "kind": "toolbox", + "path": "/computeruse/process/{processName}/logs", + "method": "GET", + "parameters": [ + { + "name": "processName", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get process logs", + "description": "Get logs for a specific computer use process", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "processName": { + "type": "string", + "description": "Process name to get logs for" + } + }, + "required": [ + "processName" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_restart_process", + "kind": "toolbox", + "path": "/computeruse/process/{processName}/restart", + "method": "POST", + "parameters": [ + { + "name": "processName", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Restart specific process", + "description": "Restart a specific computer use process", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "processName": { + "type": "string", + "description": "Process name to restart" + } + }, + "required": [ + "processName" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_process_status", + "kind": "toolbox", + "path": "/computeruse/process/{processName}/status", + "method": "GET", + "parameters": [ + { + "name": "processName", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get specific process status", + "description": "Check if a specific computer use process is running", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "processName": { + "type": "string", + "description": "Process name to check" + } + }, + "required": [ + "processName" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_list_recordings", + "kind": "toolbox", + "path": "/computeruse/recordings", + "method": "GET", + "parameters": [], + "title": "List all recordings", + "description": "Get a list of all recordings (active and completed)", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_start_recording", + "kind": "toolbox", + "path": "/computeruse/recordings/start", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Start a new recording", + "description": "Start a new screen recording session", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/StartRecordingRequest" + } + }, + "required": [ + "sandboxId" + ], + "definitions": { + "StartRecordingRequest": { + "properties": { + "label": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_stop_recording", + "kind": "toolbox", + "path": "/computeruse/recordings/stop", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Stop a recording", + "description": "Stop an active screen recording session", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/StopRecordingRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "StopRecordingRequest": { + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_delete_recording", + "kind": "toolbox", + "path": "/computeruse/recordings/{id}", + "method": "DELETE", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Delete a recording", + "description": "Delete a recording file by ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Recording ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_recording", + "kind": "toolbox", + "path": "/computeruse/recordings/{id}", + "method": "GET", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get recording details", + "description": "Get details of a specific recording by ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Recording ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_download_recording", + "kind": "toolbox", + "path": "/computeruse/recordings/{id}/download", + "method": "GET", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Download a recording", + "description": "Download a recording by providing its ID", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Recording ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_take_screenshot", + "kind": "toolbox", + "path": "/computeruse/screenshot", + "method": "GET", + "parameters": [ + { + "name": "showCursor", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Take a screenshot", + "description": "Take a screenshot of the entire screen", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "showCursor": { + "type": "boolean", + "description": "Whether to show cursor in screenshot" + } + }, + "required": [], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_take_compressed_screenshot", + "kind": "toolbox", + "path": "/computeruse/screenshot/compressed", + "method": "GET", + "parameters": [ + { + "name": "showCursor", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "format", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "quality", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "scale", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Take a compressed screenshot", + "description": "Take a compressed screenshot of the entire screen", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "showCursor": { + "type": "boolean", + "description": "Whether to show cursor in screenshot" + }, + "format": { + "type": "string", + "description": "Image format (png or jpeg)" + }, + "quality": { + "type": "integer", + "description": "JPEG quality (1-100)" + }, + "scale": { + "type": "number", + "description": "Scale factor (0.1-1.0)" + } + }, + "required": [], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_take_region_screenshot", + "kind": "toolbox", + "path": "/computeruse/screenshot/region", + "method": "GET", + "parameters": [ + { + "name": "x", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "y", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "width", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "height", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "showCursor", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Take a region screenshot", + "description": "Take a screenshot of a specific region of the screen", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "x": { + "type": "integer", + "description": "X coordinate of the region" + }, + "y": { + "type": "integer", + "description": "Y coordinate of the region" + }, + "width": { + "type": "integer", + "description": "Width of the region" + }, + "height": { + "type": "integer", + "description": "Height of the region" + }, + "showCursor": { + "type": "boolean", + "description": "Whether to show cursor in screenshot" + } + }, + "required": [ + "x", + "y", + "width", + "height" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_take_compressed_region_screenshot", + "kind": "toolbox", + "path": "/computeruse/screenshot/region/compressed", + "method": "GET", + "parameters": [ + { + "name": "x", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "y", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "width", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "height", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "showCursor", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "format", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "quality", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "scale", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Take a compressed region screenshot", + "description": "Take a compressed screenshot of a specific region of the screen", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "x": { + "type": "integer", + "description": "X coordinate of the region" + }, + "y": { + "type": "integer", + "description": "Y coordinate of the region" + }, + "width": { + "type": "integer", + "description": "Width of the region" + }, + "height": { + "type": "integer", + "description": "Height of the region" + }, + "showCursor": { + "type": "boolean", + "description": "Whether to show cursor in screenshot" + }, + "format": { + "type": "string", + "description": "Image format (png or jpeg)" + }, + "quality": { + "type": "integer", + "description": "JPEG quality (1-100)" + }, + "scale": { + "type": "number", + "description": "Scale factor (0.1-1.0)" + } + }, + "required": [ + "x", + "y", + "width", + "height" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_start_computer_use", + "kind": "toolbox", + "path": "/computeruse/start", + "method": "POST", + "parameters": [], + "title": "Start computer use processes", + "description": "Start all computer use processes and return their status", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_computer_use_system_status", + "kind": "toolbox", + "path": "/computeruse/status", + "method": "GET", + "parameters": [], + "title": "Get computer use status", + "description": "Get the current status of the computer use system", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_stop_computer_use", + "kind": "toolbox", + "path": "/computeruse/stop", + "method": "POST", + "parameters": [], + "title": "Stop computer use processes", + "description": "Stop all computer use processes and return their status", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_update_env", + "kind": "toolbox", + "path": "/env", + "method": "POST", + "parameters": [], + "bodyContentType": "*/*", + "title": "Update process environment", + "description": "Update the daemon's process environment. Newly spawned processes, sessions and PTYs inherit the change; already-running processes keep their environment.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/UpdateEnvRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "UpdateEnvRequest": { + "properties": { + "set": { + "additionalProperties": { + "type": "string" + }, + "description": "Set maps env var names to values applied to the daemon's process env, so\nprocesses spawned after the call (exec, sessions, PTYs) inherit them.", + "type": "object" + }, + "unset": { + "description": "Unset lists env var names to remove before Set is applied.", + "items": { + "type": "string" + }, + "type": "array" + }, + "unsetValuePrefix": { + "description": "UnsetValuePrefix removes every env var whose value has this prefix and\nwhose name is not a key of Set, before Set is applied. Used to reconcile\nsecret placeholder vars without the caller knowing the daemon's env.", + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_delete_file", + "kind": "toolbox", + "path": "/files", + "method": "DELETE", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "recursive", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Delete a file or directory", + "description": "Delete a file or directory at the specified path", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File or directory path to delete" + }, + "recursive": { + "type": "boolean", + "description": "Enable recursive deletion for directories" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_list_files", + "kind": "toolbox", + "path": "/files", + "method": "GET", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "depth", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "List files and directories", + "description": "List files and directories in the specified path. Use the optional depth\nparameter to list recursively: depth=1 (default) lists the directory's\nentries, depth=2 also includes their children, and so on.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Directory path to list (defaults to working directory)" + }, + "depth": { + "type": "integer", + "description": "How many levels deep to list (default: 1, must be >= 1)" + } + }, + "required": [], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_download_files", + "kind": "toolbox", + "path": "/files/bulk-download", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Download multiple files", + "description": "Download multiple files by providing their paths. Successful files are returned as multipart parts named `file`. Per-file failures are returned as multipart parts named `error` with JSON payloads shaped like ErrorResponse.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/FilesDownloadRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "FilesDownloadRequest": { + "properties": { + "paths": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "paths" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_upload_files", + "kind": "toolbox", + "path": "/files/bulk-upload", + "method": "POST", + "parameters": [], + "bodyContentType": "multipart/form-data", + "title": "Upload multiple files", + "description": "Upload multiple files with their destination paths", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "files": { + "type": "array", + "minItems": 1, + "maxItems": 100, + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "string", + "minLength": 1 + }, + "contentBase64": { + "type": "string", + "contentEncoding": "base64" + } + }, + "required": [ + "path", + "contentBase64" + ] + } + } + }, + "required": [ + "sandboxId", + "files" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_download_file", + "kind": "toolbox", + "path": "/files/download", + "method": "GET", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Download a file", + "description": "Download a file by providing its path", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path to download" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_find_in_files", + "kind": "toolbox", + "path": "/files/find", + "method": "GET", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "pattern", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Find text in files", + "description": "Search for text pattern within files in a directory", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Directory path to search in" + }, + "pattern": { + "type": "string", + "description": "Text pattern to search for" + } + }, + "required": [ + "path", + "pattern" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_create_folder", + "kind": "toolbox", + "path": "/files/folder", + "method": "POST", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "mode", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Create a folder", + "description": "Create a folder with the specified path and optional permissions", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Folder path to create" + }, + "mode": { + "type": "string", + "description": "Octal permission mode (default: 0755)" + } + }, + "required": [ + "path", + "mode" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_file_info", + "kind": "toolbox", + "path": "/files/info", + "method": "GET", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get file information", + "description": "Get detailed information about a file or directory", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File or directory path" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_move_file", + "kind": "toolbox", + "path": "/files/move", + "method": "POST", + "parameters": [ + { + "name": "source", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "destination", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Move or rename file/directory", + "description": "Move or rename a file or directory from source to destination", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "Source file or directory path" + }, + "destination": { + "type": "string", + "description": "Destination file or directory path" + } + }, + "required": [ + "source", + "destination" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_set_file_permissions", + "kind": "toolbox", + "path": "/files/permissions", + "method": "POST", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "owner", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "group", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "mode", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Set file permissions", + "description": "Set file permissions, ownership, and group for a file or directory", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File or directory path" + }, + "owner": { + "type": "string", + "description": "Owner (username or UID)" + }, + "group": { + "type": "string", + "description": "Group (group name or GID)" + }, + "mode": { + "type": "string", + "description": "File mode in octal format (e.g., 0755)" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_replace_in_files", + "kind": "toolbox", + "path": "/files/replace", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Replace text in files", + "description": "Replace text pattern with new value in multiple files", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/ReplaceRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "ReplaceRequest": { + "properties": { + "files": { + "items": { + "type": "string" + }, + "type": "array" + }, + "newValue": { + "type": "string" + }, + "pattern": { + "type": "string" + } + }, + "required": [ + "files", + "newValue", + "pattern" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_search_files", + "kind": "toolbox", + "path": "/files/search", + "method": "GET", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "pattern", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Search files by pattern", + "description": "Search for files matching a specific pattern in a directory", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Directory path to search in" + }, + "pattern": { + "type": "string", + "description": "File pattern to match (e.g., *.txt, *.go)" + } + }, + "required": [ + "path", + "pattern" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_upload_file", + "kind": "toolbox", + "path": "/files/upload-v2", + "method": "POST", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "bodyContentType": "multipart/form-data", + "title": "Upload a file", + "description": "Upload a file to the specified path. Accepts either multipart/form-data\n(field \"file\") or a raw request body (e.g. application/octet-stream).\nParent directories are created if missing; an existing file is overwritten.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Destination path for the uploaded file" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/UploadFile_request" + } + }, + "required": [ + "query", + "sandboxId" + ], + "definitions": { + "UploadFile_request": { + "properties": { + "file": { + "description": "File to upload (multipart/form-data) (base64; never a host file path)", + "type": "string", + "contentEncoding": "base64" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_add_files", + "kind": "toolbox", + "path": "/git/add", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Add files to Git staging", + "description": "Add files to the Git staging area", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitAddRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitAddRequest": { + "properties": { + "files": { + "description": "files to add (use . for all files)", + "items": { + "type": "string" + }, + "type": "array" + }, + "path": { + "type": "string" + } + }, + "required": [ + "files", + "path" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_delete_branch", + "kind": "toolbox", + "path": "/git/branches", + "method": "DELETE", + "parameters": [], + "bodyContentType": "application/json", + "title": "Delete a branch", + "description": "Delete a branch from the Git repository", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitDeleteBranchRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitDeleteBranchRequest": { + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "name", + "path" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_list_branches", + "kind": "toolbox", + "path": "/git/branches", + "method": "GET", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "List branches", + "description": "Get a list of all branches in the Git repository", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Repository path" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_create_branch", + "kind": "toolbox", + "path": "/git/branches", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create a new branch", + "description": "Create a new branch in the Git repository", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitBranchRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitBranchRequest": { + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "name", + "path" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_checkout_branch", + "kind": "toolbox", + "path": "/git/checkout", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Checkout branch or commit", + "description": "Switch to a different branch or commit in the Git repository", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitCheckoutRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitCheckoutRequest": { + "properties": { + "branch": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "branch", + "path" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_clone_repository", + "kind": "toolbox", + "path": "/git/clone", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Clone a Git repository", + "description": "Clone a Git repository to the specified path. Defaults to strict TLS verification; set insecure_skip_tls=true to skip verification for self-signed or private-CA Git servers.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitCloneRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitCloneRequest": { + "properties": { + "branch": { + "type": "string" + }, + "commit_id": { + "type": "string" + }, + "depth": { + "description": "Depth creates a shallow clone truncated to the given number of commits.", + "type": "integer" + }, + "insecure_skip_tls": { + "description": "Skip TLS certificate verification for this clone. Defaults to false (verify).\nSet to true ONLY for trusted internal Git servers with self-signed or\nprivate-CA certs; credentials, if supplied, will be transmitted over an\nunverified TLS connection and are exposed to any MITM on the route.", + "type": "boolean" + }, + "password": { + "type": "string" + }, + "path": { + "type": "string" + }, + "url": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "required": [ + "path", + "url" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_commit_changes", + "kind": "toolbox", + "path": "/git/commit", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Commit changes", + "description": "Commit staged changes to the Git repository", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitCommitRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitCommitRequest": { + "properties": { + "allow_empty": { + "type": "boolean" + }, + "author": { + "type": "string" + }, + "email": { + "type": "string" + }, + "message": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "author", + "email", + "message", + "path" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_git_config", + "kind": "toolbox", + "path": "/git/config", + "method": "GET", + "parameters": [ + { + "name": "key", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "scope", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get a Git config value", + "description": "Get a Git config value at the given scope (null when unset)", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "key": { + "type": "string", + "description": "Config key (e.g. user.name)" + }, + "path": { + "type": "string", + "description": "Repository path (required for local scope)" + }, + "scope": { + "type": "string", + "description": "Config scope: global (default), local or system" + } + }, + "required": [ + "key" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_set_git_config", + "kind": "toolbox", + "path": "/git/config", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Set a Git config value", + "description": "Set a Git config key/value at the given scope", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitSetConfigRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitSetConfigRequest": { + "properties": { + "key": { + "type": "string" + }, + "path": { + "description": "Path is the repository path, required when scope is \"local\".", + "type": "string" + }, + "scope": { + "description": "Scope is one of global (default), local or system.", + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "key", + "value" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_configure_user", + "kind": "toolbox", + "path": "/git/config/user", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Configure Git user", + "description": "Configure the Git user name and email at the given scope", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitConfigureUserRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitConfigureUserRequest": { + "properties": { + "email": { + "type": "string" + }, + "name": { + "type": "string" + }, + "path": { + "description": "Path is the repository path, required when scope is \"local\".", + "type": "string" + }, + "scope": { + "description": "Scope is one of global (default), local or system.", + "type": "string" + } + }, + "required": [ + "email", + "name" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_authenticate", + "kind": "toolbox", + "path": "/git/credentials", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Authenticate Git", + "description": "Persist Git credentials globally via the credential store. Stores the password in plaintext on disk.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitAuthenticateRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitAuthenticateRequest": { + "properties": { + "host": { + "description": "Host defaults to github.com.", + "type": "string" + }, + "password": { + "type": "string" + }, + "protocol": { + "description": "Protocol defaults to https.", + "type": "string" + }, + "username": { + "type": "string" + } + }, + "required": [ + "password", + "username" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_commit_history", + "kind": "toolbox", + "path": "/git/history", + "method": "GET", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get commit history", + "description": "Get the commit history of the Git repository", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Repository path" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_init_repository", + "kind": "toolbox", + "path": "/git/init", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Initialize a Git repository", + "description": "Initialize a new Git repository at the specified path", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitInitRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitInitRequest": { + "properties": { + "bare": { + "description": "Bare creates a repository without a working tree.", + "type": "boolean" + }, + "initial_branch": { + "description": "InitialBranch sets the name of the initial branch.", + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_pull_changes", + "kind": "toolbox", + "path": "/git/pull", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Pull changes from remote", + "description": "Pull changes from the remote Git repository", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitPullRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitPullRequest": { + "properties": { + "branch": { + "description": "Branch to pull (defaults to the current branch's upstream).", + "type": "string" + }, + "password": { + "type": "string" + }, + "path": { + "type": "string" + }, + "remote": { + "description": "Remote to pull from (defaults to \"origin\").", + "type": "string" + }, + "username": { + "type": "string" + } + }, + "required": [ + "path" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_push_changes", + "kind": "toolbox", + "path": "/git/push", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Push changes to remote", + "description": "Push local changes to the remote Git repository", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitPushRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitPushRequest": { + "properties": { + "branch": { + "description": "Branch to push (defaults to the current branch).", + "type": "string" + }, + "password": { + "type": "string" + }, + "path": { + "type": "string" + }, + "remote": { + "description": "Remote to push to (defaults to \"origin\").", + "type": "string" + }, + "set_upstream": { + "description": "SetUpstream records the pushed branch as the upstream tracking branch.", + "type": "boolean" + }, + "username": { + "type": "string" + } + }, + "required": [ + "path" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_list_remotes", + "kind": "toolbox", + "path": "/git/remotes", + "method": "GET", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "List remotes", + "description": "List the remotes configured in the Git repository", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Repository path" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_add_remote", + "kind": "toolbox", + "path": "/git/remotes", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Add a remote", + "description": "Add (or overwrite) a remote in the Git repository", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitAddRemoteRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitAddRemoteRequest": { + "properties": { + "fetch": { + "description": "Fetch fetches from the remote immediately after adding it.", + "type": "boolean" + }, + "name": { + "type": "string" + }, + "overwrite": { + "description": "Overwrite replaces an existing remote with the same name.", + "type": "boolean" + }, + "path": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "path", + "url" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_reset_changes", + "kind": "toolbox", + "path": "/git/reset", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Reset repository", + "description": "Reset the current HEAD to the specified state", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitResetRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitResetRequest": { + "properties": { + "files": { + "description": "Files constrains the reset to the given paths.", + "items": { + "type": "string" + }, + "type": "array" + }, + "mode": { + "description": "Mode is one of soft, mixed (default), hard, merge or keep.", + "type": "string" + }, + "path": { + "type": "string" + }, + "target": { + "description": "Target is the revision to reset to (defaults to HEAD).", + "type": "string" + } + }, + "required": [ + "path" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_restore_files", + "kind": "toolbox", + "path": "/git/restore", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Restore files", + "description": "Restore working tree files or unstage changes", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/GitRestoreRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "GitRestoreRequest": { + "properties": { + "files": { + "items": { + "type": "string" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "source": { + "description": "Source restores file contents from the given revision instead of the index.", + "type": "string" + }, + "staged": { + "description": "Staged restores the staging index for the given files.", + "type": "boolean" + }, + "worktree": { + "description": "Worktree restores the working tree for the given files.", + "type": "boolean" + } + }, + "required": [ + "files", + "path" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_status", + "kind": "toolbox", + "path": "/git/status", + "method": "GET", + "parameters": [ + { + "name": "path", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get Git status", + "description": "Get the Git status of the repository at the specified path", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Repository path" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_initialize", + "kind": "toolbox", + "path": "/init", + "method": "POST", + "parameters": [], + "bodyContentType": "*/*", + "title": "Initialize toolbox server", + "description": "Set the auth token and initialize telemetry for the toolbox server", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/InitializeRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "InitializeRequest": { + "properties": { + "token": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_completions", + "kind": "toolbox", + "path": "/lsp/completions", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Get code completions", + "description": "Get code completion suggestions from the LSP server", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/LspCompletionParams" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "LspCompletionParams": { + "properties": { + "context": { + "$ref": "#/definitions/CompletionContext" + }, + "languageId": { + "type": "string" + }, + "pathToProject": { + "type": "string" + }, + "position": { + "$ref": "#/definitions/LspPosition" + }, + "uri": { + "type": "string" + } + }, + "required": [ + "languageId", + "pathToProject", + "position", + "uri" + ], + "type": "object" + }, + "CompletionContext": { + "properties": { + "triggerCharacter": { + "type": "string" + }, + "triggerKind": { + "type": "integer" + } + }, + "required": [ + "triggerKind" + ], + "type": "object" + }, + "LspPosition": { + "properties": { + "character": { + "type": "integer" + }, + "line": { + "type": "integer" + } + }, + "required": [ + "character", + "line" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_did_close", + "kind": "toolbox", + "path": "/lsp/did-close", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Notify document closed", + "description": "Notify the LSP server that a document has been closed", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/LspDocumentRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "LspDocumentRequest": { + "properties": { + "languageId": { + "type": "string" + }, + "pathToProject": { + "type": "string" + }, + "uri": { + "type": "string" + } + }, + "required": [ + "languageId", + "pathToProject", + "uri" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_did_open", + "kind": "toolbox", + "path": "/lsp/did-open", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Notify document opened", + "description": "Notify the LSP server that a document has been opened", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/LspDocumentRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "LspDocumentRequest": { + "properties": { + "languageId": { + "type": "string" + }, + "pathToProject": { + "type": "string" + }, + "uri": { + "type": "string" + } + }, + "required": [ + "languageId", + "pathToProject", + "uri" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_document_symbols", + "kind": "toolbox", + "path": "/lsp/document-symbols", + "method": "GET", + "parameters": [ + { + "name": "languageId", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "pathToProject", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "uri", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get document symbols", + "description": "Get symbols (functions, classes, etc.) from a document", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "languageId": { + "type": "string", + "description": "Language ID (e.g., python, typescript)" + }, + "pathToProject": { + "type": "string", + "description": "Path to project" + }, + "uri": { + "type": "string", + "description": "Document URI" + } + }, + "required": [ + "languageId", + "pathToProject", + "uri" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_start", + "kind": "toolbox", + "path": "/lsp/start", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Start LSP server", + "description": "Start a Language Server Protocol server for the specified language", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/LspServerRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "LspServerRequest": { + "properties": { + "languageId": { + "type": "string" + }, + "pathToProject": { + "type": "string" + } + }, + "required": [ + "languageId", + "pathToProject" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_stop", + "kind": "toolbox", + "path": "/lsp/stop", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Stop LSP server", + "description": "Stop a Language Server Protocol server", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/LspServerRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "LspServerRequest": { + "properties": { + "languageId": { + "type": "string" + }, + "pathToProject": { + "type": "string" + } + }, + "required": [ + "languageId", + "pathToProject" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_workspace_symbols", + "kind": "toolbox", + "path": "/lsp/workspacesymbols", + "method": "GET", + "parameters": [ + { + "name": "query", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "languageId", + "group": "query", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "pathToProject", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get workspace symbols", + "description": "Search for symbols across the entire workspace", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "Search query" + }, + "languageId": { + "type": "string", + "description": "Language ID (e.g., python, typescript)" + }, + "pathToProject": { + "type": "string", + "description": "Path to project" + } + }, + "required": [ + "query", + "languageId", + "pathToProject" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "query", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_ports", + "kind": "toolbox", + "path": "/port", + "method": "GET", + "parameters": [], + "title": "Get active ports", + "description": "Get a list of all currently active ports", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_is_port_in_use", + "kind": "toolbox", + "path": "/port/{port}/in-use", + "method": "GET", + "parameters": [ + { + "name": "port", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Check if port is in use", + "description": "Check if a specific port is currently in use", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "port": { + "type": "integer", + "description": "Port number (3000-9999)" + } + }, + "required": [ + "port" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_code_run", + "kind": "toolbox", + "path": "/process/code-run", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Execute code", + "description": "Execute Python, JavaScript, or TypeScript code and return output, exit code, and artifacts", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/CodeRunRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "CodeRunRequest": { + "properties": { + "argv": { + "items": { + "type": "string" + }, + "type": "array" + }, + "code": { + "type": "string" + }, + "envs": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "language": { + "description": "python, javascript, typescript", + "type": "string" + }, + "timeout": { + "type": "integer" + } + }, + "required": [ + "code", + "language" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_execute_command", + "kind": "toolbox", + "path": "/process/execute", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Execute a command", + "description": "Execute a shell command and return the output and exit code", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/ExecuteRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "ExecuteRequest": { + "properties": { + "command": { + "type": "string" + }, + "cwd": { + "description": "Current working directory", + "type": "string" + }, + "envs": { + "additionalProperties": { + "type": "string" + }, + "description": "Environment variables to set for the command", + "type": "object" + }, + "timeout": { + "description": "Timeout in seconds, defaults to 10 seconds", + "type": "integer" + } + }, + "required": [ + "command" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_list_interpreter_contexts", + "kind": "toolbox", + "path": "/process/interpreter/context", + "method": "GET", + "parameters": [], + "title": "List all user-created interpreter contexts", + "description": "Returns information about all user-created interpreter contexts (excludes default context)", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_create_interpreter_context", + "kind": "toolbox", + "path": "/process/interpreter/context", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create a new interpreter context", + "description": "Creates a new isolated interpreter context with optional working directory and language", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/CreateContextRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "CreateContextRequest": { + "properties": { + "cwd": { + "type": "string" + }, + "language": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_delete_interpreter_context", + "kind": "toolbox", + "path": "/process/interpreter/context/{id}", + "method": "DELETE", + "parameters": [ + { + "name": "id", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Delete an interpreter context", + "description": "Deletes an interpreter context and shuts down its worker process", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Context ID" + } + }, + "required": [ + "id" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_list_pty_sessions", + "kind": "toolbox", + "path": "/process/pty", + "method": "GET", + "parameters": [], + "title": "List all PTY sessions", + "description": "Get a list of all active pseudo-terminal sessions", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_create_pty_session", + "kind": "toolbox", + "path": "/process/pty", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create a new PTY session", + "description": "Create a new pseudo-terminal session with specified configuration", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/PtyCreateRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "PtyCreateRequest": { + "properties": { + "cols": { + "type": "integer" + }, + "cwd": { + "type": "string" + }, + "envs": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "id": { + "type": "string" + }, + "lazyStart": { + "description": "Don't start PTY until first client connects", + "type": "boolean" + }, + "rows": { + "type": "integer" + } + }, + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_delete_pty_session", + "kind": "toolbox", + "path": "/process/pty/{sessionId}", + "method": "DELETE", + "parameters": [ + { + "name": "sessionId", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Delete a PTY session", + "description": "Delete a pseudo-terminal session and terminate its process", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "PTY session ID" + } + }, + "required": [ + "sessionId" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_pty_session", + "kind": "toolbox", + "path": "/process/pty/{sessionId}", + "method": "GET", + "parameters": [ + { + "name": "sessionId", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get PTY session information", + "description": "Get detailed information about a specific pseudo-terminal session", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "PTY session ID" + } + }, + "required": [ + "sessionId" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_resize_pty_session", + "kind": "toolbox", + "path": "/process/pty/{sessionId}/resize", + "method": "POST", + "parameters": [ + { + "name": "sessionId", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Resize a PTY session", + "description": "Resize the terminal dimensions of a pseudo-terminal session", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "PTY session ID" + } + }, + "required": [ + "sessionId" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/PtyResizeRequest" + } + }, + "required": [ + "path", + "sandboxId", + "body" + ], + "definitions": { + "PtyResizeRequest": { + "properties": { + "cols": { + "maximum": 1000, + "minimum": 1, + "type": "integer" + }, + "rows": { + "maximum": 1000, + "minimum": 1, + "type": "integer" + } + }, + "required": [ + "cols", + "rows" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_list_sessions", + "kind": "toolbox", + "path": "/process/session", + "method": "GET", + "parameters": [], + "title": "List all sessions", + "description": "Get a list of all active shell sessions", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_create_session", + "kind": "toolbox", + "path": "/process/session", + "method": "POST", + "parameters": [], + "bodyContentType": "application/json", + "title": "Create a new session", + "description": "Create a new shell session for command execution", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/CreateSessionRequest" + } + }, + "required": [ + "sandboxId", + "body" + ], + "definitions": { + "CreateSessionRequest": { + "properties": { + "sessionId": { + "type": "string" + } + }, + "required": [ + "sessionId" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_entrypoint_session", + "kind": "toolbox", + "path": "/process/session/entrypoint", + "method": "GET", + "parameters": [], + "title": "Get entrypoint session details", + "description": "Get details of an entrypoint session including its commands", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_entrypoint_logs", + "kind": "toolbox", + "path": "/process/session/entrypoint/logs", + "method": "GET", + "parameters": [ + { + "name": "follow", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get entrypoint logs", + "description": "Get logs for a sandbox entrypoint session. Returns JSON with separated stdout/stderr for SDK >= 0.161.0, plain text otherwise. Supports WebSocket streaming.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "object", + "properties": { + "follow": { + "type": "boolean", + "description": "Follow logs in real-time (WebSocket only)" + } + }, + "required": [], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_delete_session", + "kind": "toolbox", + "path": "/process/session/{sessionId}", + "method": "DELETE", + "parameters": [ + { + "name": "sessionId", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Delete a session", + "description": "Delete an existing shell session", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Session ID" + } + }, + "required": [ + "sessionId" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_session", + "kind": "toolbox", + "path": "/process/session/{sessionId}", + "method": "GET", + "parameters": [ + { + "name": "sessionId", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get session details", + "description": "Get details of a specific session including its commands", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Session ID" + } + }, + "required": [ + "sessionId" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_session_command", + "kind": "toolbox", + "path": "/process/session/{sessionId}/command/{commandId}", + "method": "GET", + "parameters": [ + { + "name": "sessionId", + "group": "path", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "commandId", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get session command details", + "description": "Get details of a specific command within a session", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Session ID" + }, + "commandId": { + "type": "string", + "description": "Command ID" + } + }, + "required": [ + "sessionId", + "commandId" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_send_input", + "kind": "toolbox", + "path": "/process/session/{sessionId}/command/{commandId}/input", + "method": "POST", + "parameters": [ + { + "name": "sessionId", + "group": "path", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "commandId", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Send input to command", + "description": "Send input data to a running command in a session for interactive execution", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Session ID" + }, + "commandId": { + "type": "string", + "description": "Command ID" + } + }, + "required": [ + "sessionId", + "commandId" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/SessionSendInputRequest" + } + }, + "required": [ + "path", + "sandboxId", + "body" + ], + "definitions": { + "SessionSendInputRequest": { + "properties": { + "data": { + "type": "string" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_session_command_logs", + "kind": "toolbox", + "path": "/process/session/{sessionId}/command/{commandId}/logs", + "method": "GET", + "parameters": [ + { + "name": "sessionId", + "group": "path", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "commandId", + "group": "path", + "style": "form", + "explode": true, + "json": false + }, + { + "name": "follow", + "group": "query", + "style": "form", + "explode": true, + "json": false + } + ], + "title": "Get session command logs", + "description": "Get logs for a specific command within a session. Returns JSON with separated stdout/stderr for SDK >= 0.167.0, plain text otherwise. Supports WebSocket streaming.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Session ID" + }, + "commandId": { + "type": "string", + "description": "Command ID" + } + }, + "required": [ + "sessionId", + "commandId" + ], + "additionalProperties": false + }, + "query": { + "type": "object", + "properties": { + "follow": { + "type": "boolean", + "description": "Follow logs in real-time (WebSocket only)" + } + }, + "required": [], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "path", + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_session_execute_command", + "kind": "toolbox", + "path": "/process/session/{sessionId}/exec", + "method": "POST", + "parameters": [ + { + "name": "sessionId", + "group": "path", + "style": "form", + "explode": true, + "json": false + } + ], + "bodyContentType": "application/json", + "title": "Execute command in session", + "description": "Execute a command within an existing shell session", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Session ID" + } + }, + "required": [ + "sessionId" + ], + "additionalProperties": false + }, + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "$ref": "#/definitions/SessionExecuteRequest" + } + }, + "required": [ + "path", + "sandboxId", + "body" + ], + "definitions": { + "SessionExecuteRequest": { + "properties": { + "async": { + "type": "boolean" + }, + "command": { + "type": "string" + }, + "runAsync": { + "type": "boolean" + }, + "suppressInputEcho": { + "type": "boolean" + } + }, + "required": [ + "command" + ], + "type": "object" + } + } + }, + "annotations": { + "readOnlyHint": false, + "destructiveHint": true, + "idempotentHint": false, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_system_metrics", + "kind": "toolbox", + "path": "/system/metrics", + "method": "GET", + "parameters": [], + "title": "Get sandbox resource metrics", + "description": "Latest CPU/memory/disk usage snapshot for the sandbox. cpuUsedPct is the\naverage CPU usage as a percentage of the CPU limit over the last sample\nwindow (0 until the first sample completes). Byte fields are in bytes.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_user_home_dir", + "kind": "toolbox", + "path": "/user-home-dir", + "method": "GET", + "parameters": [], + "title": "Get user home directory", + "description": "Get the current user home directory path.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_version", + "kind": "toolbox", + "path": "/version", + "method": "GET", + "parameters": [], + "title": "Get version", + "description": "Get the current daemon version", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + }, + { + "name": "daytona_toolbox_get_work_dir", + "kind": "toolbox", + "path": "/work-dir", + "method": "GET", + "parameters": [], + "title": "Get working directory", + "description": "Get the current working directory path. This is default directory used for running commands.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "sandboxId" + ] + }, + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true + } + } + ], + "streaming": [ + { + "name": "daytona_toolbox_execute_interpreter_code", + "kind": "toolbox", + "path": "/process/interpreter/execute", + "method": "GET", + "transport": "websocket" + }, + { + "name": "daytona_toolbox_connect_pty_session", + "kind": "toolbox", + "path": "/process/pty/{sessionId}/connect", + "method": "GET", + "transport": "websocket" + } + ] +} diff --git a/server/src/services/tool-access.ts b/server/src/services/tool-access.ts index f37c81032fe..cc068babbda 100644 --- a/server/src/services/tool-access.ts +++ b/server/src/services/tool-access.ts @@ -1,3 +1,5 @@ +import { stableHash, descriptorHash } from "./tool-catalog-hash.js"; +import { DAYTONA_TOOLS, daytonaClient, daytonaRisk, isDaytonaConnection, isDaytonaToolName } from "./daytona.js"; import { chatCredentialMutationLease } from "./chat-credential-mutation-lease.js"; import { notifyChatEndpointWork } from "./chat-work-notifications.js"; import { removeSlackRegistration } from "./chat-slack-registration-cleanup.js"; @@ -2255,11 +2257,6 @@ function buildProfileDetails(input: { }; } -function stableHash(value: unknown): string { - return createHash("sha256") - .update(JSON.stringify(value, Object.keys(flattenKeys(value)).sort())) - .digest("hex"); -} function connectionSetupMutationFingerprint( row: typeof toolConnections.$inferSelect, @@ -2280,20 +2277,6 @@ function connectionSetupMutationFingerprint( }); } -function flattenKeys( - value: unknown, - keys: Record = {}, -): Record { - if (value && typeof value === "object") { - for (const [key, nested] of Object.entries( - value as Record, - )) { - keys[key] = true; - flattenKeys(nested, keys); - } - } - return keys; -} function normalizeToolDescriptor(tool: unknown): McpToolDescriptor | null { const record = asRecord(tool); @@ -2401,6 +2384,7 @@ export function classifyRisk( if (sourceTemplateKey === "browser-use-cloud") { return BROWSER_USE_TOOLS.find(t => t.name === tool.name)?.annotations.readOnlyHint ? "read" : "destructive"; } + if (sourceTemplateKey === "daytona") return daytonaRisk(tool.name); if (sourceTemplateKey === "railway") { const reviewed = railwayRisk(normalizedToolName); return reviewed === "read" && (annotations.readOnlyHint === false || annotations.writeHint === true) ? "write" : reviewed; @@ -2866,19 +2850,6 @@ function recordValue(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } -function descriptorHash( - tool: McpToolDescriptor, - riskLevel: ToolRiskLevel, -): string { - return stableHash({ - name: tool.name, - title: tool.title ?? null, - description: tool.description ?? null, - inputSchema: tool.inputSchema ?? {}, - annotations: tool.annotations ?? {}, - riskLevel, - }); -} /** * Did this error come from the OAuth endpoint gate (PAP-17099)? Such a refusal @@ -3688,7 +3659,7 @@ export function toolAccessService( function shouldQuarantineNewEntries( connection: typeof toolConnections.$inferSelect, ): boolean { - return asRecord(connection.config).quarantineNewEntries === true; + return isDaytonaConnection(connection) || asRecord(connection.config).quarantineNewEntries === true; } function isAttentionHealthStatus( @@ -7502,6 +7473,11 @@ export function toolAccessService( ): Promise { assertSupportedConnection(connection); if (connection.connectionPurpose === "ai") throw unprocessable("AI connections provide runtime authentication, not tool actions"); + if (isDaytonaConnection(connection)) { + const headers = credentialHeaders ?? await resolveCredentialHeaders(connection, actor); + await daytonaClient(headers, (url, init) => requestRemoteHttpEndpoint(new URL(url), init), asRecord(connection.config.methodConfig).organizationId).probe(); + return DAYTONA_TOOLS; + } if (isBrowserUseConnection(connection)) { const headers = credentialHeaders ?? await resolveCredentialHeaders(connection, actor); await browserUseClient(headers, (url, init) => requestRemoteHttpEndpoint(new URL(url), init), connection.id).probe(); @@ -7657,7 +7633,7 @@ export function toolAccessService( }); for (const grant of grantsToCheck) await refreshManagedGitHubGrantAccess(connection, grant, actor); - } else if (isBrowserUseConnection(connection)) { + } else if (isBrowserUseConnection(connection) || isDaytonaConnection(connection)) { await discoverTools(connection, undefined, actor); } else if (isAgentMailConnection(connection)) { await validateAgentMailConnection(connection); @@ -7691,6 +7667,8 @@ export function toolAccessService( config.sourceTemplateKey === "github" && oauth.connectorProfile === "github.code" ? "GitHub account, installation, and repository access are available." + : isDaytonaConnection(connection) + ? "Daytona API access is connected." : isBrowserUseConnection(connection) ? "Browser Use API key is connected." : isAgentMailConnection(connection) @@ -7801,11 +7779,13 @@ export function toolAccessService( const existingByName = new Map( existingRows.map((entry) => [entry.toolName, entry]), ); - if (isRemoteMcpConnectorMethod(connection.config.sourceTemplateKey, connection.config.connectionMethodKey)) { + const nativeDaytona = isDaytonaConnection(connection); + if (nativeDaytona || isRemoteMcpConnectorMethod(connection.config.sourceTemplateKey, connection.config.connectionMethodKey)) { const discoveredNames = new Set(descriptors.map((descriptor) => descriptor.name)); - const removedIds = existingRows.filter((entry) => !discoveredNames.has(entry.toolName) && entry.status !== "disabled").map((entry) => entry.id); + const removedStatus = nativeDaytona ? "removed" : "disabled"; + const removedIds = existingRows.filter((entry) => !discoveredNames.has(entry.toolName) && entry.status !== removedStatus).map((entry) => entry.id); if (removedIds.length) await db.update(toolCatalogEntries) - .set({ status: "disabled", quarantineReason: "mcp_tool_removed", updatedAt: refreshedAt }) + .set({ status: removedStatus, quarantineReason: nativeDaytona ? "provider_tool_removed" : "mcp_tool_removed", updatedAt: refreshedAt }) .where(and(eq(toolCatalogEntries.companyId, connection.companyId), eq(toolCatalogEntries.connectionId, connection.id), inArray(toolCatalogEntries.id, removedIds))); } // Retired native actions are absent from discovery, but old catalog rows @@ -7843,7 +7823,7 @@ export function toolAccessService( ? googleProfileValue : null; const preserveReviewedCatalog = - (isRailwayEndpoint(connection.config.url) || sourceTemplateKey === "enterpret") && + (isRailwayEndpoint(connection.config.url) || sourceTemplateKey === "enterpret" || isDaytonaConnection(connection)) && existingRows.length > 0; const quarantineOnRefresh = (!refreshOptions.enableAllByDefault || preserveReviewedCatalog) && @@ -7865,7 +7845,7 @@ export function toolAccessService( quarantineOnRefresh && (!existing || changed) && existing?.status !== "disabled" && - (!safeDefault || riskLevel !== "read"); + (!safeDefault || riskLevel !== "read" || nativeDaytona); const providerPermanentlyBlocked = Boolean( googleProfile && !isGoogleWorkspaceToolAllowed(googleProfile, descriptor), @@ -7946,7 +7926,7 @@ export function toolAccessService( } const preserveQuarantine = - isRailwayEndpoint(connection.config.url) || sourceTemplateKey === "enterpret"; + isRailwayEndpoint(connection.config.url) || sourceTemplateKey === "enterpret" || isDaytonaConnection(connection); const normalizedConfig = preserveQuarantine ? { ...connection.config, quarantineNewEntries: true } : refreshOptions.enableAllByDefault @@ -12835,7 +12815,7 @@ export function toolAccessService( // Grant-backed setup keeps the full discovered catalog selectable; // the wizard projects the app's action defaults into policies at // finish time instead of using catalog quarantine as access state. - quarantineNewEntries: galleryEntry.slug === "railway" || galleryEntry.slug === "enterpret", + quarantineNewEntries: ["railway", "enterpret", "daytona"].includes(galleryEntry.slug), ...(remoteMcpConnector ? { mcpSessionRequired: true, mcpAuthMode: input.authMode ?? "auto", @@ -13163,7 +13143,7 @@ export function toolAccessService( applicationKey: `app-gallery:${galleryEntry?.slug ?? "link"}:${randomUUID()}`, name: applicationName, description: safeApplicationDescription, - type: transport === "rest_api" && galleryEntry?.slug === "browser-use-cloud" ? "rest_api" : transport === "mcp_remote" ? "mcp_http" : "mcp_stdio", + type: transport === "rest_api" && ["browser-use-cloud", "daytona"].includes(galleryEntry?.slug ?? "") ? "rest_api" : transport === "mcp_remote" ? "mcp_http" : "mcp_stdio", status: "draft", metadata: galleryEntry ? { @@ -18123,7 +18103,7 @@ export function toolAccessService( companyId, applicationKey: normalizeKey(input.applicationName ?? input.name), name: input.applicationName ?? input.name, - type: isBrowserUseConnection({ transport, config }) ? "rest_api" : transport === "mcp_remote" ? "mcp_http" : "mcp_stdio", + type: isBrowserUseConnection({ transport, config }) || isDaytonaConnection({ transport, config }) ? "rest_api" : transport === "mcp_remote" ? "mcp_http" : "mcp_stdio", status: "active", metadata: {}, }) @@ -19145,6 +19125,7 @@ export function toolAccessService( listCatalog: async ( connectionId: string, companyId?: string, + actor?: ActorInfo, ): Promise => { const connection = await getConnectionRow(connectionId, companyId); let rows = await db @@ -19152,17 +19133,29 @@ export function toolAccessService( .from(toolCatalogEntries) .where(eq(toolCatalogEntries.connectionId, connection.id)) .orderBy(desc(toolCatalogEntries.updatedAt)); - const cacheExpired = + // Native provider catalogs change with the deployed code. Upgrade saved + // Daytona connections too; their first small catalog must not survive + // merely because REST discovery has no remote MCP cache timer. + const nativeDaytona = isDaytonaConnection(connection); + const rowsByName = new Map(rows.map((row) => [row.toolName, row])); + const daytonaCatalogChanged = nativeDaytona && connection.status === "active" && ( + rows.some((row) => row.status !== "removed" && !isDaytonaToolName(row.toolName)) + || DAYTONA_TOOLS.some((tool) => { + const existing = rowsByName.get(tool.name); + return !existing || existing.versionHash !== descriptorHash(tool, daytonaRisk(tool.name)); + }) + ); + const cacheExpired = daytonaCatalogChanged || ( connection.transport === "mcp_remote" && connection.status !== "archived" && (rows.length === 0 || !connection.lastCatalogRefreshAt || connection.lastCatalogRefreshAt.getTime() <= - now().getTime() - catalogCacheTtlMs); + now().getTime() - catalogCacheTtlMs)); if (cacheExpired) { try { await singleFlight(catalogRefreshFlights, connection.id, () => - refreshCatalog(connection.id, { + refreshCatalog(connection.id, nativeDaytona && actor ? actor : { actorType: "system", actorId: "tool_catalog_cache", }), @@ -19179,7 +19172,11 @@ export function toolAccessService( if (rows.length === 0) throw error; } } - return rows.map((row) => toCatalogEntryForConnection(row, connection)); + // Even failed discovery must not keep retired native tools visible. + // Their database rows remain available to historical invocation records. + return rows + .filter((row) => !nativeDaytona || (row.status !== "removed" && isDaytonaToolName(row.toolName))) + .map((row) => toCatalogEntryForConnection(row, connection)); }, /** Recent tool-call events for one connection โ€” drives App detail ยท Recent activity. */ @@ -20194,6 +20191,7 @@ export function toolAccessService( input.connectionId, input.companyId, ); + if (isDaytonaConnection(connection)) throw forbidden("Daytona credentials stay in the governed tool gateway and cannot be exported."); if (isBrowserUseConnection(connection)) throw forbidden("Browser Use credentials stay in the governed tool gateway and cannot be exported."); if (connection.connectionPurpose === "ai") throw unprocessable("AI credentials are available only through the runtime resolver"); const application = await getConnectionApplication(connection); diff --git a/server/src/services/tool-catalog-hash.ts b/server/src/services/tool-catalog-hash.ts new file mode 100644 index 00000000000..daffe926cee --- /dev/null +++ b/server/src/services/tool-catalog-hash.ts @@ -0,0 +1,37 @@ +import { createHash } from "node:crypto"; + +// Keep catalog discovery and native-provider admission on the same saved contract. +export function stableHash(value: unknown): string { + return createHash("sha256") + .update(JSON.stringify(value, Object.keys(flattenKeys(value)).sort())) + .digest("hex"); +} + +function flattenKeys( + value: unknown, + keys: Record = {}, +): Record { + if (value && typeof value === "object") { + for (const [key, nested] of Object.entries( + value as Record, + )) { + keys[key] = true; + flattenKeys(nested, keys); + } + } + return keys; +} + +export function descriptorHash( + tool: { name: string; title?: string | null; description?: string | null; inputSchema?: Record; annotations?: Record }, + riskLevel: string, +): string { + return stableHash({ + name: tool.name, + title: tool.title ?? null, + description: tool.description ?? null, + inputSchema: tool.inputSchema ?? {}, + annotations: tool.annotations ?? {}, + riskLevel, + }); +} diff --git a/server/src/services/tool-gateway.ts b/server/src/services/tool-gateway.ts index 61693f5701c..393278dd4e1 100644 --- a/server/src/services/tool-gateway.ts +++ b/server/src/services/tool-gateway.ts @@ -1,5 +1,6 @@ import { notifyDeliveryWork, DELIVERY_QUEUES } from "./delivery-work-notifications.js"; import { measureToolDiscovery, measureRunPhase } from "./execution-preparation-timing.js"; +import { executeDaytonaTool, isDaytonaConnection, isCurrentDaytonaCatalogEntry } from "./daytona.js"; import { composeConnectionInstructions } from "./connection-instructions.js"; import { isInsufficientConnectionScope, INSUFFICIENT_CONNECTION_SCOPE_MESSAGE } from "./connection-permission-errors.js"; import { boundedMcpToolName } from "./mcp-tool-names.js"; @@ -1398,8 +1399,9 @@ export function createToolGatewayService( const eligibleRows = rows.filter( ({ catalogEntry, connection, application }) => !isRetiredComposioConnection(connection) && + !(isDaytonaConnection(connection) && !isCurrentDaytonaCatalogEntry(catalogEntry)) && !(isRailwayEndpoint(connection.config.url) && (isRailwayToolBlocked(catalogEntry.toolName) || (normalizeRailwayToolName(catalogEntry.toolName).startsWith(RAILWAY_TOOL_PREFIX) && connection.config.railwayApiStatus !== "available"))) && - ((isBrowserUseConnection(connection) && application.type === "rest_api") || + (((isBrowserUseConnection(connection) || isDaytonaConnection(connection)) && application.type === "rest_api") || (connection.transport === "mcp_remote" && application.type === "mcp_http") || (connection.transport === "local_stdio" && @@ -1425,7 +1427,7 @@ export function createToolGatewayService( ({ catalogEntry, connection, application }, index) => { if ( connection.transport !== "mcp_remote" && - connection.transport !== "local_stdio" && !isBrowserUseConnection(connection) + connection.transport !== "local_stdio" && !isBrowserUseConnection(connection) && !isDaytonaConnection(connection) ) { throw new Error( `Non-MCP connection ${connection.id} cannot be exposed through the MCP gateway`, @@ -4840,7 +4842,7 @@ export function createToolGatewayService( ), ) .limit(1); - if (!connection || (connection.transport !== "mcp_remote" && !isBrowserUseConnection(connection))) { + if (!connection || (connection.transport !== "mcp_remote" && !isBrowserUseConnection(connection) && !isDaytonaConnection(connection))) { throw new ToolGatewayHttpError( 404, `Tool "${tool.name}" not found`, @@ -4863,6 +4865,9 @@ export function createToolGatewayService( if (isRailwayEndpoint(connection.config.url) && isRailwayToolBlocked(entry.toolName)) { throw new ToolGatewayHttpError(403, "This Railway action cannot bind its effects to an approved target. Use redeploy, restart, or rollback for an existing deployment.", "railway_action_blocked"); } + if (isDaytonaConnection(connection) && !isCurrentDaytonaCatalogEntry(entry)) { + throw new ToolGatewayHttpError(409, "Daytona's action catalog changed. Review the updated actions in Permissions.", "daytona_catalog_changed"); + } return { entry, connection }; } @@ -5986,6 +5991,17 @@ export function createToolGatewayService( ms = railwayCommandBudgetMs(parameters); } const grant = await resolveConnectionGrant(session, connection); + if (isDaytonaConnection(connection)) { + const budgetMs = Math.min(ms, 30_000); + const deadlineAt = Date.now() + budgetMs; + const signal = AbortSignal.timeout(budgetMs); + const data = await executeDaytonaTool({ binding: session, connection, + headers: await resolveCredentialHeaders(session, connection, grant), + request: (url, init) => options.remoteHttpRequest ? options.remoteHttpRequest(url, init) + : guardedRemoteHttpFetch(url, init, remoteHttpFetchOptions()), + toolName: entry.toolName, parameters, signal, deadlineAt }); + return { result: { content: JSON.stringify(data), data: { structuredContent: data, transport: "rest_api" } } }; + } if (isBrowserUseConnection(connection)) { const data = await browserUseService(db, options.remoteHttpRequest).execute(session, grant, invocationId!, entry.toolName, parameters); return { result: { content: JSON.stringify(data), data: { structuredContent: data, transport: "rest_api" } } }; diff --git a/tests/e2e/daytona-connector.spec.ts b/tests/e2e/daytona-connector.spec.ts new file mode 100644 index 00000000000..b8062f91efa --- /dev/null +++ b/tests/e2e/daytona-connector.spec.ts @@ -0,0 +1,25 @@ +import { expect, test } from "@playwright/test"; + +test("Daytona uses the ordinary access and credential wizard", async ({ page, request }) => { + const response = await request.post("/api/companies", { data: { name: `Daytona setup ${Date.now()}` } }); + expect(response.ok()).toBe(true); + const company = await response.json(); + await page.goto(`/${company.issuePrefix}/apps`); + await expect(page.getByRole("heading", { name: "Connectors", exact: true })).toBeVisible(); + await page.getByRole("searchbox", { name: "Search connectors" }).fill("Daytona"); + const card = page.getByRole("list", { name: "Connector list" }).getByRole("listitem").filter({ hasText: "Daytona" }); + await expect(card).toHaveCount(1); + // App marks are decorative (empty alt), so they have no accessible img role. + await expect(card.locator('img[src="/brands/apps/daytona.svg"]')).toBeVisible(); + await card.getByRole("button", { name: "Add key Daytona", exact: true }).click(); + await expect(page.getByRole("heading", { name: "Connect Daytona", exact: true })).toBeVisible(); + await expect(page.getByLabel("Your Daytona key", { exact: true })).toBeVisible(); + await expect(page.getByLabel("Your Daytona key", { exact: true })).toHaveAttribute("type", "password"); + await expect(page.getByLabel("Pin to organization ID", { exact: true })).not.toBeVisible(); + await expect(page.getByText("Connects for everyone in your organization, available to all agents.", { exact: true })).toBeVisible(); + await page.getByRole("button", { name: "Change", exact: true }).click(); + await expect(page.getByText("Which humans can use this credential?", { exact: true })).toBeVisible(); + await expect(page.getByLabel("Pin to organization ID", { exact: true })).toBeVisible(); + // No key is submitted and no real provider connection is created. Gateway + // lifecycle and provider reads are exercised in the database-backed suite. +}); diff --git a/ui/public/brands/apps/daytona-dark.svg b/ui/public/brands/apps/daytona-dark.svg new file mode 100644 index 00000000000..662acb7d1de --- /dev/null +++ b/ui/public/brands/apps/daytona-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/public/brands/apps/daytona.svg b/ui/public/brands/apps/daytona.svg new file mode 100644 index 00000000000..6a11e340976 --- /dev/null +++ b/ui/public/brands/apps/daytona.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/public/brands/apps/manifest.json b/ui/public/brands/apps/manifest.json index f3f24cdbd9f..597371920bc 100644 --- a/ui/public/brands/apps/manifest.json +++ b/ui/public/brands/apps/manifest.json @@ -665,6 +665,13 @@ "catalogVisible": false, "localAsset": "/brands/apps/monday.png", "darkAsset": "/brands/apps/monday-dark.png" + }, + { + "slug": "daytona", + "provider": "Daytona", + "catalogVisible": true, + "localAsset": "/brands/apps/daytona.svg", + "darkAsset": "/brands/apps/daytona-dark.svg" } ] }