Python 88.3%
TypeScript 7.6%
Shell 4.1%
1#!/usr/bin/env bash2# Anthropic Managed Agents (beta) — create agent -> create environment -> create session ->3# send user.message -> stream SSE events -> clean up everything that was created.4#5# 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.6# Model: claude-haiku-4-5-202510017# Beta header: anthropic-beta: managed-agents-2026-04-018# Budget: max budget minimal — session budget capped at 5 US cents ({"amount":"5","currency":"USD"}),9# prompt "Reply with OK.", no tools enabled (tools omitted => nothing runs in the sandbox).10# Names are prefixed "atlas-platform-agent".11#12# Requires: ANTHROPIC_API_KEY in the environment (source .env; never print it), curl, jq.13# Cleanup: DELETE session (after it is idle), POST /archive agent, DELETE environment (falls back to14# /archive if the environment is still referenced), all via an EXIT trap.15#16# Docs: https://platform.claude.com/docs/en/managed-agents/quickstart17# https://platform.claude.com/docs/en/managed-agents/events-and-streaming18set -eo pipefail1920: "${ANTHROPIC_API_KEY:?set ANTHROPIC_API_KEY (source .env)}"21BASE="${ANTHROPIC_BASE_URL:-https://api.anthropic.com}"22BETA="managed-agents-2026-04-01"23MODEL="claude-haiku-4-5-20251001"24TS="$(date +%s)"2526ant() { # ant METHOD PATH [json-body] -> prints response body; fails on non-2xx27 local method="$1" path="$2" body="${3:-}"28 if [[ -n "$body" ]]; then29 curl -sS --fail-with-body -X "$method" "$BASE$path" \30 -H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2023-06-01" \31 -H "anthropic-beta: $BETA" -H "content-type: application/json" --data "$body"32 else33 curl -sS --fail-with-body -X "$method" "$BASE$path" \34 -H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2023-06-01" \35 -H "anthropic-beta: $BETA"36 fi37}3839AGENT_ID="" ENV_ID="" SESSION_ID="" STREAM_PID=""40cleanup() {41 set +e42 [[ -n "$STREAM_PID" ]] && kill "$STREAM_PID" 2>/dev/null43 if [[ -n "$SESSION_ID" ]]; then44 # A running session cannot be deleted: interrupt first, then wait for idle (max ~60 s).45 status=$(ant GET "/v1/sessions/$SESSION_ID" | jq -r '.status')46 if [[ "$status" == "running" ]]; then47 ant POST "/v1/sessions/$SESSION_ID/events" '{"events":[{"type":"user.interrupt"}]}' >/dev/null48 for _ in $(seq 1 30); do49 sleep 250 status=$(ant GET "/v1/sessions/$SESSION_ID" | jq -r '.status')51 [[ "$status" != "running" ]] && break52 done53 fi54 ant DELETE "/v1/sessions/$SESSION_ID" >/dev/null && echo "deleted session $SESSION_ID"55 fi56 [[ -n "$AGENT_ID" ]] && ant POST "/v1/agents/$AGENT_ID/archive" >/dev/null && echo "archived agent $AGENT_ID"57 if [[ -n "$ENV_ID" ]]; then58 ant DELETE "/v1/environments/$ENV_ID" >/dev/null 2>&1 && echo "deleted environment $ENV_ID" \59 || { ant POST "/v1/environments/$ENV_ID/archive" >/dev/null && echo "archived environment $ENV_ID"; }60 fi61}62trap cleanup EXIT6364# 1) Agent (versioned resource). No tools => minimal, nothing executes in the sandbox.65agent=$(ant POST /v1/agents "$(jq -n --arg n "atlas-platform-agent-$TS" --arg m "$MODEL" \66 '{name:$n, model:$m, system:"You are a terse test agent. Reply with OK.", metadata:{origin:"api-atlas"}}')")67AGENT_ID=$(jq -er '.id' <<<"$agent"); echo "agent: $AGENT_ID v$(jq -r .version <<<"$agent")"6869# 2) Environment (cloud sandbox, limited egress). Every session gets its own fresh container.70env_json=$(ant POST /v1/environments "$(jq -n --arg n "atlas-platform-agent-env-$TS" \71 '{name:$n, config:{type:"cloud", networking:{type:"limited", allowed_hosts:["example.com"]}}}')")72ENV_ID=$(jq -er '.id' <<<"$env_json"); echo "environment: $ENV_ID"7374# 3) Session with a hard 5-cent list-cost budget (budget can only be attached at creation).75session=$(ant POST /v1/sessions "$(jq -n --arg a "$AGENT_ID" --arg e "$ENV_ID" --arg t "atlas-platform-agent-session-$TS" \76 '{agent:$a, environment_id:$e, title:$t, budget:{type:"limit", max_list_cost:{amount:"5", currency:"USD"}}}')")77SESSION_ID=$(jq -er '.id' <<<"$session"); echo "session: $SESSION_ID status=$(jq -r .status <<<"$session")"7879# 4) Open the SSE stream BEFORE sending the message (only events after the stream opens are delivered).80STREAM_LOG=$(mktemp)81curl -sS -N "$BASE/v1/sessions/$SESSION_ID/events/stream" \82 -H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2023-06-01" \83 -H "anthropic-beta: $BETA" -H "accept: text/event-stream" > "$STREAM_LOG" &84STREAM_PID=$!85sleep 18687# 5) Send the user message (returns as soon as the event is queued).88ant POST "/v1/sessions/$SESSION_ID/events" \89 '{"events":[{"type":"user.message","content":[{"type":"text","text":"Reply with OK."}]}]}' >/dev/null9091# 6) Tail the stream until the session goes idle (or 180 s timeout). Print type + text of each event.92deadline=$(( $(date +%s) + 180 ))93while IFS= read -r line; do94 [[ $line == data:* ]] || continue95 ev=${line#data: }96 type=$(jq -r '.type' <<<"$ev")97 case "$type" in98 agent.message) printf '[%s] %s\n' "$type" "$(jq -j '[.content[] | select(.type=="text") | .text] | join("")' <<<"$ev")" ;;99 session.usage) printf '[%s] list_cost=%s active_seconds=%s\n' "$type" "$(jq -r '.usage.list_cost.amount' <<<"$ev")" "$(jq -r '.usage.active_seconds' <<<"$ev")" ;;100 session.status_idle) printf '[%s] stop_reason=%s\n' "$type" "$(jq -r '.stop_reason.type' <<<"$ev")"; break ;;101 session.error) printf '[%s] %s (%s)\n' "$type" "$(jq -r '.error.type' <<<"$ev")" "$(jq -r '.error.retry_status.type // empty' <<<"$ev")"; break ;;102 *) printf '[%s]\n' "$type" ;;103 esac104 (( $(date +%s) > deadline )) && { echo "timeout waiting for idle"; break; }105done < <(tail -f -n +1 "$STREAM_LOG")106107# 7) Final session snapshot (usage priced at list rates).108ant GET "/v1/sessions/$SESSION_ID" | jq '{status, usage: {input_tokens: .usage.input_tokens, output_tokens: .usage.output_tokens, list_cost: .usage.list_cost}}'109rm -f "$STREAM_LOG"110# cleanup() runs on EXIT111