@ag-ui/claude-managed-agents

中文文档
0.0.4发布于 2026/10/21MITTypeScriptESM + CJS构建来源已验证近 30 天下载 9996

AG-UI integration for Claude Managed Agents (Anthropic hosted agent sessions)

原始使用文档
文档目录10 节
  1. Installation
  2. Usage
  3. What it does
  4. Frontend tools (human-in-the-loop)
  5. Backend tools
  6. Options
  7. Security: authenticate and bind threads to callers
  8. Notes
  9. Running the examples
  10. Reconnect existing sessions

@ag-ui/claude-managed-agents

Connect an AG-UI frontend to Claude Managed Agents, 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.

Installation

npm install @ag-ui/claude-managed-agents @anthropic-ai/sdk

Usage

Create a managed agent and an environment once (in the Console, or via the SDK), then wrap them:

import { ManagedAgentsAgent } from "@ag-ui/claude-managed-agents";

const agent = new ManagedAgentsAgent({
  managedAgentId: "agent_...",
  environmentId: "env_...",
});

agent
  .run({ threadId, runId, messages, tools, state, context, forwardedProps })
  .subscribe({
    next: (event) => console.log(event.type),
  });

The Anthropic client reads ANTHROPIC_API_KEY from the environment. Pass client to supply your own.

What it does

Managed AgentsAG-UI
agent.message (with event_delta previews)TEXT_MESSAGE_START / CONTENT / END
agent.thinkingREASONING_START / REASONING_MESSAGE_START / REASONING_MESSAGE_END / REASONING_END
agent.tool_use, agent.mcp_tool_use + resultsTOOL_CALL_* + TOOL_CALL_RESULT (server-executed, display only)
agent.custom_tool_use for a frontend toolTOOL_CALL_*, then the run ends so the client can run the tool
agent.custom_tool_use for a backend toolTOOL_CALL_* + TOOL_CALL_RESULT, and the handler's result is posted back
session.error (terminal)RUN_ERROR with the error type as code
session.status_idle (end_turn)RUN_FINISHED

Frontend tools (human-in-the-loop)

Tools 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.

Backend tools

Tools your server executes go in backendTools:

new ManagedAgentsAgent({
  managedAgentId,
  environmentId,
  backendTools: [
    {
      name: "get_weather",
      description: "Get the weather for a location.",
      parameters: {
        type: "object",
        properties: { location: { type: "string" } },
      },
      handler: async (input) => JSON.stringify({ temperature: 21 }),
    },
  ],
});

The tool call and its result stream to the UI, and the result is returned to the agent.

Options

OptionDefault
managedAgentId, environmentIdrequiredThe managed agent (agent_...) and environment behind each session.
agentVersionlatestPin an agent version.
clientnew Anthropic()Bring your own Anthropic client.
sessionStorein-memoryThread↔session mapping, keyed by managedAgentId:threadId. Provide your own to survive restarts.
backendTools[]Server-executed custom tools.
sessionTitleAG-UI thread <id>Title for created sessions.
vaultIds[]Vault IDs (vlt_...) for stored credentials the agent may use, e.g. for MCP servers that authenticate. Applied at session creation.
toolConfirmationapproval interrupt"allow"/"deny" to answer built-in tools on fresh runs. Reconnect requires explicit approval responses.
turnTimeoutMs300000Interrupt turns that run longer.
streamDeltastrueRequest text/thinking previews for token streaming.
onErrornoneNotified 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.

Security: authenticate and bind threads to callers

AG-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:

  • Put the endpoint behind your own authentication. Never expose it unauthenticated.
  • 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).
  • 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):

The 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:

class PerCallerStore implements SessionStore {
  constructor(
    private ownerId: string,
    private inner = new Map<string, SessionRecord>(),
  ) {}
  private scoped = (key: string) => `${this.ownerId}|${key}`;
  get = (key: string) => this.inner.get(this.scoped(key));
  set = (key: string, record: SessionRecord) =>
    void this.inner.set(this.scoped(key), record);
  delete = (key: string) => void this.inner.delete(this.scoped(key));
}

Reuse ONE store instance per caller — construct it once and cache it:

const shared = new Map<string, SessionRecord>();
const stores = new Map<string, PerCallerStore>();
const storeFor = (ownerId: string): PerCallerStore => {
  let store = stores.get(ownerId);
  if (!store)
    stores.set(ownerId, (store = new PerCallerStore(ownerId, shared)));
  return store;
};

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).

Notes

  • The default session store is in-memory: restarting the process starts new sessions. Managed sessions themselves persist server-side.
  • Turns are serial per thread. A second run on a busy thread errors with code run_in_progress.
  • 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.
  • When the client disconnects during a fresh turn (or abortRun() is called), the adapter posts user.interrupt to stop the session. Reconnect closes its stream without interrupting the existing 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • 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.

