Pular para o conteúdo principal

SDK Python e TypeScript

Os dois SDKs falam com a mesma API (/api/v1/orgs/{orgId}/projects/{projectId}/sandboxes) e passam pelos mesmos testes de contrato. Autentique com um token de conta de serviço com os escopos sandboxes:read, sandboxes:write e sandboxes:exec.

Variáveis lidas por padrão: CODA_API_URL, CODA_TOKEN, CODA_ORG_ID e CODA_PROJECT_ID. Os nomes antigos ATLAS_* continuam aceitos como reserva, assim como os aliases AtlasClient e AtlasError.

Python​

pip install coda-sandbox
from coda_sandbox import CodaClient

with CodaClient() as coda:
with coda.sandboxes.create(image="python-3.13", network_profile="pypi-only", ttl_seconds=1800) as sbx:
sbx.exec("pip install --user requests") # modo sync
exit = sbx.run(["python", "-c", "import requests; print(requests.__version__)"],
on_stdout=lambda b: print(b.decode(), end="")) # modo stream (SSE)
print("saída:", exit["exitCode"])

sbx.files.write("app/main.py", "print('olá')")
print(sbx.files.read_text("app/main.py"))

sbx.spawn(["python", "-m", "http.server", "8000"]) # modo background
port = sbx.expose_port(8000) # visibilidade TOKEN
print(port["url"], port["authUrl"])
# o with encerra a sandbox

TypeScript​

npm install @coda-cloud/sandbox
import { CodaClient } from "@coda-cloud/sandbox";

const coda = new CodaClient();
await using sbx = await coda.sandboxes.create({ image: "node-24", networkProfile: "npm-only" });

await sbx.exec("npm install --prefix /workspace left-pad");
const exit = await sbx.run(["node", "-e", "console.log(42)"], {
onStdout: (chunk) => process.stdout.write(chunk),
onStderr: (chunk) => process.stderr.write(chunk),
});
console.log("saída", exit.exitCode);

await sbx.files.write("index.js", 'console.log("olá")');
const tarGz = await sbx.files.download(".");

await using encerra a sandbox no fim do bloco (TypeScript 5.2+); sem ele, chame sbx.terminate().

Modos de execução​

ModoMétodoQuando usar
streamrunver a saída enquanto o comando roda; o fim chega no evento exit
syncexeccomandos curtos; até 1 MiB de cada saída, com stdoutTruncated
backgroundspawn + command, output, cancelservidores e tarefas longas; a saída é lida por offset

Um comando aceita cwd, env, tempo limite (padrão 300 s) e stdin. Uma string vira /bin/sh -c; uma lista é o argv direto (funciona em imagens sem shell).

Erros​

Toda resposta de erro vira uma exceção tipada:

ExceçãoQuando
PlanLimitError400 plan.limit_exceeded: um campo acima do teto do plano (params.key diz qual)
FeatureUnavailableError403 plan.feature_unavailable: pausa, porta pública, egress aberto fora do plano
ForbiddenError403: papel ou escopo insuficiente (scopes traz o escopo pedido)
QuotaExceededError422 quota.exceeded: sandboxes simultâneas, portas ou vCPU·s do mês
NotFoundError404: a sandbox ou o arquivo não existe
ConflictError409: sandbox pausada ou encerrada, ou microVM indisponível na região
RateLimitedError429: retry_after_seconds (Python) ou retryAfterSeconds (TS) diz quando tentar de novo
RestrictedError423: organização restrita
UnavailableError503: kill switch, sandboxes desligadas ou runtime indisponível

Idempotência​

create(..., idempotency_key="pedido-123") (Python) ou create({ idempotencyKey: 'pedido-123' }) (TS) envia o cabeçalho Idempotency-Key: repetir a chamada com a mesma chave devolve a mesma sandbox, útil quando o agente refaz um passo.