Skip to content

feat(managed-agents): add @chat-adapter/managed-agents with Claude, Cursor, and OpenAI drivers - #1034

Draft
roboeve[bot] wants to merge 9 commits into
mainfrom
feat/managed-agents
Draft

roboeve[bot] wants to merge 9 commits into
mainfrom
feat/managed-agents

Conversation

@roboeve

@roboeve roboeve Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds @chat-adapter/managed-agents, which runs a hosted agent session in each chat thread. It ships with drivers for Claude Managed Agents, the Cursor SDK, and the OpenAI Agents API.

Connecting a hosted agent to Chat SDK takes a lot of glue code today. The Claude Managed Agents template spends about 560 lines mapping threads to sessions, adapting provider events into a thread.post() stream, reconciling previews with final messages, skipping events from earlier turns, and serializing turns with an in-process queue. Every provider with sessions needs the same chat-side work, so this package does it once.

const agent = createManagedAgent({
  driver: createClaudeDriver({ agentId, environmentId }),
});

bot.onNewMention(async (thread, message, context) => {
  await thread.subscribe();
  await agent.reply(thread, message, context);
});
bot.onSubscribedMessage((thread, message, context) => agent.reply(thread, message, context));
bot.onAction([...agent.actionIds], (event) => agent.handleAction(event));

Core

createManagedAgent({ driver }) handles the chat side:

  • Stores { driver, sessionId } in thread state, and starts a new session when the stored one can't be resumed.
  • Streams replies, with tool calls as task_update chunks.
  • Posts Approve/Deny cards for tool approvals. Each card is answered once.
  • Posts a message when the session ends, the turn stops early, or the stream drops.
  • Stops the provider turn when thread.signal aborts.
  • Uses the queue concurrency strategy for turn order, and sends queued messages (context.skipped) with the latest one.

A driver implements ManagedAgentDriver (createSession, resumeSession, runTurn, and an optional respondToApproval) and translates provider events into text-delta, message, tool-call, approval-request, turn-end, and session-ended. The core never imports a provider SDK. Each SDK is an optional peer dependency that only its subpath uses.

The package isn't a platform or state adapter, so it doesn't use the adapter-* or state-* naming and konsistent doesn't apply to it.

Drivers

Subpath Configuration from the environment Stopping a turn Tool approvals
/claude ANTHROPIC_API_KEY, CLAUDE_AGENT_ID, CLAUDE_ENVIRONMENT_ID Sends user.interrupt Batched user.tool_confirmation events
/cursor CURSOR_API_KEY, read by the SDK. The agent option is required. Cancels the run Not supported: the run is cancelled and the thread gets a notice
/openai OPENAI_API_KEY, OPENAI_AGENT_ID, and optionally OPENAI_ENVIRONMENT_ID Sends agent.session.input.cancel Required actions don't fit Approve/Deny, so the turn stops with a notice naming the action
  • Claude ports the template's event loop. It opens the event stream before sending, skips events until the sent event is echoed back, treats agent.message as authoritative over previews, and only reuses sessions owned by the configured agent.
  • Cursor creates one agent per thread and one run per message, and treats AgentNotFoundError as an ended session.
  • OpenAI targets the Agents API beta (client.beta.agents.sessions in openai 7.32+). Sending returns no event ID, so the driver anchors on the first turn.created event and ignores events for other turns. Without an environment ID, sessions use { type: "none" }.

Slack task cards

taskDisplay: "timeline" | "plan" sets how Slack groups task cards, through StreamingPlan (groupTasks).

When the final message differs from the streamed preview, the message is edited to the final text only if no task cards were streamed, because an edit replaces the whole message and would remove them. Otherwise the preview stays and a warning is logged. The same applies when taskDisplay is set, because a StreamingPlan post returns no SentMessage to edit.

Replies after an approval click keep native streaming and task cards. Chat SDK builds the action's thread with the clicking user and the block_actions payload, which supply the user and team that Slack's native streaming needs.

Example app

examples/nextjs-managed-agents is a Next.js Slack bot that uses the package. AGENT_PROVIDER=claude|cursor|openai picks the driver (default claude). The Slack manifest enables agent_view and assistant:write for task cards and the stop button, plus interactivity for approval buttons. The webhook route imports the bot at request time, so next build doesn't need agent credentials.

Test plan

  • pnpm --filter @chat-adapter/managed-agents test passes. It also type-checks the test files through tsconfig.typecheck.json, as packages/chat does, because tsc skips them.
    • Unit tests cover the core and stream rendering: sessions, skipped messages, divergent previews, task cards, aborts, and approvals.
    • Driver fixtures use the real SDK types and error classes, so SDK shape changes fail type-checking. Only network calls are mocked, and Claude events run through the SDK's accumulateManagedAgentsEvent.
    • chat.integration.test.ts runs a real Chat and ThreadImpl with @chat-adapter/tests mocks, from the mention through the approval click to the continuation stream.
    • index.test-d.ts checks the public API types against real Chat handlers.
  • typecheck, build, pnpm knip, and pnpm konsistent pass, and ultracite check passes on the changed files.
  • In examples/nextjs-managed-agents, next build and tsc --noEmit pass with no environment variables set.
  • pnpm validate doesn't fully pass locally. pnpm check fails on an existing warning in apps/docs/lib/read-more.ts, and installation.test.ts and main-readme.test.ts need every package built, so they also fail on main.
  • Not tested against the live Anthropic, Cursor, or OpenAI APIs. Two behaviors come from the SDK types rather than live runs: that the Claude stream echoes user.tool_confirmation events, which the driver anchors on, and that Cursor assistant events are deltas.

Checklist

  • All commits are signed and verified
  • All commits are signed off for the DCO (git commit -s). Needs a sign-off or remediation commit from the author
  • pnpm validate passes (see notes above)
  • Changeset added
  • Documentation updated (/docs/ai/managed-agents)

@socket-security

socket-security Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​anthropic-ai/​sdk@​0.133.06610092100100
Addednpm/​openai@​7.32.075100100100100
Addednpm/​@​cursor/​sdk@​1.0.379910084100100

View full report

@vercel

vercel Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
chat Ready Ready Preview, v0 Oct 19, 2026 3:53am UTC

@roboeve roboeve Bot changed the title feat(managed-agents): add @chat-adapter/managed-agents with Claude and Cursor drivers feat(managed-agents): add @chat-adapter/managed-agents with Claude, Cursor, and OpenAI drivers Oct 13, 2026
@socket-security

socket-security Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

@roboeve

roboeve Bot commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

CI on a6cb121 failed at pnpm install --frozen-lockfile ("no entry for '@next/env@16.3.6'"). The cause was the CI merge with main: main bumped next to 16.3.8 in #1066 and #1067, and the lockfile auto-merge left this example pointing at 16.3.6.

Fix: merged main into the branch and pushed 2d461b6. That commit bumps examples/nextjs-managed-agents to next@^16.3.8, which also clears the Socket CVE warning, and regenerates the lockfile. Checked locally: frozen install passes, managed-agents has 153 tests and typecheck passing, and the example typechecks. New CI is pending.

This branch was successfully deployed

1 active deployment
Preview — 2d461b6a Deployed Oct 19, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants