@agent-native/core 0.56.1 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +66 -10
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/skills.d.ts +2 -2
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +13 -5
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +8 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +24 -4
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +39 -4
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/connectors.d.ts +19 -0
- package/dist/client/chat/connectors.d.ts.map +1 -0
- package/dist/client/chat/connectors.js +992 -0
- package/dist/client/chat/connectors.js.map +1 -0
- package/dist/client/chat/index.d.ts +2 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +2 -0
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/chat/runtime.d.ts +93 -0
- package/dist/client/chat/runtime.d.ts.map +1 -1
- package/dist/client/chat/runtime.js +934 -1
- package/dist/client/chat/runtime.js.map +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +48 -3
- package/dist/mcp/build-server.js.map +1 -1
- package/docs/content/actions.md +5 -1
- package/docs/content/agent-surfaces.md +273 -0
- package/docs/content/components.md +46 -17
- package/docs/content/drop-in-agent.md +10 -5
- package/docs/content/embedding-sdk.md +4 -0
- package/docs/content/external-agents.md +1 -0
- package/docs/content/getting-started.md +2 -0
- package/docs/content/harness-agents.md +232 -0
- package/docs/content/key-concepts.md +24 -22
- package/docs/content/mcp-apps.md +1 -1
- package/docs/content/native-chat-ui.md +101 -22
- package/docs/content/plan-plugin.md +27 -1
- package/docs/content/pure-agent-apps.md +2 -1
- package/docs/content/using-your-agent.md +1 -0
- package/docs/content/what-is-agent-native.md +3 -2
- package/package.json +1 -1
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Agent Surfaces"
|
|
3
|
+
description: "Use Agent-Native headlessly, as rich chat, inside an existing app, or as a full agent-native application."
|
|
4
|
+
search: "headless agent rich chat full app BYO agent runtime AgentChatRuntime embed actions MCP A2A HTTP CLI"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Agent Surfaces
|
|
8
|
+
|
|
9
|
+
Agent-Native is deliberately composable. You can use the agent without much UI,
|
|
10
|
+
use the UI without the built-in agent runtime, or use both together as a full
|
|
11
|
+
application.
|
|
12
|
+
|
|
13
|
+
The useful way to choose is not by protocol first. Choose the product surface
|
|
14
|
+
you want, then use the matching primitive.
|
|
15
|
+
|
|
16
|
+
| Surface | Use it when | Start with |
|
|
17
|
+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
18
|
+
| **Headless agent/actions** | Code, jobs, scripts, another app, or another agent should call the work directly. | `defineAction`, HTTP, CLI, MCP, A2A |
|
|
19
|
+
| **Rich chat on Agent-Native** | You want a standalone or embedded chat backed by the built-in agent loop. | `<AgentChatSurface>`, `<AssistantChat>`, `createAgentChatPlugin()` |
|
|
20
|
+
| **Rich chat on your agent** | You built the agent elsewhere and want Agent-Native's composer, transcript, tool cards, and native widgets. | `AgentChatRuntime`, `<AssistantChat runtime={runtime}>` |
|
|
21
|
+
| **Embedded sidecar** | You already have a SaaS app and want an agent beside it with page context and host commands. | `createAgentNativeEmbeddedPlugin()`, `AgentNativeEmbedded` |
|
|
22
|
+
| **Full application** | Humans and agents should share durable screens, data, navigation, and collaboration. | Templates, actions, SQL state, context awareness |
|
|
23
|
+
|
|
24
|
+
Those are stages, not separate products. A workflow can start as a headless
|
|
25
|
+
action, appear in chat as a table or chart, and later become a full screen in an
|
|
26
|
+
app without changing the operation the agent calls.
|
|
27
|
+
|
|
28
|
+
## Headless agent/actions {#headless}
|
|
29
|
+
|
|
30
|
+
Use the headless path when no one needs to stare at a custom app screen while
|
|
31
|
+
the work runs: scheduled jobs, integrations, backend workflows, CLI loops,
|
|
32
|
+
another agent, or an existing product calling into Agent-Native.
|
|
33
|
+
|
|
34
|
+
Most headless integrations should start with actions:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// actions/summarize-week.ts
|
|
38
|
+
import { defineAction } from "@agent-native/core";
|
|
39
|
+
import { z } from "zod";
|
|
40
|
+
|
|
41
|
+
export default defineAction({
|
|
42
|
+
description: "Summarize this week's submissions.",
|
|
43
|
+
readOnly: true,
|
|
44
|
+
schema: z.object({ formId: z.string() }),
|
|
45
|
+
run: async ({ formId }) => {
|
|
46
|
+
return { formId, summary: "34 submissions, up 18% from last week." };
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
One action is then callable as:
|
|
52
|
+
|
|
53
|
+
- **HTTP** — `POST /_agent-native/actions/summarize-week`
|
|
54
|
+
- **CLI** — `pnpm action summarize-week --formId form_123`
|
|
55
|
+
- **MCP** — from Claude, ChatGPT, Codex, Cursor, OpenCode, Copilot, and other MCP hosts
|
|
56
|
+
- **A2A** — from another agent-native app or agent peer
|
|
57
|
+
- **UI** — through `useActionQuery`, `useActionMutation`, or `callAction`
|
|
58
|
+
- **Agent tool** — from the built-in chat loop
|
|
59
|
+
|
|
60
|
+
If you need the whole agent loop headlessly, use the server API from a worker,
|
|
61
|
+
job, integration webhook, or custom host. This is lower-level than actions: you
|
|
62
|
+
provide the engine, model, messages, actions, and event sink yourself.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import {
|
|
66
|
+
actionsToEngineTools,
|
|
67
|
+
resolveEngine,
|
|
68
|
+
runAgentLoop,
|
|
69
|
+
} from "@agent-native/core/server";
|
|
70
|
+
|
|
71
|
+
const engine = await resolveEngine({ engineOption: undefined });
|
|
72
|
+
const model = engine.defaultModel;
|
|
73
|
+
const controller = new AbortController();
|
|
74
|
+
|
|
75
|
+
await runAgentLoop({
|
|
76
|
+
engine,
|
|
77
|
+
model,
|
|
78
|
+
systemPrompt: "You are the reporting agent for this workspace.",
|
|
79
|
+
actions,
|
|
80
|
+
tools: actionsToEngineTools(actions),
|
|
81
|
+
messages: [
|
|
82
|
+
{
|
|
83
|
+
role: "user",
|
|
84
|
+
content: [{ type: "text", text: "Summarize this week's forms." }],
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
send: (event) => {
|
|
88
|
+
// Persist, log, stream, or translate AgentChatEvent objects.
|
|
89
|
+
},
|
|
90
|
+
signal: controller.signal,
|
|
91
|
+
ownerEmail: user.email,
|
|
92
|
+
orgId: user.orgId,
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
For most apps, scheduled prompts and integration webhooks already call this loop
|
|
97
|
+
for you. Reach for direct `runAgentLoop()` when you are building a custom
|
|
98
|
+
headless host, eval runner, or server-side orchestration surface.
|
|
99
|
+
|
|
100
|
+
## Rich chat on Agent-Native {#rich-chat}
|
|
101
|
+
|
|
102
|
+
Use the built-in chat when the user should talk to the agent, see tool calls,
|
|
103
|
+
approve work, inspect native results, and keep a durable thread history.
|
|
104
|
+
|
|
105
|
+
The simplest full-page chat:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { AgentChatSurface } from "@agent-native/core/client/chat";
|
|
109
|
+
|
|
110
|
+
export default function ChatRoute() {
|
|
111
|
+
return <AgentChatSurface mode="page" className="h-screen" />;
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The simplest embedded chat with your own chrome:
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
import { AssistantChat } from "@agent-native/core/client/chat";
|
|
119
|
+
|
|
120
|
+
export function ProjectChat({ threadId }: { threadId: string }) {
|
|
121
|
+
return <AssistantChat threadId={threadId} />;
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Actions can return explicit native widget results so chat output is not just
|
|
126
|
+
text. Tables, charts, and typed product cards render as first-party React
|
|
127
|
+
components in the chat, without iframes. See [Native Chat UI](/docs/native-chat-ui).
|
|
128
|
+
|
|
129
|
+
## Rich chat on your agent {#byo-agent}
|
|
130
|
+
|
|
131
|
+
Use this path when your agent is already built with another framework or
|
|
132
|
+
runtime and you want Agent-Native's chat UI around it.
|
|
133
|
+
|
|
134
|
+
`AgentChatRuntime` is the boundary. Your runtime streams normalized events;
|
|
135
|
+
Agent-Native renders the composer, transcript, tool calls, approvals, native
|
|
136
|
+
widgets, and app layout.
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import {
|
|
140
|
+
AssistantChat,
|
|
141
|
+
createHttpAgentChatRuntime,
|
|
142
|
+
} from "@agent-native/core/client/chat";
|
|
143
|
+
|
|
144
|
+
const runtime = createHttpAgentChatRuntime({
|
|
145
|
+
id: "external:support-agent",
|
|
146
|
+
label: "Support agent",
|
|
147
|
+
endpoint: "/api/support-agent/chat",
|
|
148
|
+
headers: async () => ({ Authorization: `Bearer ${await getToken()}` }),
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
export function SupportAgentChat() {
|
|
152
|
+
return <AssistantChat runtime={runtime} threadId="support" />;
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Use `createOpenAIAgentsChatRuntime()`,
|
|
157
|
+
`createOpenAIResponsesChatRuntime()`, `createClaudeAgentChatRuntime()`,
|
|
158
|
+
`createVercelAiChatRuntime()`, or `createAgUiChatRuntime()` when your endpoint
|
|
159
|
+
already streams one of those event shapes. Use `createHttpAgentChatRuntime()`
|
|
160
|
+
when your agent streams Agent-Native's normalized event shape directly:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import { createOpenAIAgentsChatRuntime } from "@agent-native/core/client/chat";
|
|
164
|
+
|
|
165
|
+
const runtime = createOpenAIAgentsChatRuntime({
|
|
166
|
+
endpoint: "/api/openai-agent/chat",
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The endpoint can stream SSE or NDJSON events:
|
|
171
|
+
|
|
172
|
+
```txt
|
|
173
|
+
data: {"type":"message-delta","messageId":"m1","delta":{"type":"text","text":"I found 34 submissions."}}
|
|
174
|
+
data: {"type":"tool-start","toolCall":{"id":"t1","name":"query","input":{"formId":"form_123"}}}
|
|
175
|
+
data: {"type":"tool-done","toolCallId":"t1","toolName":"query","status":"completed","resultText":"34 rows"}
|
|
176
|
+
data: {"type":"done","reason":"complete"}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
For a trivial integration, returning `{ "text": "..." }` also works. For richer
|
|
180
|
+
integrations, stream `message-*`, `tool-*`, `approval-request`, `status`,
|
|
181
|
+
`artifact`, `file`, `usage`, `error`, and `done` events. Tool results can carry
|
|
182
|
+
`chatUI` metadata so the same native table/chart/card renderers work with your
|
|
183
|
+
agent too.
|
|
184
|
+
|
|
185
|
+
This is the right place to adapt the OpenAI Agents SDK, Claude Agent SDK, Vercel
|
|
186
|
+
AI SDK, Mastra, Flue, Eve, LangGraph, a custom service, or an AG-UI-compatible
|
|
187
|
+
event stream. Do not use ACP as the default end-user app chat protocol; ACP is
|
|
188
|
+
better framed as coding-agent/editor interoperability. Agent-Native does not
|
|
189
|
+
currently claim A2UI support.
|
|
190
|
+
|
|
191
|
+
## Embedded sidecar {#embedded-sidecar}
|
|
192
|
+
|
|
193
|
+
Use the embedded sidecar when the main product already exists and you want an
|
|
194
|
+
agent beside it.
|
|
195
|
+
|
|
196
|
+
The server plugin mounts Agent-Native routes into your host app and resolves
|
|
197
|
+
host identity server-side:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { createAgentNativeEmbeddedPlugin } from "@agent-native/core/server";
|
|
201
|
+
|
|
202
|
+
export default createAgentNativeEmbeddedPlugin({
|
|
203
|
+
databaseUrl: process.env.AGENT_NATIVE_DATABASE_URL,
|
|
204
|
+
auth: getHostSession,
|
|
205
|
+
actions: hostActions,
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The React sidecar passes page context and host commands:
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
import { AgentNativeEmbedded } from "@agent-native/core/client";
|
|
213
|
+
|
|
214
|
+
export function AppShell({ children }) {
|
|
215
|
+
return (
|
|
216
|
+
<AgentNativeEmbedded
|
|
217
|
+
getContext={() => ({
|
|
218
|
+
route: { pathname: window.location.pathname },
|
|
219
|
+
selection: { text: window.getSelection()?.toString() || undefined },
|
|
220
|
+
})}
|
|
221
|
+
onNavigate={(payload) =>
|
|
222
|
+
router.navigate((payload as { path: string }).path)
|
|
223
|
+
}
|
|
224
|
+
onRefresh={() => queryClient.invalidateQueries()}
|
|
225
|
+
>
|
|
226
|
+
{children}
|
|
227
|
+
</AgentNativeEmbedded>
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
See [Embedding SDK](/docs/embedding-sdk) for host auth, database isolation,
|
|
233
|
+
iframe/picker mode, and lower-level bridge APIs.
|
|
234
|
+
|
|
235
|
+
## Full application {#full-application}
|
|
236
|
+
|
|
237
|
+
Use the full app path when users need durable objects and workflows: forms,
|
|
238
|
+
dashboards, calendars, inboxes, editors, documents, assets, or reports.
|
|
239
|
+
|
|
240
|
+
Full apps add product UI around the same action and agent contract:
|
|
241
|
+
|
|
242
|
+
- **SQL state** — app data, navigation, settings, and chat history are durable.
|
|
243
|
+
- **Context awareness** — the agent knows the current route, selection, and focused object.
|
|
244
|
+
- **Live sync** — agent changes update the UI, and UI changes update the agent's context.
|
|
245
|
+
- **Deep links** — action results can open the right app view.
|
|
246
|
+
- **Native chat widgets** — tables, charts, cards, approvals, and typed results appear inline.
|
|
247
|
+
|
|
248
|
+
Start from a [template](/docs/cloneable-saas) when you want a complete app, or
|
|
249
|
+
from [Starter](/docs/template-starter) when you want only the framework wiring.
|
|
250
|
+
|
|
251
|
+
## How to choose {#how-to-choose}
|
|
252
|
+
|
|
253
|
+
| If you are thinking... | Choose |
|
|
254
|
+
| --------------------------------------------------------------- | ------------------------- |
|
|
255
|
+
| "I just need a callable tool or workflow." | Headless action |
|
|
256
|
+
| "I want the framework's agent, but chat should be the main UI." | Rich chat on Agent-Native |
|
|
257
|
+
| "I already have an agent; I need a polished chat UI for it." | Rich chat on your agent |
|
|
258
|
+
| "I already have a SaaS app; add an agent beside it." | Embedded sidecar |
|
|
259
|
+
| "The agent and UI should evolve together as the product." | Full application |
|
|
260
|
+
|
|
261
|
+
Keep the contract small: define durable operations as actions, return explicit
|
|
262
|
+
widget results when chat needs rich UI, and add full screens only when users
|
|
263
|
+
need to browse, compare, configure, or collaborate over persistent objects.
|
|
264
|
+
|
|
265
|
+
## Related docs {#related-docs}
|
|
266
|
+
|
|
267
|
+
- [Actions](/docs/actions) — define the headless operation once.
|
|
268
|
+
- [Native Chat UI](/docs/native-chat-ui) — render typed action results in chat.
|
|
269
|
+
- [Drop-in Agent](/docs/drop-in-agent) — mount chat, sidebar, or panel surfaces.
|
|
270
|
+
- [Component API](/docs/components) — lower-level React chat/composer pieces.
|
|
271
|
+
- [Embedding SDK](/docs/embedding-sdk) — add Agent-Native to an existing app.
|
|
272
|
+
- [External Agents](/docs/external-agents) — connect MCP-compatible hosts to an app.
|
|
273
|
+
- [A2A Protocol](/docs/a2a-protocol) — call agents from other agents.
|
|
@@ -27,23 +27,31 @@ so bundlers choose the browser-safe entry.
|
|
|
27
27
|
|
|
28
28
|
## Agent And Chat UI {#agent-chat-ui}
|
|
29
29
|
|
|
30
|
-
| API
|
|
31
|
-
|
|
|
32
|
-
| `<AgentSidebar>`
|
|
33
|
-
| `<AgentToggleButton>`
|
|
34
|
-
| `<AgentPanel>`
|
|
35
|
-
| `<AgentChatSurface>`
|
|
36
|
-
| `<AssistantChat>`
|
|
37
|
-
| `<MultiTabAssistantChat>`
|
|
38
|
-
| `
|
|
39
|
-
| `
|
|
40
|
-
| `
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
`
|
|
30
|
+
| API | Import path | Use when |
|
|
31
|
+
| ------------------------------------ | --------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
32
|
+
| `<AgentSidebar>` | `@agent-native/core/client` or `/client/chat` | You want the complete sidebar around your app. |
|
|
33
|
+
| `<AgentToggleButton>` | `@agent-native/core/client` or `/client/chat` | You render your own header button for the sidebar. |
|
|
34
|
+
| `<AgentPanel>` | `@agent-native/core/client` or `/client/chat` | You want the full panel in your own layout, route, dialog, or side column. |
|
|
35
|
+
| `<AgentChatSurface>` | `@agent-native/core/client` or `/client/chat` | You want chat in panel or page mode without the sidebar wrapper. |
|
|
36
|
+
| `<AssistantChat>` | `@agent-native/core/client` or `/client/chat` | You want to own surrounding chrome while keeping the standard conversation and composer runtime. |
|
|
37
|
+
| `<MultiTabAssistantChat>` | `@agent-native/core/client` or `/client/chat` | You want the framework's thread tabs without `AgentPanel` chrome. |
|
|
38
|
+
| `createHttpAgentChatRuntime()` | `@agent-native/core/client` or `/client/chat` | You have a BYO agent endpoint that streams normalized chat events. |
|
|
39
|
+
| `createOpenAIAgentsChatRuntime()` | `@agent-native/core/client` or `/client/chat` | You have an OpenAI Agents SDK stream and want the standard chat UI around it. |
|
|
40
|
+
| `createOpenAIResponsesChatRuntime()` | `@agent-native/core/client` or `/client/chat` | You have an OpenAI Responses event stream and want it normalized into the chat UI. |
|
|
41
|
+
| `createAgUiChatRuntime()` | `@agent-native/core/client` or `/client/chat` | You have an AG-UI event stream and want it normalized into the chat UI. |
|
|
42
|
+
| `createClaudeAgentChatRuntime()` | `@agent-native/core/client` or `/client/chat` | You have a Claude Agent SDK stream and want it normalized into the chat UI. |
|
|
43
|
+
| `createVercelAiChatRuntime()` | `@agent-native/core/client` or `/client/chat` | You have a Vercel AI SDK stream and want it normalized into the chat UI. |
|
|
44
|
+
| `createAgentChatRuntimeAdapter()` | `@agent-native/core/client` or `/client/chat` | You need to adapt an `AgentChatRuntime` into assistant-ui yourself. |
|
|
45
|
+
| `createAgentChatAdapter()` | `@agent-native/core/client` or `/client/chat` | You need the built-in Agent-Native SSE transport as a low-level assistant-ui adapter. |
|
|
46
|
+
| `useChatThreads()` | `@agent-native/core/client` or `/client/chat` | You need a custom thread list, history picker, or scoped chat UI. |
|
|
47
|
+
| `sendToAgentChat()` | `@agent-native/core/client` or `/client/chat` | A product action should hand work to the agent chat. |
|
|
48
|
+
|
|
49
|
+
`AgentChatRuntime` is the BYO-agent contract for the standard chat shell. Pass
|
|
50
|
+
`runtime` to `<AssistantChat>` when an external agent should power the
|
|
51
|
+
conversation while Agent-Native keeps the composer, transcript, tool cards, and
|
|
52
|
+
native widget rendering. If you are choosing between headless actions, rich
|
|
53
|
+
chat, embedded sidecar, and full app shapes, see
|
|
54
|
+
[Agent Surfaces](/docs/agent-surfaces).
|
|
47
55
|
|
|
48
56
|
The shortest custom route is still a pre-wired surface:
|
|
49
57
|
|
|
@@ -77,6 +85,27 @@ function CustomChat({ projectSlug }: { projectSlug: string }) {
|
|
|
77
85
|
}
|
|
78
86
|
```
|
|
79
87
|
|
|
88
|
+
For a bring-your-own agent endpoint:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import {
|
|
92
|
+
AssistantChat,
|
|
93
|
+
createOpenAIAgentsChatRuntime,
|
|
94
|
+
} from "@agent-native/core/client/chat";
|
|
95
|
+
|
|
96
|
+
const runtime = createOpenAIAgentsChatRuntime({
|
|
97
|
+
endpoint: "/api/my-agent/chat",
|
|
98
|
+
label: "My agent",
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
export function MyAgentChat() {
|
|
102
|
+
return <AssistantChat runtime={runtime} />;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Use `createHttpAgentChatRuntime()` instead when your endpoint already emits
|
|
107
|
+
Agent-Native normalized events.
|
|
108
|
+
|
|
80
109
|
## Chat Field And Composer {#composer}
|
|
81
110
|
|
|
82
111
|
Use `@agent-native/core/client/composer` when you need to place the same chat
|
|
@@ -184,20 +184,25 @@ framework own the agent runtime:
|
|
|
184
184
|
- **`@agent-native/core/client/conversation`** — use this for transcript
|
|
185
185
|
rendering without the full chat runtime.
|
|
186
186
|
- **`createAgentChatAdapter()`** — use this only when building a custom
|
|
187
|
-
assistant-ui transport for the
|
|
187
|
+
assistant-ui transport for the built-in Agent-Native chat endpoint. It
|
|
188
188
|
connects to the same `/_agent-native/agent-chat` stream and preserves
|
|
189
189
|
run-manager recovery, attachments, model selection, native widgets, and
|
|
190
190
|
thread metadata.
|
|
191
|
+
- **`createHttpAgentChatRuntime()`** — use this when a BYO agent exposes a
|
|
192
|
+
POST endpoint that streams `AgentChatRuntime` events. Pass the runtime to
|
|
193
|
+
`<AssistantChat runtime={runtime} />`.
|
|
191
194
|
|
|
192
195
|
Avoid posting directly to `/_agent-native/agent-chat` from product UI. If a
|
|
193
196
|
lower-level helper is missing for a real custom surface, add that named helper
|
|
194
197
|
first so client code does not learn a second, ad hoc transport.
|
|
195
198
|
|
|
196
199
|
For BYO agent runtimes, keep actions and SQL-backed app state as the contract.
|
|
197
|
-
Adapt the runtime into `<AssistantChat
|
|
198
|
-
Agent-Native chat behavior
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
Adapt the runtime into `<AssistantChat runtime={...} />` when you want
|
|
201
|
+
Agent-Native chat behavior. Use `<AssistantChat createAdapter={...} />` only
|
|
202
|
+
for lower-level assistant-ui transports, or `PromptComposer` by itself only
|
|
203
|
+
when the external runtime owns the transcript and loop. See
|
|
204
|
+
[Native Chat UI](/docs/native-chat-ui#byo-agent-runtimes) and
|
|
205
|
+
[Agent Surfaces](/docs/agent-surfaces#byo-agent).
|
|
201
206
|
|
|
202
207
|
### Build your own sidebar from pieces {#build-your-own-sidebar}
|
|
203
208
|
|
|
@@ -29,6 +29,10 @@ pnpm add @agent-native/core
|
|
|
29
29
|
|
|
30
30
|
## Choosing a mode {#choosing-a-mode}
|
|
31
31
|
|
|
32
|
+
This page is for embedding Agent-Native into an existing product. If you are
|
|
33
|
+
still deciding between headless actions, rich chat, an embedded sidecar, or a
|
|
34
|
+
full app, start with [Agent Surfaces](/docs/agent-surfaces).
|
|
35
|
+
|
|
32
36
|
| Mode | Use it when | Package |
|
|
33
37
|
| ------------------------------------ | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
|
34
38
|
| **EmbeddedApp picker** | Launching a full Agent-Native app as a focused iframe (asset picker, form builder, approval panel). | `@agent-native/embedding` |
|
|
@@ -13,6 +13,7 @@ The external-agent bridge closes the loop. First you connect your own agent to a
|
|
|
13
13
|
## Which agent path do you need? {#which-agent-path}
|
|
14
14
|
|
|
15
15
|
- **External MCP host:** use this page when Claude, ChatGPT, Codex, Cursor, OpenCode, GitHub Copilot / VS Code, or another MCP-compatible host should call your hosted agent-native app.
|
|
16
|
+
- **Your own runtime behind Agent-Native chat:** see [Agent Surfaces](/docs/agent-surfaces#byo-agent) and [Native Chat UI](/docs/native-chat-ui#byo-agent-runtimes) when an agent built with another framework should power `<AssistantChat runtime={...}>`.
|
|
16
17
|
- **Your app consuming MCP tools:** see [MCP Clients](/docs/mcp-clients) when an agent-native app needs to call tools exposed by another MCP server.
|
|
17
18
|
- **Another app or agent via A2A:** use [Agent Mentions](/docs/agent-mentions) and [A2A](/docs/a2a-protocol) when agent-native apps should discover and delegate to each other.
|
|
18
19
|
- **Local custom sub-agents:** use [Workspace](/docs/workspace) when you want custom agent profiles inside the agent-native workspace itself.
|
|
@@ -13,6 +13,7 @@ Start with the path that matches what you want to do next:
|
|
|
13
13
|
|
|
14
14
|
- **Use a starter app.** Browse the [template gallery](/templates). Hosted apps already include sign-in, data, and the agent sidebar. No install required.
|
|
15
15
|
- **Build or customize your own app.** Continue with [Create a local app](#create-your-app). You'll scaffold a template, run it locally, then change the code, brand, data model, and integrations.
|
|
16
|
+
- **Choose headless, chat, embedded, or full app.** Use [Agent Surfaces](/docs/agent-surfaces) when you know the workflow but not how much UI belongs around it.
|
|
16
17
|
- **Add agent-native skills to a code tool.** Jump to [Try it with a skill](#try-with-a-skill) to add Plans or PR Recaps to Claude Code, Codex, or Cursor without scaffolding an app.
|
|
17
18
|
- **Connect an external agent to an app.** Use [External Agents](/docs/external-agents) to connect Claude, ChatGPT, Codex, Cursor, OpenCode, GitHub Copilot / VS Code, or another MCP host to an existing app.
|
|
18
19
|
|
|
@@ -122,6 +123,7 @@ Once your app is running, the usual next step is small and concrete:
|
|
|
122
123
|
Useful follow-up docs:
|
|
123
124
|
|
|
124
125
|
- [Key Concepts](/docs/key-concepts) for the architecture: SQL, actions, polling sync, and context awareness
|
|
126
|
+
- [Agent Surfaces](/docs/agent-surfaces) for choosing headless, rich chat, embedded sidecar, or full app
|
|
125
127
|
- [Workspace](/docs/workspace) for instructions, skills, memory, and per-user MCP connections
|
|
126
128
|
- [Messaging](/docs/messaging) for Slack, email, Telegram, and other ways to reach the agent
|
|
127
129
|
- [FAQ](/docs/faq) for setup and product questions
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Harness Agents"
|
|
3
|
+
description: "Run Claude Code, Codex, Pi, and other full coding harnesses as embedded agents inside Agent-Native, with their own loop, sandbox, native tools, and resumable SQL-backed sessions."
|
|
4
|
+
search: "harness agents AgentHarness ai-sdk HarnessAgent Claude Code Codex Pi Cursor Mastra embedded coding agent resolveAgentHarness startAgentHarnessRun resumable session sandbox host tools"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Harness Agents
|
|
8
|
+
|
|
9
|
+
A harness agent is a full agent runtime — Claude Code, Codex, Pi, and similar —
|
|
10
|
+
that owns its own loop, workspace, native file tools, session state, compaction,
|
|
11
|
+
approval model, and sandbox behavior. Agent-Native runs these through the
|
|
12
|
+
**`AgentHarness`** substrate in `@agent-native/core/agent/harness`, streams their
|
|
13
|
+
events into the normal transcript, and persists their native session so a thread
|
|
14
|
+
can pause and resume.
|
|
15
|
+
|
|
16
|
+
This is different from the built-in chat agent and from bringing your own chat
|
|
17
|
+
runtime. The built-in agent and `AgentEngine` are for one model round trip
|
|
18
|
+
beneath `runAgentLoop`. A harness is not an `AgentEngine` provider — it runs its
|
|
19
|
+
own loop end to end, so Agent-Native drives it as a session, not as a single
|
|
20
|
+
model call.
|
|
21
|
+
|
|
22
|
+
| You want to… | Use |
|
|
23
|
+
| -------------------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
24
|
+
| Run Claude Code / Codex / Pi **as the agent**, with their own loop + tools | **Harness agents** (this page) |
|
|
25
|
+
| Put an agent you built elsewhere behind Agent-Native's **chat UI** | [`AgentChatRuntime`](/docs/native-chat-ui#byo-agent-runtimes) |
|
|
26
|
+
| Let an external MCP host (Claude Code, Cursor, …) **call into your app** | [External Agents](/docs/external-agents) |
|
|
27
|
+
| Render a Claude-Code/Codex-style **coding workspace UI** | [Agent-Native Code UI](/docs/code-agents-ui) |
|
|
28
|
+
| Spawn background / sub-agent runs and teams | [Custom Agents & Teams](/docs/agent-teams) |
|
|
29
|
+
|
|
30
|
+
## Built-in harnesses {#built-in}
|
|
31
|
+
|
|
32
|
+
`registerBuiltinAgentHarnesses()` registers three adapters backed by the AI SDK
|
|
33
|
+
`HarnessAgent`:
|
|
34
|
+
|
|
35
|
+
| Name | Runtime | Sandbox | Approvals |
|
|
36
|
+
| ---------------------------- | ----------- | ------- | --------- |
|
|
37
|
+
| `ai-sdk-harness:claude-code` | Claude Code | yes | yes |
|
|
38
|
+
| `ai-sdk-harness:codex` | Codex | yes | no |
|
|
39
|
+
| `ai-sdk-harness:pi` | Pi | no | yes |
|
|
40
|
+
|
|
41
|
+
Their runtime packages are **optional peer dependencies** and load lazily, so an
|
|
42
|
+
app that never uses a harness does not pay for it. Each adapter carries an
|
|
43
|
+
`installPackage` hint (for example `@ai-sdk/harness@canary
|
|
44
|
+
@ai-sdk/harness-codex@canary`); `resolveAgentHarness` throws a clear install
|
|
45
|
+
error if the packages are missing, and `isAgentHarnessPackageInstalled(entry)`
|
|
46
|
+
lets you check first.
|
|
47
|
+
|
|
48
|
+
## Register and resolve {#register-resolve}
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import {
|
|
52
|
+
registerBuiltinAgentHarnesses,
|
|
53
|
+
resolveAgentHarness,
|
|
54
|
+
} from "@agent-native/core/agent/harness";
|
|
55
|
+
|
|
56
|
+
registerBuiltinAgentHarnesses();
|
|
57
|
+
const adapter = resolveAgentHarness("ai-sdk-harness:codex");
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`resolveAgentHarness(name, config?)` returns an `AgentHarnessAdapter`. The
|
|
61
|
+
optional `config` is forwarded to the adapter factory — for the AI SDK adapters
|
|
62
|
+
that maps to `AiSdkHarnessAdapterOptions` (`label`, `description`,
|
|
63
|
+
`permissionMode`, `harnessOptions`, `agentOptions`). Use `listAgentHarnesses()`
|
|
64
|
+
to enumerate what is registered for a picker.
|
|
65
|
+
|
|
66
|
+
## Run a turn {#run-a-turn}
|
|
67
|
+
|
|
68
|
+
`startAgentHarnessRun` bridges a harness session into the shared run-manager
|
|
69
|
+
lifecycle. It creates (or reuses) the native session, persists it, streams the
|
|
70
|
+
turn, translates each harness event into transcript events, and detaches the
|
|
71
|
+
resumable state when the turn completes.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { startAgentHarnessRun } from "@agent-native/core/agent/harness";
|
|
75
|
+
|
|
76
|
+
const run = startAgentHarnessRun({
|
|
77
|
+
runId,
|
|
78
|
+
threadId,
|
|
79
|
+
adapter,
|
|
80
|
+
input: { prompt },
|
|
81
|
+
createSession: {
|
|
82
|
+
sessionId,
|
|
83
|
+
resumeState, // opaque value from a previous turn, if resuming
|
|
84
|
+
instructions,
|
|
85
|
+
sandbox, // required for sandboxed harnesses — see Sandbox Adapters
|
|
86
|
+
permissionMode: "allow-reads",
|
|
87
|
+
tools, // a narrow, intentional set of host tools (see below)
|
|
88
|
+
},
|
|
89
|
+
ownerEmail,
|
|
90
|
+
orgId,
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`startAgentHarnessRun` returns the `ActiveRun` from the run-manager, so the turn
|
|
95
|
+
shows up through the existing run routes, transcript, and cancellation just like
|
|
96
|
+
any other agent run. Pass an already-created `session` instead of `createSession`
|
|
97
|
+
to continue a session you are holding in memory.
|
|
98
|
+
|
|
99
|
+
## Sessions and resume {#sessions}
|
|
100
|
+
|
|
101
|
+
A harness owns long-lived native session state. Agent-Native persists it in SQL
|
|
102
|
+
so a thread can survive across turns, processes, and deploys. The `resumeState`
|
|
103
|
+
is **opaque** — Agent-Native stores it and hands it back, but never inspects or
|
|
104
|
+
interprets it.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import {
|
|
108
|
+
getLatestAgentHarnessSessionForThread,
|
|
109
|
+
listAgentHarnessSessions,
|
|
110
|
+
} from "@agent-native/core/agent/harness";
|
|
111
|
+
|
|
112
|
+
const last = await getLatestAgentHarnessSessionForThread(threadId);
|
|
113
|
+
// Feed last?.resumeState into createSession.resumeState on the next turn.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The store also exposes `saveAgentHarnessSession`, `updateAgentHarnessSession`,
|
|
117
|
+
`getAgentHarnessSession`, `getAgentHarnessSessionByRunId`,
|
|
118
|
+
`markAgentHarnessSessionStopped`, and `ensureAgentHarnessSessionTables`.
|
|
119
|
+
`startAgentHarnessRun` calls the save/update/stop paths for you; reach for them
|
|
120
|
+
directly only in a custom host.
|
|
121
|
+
|
|
122
|
+
## Host tools and permissions {#host-tools}
|
|
123
|
+
|
|
124
|
+
A harness brings its own native tools (read, edit, write, shell, and so on), so
|
|
125
|
+
you do **not** re-expose file editing as host tools. Pass only a **narrow,
|
|
126
|
+
intentional set** of Agent-Native actions through `createSession.tools` when you
|
|
127
|
+
want the harness to reach specific app operations — and keep `defineAction`
|
|
128
|
+
auth, request context, timeouts, truncation, and read-only metadata intact when
|
|
129
|
+
you do.
|
|
130
|
+
|
|
131
|
+
`permissionMode` gates what the harness may do without approval:
|
|
132
|
+
|
|
133
|
+
| Mode | Meaning |
|
|
134
|
+
| ------------- | -------------------------------------------------- |
|
|
135
|
+
| `allow-reads` | Default. Reads run; edits and risky actions prompt |
|
|
136
|
+
| `allow-edits` | Reads and edits run; other risky actions prompt |
|
|
137
|
+
| `allow-all` | No approval gating |
|
|
138
|
+
|
|
139
|
+
When a harness pauses for approval it emits an `approval-request` event and the
|
|
140
|
+
session is marked `idle` with the pending approval recorded, so the UI can
|
|
141
|
+
surface it and resume on the user's decision. See
|
|
142
|
+
[Human Approval](/docs/human-approval) for the approval surface.
|
|
143
|
+
|
|
144
|
+
## Events {#events}
|
|
145
|
+
|
|
146
|
+
A harness session streams `AgentHarnessEvent` values, which Agent-Native
|
|
147
|
+
translates to the standard `AgentChatEvent` stream with
|
|
148
|
+
`agentHarnessEventToAgentChatEvents`. The event union covers `text-delta`,
|
|
149
|
+
`thinking-delta`, `activity`, `tool-start`, `tool-done` (which can carry an
|
|
150
|
+
`mcpApp` payload for native widgets), `approval-request`, `file-change`,
|
|
151
|
+
`compaction`, `usage`, `error`, and `done`. Because tool results flow through the
|
|
152
|
+
same translation, action-declared native widgets still render — see
|
|
153
|
+
[Native Chat UI](/docs/native-chat-ui).
|
|
154
|
+
|
|
155
|
+
## Background runs and the UI {#background-runs}
|
|
156
|
+
|
|
157
|
+
Harness runs project into the shared `BackgroundAgentRun` shape with
|
|
158
|
+
`createAgentHarnessBackgroundAgentController()` and are available through the
|
|
159
|
+
existing run routes as `goalId=agent-harness`. That means a long-running Claude
|
|
160
|
+
Code or Codex session appears in the same background-run and transcript surfaces
|
|
161
|
+
as Agent Teams and other adapters, with `listAgentHarnessBackgroundRuns`,
|
|
162
|
+
`listAgentHarnessBackgroundTranscriptEvents`, `getAgentHarnessBackgroundRun`, and
|
|
163
|
+
`stopAgentHarnessBackgroundRun` available for custom hosts.
|
|
164
|
+
|
|
165
|
+
## Custom adapters {#custom-adapters}
|
|
166
|
+
|
|
167
|
+
To wrap a runtime that is not one of the built-ins, implement
|
|
168
|
+
`AgentHarnessAdapter` and register it. The adapter declares its capabilities and
|
|
169
|
+
creates sessions; a session exposes `streamTurn` and optional `continueTurn`,
|
|
170
|
+
`approve`, `detach`, `stop`, and `destroy`.
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import {
|
|
174
|
+
registerAgentHarness,
|
|
175
|
+
type AgentHarnessAdapter,
|
|
176
|
+
} from "@agent-native/core/agent/harness";
|
|
177
|
+
|
|
178
|
+
const myHarness: AgentHarnessAdapter = {
|
|
179
|
+
name: "acme:my-coder",
|
|
180
|
+
label: "Acme Coder",
|
|
181
|
+
description: "Runs the Acme coding agent.",
|
|
182
|
+
installPackage: "@acme/coder",
|
|
183
|
+
capabilities: {
|
|
184
|
+
sandbox: true,
|
|
185
|
+
resumable: true,
|
|
186
|
+
approvals: true,
|
|
187
|
+
hostTools: true,
|
|
188
|
+
fileEvents: true,
|
|
189
|
+
},
|
|
190
|
+
async createSession(opts) {
|
|
191
|
+
// Build your native session and adapt it to AgentHarnessSession.
|
|
192
|
+
return createAcmeSession(opts);
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
registerAgentHarness({
|
|
197
|
+
name: myHarness.name,
|
|
198
|
+
label: myHarness.label,
|
|
199
|
+
description: myHarness.description,
|
|
200
|
+
installPackage: myHarness.installPackage,
|
|
201
|
+
capabilities: myHarness.capabilities,
|
|
202
|
+
create: () => myHarness,
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Keep the runtime package optional with a dynamic import in `createSession` and an
|
|
207
|
+
`installPackage` hint. For bridge-backed coding harnesses, require a real
|
|
208
|
+
sandbox/workspace provider rather than running an arbitrary coding agent in the
|
|
209
|
+
host process — see [Sandbox Adapters](/docs/sandbox-adapters). The AI SDK adapter
|
|
210
|
+
(`createAiSdkHarnessAdapter`, backed by `HarnessAgent` from `@ai-sdk/harness`) is
|
|
211
|
+
one implementation of this contract, not the public abstraction.
|
|
212
|
+
|
|
213
|
+
## Don't {#donts}
|
|
214
|
+
|
|
215
|
+
- Don't add Claude Code, Codex, Cursor, Mastra, or Pi as an `AgentEngine`. They
|
|
216
|
+
own their loop; running one under `AgentEngine.stream()` double-runs the loop
|
|
217
|
+
and loses session lifecycle semantics.
|
|
218
|
+
- Don't replay full Agent-Native chat history into a harness each turn. Resume
|
|
219
|
+
the harness session with its `resumeState` instead.
|
|
220
|
+
- Don't store `resumeState` in `application_state`. It belongs in the harness
|
|
221
|
+
session SQL table.
|
|
222
|
+
- Don't expose every app action to every harness session by default. Hand it a
|
|
223
|
+
small, intentional tool set.
|
|
224
|
+
|
|
225
|
+
## Related docs {#related-docs}
|
|
226
|
+
|
|
227
|
+
- [Native Chat UI](/docs/native-chat-ui) — put your own agent behind the chat UI with `AgentChatRuntime`.
|
|
228
|
+
- [Agent Surfaces](/docs/agent-surfaces) — choose headless, chat, sidecar, or full-app.
|
|
229
|
+
- [Agent-Native Code UI](/docs/code-agents-ui) — the reusable coding workspace surface.
|
|
230
|
+
- [Custom Agents & Teams](/docs/agent-teams) — background runs and sub-agent delegation.
|
|
231
|
+
- [Sandbox Adapters](/docs/sandbox-adapters) — pluggable execution backends for coding harnesses.
|
|
232
|
+
- [Human Approval](/docs/human-approval) — the approval surface harness runs use.
|