{"_id":"@ag-ui/claude-managed-agents","name":"@ag-ui/claude-managed-agents","dist-tags":{"latest":"0.0.1"},"versions":{"0.0.1":{"name":"@ag-ui/claude-managed-agents","version":"0.0.1","description":"AG-UI integration for Claude Managed Agents (Anthropic hosted agent sessions)","license":"MIT","repository":{"type":"git","url":"git+https://github.com/ag-ui-protocol/ag-ui.git"},"main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","sideEffects":false,"engines":{"node":">=20.3.0"},"private":false,"publishConfig":{"access":"public"},"dependencies":{"rxjs":"7.8.1"},"peerDependencies":{"@ag-ui/core":">=0.0.42","@ag-ui/client":">=0.0.42","@anthropic-ai/sdk":">=0.109.0"},"devDependencies":{"@anthropic-ai/sdk":"^0.113.0","@types/node":"^20.11.19","publint":"^0.3.12","@arethetypeswrong/cli":"^0.17.4","tsx":"^4.20.6","vitest":"^4.0.18","tsdown":"^0.20.1","typescript":"^5.3.3","@ag-ui/core":"0.0.57","@ag-ui/client":"0.0.57","@ag-ui/encoder":"0.0.57"},"exports":{".":{"require":"./dist/index.js","import":"./dist/index.mjs"},"./package.json":"./package.json"},"scripts":{"build":"tsdown","dev":"tsdown --watch","dev:examples":"tsx --watch examples/server.ts","setup:examples":"tsx examples/setup.ts","clean":"git clean -fdX --exclude=\"!.env\"","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","test:exports":"publint --strict && attw --pack","link:global":"pnpm link --global","unlink:global":"pnpm unlink --global"},"_id":"@ag-ui/claude-managed-agents@0.0.1","bugs":{"url":"https://github.com/ag-ui-protocol/ag-ui/issues"},"homepage":"https://github.com/ag-ui-protocol/ag-ui#readme","_integrity":"sha512-OluOLnkfmz+CPCg30qHUTOl19HV7/QKDftzCvMVKe3p5rBuObTUNIvsa3dKXypr1y6OLBuht7ENfYVJXnhSkRw==","_resolved":"/Users/mme/Projects/herdr/ag-ui-anthropic/integrations/claude-managed-agents/typescript/ag-ui-claude-managed-agents-0.0.1.tgz","_from":"file:ag-ui-claude-managed-agents-0.0.1.tgz","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-OluOLnkfmz+CPCg30qHUTOl19HV7/QKDftzCvMVKe3p5rBuObTUNIvsa3dKXypr1y6OLBuht7ENfYVJXnhSkRw==","shasum":"e2b143a2db7dfbe80b740b35c45899e0a58c98ea","tarball":"https://registry.npmjs.org/@ag-ui/claude-managed-agents/-/claude-managed-agents-0.0.1.tgz","fileCount":11,"unpackedSize":252387,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBbeg100RxAvMcy7aABKJSLmCBAJ6Ybz27odaX+7BvIlAiAAyDr1Mlx35FKW6Zfmsh9E/RMkoRVyXESYbM4jlI9zlQ=="}]},"_npmUser":{"name":"_mme","email":"markus.ecker@gmail.com"},"directories":{},"maintainers":[{"name":"_mme","email":"markus.ecker@gmail.com"},{"name":"copilotkit","email":"devops@copilotkit.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/claude-managed-agents_0.0.1_1785404884264_0.8507528939831357"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-30T09:48:04.164Z","0.0.1":"2026-07-30T09:48:04.393Z","modified":"2026-07-30T09:48:04.596Z"},"maintainers":[{"name":"_mme","email":"markus.ecker@gmail.com"},{"name":"copilotkit","email":"devops@copilotkit.ai"}],"description":"AG-UI integration for Claude Managed Agents (Anthropic hosted agent sessions)","homepage":"https://github.com/ag-ui-protocol/ag-ui#readme","repository":{"type":"git","url":"git+https://github.com/ag-ui-protocol/ag-ui.git"},"bugs":{"url":"https://github.com/ag-ui-protocol/ag-ui/issues"},"license":"MIT","readme":"# @ag-ui/claude-managed-agents\n\nConnect an [AG-UI](https://ag-ui.com) frontend to [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview), Anthropic's hosted agent runtime. Each AG-UI thread maps to one managed session. Each run drives one turn of that session and streams the agent's events back as AG-UI events.\n\n## Installation\n\n```bash\nnpm install @ag-ui/claude-managed-agents @anthropic-ai/sdk\n```\n\n## Usage\n\nCreate a managed agent and an environment once (in the Console, or via the SDK), then wrap them:\n\n```typescript\nimport { ManagedAgentsAgent } from \"@ag-ui/claude-managed-agents\";\n\nconst agent = new ManagedAgentsAgent({\n  managedAgentId: \"agent_...\",\n  environmentId: \"env_...\",\n});\n\nagent.run({ threadId, runId, messages, tools, state, context, forwardedProps }).subscribe({\n  next: (event) => console.log(event.type),\n});\n```\n\nThe Anthropic client reads `ANTHROPIC_API_KEY` from the environment. Pass `client` to supply your own.\n\n## What it does\n\n| Managed Agents | AG-UI |\n| --- | --- |\n| `agent.message` (with `event_delta` previews) | `TEXT_MESSAGE_START` / `CONTENT` / `END` |\n| `agent.thinking` | `REASONING_START` / `REASONING_MESSAGE_START` / `REASONING_MESSAGE_END` / `REASONING_END` |\n| `agent.tool_use`, `agent.mcp_tool_use` + results | `TOOL_CALL_*` + `TOOL_CALL_RESULT` (server-executed, display only) |\n| `agent.custom_tool_use` for a frontend tool | `TOOL_CALL_*`, then the run ends so the client can run the tool |\n| `agent.custom_tool_use` for a backend tool | `TOOL_CALL_*` + `TOOL_CALL_RESULT`, and the handler's result is posted back |\n| `session.error` (terminal) | `RUN_ERROR` with the error type as `code` |\n| `session.status_idle` (`end_turn`) | `RUN_FINISHED` |\n\n### Frontend tools (human-in-the-loop)\n\nTools passed in `RunAgentInput.tools` are registered on the session as custom tools. When the agent calls one, the run emits the tool call and finishes, leaving the session parked. The client executes the tool and starts the next run with a `role: \"tool\"` message carrying `toolCallId`. The adapter forwards it into the session as the tool result and resumes streaming.\n\n### Backend tools\n\nTools your server executes go in `backendTools`:\n\n```typescript\nnew ManagedAgentsAgent({\n  managedAgentId,\n  environmentId,\n  backendTools: [\n    {\n      name: \"get_weather\",\n      description: \"Get the weather for a location.\",\n      parameters: { type: \"object\", properties: { location: { type: \"string\" } } },\n      handler: async (input) => JSON.stringify({ temperature: 21 }),\n    },\n  ],\n});\n```\n\nThe tool call and its result stream to the UI, and the result is returned to the agent.\n\n## Options\n\n| Option | Default | |\n| --- | --- | --- |\n| `managedAgentId`, `environmentId` | required | The managed agent (`agent_...`) and environment behind each session. |\n| `agentVersion` | latest | Pin an agent version. |\n| `client` | `new Anthropic()` | Bring your own Anthropic client. |\n| `sessionStore` | in-memory | Thread↔session mapping, keyed by `managedAgentId:threadId`. Provide your own to survive restarts. |\n| `backendTools` | `[]` | Server-executed custom tools. |\n| `sessionTitle` | `AG-UI thread <id>` | Title for created sessions. |\n| `vaultIds` | `[]` | Vault IDs (`vlt_...`) for stored credentials the agent may use, e.g. for MCP servers that authenticate. Applied at session creation. |\n| `toolConfirmation` | error | `\"allow\"`/`\"deny\"` to answer built-in tools whose permission policy asks. |\n| `turnTimeoutMs` | 300000 | Interrupt turns that run longer. |\n| `streamDeltas` | `true` | Request text/thinking previews for token streaming. |\n| `onError` | none | Notified when a best-effort operation fails. May be `async`; its rejection is absorbed, so nothing it does can fail a run. Bounded like any other best-effort call, so a hook that never settles cannot hold a run open. With no hook set, the cause goes to `console.error` instead — never to the client. |\n\n## Security: authenticate and bind threads to callers\n\nAG-UI thread IDs are supplied by the client and this agent keys thread↔session state by `managedAgentId:threadId`, so a thread ID is effectively a bearer identifier: **any caller who presents a thread ID resumes that thread's session.** The AG-UI protocol carries no user identity of its own, so authorization is your host's responsibility:\n\n- Put the endpoint behind your own authentication. Never expose it unauthenticated.\n- `RUN_ERROR` never relays the text of a failure this integration did not author. An SDK, session-store or API exception can carry session ids, request paths or credentials, so its message goes to `onError` and the client gets a stable message plus the machine-readable `code`. Two things are deliberately still verbatim, because they are the point of the event: a `session.error` from the API (a structured field with its own `type` code, and the only account of why a session broke) and a backend tool's own exception message (your code, and what the agent needs to recover).\n- In multi-tenant deployments, bind threads to the authenticated caller so one caller cannot resume another's session by guessing or replaying a thread ID. Do this with a `sessionStore` whose keys include the caller identity derived from your auth layer (never from the request body):\n\nThe key the agent passes in is already scoped to the managed agent; treat it as an opaque string and prefix it with the caller identity rather than parsing it:\n\n```ts\nclass PerCallerStore implements SessionStore {\n  constructor(private ownerId: string, private inner = new Map<string, SessionRecord>()) {}\n  private scoped = (key: string) => `${this.ownerId}|${key}`;\n  get = (key: string) => this.inner.get(this.scoped(key));\n  set = (key: string, record: SessionRecord) => void this.inner.set(this.scoped(key), record);\n  delete = (key: string) => void this.inner.delete(this.scoped(key));\n}\n```\n\n  Reuse ONE store instance per caller — construct it once and cache it:\n\n```ts\nconst shared = new Map<string, SessionRecord>();\nconst stores = new Map<string, PerCallerStore>();\nconst storeFor = (ownerId: string): PerCallerStore => {\n  let store = stores.get(ownerId);\n  if (!store) stores.set(ownerId, (store = new PerCallerStore(ownerId, shared)));\n  return store;\n};\n```\n\n  Runs are serialized per thread within a store instance, so a fresh wrapper per request would let a double-submitted thread post into the same session twice. Cache the store (as above) and construct the agent with `storeFor(ownerId)`.\n\n## Notes\n\n- The default session store is in-memory: restarting the process starts new sessions. Managed sessions themselves persist server-side.\n- Turns are serial per thread. A second run on a busy thread errors with code `run_in_progress`.\n- Only the text of a user message is forwarded. A message with image or binary parts and no text errors with code `empty_run` instead of creating a session.\n- When the client disconnects mid-turn (or `abortRun()` is called), the adapter posts `user.interrupt` to stop the session. A turn that exceeds `turnTimeoutMs` is interrupted the same way and errors. A backend tool handler still running at that point is abandoned and answered with an error so the session is not left parked.\n- Built-in tools (bash, file editing, web) execute inside the managed environment. This adapter surfaces them for display, so enable them on your agent as usual.\n- Tool-result `text` blocks reach the UI verbatim: they carry literal output (a file read, a shell transcript), where `&lt;` means those four characters. Only `search_result` blocks, whose bodies are extracted from HTML, have their entities decoded.\n- A follow-up message posted immediately after a tool result can race the session's asynchronous un-park and be rejected with a 400. That specific rejection is retried, matched on the message containing `waiting on responses` — wording that has not been confirmed against the live API. If the API rewords it the retry stops firing and the 400 surfaces as a run error; nothing else is affected. See the comment on the matcher.\n- The default in-memory store is bounded (`IN_MEMORY_SESSION_STORE_MAX_ENTRIES`, 10 000 mappings): thread ids are client-supplied, so past that the least-recently-used mapping is evicted and that thread starts a fresh session. Pass a smaller cap to `new InMemorySessionStore(n)`, or supply a persistent store.\n- A run that is interrupted — a turn timeout, a client disconnect, or a blocked action this integration cannot answer — forgets the frontend tool calls it had recorded as parked. The interrupt cancels whatever the session was waiting on, so answering one of those calls on the next run would be rejected as stale. If the interrupt itself could not be delivered the ids are kept, since the session may still be parked on them.\n- A session that registers custom tools holds a full replacement tool list, frozen at the last update, so the agent's own tools are re-read once per run to catch a Console edit to them. A session with no custom tools runs the agent as-is and skips that read entirely.\n\n## Running the examples\n\n```bash\ncd integrations/claude-managed-agents/typescript\npnpm install\nexport ANTHROPIC_API_KEY=sk-ant-...   # or ANTHROPIC_AUTH_TOKEN\npnpm setup:examples   # provisions an environment + one agent per Dojo feature (idempotent)\npnpm dev:examples     # http://localhost:8024\n```\n\nSetup writes the provisioned IDs to `examples/.managed-agents.json` (gitignored). It reuses existing agents by name and does not modify them: to apply prompt changes from `examples/agents.ts`, archive the agent and re-run setup.\n","readmeFilename":"README.md","_rev":"1-6783beb4c0d25ddead047357e455a69a"}