Running the examples

cd integrations/claude-managed-agents/typescript
pnpm install
export ANTHROPIC_API_KEY=sk-ant-...   # or ANTHROPIC_AUTH_TOKEN
pnpm setup:examples   # provisions an environment + one agent per Dojo feature (idempotent)
pnpm dev:examples     # http://localhost:8024

Setup writes the provisioned IDs to examples/.managed-agents.json (gitignored). It reuses existing agents by name and does not modify them: to apply prompt or model changes from examples/agents.ts, archive the agent and re-run setup.

The examples default to claude-sonnet-5-5, which supports runtime context via native system messages. MANAGED_AGENTS_MODEL overrides this default; choose a model from the system-injection support list. Existing agents created on Sonnet 5 are not upgraded by changing this variable or rerunning setup. To migrate, archive the old example agents, rerun setup to provision replacements and rewrite the saved IDs, then restart the example server and start new sessions. Existing sessions remain bound to their original agents.

Reconnect existing sessions

Supply a persistent SessionStore to keep the thread/session binding, pending requests and native event cursor across backend restarts. The default store is in memory. Stores must partition records by authenticated caller and serialize runs across replicas; the adapter's in-process lock does not coordinate servers.

For imported sessions, configure resolveSession(threadId) on the server. The callback must authorize the caller's access and return the original binding:

resolveSession: async (threadId) => {
  const imported = await authorizedImports.find(threadId);
  if (!imported) return undefined; // Only for genuinely new conversations.
  return {
    sessionId: imported.sessionId,
    lastUserMessageId: imported.lastUserMessageId,
    lastEventId: imported.lastNativeEventId,
  };
};

authorizedImports represents your authenticated application's durable import mapping, not a client-supplied session selector. Throw for inaccessible or missing imported sessions instead of returning undefined, which permits new-session creation. lastUserMessageId is the last imported AG-UI user message ID; lastEventId is the last native event already saved by the importer. If omitted, initial adoption treats the submitted user history and current native history as already imported. Supplying both boundaries allows the first follow-up and any activity since import to be distinguished from old history.

An empty run reconnects an existing mapping without sending user text. Adopted sessions retain their native tool configuration. Reconnect opens the native stream before listing history, recovers pending calls by their original IDs, and replays activity after the saved event cursor without executing old tools. Terminated or unavailable sessions return an explicit run error and retain their binding; start a new AG-UI thread to create a replacement.

Custom-tool answers use ordinary role: "tool" messages with the original toolCallId. Native tool permissions appear as RUN_FINISHED.outcome interrupts with reason tool-approval; answer with resume: [{ interruptId, status: "resolved", payload: "allow" }] or payload "deny". status: "cancelled" explicitly denies that request. Partial answers leave the other requests pending; a new user message never rejects them.

A binding may include sessionThreadId to inspect and answer a child thread. Native tool IDs route results to the correct child automatically. New user messages must target the primary session; the adapter rejects child follow-ups rather than delivering them to the wrong agent. Other native content replayed as RAW events remains available to the recording application; rendering richer content depends on the application's event handling.

版本与发布记录

@ag-ui/claude-managed-agents 共发布 4 个版本,首次发布于 2026/07/30;过去 12 个月发布了 4 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.0.4latest2026/10/2117 天前
0.0.32026/10/1622 天前
0.0.22026/10/1226 天前
0.0.12026/07/303 个月前

关于 @ag-ui/claude-managed-agents 的常见问题

@ag-ui/claude-managed-agents 是什么?

AG-UI integration for Claude Managed Agents (Anthropic hosted agent sessions)

如何安装 @ag-ui/claude-managed-agents?

在项目目录运行 npm install @ag-ui/claude-managed-agents,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@ag-ui/core(>=1.0.0)、@ag-ui/client(>=1.0.0)、@anthropic-ai/sdk(>=0.109.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@ag-ui/claude-managed-agents 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@ag-ui/claude-managed-agents 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@ag-ui/claude-managed-agents 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20.3.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@ag-ui/claude-managed-agents 可以商用吗?

@ag-ui/claude-managed-agents 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@ag-ui/claude-managed-agents 的下载量有多少?

根据 npm 官方下载统计,@ag-ui/claude-managed-agents 在 2026/10/05 – 2026/11/03 这 30 天内被下载 9,996 次,日均约 333 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ag-ui/claude-managed-agents 还在维护吗?

最新版本 0.0.4 发布于 2026/10/21(17 天前);至今共发布 4 个版本,其中过去 12 个月发布了 4 个;首次发布于 2026/07/30。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。