SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
14 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
6.2 KB · 134 lines typescript
Raw Blame History
1// Anthropic Managed Agents (beta) — create agent -> create environment -> create session ->2// send user.message -> stream SSE events (raw fetch) -> clean up everything created.3//4// STATUS: LIVE_VERIFIED 2026-09-18 — the identical HTTP sequence (env → agent → session with string-cents budget → user.message → SSE stream → cleanup) ran via scripts/live.py (tmp-live/platform-anthropic/agents-probes-2.json); this file itself was not executed.5// Model: claude-haiku-4-5-202510016// Beta header: anthropic-beta: managed-agents-2026-04-017// Budget: max budget minimal — session budget capped at 5 US cents, prompt "Reply with OK.", no tools.8// Names are prefixed "atlas-platform-agent".9//10// Run:  node --env-file=.env --experimental-strip-types examples/anthropic/agents/create_agent_session_stream.ts11// Uses process.env.ANTHROPIC_API_KEY only; never prints it.12//13// Docs: https://platform.claude.com/docs/en/managed-agents/quickstart14//       https://platform.claude.com/docs/en/managed-agents/events-and-streaming1516const API_KEY = process.env.ANTHROPIC_API_KEY;17if (!API_KEY) throw new Error("ANTHROPIC_API_KEY missing (node --env-file=.env ...)");18const BASE = process.env.ANTHROPIC_BASE_URL ?? "https://api.anthropic.com";19const BETA = "managed-agents-2026-04-01";20const MODEL = "claude-haiku-4-5-20251001";21const TS = Date.now();2223const headers: Record<string, string> = {24  "x-api-key": API_KEY,25  "anthropic-version": "2023-06-01",26  "anthropic-beta": BETA,27  "content-type": "application/json",28};2930async function ant<T = any>(method: string, path: string, body?: unknown): Promise<T> {31  const res = await fetch(BASE + path, { method, headers, body: body === undefined ? undefined : JSON.stringify(body) });32  const text = await res.text();33  if (!res.ok) throw new Error(`${method} ${path} -> ${res.status}: ${text.slice(0, 500)}`);34  return text ? (JSON.parse(text) as T) : (undefined as T);35}3637let agentId = "", envId = "", sessionId = "";38const abort = new AbortController();3940async function cleanup() {41  abort.abort();42  try {43    if (sessionId) {44      let s = await ant("GET", `/v1/sessions/${sessionId}`);45      if (s.status === "running") {46        await ant("POST", `/v1/sessions/${sessionId}/events`, { events: [{ type: "user.interrupt" }] });47        for (let i = 0; i < 30 && s.status === "running"; i++) {48          await new Promise((r) => setTimeout(r, 2000));49          s = await ant("GET", `/v1/sessions/${sessionId}`);50        }51      }52      await ant("DELETE", `/v1/sessions/${sessionId}`);53      console.log("deleted session", sessionId);54    }55    if (agentId) { await ant("POST", `/v1/agents/${agentId}/archive`); console.log("archived agent", agentId); }56    if (envId) {57      try { await ant("DELETE", `/v1/environments/${envId}`); console.log("deleted environment", envId); }58      catch { await ant("POST", `/v1/environments/${envId}/archive`); console.log("archived environment", envId); }59    }60  } catch (e) { console.error("cleanup error:", (e as Error).message); }61}6263async function main() {64  // 1) Agent (no tools => nothing executes in the sandbox)65  const agent = await ant("POST", "/v1/agents", {66    name: `atlas-platform-agent-${TS}`, model: MODEL,67    system: "You are a terse test agent. Reply with OK.", metadata: { origin: "api-atlas" },68  });69  agentId = agent.id; console.log("agent:", agentId, "v" + agent.version);7071  // 2) Environment (cloud sandbox, limited egress)72  const env = await ant("POST", "/v1/environments", {73    name: `atlas-platform-agent-env-${TS}`,74    config: { type: "cloud", networking: { type: "limited", allowed_hosts: ["example.com"] } },75  });76  envId = env.id; console.log("environment:", envId);7778  // 3) Session with a 5-cent hard budget79  const session = await ant("POST", "/v1/sessions", {80    agent: agentId, environment_id: envId, title: `atlas-platform-agent-session-${TS}`,81    budget: { type: "limit", max_list_cost: { amount: "5", currency: "USD" } },82  });83  sessionId = session.id; console.log("session:", sessionId, "status=" + session.status);8485  // 4) Open the stream before sending the message86  const streamRes = await fetch(`${BASE}/v1/sessions/${sessionId}/events/stream`, {87    headers: { ...headers, accept: "text/event-stream" }, signal: abort.signal,88  });89  if (!streamRes.ok || !streamRes.body) throw new Error(`stream -> ${streamRes.status}`);9091  // 5) Send user.message92  await ant("POST", `/v1/sessions/${sessionId}/events`, {93    events: [{ type: "user.message", content: [{ type: "text", text: "Reply with OK." }] }],94  });9596  // 6) Parse SSE ("data: {...}" lines) until session.status_idle / session.error / timeout97  const reader = streamRes.body.getReader();98  const dec = new TextDecoder();99  let buf = "";100  const timer = setTimeout(() => abort.abort(), 180_000);101  const seen: string[] = [];102  outer: while (true) {103    const { value, done } = await reader.read().catch(() => ({ value: undefined, done: true }));104    if (done) break;105    buf += dec.decode(value, { stream: true });106    let idx: number;107    while ((idx = buf.indexOf("\n")) >= 0) {108      const line = buf.slice(0, idx).trimEnd(); buf = buf.slice(idx + 1);109      if (!line.startsWith("data:")) continue;110      const ev = JSON.parse(line.slice(5).trim());111      seen.push(ev.type);112      if (ev.type === "agent.message") {113        console.log("[agent.message]", ev.content.filter((c: any) => c.type === "text").map((c: any) => c.text).join(""));114      } else if (ev.type === "session.usage") {115        console.log("[session.usage] list_cost=", ev.usage?.list_cost?.amount, "active_seconds=", ev.usage?.active_seconds);116      } else if (ev.type === "session.status_idle") {117        console.log("[session.status_idle] stop_reason=", ev.stop_reason?.type); break outer;118      } else if (ev.type === "session.error") {119        console.log("[session.error]", ev.error?.type, ev.error?.retry_status?.type); break outer;120      } else {121        console.log(`[${ev.type}]`);122      }123    }124  }125  clearTimeout(timer);126  console.log("event sequence:", seen.join(" -> "));127128  // 7) Final snapshot129  const fin = await ant("GET", `/v1/sessions/${sessionId}`);130  console.log(JSON.stringify({ status: fin.status, usage: fin.usage }, null, 2));131}132133main().catch((e) => { console.error("error:", (e as Error).message); process.exitCode = 1; }).finally(cleanup);134