@agent-native/core 0.63.0 → 0.63.1
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/dist/cli/code-agent-executor.js +1 -1
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/create.js +1 -1
- package/dist/cli/create.js.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.js +1 -1
- package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
- 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 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/chat-view-transition.d.ts +17 -0
- package/dist/client/chat-view-transition.d.ts.map +1 -1
- package/dist/client/chat-view-transition.js +46 -0
- package/dist/client/chat-view-transition.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 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts +27 -0
- package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -0
- package/dist/client/use-agent-chat-home-handoff.js +120 -0
- package/dist/client/use-agent-chat-home-handoff.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/styles/agent-native.css +2 -6
- package/dist/templates/workspace-root/README.md +4 -4
- package/docs/content/actions.md +32 -42
- package/docs/content/agent-surfaces.md +105 -84
- package/docs/content/agent-teams.md +2 -14
- package/docs/content/agent-web-surfaces.md +4 -4
- package/docs/content/authentication.md +40 -24
- package/docs/content/automations.md +18 -36
- package/docs/content/blueprint-installer.md +3 -0
- package/docs/content/cli-adapters.md +24 -168
- package/docs/content/client.md +11 -77
- package/docs/content/cloneable-saas.md +1 -1
- package/docs/content/code-agents-ui.md +43 -0
- package/docs/content/components.md +10 -23
- package/docs/content/context-awareness.md +3 -3
- package/docs/content/creating-templates.md +20 -18
- package/docs/content/database.md +1 -1
- package/docs/content/deployment.md +5 -37
- package/docs/content/dispatch.md +17 -28
- package/docs/content/drop-in-agent.md +24 -111
- package/docs/content/durable-resume.md +4 -0
- package/docs/content/embedding-sdk.md +141 -135
- package/docs/content/evals.md +3 -3
- package/docs/content/extensions.md +1 -1
- package/docs/content/external-agents.md +34 -60
- package/docs/content/faq.md +5 -5
- package/docs/content/frames.md +13 -4
- package/docs/content/getting-started.md +96 -142
- package/docs/content/harness-agents.md +24 -7
- package/docs/content/human-approval.md +1 -1
- package/docs/content/key-concepts.md +14 -99
- package/docs/content/local-file-mode.md +2 -2
- package/docs/content/mcp-apps.md +9 -2
- package/docs/content/mcp-clients.md +8 -3
- package/docs/content/mcp-protocol.md +11 -29
- package/docs/content/messaging.md +1 -1
- package/docs/content/migration-workbench.md +14 -175
- package/docs/content/multi-app-workspace.md +1 -1
- package/docs/content/multi-tenancy.md +18 -47
- package/docs/content/native-chat-ui.md +15 -12
- package/docs/content/observability.md +16 -4
- package/docs/content/observational-memory.md +1 -1
- package/docs/content/pure-agent-apps.md +17 -124
- package/docs/content/real-time-collaboration.md +14 -14
- package/docs/content/routing.md +71 -0
- package/docs/content/sandbox-adapters.md +78 -4
- package/docs/content/security.md +59 -39
- package/docs/content/server.md +16 -8
- package/docs/content/sharing.md +1 -6
- package/docs/content/skills-guide.md +3 -1
- package/docs/content/template-analytics.md +1 -1
- package/docs/content/template-assets.md +12 -3
- package/docs/content/template-brain.md +64 -72
- package/docs/content/template-chat.md +32 -4
- package/docs/content/template-clips.md +35 -4
- package/docs/content/template-design.md +19 -3
- package/docs/content/template-dispatch.md +9 -0
- package/docs/content/template-forms.md +15 -10
- package/docs/content/template-plan.md +7 -0
- package/docs/content/template-slides.md +14 -14
- package/docs/content/template-videos.md +10 -12
- package/docs/content/tracking.md +66 -55
- package/docs/content/using-your-agent.md +6 -16
- package/docs/content/what-is-agent-native.md +5 -11
- package/docs/content/workspace-management.md +2 -2
- package/docs/content/workspace.md +20 -160
- package/package.json +1 -1
- package/src/templates/workspace-root/README.md +4 -4
package/docs/content/actions.md
CHANGED
|
@@ -19,6 +19,10 @@ One definition, seven consumers. This is rung 3 of the [ladder](/docs/what-is-ag
|
|
|
19
19
|
If you are deciding whether to expose an operation headlessly, in chat, in an
|
|
20
20
|
embedded sidecar, or as a full app screen, see [Agent Surfaces](/docs/agent-surfaces).
|
|
21
21
|
|
|
22
|
+
If the UI and agent both need to do something, reach for an action — not a custom
|
|
23
|
+
route. For when a route-shaped protocol _is_ the right call, see [Prefer Actions
|
|
24
|
+
For App Operations](/docs/server#actions-first).
|
|
25
|
+
|
|
22
26
|
## Start with one action {#hello-action}
|
|
23
27
|
|
|
24
28
|
The primitive-first on-ramp is one action, not a template. In a headless
|
|
@@ -154,9 +158,22 @@ Every action the agent can see is a tool in the model's context window, and a lo
|
|
|
154
158
|
|
|
155
159
|
A repo-level advisory helper, `node scripts/audit-template-actions.mjs [template ...]` (alias `pnpm actions:audit`), statically scans a template's `actions/` and flags likely UI-dead actions and redundant per-field clusters. It is advisory only (always exits 0, never fails CI) and uses conservative heuristics, so review its suggestions rather than treating them as errors.
|
|
156
160
|
|
|
157
|
-
###
|
|
161
|
+
### Exposure flags {#exposure-flags}
|
|
162
|
+
|
|
163
|
+
Four flags control _who_ can invoke an action. All default to the permissive value, so you only set one to tighten a specific surface. This table is the glanceable summary; the subsections add the one detail each needs.
|
|
164
|
+
|
|
165
|
+
| Flag | Default | Restrictive value → who can still call | Typical use |
|
|
166
|
+
| --------------- | ------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
167
|
+
| `agentTool` | `true` | `false` → UI, HTTP, CLI only — **hidden from the model**, MCP, and A2A | UI-only / programmatic actions that shouldn't spend a tool slot |
|
|
168
|
+
| `toolCallable` | `true` | `false` → everything **except** the sandboxed extension iframe bridge (403) | Auth-adjacent ops (delete account, change org membership/roles) |
|
|
169
|
+
| `publicAgent` | off (private) | `{ expose: true }` → adds the action to **public** MCP/A2A/OpenAPI surfaces | Safe read/ingest tools reachable without authentication |
|
|
170
|
+
| `needsApproval` | `false` | `true` → the agent **pauses**; a human must approve the specific call | Consequential side effects (send email, charge a card, delete) |
|
|
158
171
|
|
|
159
|
-
|
|
172
|
+
These are independent: `agentTool` controls the model's view, `toolCallable` controls only the extension iframe, `publicAgent` adds an opt-in public surface (public web routes never imply public tool exposure), and `needsApproval` gates execution after the call is made — see [Human-in-the-loop approval](#needs-approval) below.
|
|
173
|
+
|
|
174
|
+
#### `agentTool` — hide from the model {#agent-tool}
|
|
175
|
+
|
|
176
|
+
By default every action is a callable agent tool. Set `agentTool: false` to keep it behind the framework's auth + action surface while removing it from every agent tool list — it stays callable from the UI (`useActionMutation` / `callAction`), CLI, and `/_agent-native/actions/<name>`:
|
|
160
177
|
|
|
161
178
|
```ts
|
|
162
179
|
export default defineAction({
|
|
@@ -170,24 +187,11 @@ export default defineAction({
|
|
|
170
187
|
});
|
|
171
188
|
```
|
|
172
189
|
|
|
173
|
-
|
|
174
|
-
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
175
|
-
| `true` | Allow (same as undefined). Useful for documenting intent. |
|
|
176
|
-
| `false` | **Hidden from the model entirely** — not in the agent's tool list, MCP, or A2A. Still callable from the UI (`useActionMutation` / `callAction`), CLI, and `/_agent-native/actions/<name>`. |
|
|
177
|
-
| `undefined` | **Default-allow.** The action is a normal agent tool. |
|
|
178
|
-
|
|
179
|
-
`agentTool: false` is **not** the same as [`toolCallable: false`](#tool-callable):
|
|
190
|
+
Reach for it when you add a UI-only or purely programmatic action, or when the UI stops using an action you'd otherwise leave exposed to the model.
|
|
180
191
|
|
|
181
|
-
|
|
182
|
-
- **`toolCallable: false`** only blocks the sandboxed **extension iframe bridge** (`appAction(...)`). The action stays fully visible to the model, UI, CLI, MCP, and A2A. It exists for high-blast-radius operations (account/org/auth changes), not for trimming the tool list.
|
|
192
|
+
#### `toolCallable` — block the extension iframe {#tool-callable}
|
|
183
193
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
### Extension callability {#tool-callable}
|
|
187
|
-
|
|
188
|
-
Extensions (Alpine.js mini-apps that run inside sandboxed iframes — see [Extensions](/docs/extensions)) call actions via `appAction(name, params)`. Because a shared extension's HTML/JS executes inside the _viewer's_ session, an action invoked from an extension runs with the viewer's permissions, secrets, and SQL scope. For high-blast-radius operations, that is too much trust to grant by default.
|
|
189
|
-
|
|
190
|
-
Use the `toolCallable` flag to control this (the flag name is kept for backward compatibility — it gates extension iframe callability):
|
|
194
|
+
Extensions ([Alpine.js mini-apps in sandboxed iframes](/docs/extensions)) call actions via `appAction(name, params)`, running with the _viewer's_ permissions, secrets, and SQL scope. For high-blast-radius operations that is too much trust by default. Set `toolCallable: false` to make the extension bridge return 403 while keeping the action callable from the UI, agent, CLI, MCP, and A2A:
|
|
191
195
|
|
|
192
196
|
```ts
|
|
193
197
|
export default defineAction({
|
|
@@ -200,20 +204,7 @@ export default defineAction({
|
|
|
200
204
|
});
|
|
201
205
|
```
|
|
202
206
|
|
|
203
|
-
|
|
204
|
-
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
205
|
-
| `true` | Allow (same as undefined). Useful for documentation of intent. |
|
|
206
|
-
| `false` | Explicit deny. The extension bridge returns 403; the action is still callable normally from the UI, agent, CLI, MCP, and A2A. |
|
|
207
|
-
| `undefined` | **Default-allow.** Extensions are intra-org and typically authored by trusted teammates, so the default trusts the org-level access controls. Set `false` only for genuinely auth-adjacent operations (account deletion, org membership changes). |
|
|
208
|
-
|
|
209
|
-
Enforcement: the parent host tags every outbound action call from an extension iframe with the header `X-Agent-Native-Tool-Bridge: 1`. The action route layer reads this header and applies the rule above. Regular UI/agent/CLI/A2A calls do not carry the header and are unaffected. The header is set by the React host; the iframe's user-authored content cannot spoof it because the bridge sanitizes iframe-supplied headers.
|
|
210
|
-
|
|
211
|
-
Set `toolCallable: false` for actions that:
|
|
212
|
-
|
|
213
|
-
- delete or transfer ownership of any account/org,
|
|
214
|
-
- change auth state (sign-out-all sessions, rotate tokens),
|
|
215
|
-
- modify org membership (invite/remove members, change roles),
|
|
216
|
-
- change resource visibility or grant share access (the framework's built-in `share-resource`, `unshare-resource`, and `set-resource-visibility` are already opted out).
|
|
207
|
+
Use it for actions that delete or transfer accounts/orgs, change auth state, modify org membership, or grant share access. The framework's built-in `share-resource`, `unshare-resource`, and `set-resource-visibility` are already opted out. Enforcement is by an unspoofable host-set header on iframe calls; regular UI/agent/CLI/MCP/A2A calls are unaffected — see [Security](/docs/security) for details.
|
|
217
208
|
|
|
218
209
|
### Run context (second argument) {#run-context}
|
|
219
210
|
|
|
@@ -307,10 +298,10 @@ export default defineAction({
|
|
|
307
298
|
});
|
|
308
299
|
```
|
|
309
300
|
|
|
310
|
-
`needsApproval` accepts a
|
|
301
|
+
`needsApproval` also accepts a predicate `(args, ctx) => boolean | Promise<boolean>` to gate conditionally (e.g. only external recipients, only above a threshold); it **fails closed**, so a throw counts as "approval required". When the gate is truthy and unapproved, the loop stops the turn and the side effect never fires until a human approves in the chat UI.
|
|
311
302
|
|
|
312
303
|
> [!WARNING]
|
|
313
|
-
> Keep approvals rare. Each gated action is a hard stop in the agent loop. The default is **off**, and almost every action should leave it off. See [Human-in-the-Loop Approvals](/docs/human-approval) for the full flow.
|
|
304
|
+
> Keep approvals rare. Each gated action is a hard stop in the agent loop. The default is **off**, and almost every action should leave it off. See [Human-in-the-Loop Approvals](/docs/human-approval) for the predicate API, the `approval_required` event, and the full flow.
|
|
314
305
|
|
|
315
306
|
## Calling it from the UI {#ui}
|
|
316
307
|
|
|
@@ -394,12 +385,11 @@ export default defineAction({
|
|
|
394
385
|
```
|
|
395
386
|
|
|
396
387
|
The built-in discriminants are `"data-table"`, `"data-chart"`, and
|
|
397
|
-
`"data-insights"
|
|
398
|
-
`@agent-native/core/data-widgets
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
screen.
|
|
388
|
+
`"data-insights"`, with server-safe builders and schemas in
|
|
389
|
+
`@agent-native/core/data-widgets`. See [Native Chat UI](/docs/native-chat-ui)
|
|
390
|
+
for the full result contract and BYO runtime guidance, or
|
|
391
|
+
[Agent Surfaces](/docs/agent-surfaces) for how the same action can stay
|
|
392
|
+
headless, render in chat, or grow into a full screen.
|
|
403
393
|
|
|
404
394
|
## Calling it from the CLI {#cli}
|
|
405
395
|
|
|
@@ -417,9 +407,9 @@ If your app is an [A2A](/docs/a2a-protocol) peer, other agent-native apps discov
|
|
|
417
407
|
|
|
418
408
|
## Exposing it over MCP {#mcp}
|
|
419
409
|
|
|
420
|
-
With MCP enabled, your actions show up in the framework's MCP server at `/_agent-native/mcp`. Every caller gets a compact catalog by default —
|
|
410
|
+
With MCP enabled, your actions show up in the framework's MCP server at `/_agent-native/mcp`. Every caller gets a compact catalog by default — app-facing builtins plus the template-declared app actions — and `tool-search` is always present so any other tool stays reachable on demand. The full action surface is served only on explicit opt-in (`--full-catalog` token or `AGENT_NATIVE_MCP_FULL_CATALOG=1`), and `publicAgent.expose` opts a safe read/ingest tool onto the public surface. See [MCP Protocol](/docs/mcp-protocol) for catalog tiers, auth, and the `mcpApp` resource details.
|
|
421
411
|
|
|
422
|
-
For UI-capable MCP hosts, an action can
|
|
412
|
+
For UI-capable MCP hosts, an action can declare an optional MCP Apps resource via the `mcpApp` field (plus a matching `link`) so capable hosts render the result inline. When `link` and `mcpApp` should point at the same route, `embedRoute()` builds both from one pure path builder:
|
|
423
413
|
|
|
424
414
|
```ts
|
|
425
415
|
import { embedRoute } from "@agent-native/core";
|
|
@@ -15,23 +15,60 @@ you want, then use the matching primitive.
|
|
|
15
15
|
|
|
16
16
|
| Surface | Use it when | Start with |
|
|
17
17
|
| ----------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
18
|
-
| **Headless agent
|
|
18
|
+
| **Headless agent** | Code, jobs, scripts, another app, or another agent should call the work directly. | `agent-native create --headless`, `defineAction`, `agent-native agent`, HTTP, CLI, MCP, A2A |
|
|
19
19
|
| **Rich chat on Agent-Native** | You want a standalone or embedded chat backed by the built-in agent loop. | [Chat template](/docs/template-chat), `<AgentChatSurface>`, `<AssistantChat>` |
|
|
20
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
21
|
| **Embedded sidecar** | You already have a SaaS app and want an agent beside it with page context and host commands. | `createAgentNativeEmbeddedPlugin()`, `AgentNativeEmbedded` |
|
|
22
22
|
| **Full application** | Humans and agents should share durable screens, data, navigation, and collaboration. | Templates, actions, SQL state, context awareness |
|
|
23
23
|
|
|
24
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
|
|
26
|
-
app without changing the operation the agent calls.
|
|
25
|
+
agent with one action, appear in chat as a table or chart, and later become a
|
|
26
|
+
full screen in an app without changing the operation the agent calls.
|
|
27
27
|
|
|
28
|
-
## Headless agent
|
|
28
|
+
## Headless agent {#headless}
|
|
29
29
|
|
|
30
30
|
Use the headless path when no one needs to stare at a custom app screen while
|
|
31
31
|
the work runs: scheduled jobs, integrations, backend workflows, CLI loops,
|
|
32
32
|
another agent, or an existing product calling into Agent-Native.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
This is also the shape to reach for when **the agent _is_ the product** — the
|
|
35
|
+
app-agent loop is the front door, not a dashboard. You send a request from the
|
|
36
|
+
terminal, Slack, email, a scheduled job, another agent, or Chat — "summarize my
|
|
37
|
+
unread emails," "post the daily metrics to Slack," "find the candidates who
|
|
38
|
+
replied last week" — and the agent acts and returns the result wherever it
|
|
39
|
+
belongs. It is still a real app, not a stateless prompt: actions, auth sessions,
|
|
40
|
+
app state, thread/run history, settings, credentials, and share records all live
|
|
41
|
+
in SQL.
|
|
42
|
+
|
|
43
|
+
Pick this pattern when:
|
|
44
|
+
|
|
45
|
+
- **The work happens in the background.** Most of the value is created while the user isn't looking — triage agents, daily-report agents, on-call responders.
|
|
46
|
+
- **The output leaves the app.** The agent posts to Slack, sends email, or updates a third-party system; there's nothing to browse in-app.
|
|
47
|
+
- **The domain is one-shot.** Research bot, summary generator, report writer — no persistent object that needs a list view.
|
|
48
|
+
- **You're prototyping.** Ship the agent now; add richer UI later if users want one.
|
|
49
|
+
|
|
50
|
+
If your product is built around persistent objects users browse, pivot, and
|
|
51
|
+
share — emails, events, documents, charts — pick a [full application](#full-application)
|
|
52
|
+
or a [template](/docs/cloneable-saas) instead; those add a full UI _plus_ the agent.
|
|
53
|
+
|
|
54
|
+
### What ships in the box {#in-the-box}
|
|
55
|
+
|
|
56
|
+
A headless app skips weeks of dashboard work, and it's channel-agnostic from day
|
|
57
|
+
one — the same agent runs from the web, Slack, Telegram, email, and other agents
|
|
58
|
+
because everything goes through the agent, not the UI. The trade-off is there's
|
|
59
|
+
no "browse-everything-at-a-glance" view; if users need that, mix patterns and
|
|
60
|
+
add a small status page or list view.
|
|
61
|
+
|
|
62
|
+
When you add the built-in Chat shell, the framework provides five management
|
|
63
|
+
surfaces you don't have to build: **Chat** (the main input), **Workspace**
|
|
64
|
+
(skills, memory, instructions, sub-agents, connected MCP servers, scheduled
|
|
65
|
+
jobs), **Job history**, **Thread history**, and **Settings**. Those are usually
|
|
66
|
+
enough — talk to it, see what it's done, configure how it behaves. Reach for
|
|
67
|
+
[Chat](/docs/template-chat) when you're ready to add that browser UI, or the
|
|
68
|
+
[Dispatch template](/docs/template-dispatch) for a workspace-style starting
|
|
69
|
+
point with Slack/Telegram, scheduled jobs, and shared secrets out of the box.
|
|
70
|
+
|
|
71
|
+
The smallest local path is a headless agent scaffold plus one action:
|
|
35
72
|
|
|
36
73
|
```bash
|
|
37
74
|
npx @agent-native/core@latest create my-agent --headless
|
|
@@ -81,45 +118,20 @@ If another app or script needs to call the whole agent, use
|
|
|
81
118
|
`agentNative.invoke("analytics", "...")` or the `agent-native invoke` CLI. That
|
|
82
119
|
keeps cross-app work on the A2A path while local work stays on actions.
|
|
83
120
|
|
|
84
|
-
Workers, jobs, integration webhooks, and custom hosts can
|
|
85
|
-
directly. This is lower-level than actions
|
|
86
|
-
messages, actions, and event sink yourself
|
|
121
|
+
Workers, jobs, integration webhooks, and custom hosts can drive the agent loop
|
|
122
|
+
directly through the server API. This is lower-level than actions — you provide
|
|
123
|
+
the engine, model, messages, actions, and event sink yourself:
|
|
87
124
|
|
|
88
125
|
```ts
|
|
89
|
-
import {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
runAgentLoop,
|
|
93
|
-
} from "@agent-native/core/server";
|
|
94
|
-
|
|
95
|
-
const engine = await resolveEngine({ engineOption: undefined });
|
|
96
|
-
const model = engine.defaultModel;
|
|
97
|
-
const controller = new AbortController();
|
|
98
|
-
|
|
99
|
-
await runAgentLoop({
|
|
100
|
-
engine,
|
|
101
|
-
model,
|
|
102
|
-
systemPrompt: "You are the reporting agent for this workspace.",
|
|
103
|
-
actions,
|
|
104
|
-
tools: actionsToEngineTools(actions),
|
|
105
|
-
messages: [
|
|
106
|
-
{
|
|
107
|
-
role: "user",
|
|
108
|
-
content: [{ type: "text", text: "Summarize this week's forms." }],
|
|
109
|
-
},
|
|
110
|
-
],
|
|
111
|
-
send: (event) => {
|
|
112
|
-
// Persist, log, stream, or translate AgentChatEvent objects.
|
|
113
|
-
},
|
|
114
|
-
signal: controller.signal,
|
|
115
|
-
ownerEmail: user.email,
|
|
116
|
-
orgId: user.orgId,
|
|
117
|
-
});
|
|
126
|
+
import { runAgentLoop } from "@agent-native/core/server";
|
|
127
|
+
|
|
128
|
+
await runAgentLoop({ engine, model, systemPrompt, actions, messages, send });
|
|
118
129
|
```
|
|
119
130
|
|
|
120
131
|
For most apps, scheduled prompts and integration webhooks already call this loop
|
|
121
|
-
for you. Reach for
|
|
122
|
-
|
|
132
|
+
for you. Reach for it directly only when building a custom headless host, eval
|
|
133
|
+
runner, or server-side orchestration surface — see [Server — Production agent
|
|
134
|
+
handler](/docs/server#agent-handler) for the full signature.
|
|
123
135
|
|
|
124
136
|
### Running against a folder {#folder-loop}
|
|
125
137
|
|
|
@@ -178,6 +190,48 @@ export default function ChatRoute() {
|
|
|
178
190
|
}
|
|
179
191
|
```
|
|
180
192
|
|
|
193
|
+
When an app has both a full-page chat tab and an `AgentSidebar`, use the same
|
|
194
|
+
`storageKey` on both surfaces, enable `chatViewTransition`, and install the
|
|
195
|
+
chat-home handoff helpers in the layout. Ordinary in-app links out of the chat
|
|
196
|
+
page can then morph the full chat into the sidebar while keeping the active
|
|
197
|
+
thread:
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
import {
|
|
201
|
+
AgentChatSurface,
|
|
202
|
+
AgentSidebar,
|
|
203
|
+
useAgentChatHomeHandoff,
|
|
204
|
+
useAgentChatHomeHandoffLinks,
|
|
205
|
+
} from "@agent-native/core/client/chat";
|
|
206
|
+
import { useLocation } from "react-router";
|
|
207
|
+
|
|
208
|
+
function ChatRoute() {
|
|
209
|
+
return (
|
|
210
|
+
<AgentChatSurface mode="page" storageKey="my-app" chatViewTransition />
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function AppLayout({ children }: { children: React.ReactNode }) {
|
|
215
|
+
const location = useLocation();
|
|
216
|
+
const handoffActive = useAgentChatHomeHandoff({
|
|
217
|
+
storageKey: "my-app",
|
|
218
|
+
activePath: location.pathname,
|
|
219
|
+
enabled: location.pathname !== "/chat",
|
|
220
|
+
});
|
|
221
|
+
useAgentChatHomeHandoffLinks({ storageKey: "my-app", chatPath: "/chat" });
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<AgentSidebar
|
|
225
|
+
storageKey="my-app"
|
|
226
|
+
chatViewTransition
|
|
227
|
+
openOnChatRunning={handoffActive}
|
|
228
|
+
>
|
|
229
|
+
{children}
|
|
230
|
+
</AgentSidebar>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
181
235
|
The simplest embedded chat with your own chrome:
|
|
182
236
|
|
|
183
237
|
```tsx
|
|
@@ -195,14 +249,9 @@ components in the chat, without iframes. See [Native Chat UI](/docs/native-chat-
|
|
|
195
249
|
## Rich chat on your agent {#byo-agent}
|
|
196
250
|
|
|
197
251
|
Use this path when your agent is already built with another framework or
|
|
198
|
-
runtime and you want Agent-Native's chat UI around it.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
shell and thread UI, then swap the runtime behind the chat plugin or route.
|
|
202
|
-
|
|
203
|
-
`AgentChatRuntime` is the boundary. Your runtime streams normalized events;
|
|
204
|
-
Agent-Native renders the composer, transcript, tool calls, approvals, native
|
|
205
|
-
widgets, and app layout.
|
|
252
|
+
runtime and you want Agent-Native's chat UI around it. `AgentChatRuntime` is the
|
|
253
|
+
boundary: your runtime streams normalized events, and Agent-Native renders the
|
|
254
|
+
composer, transcript, tool calls, approvals, native widgets, and app layout.
|
|
206
255
|
|
|
207
256
|
```tsx
|
|
208
257
|
import {
|
|
@@ -211,10 +260,7 @@ import {
|
|
|
211
260
|
} from "@agent-native/core/client/chat";
|
|
212
261
|
|
|
213
262
|
const runtime = createHttpAgentChatRuntime({
|
|
214
|
-
id: "external:support-agent",
|
|
215
|
-
label: "Support agent",
|
|
216
263
|
endpoint: "/api/support-agent/chat",
|
|
217
|
-
headers: async () => ({ Authorization: `Bearer ${await getToken()}` }),
|
|
218
264
|
});
|
|
219
265
|
|
|
220
266
|
export function SupportAgentChat() {
|
|
@@ -222,40 +268,15 @@ export function SupportAgentChat() {
|
|
|
222
268
|
}
|
|
223
269
|
```
|
|
224
270
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
```ts
|
|
232
|
-
import { createOpenAIAgentsChatRuntime } from "@agent-native/core/client/chat";
|
|
233
|
-
|
|
234
|
-
const runtime = createOpenAIAgentsChatRuntime({
|
|
235
|
-
endpoint: "/api/openai-agent/chat",
|
|
236
|
-
});
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
The endpoint can stream SSE or NDJSON events:
|
|
240
|
-
|
|
241
|
-
```txt
|
|
242
|
-
data: {"type":"message-delta","messageId":"m1","delta":{"type":"text","text":"I found 34 submissions."}}
|
|
243
|
-
data: {"type":"tool-start","toolCall":{"id":"t1","name":"query","input":{"formId":"form_123"}}}
|
|
244
|
-
data: {"type":"tool-done","toolCallId":"t1","toolName":"query","status":"completed","resultText":"34 rows"}
|
|
245
|
-
data: {"type":"done","reason":"complete"}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
For a trivial integration, returning `{ "text": "..." }` also works. For richer
|
|
249
|
-
integrations, stream `message-*`, `tool-*`, `approval-request`, `status`,
|
|
250
|
-
`artifact`, `file`, `usage`, `error`, and `done` events. Tool results can carry
|
|
251
|
-
`chatUI` metadata so the same native table/chart/card renderers work with your
|
|
252
|
-
agent too.
|
|
271
|
+
Ready-made runtime helpers exist for OpenAI Agents, OpenAI Responses, the Claude
|
|
272
|
+
Agent SDK, the Vercel AI SDK, and AG-UI, plus the normalized HTTP runtime above
|
|
273
|
+
for any other agent (Mastra, Flue, Eve, LangGraph, or a custom service). ACP is
|
|
274
|
+
not the default end-user app chat protocol, and Agent-Native does not currently
|
|
275
|
+
claim A2UI support.
|
|
253
276
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
better framed as coding-agent/editor interoperability. Agent-Native does not
|
|
258
|
-
currently claim A2UI support.
|
|
277
|
+
[Native Chat UI — BYO agent runtimes](/docs/native-chat-ui#byo-agent-runtimes)
|
|
278
|
+
is the canonical home for the event shapes, the runtime helpers, and `chatUI`
|
|
279
|
+
tool-result metadata. Start there when wiring an external agent into the chat.
|
|
259
280
|
|
|
260
281
|
## Embedded sidecar {#embedded-sidecar}
|
|
261
282
|
|
|
@@ -322,7 +343,7 @@ want a complete product shape.
|
|
|
322
343
|
|
|
323
344
|
| If you are thinking... | Choose |
|
|
324
345
|
| --------------------------------------------------------------- | ------------------------- |
|
|
325
|
-
| "I just need a callable tool or workflow." | Headless
|
|
346
|
+
| "I just need a callable tool or workflow." | Headless agent |
|
|
326
347
|
| "I want the framework's agent, but chat should be the main UI." | Rich chat on Agent-Native |
|
|
327
348
|
| "I already have an agent; I need a polished chat UI for it." | Rich chat on your agent |
|
|
328
349
|
| "I already have a SaaS app; add an agent beside it." | Embedded sidecar |
|
|
@@ -127,19 +127,7 @@ interface AgentTask {
|
|
|
127
127
|
|
|
128
128
|
## Custom agent profiles {#profiles}
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
```markdown
|
|
133
|
-
---
|
|
134
|
-
name: Code Review
|
|
135
|
-
description: Reviews TypeScript PRs for correctness and type safety.
|
|
136
|
-
model: inherit
|
|
137
|
-
---
|
|
138
|
-
|
|
139
|
-
You are a meticulous code reviewer. Be terse and concrete — cite file:line wherever you can.
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Store at `agents/code-review.md` in the workspace. It appears in the `@mention` dropdown and is available to the main agent as a delegation target. See [Workspace — Custom Agents](/docs/workspace#custom-agents) for the full format including `tools`, `delegate-default`, and model overrides.
|
|
130
|
+
Sub-agents map to custom agent profiles — Markdown files at `agents/<slug>.md` in the workspace that appear in the `@mention` dropdown and serve as delegation targets. [Workspace — Custom Agents](/docs/workspace#custom-agents) owns the full format (frontmatter, `tools`, `delegate-default`, model overrides).
|
|
143
131
|
|
|
144
132
|
## Delegation depth guard {#depth-guard}
|
|
145
133
|
|
|
@@ -147,7 +135,7 @@ Sub-agents can spawn sub-agents, which is a runaway/cost risk: an unbounded chai
|
|
|
147
135
|
|
|
148
136
|
The top-level chat is depth `0`. A sub-agent it spawns is depth `1`; that sub-agent may spawn once more (depth `2`); a spawn that would create a depth-`3` sub-agent is **refused**. The default cap is **2**.
|
|
149
137
|
|
|
150
|
-
```
|
|
138
|
+
```text
|
|
151
139
|
depth 0 top-level chat (may spawn)
|
|
152
140
|
depth 1 sub-agent (may spawn)
|
|
153
141
|
depth 2 sub-agent's sub-agent (at the cap — may NOT spawn)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Agent Web
|
|
3
|
-
description: "Make public routes crawlable, readable, citable, and optionally callable by agents."
|
|
2
|
+
title: "Public Agent Web"
|
|
3
|
+
description: "Make public routes crawlable, readable, citable, and optionally callable by agents — robots.txt, llms.txt, markdown mirrors, JSON-LD, and a public MCP surface."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Agent Web
|
|
6
|
+
# Public Agent Web
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
The public agent web makes public Agent-Native routes easy for agents to crawl, read, cite, and call. The goal is not to make every app endpoint public. The goal is to publish a clean public surface for pages that are already public, while keeping private data and tool access behind explicit controls.
|
|
9
9
|
|
|
10
10
|
The docs site is the reference implementation. Today it ships:
|
|
11
11
|
|
|
@@ -9,13 +9,25 @@ Agent-native apps use [Better Auth](https://better-auth.com) for authentication
|
|
|
9
9
|
|
|
10
10
|
## Overview {#overview}
|
|
11
11
|
|
|
12
|
-
Auth is configured automatically via `autoMountAuth(app)` in the auth server plugin.
|
|
12
|
+
Auth is configured automatically via `autoMountAuth(app)` in the auth server plugin. There are three modes:
|
|
13
13
|
|
|
14
14
|
- **Default:** Better Auth with email/password + social providers. Onboarding page shown on first visit.
|
|
15
15
|
- **Remote MCP OAuth:** Standard OAuth 2.1 for MCP hosts such as Claude Code and ChatGPT connectors.
|
|
16
16
|
- **Custom:** Bring your own auth via `getSession` callback.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
The browser flow is the same Better Auth flow everywhere — there is **no dev auth bypass**, and `getSession()` never falls back to a `local@localhost` sentinel. What changes between environments is signup friction, not the login wall:
|
|
19
|
+
|
|
20
|
+
| Environment | First-load behavior | Email verification |
|
|
21
|
+
| ---------------- | ----------------------------------------------------------------------------- | ----------------------------------------------- |
|
|
22
|
+
| **Local dev** | Auto-creates a throwaway dev account and signs you in (no login wall) | Skipped by default (and when no email provider) |
|
|
23
|
+
| **QA / preview** | Normal signup, but verification can be skipped so testers don't wait on email | Skip with `AUTH_SKIP_EMAIL_VERIFICATION=1` |
|
|
24
|
+
| **Production** | Normal Better Auth signup/login | Required (when an email provider is configured) |
|
|
25
|
+
|
|
26
|
+
A few flags tune this; full details are in the [Environment Variables](#environment-variables) table:
|
|
27
|
+
|
|
28
|
+
- `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT=1` — use the normal signup page in local dev instead of the auto dev account.
|
|
29
|
+
- `AUTH_DISABLED=true` — skip login/signup entirely and run every request as one shared user (local dev / previews / demos only, never production with real users).
|
|
30
|
+
- `AUTH_MODE=local` — affects only CLI/agent identity (which dev user `pnpm action` runs as); it is **not** a browser login bypass.
|
|
19
31
|
|
|
20
32
|
## Better Auth (Default) {#better-auth}
|
|
21
33
|
|
|
@@ -36,24 +48,23 @@ Better Auth routes are mounted at `/_agent-native/auth/ba/*`. The framework also
|
|
|
36
48
|
|
|
37
49
|
## Cookie Realms {#cookie-realms}
|
|
38
50
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
own auth database, so
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
`AGENT_NATIVE_SHARE_COOKIE_DOMAIN=1` alongside `COOKIE_DOMAIN`.
|
|
51
|
+
The session cookie's realm follows the deployment shape, so apps that share a
|
|
52
|
+
database/origin share sign-in and apps that don't stay isolated:
|
|
53
|
+
|
|
54
|
+
| Deployment shape | Cookie realm |
|
|
55
|
+
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
56
|
+
| Standalone app | Isolated per app by slug (`APP_NAME`, or package name in local dev); stable `an` prefix in production |
|
|
57
|
+
| Workspace mode (`AGENT_NATIVE_WORKSPACE=1`) | One shared realm — workspace apps share an origin and database |
|
|
58
|
+
| Custom same-database subdomains | Opt into shared cookies with `COOKIE_DOMAIN` |
|
|
59
|
+
| First-party hosted (`*.agent-native.com`) | Isolated namespace per app (each has its own auth database); `COOKIE_DOMAIN=.agent-native.com` is ignored by default |
|
|
60
|
+
|
|
61
|
+
First-party hosted apps each have their own auth database, so cross-app sign-in
|
|
62
|
+
goes through [Cross-App SSO](/docs/cross-app-sso) rather than a shared cookie.
|
|
63
|
+
These deploys must provide `APP_NAME` or a derivable app URL (`APP_URL`, `URL`,
|
|
64
|
+
`DEPLOY_PRIME_URL`, or `DEPLOY_URL`); otherwise startup fails instead of falling
|
|
65
|
+
back to the shared `an_session` name. To intentionally share one auth database
|
|
66
|
+
across subdomains, set `AGENT_NATIVE_SHARE_COOKIE_DOMAIN=1` alongside
|
|
67
|
+
`COOKIE_DOMAIN`.
|
|
57
68
|
|
|
58
69
|
## QA Accounts {#qa-accounts}
|
|
59
70
|
|
|
@@ -136,7 +147,7 @@ Access tokens are signed with `A2A_SECRET` when set, otherwise `BETTER_AUTH_SECR
|
|
|
136
147
|
|
|
137
148
|
Pass a custom `getSession` callback to use any auth provider (Clerk, Auth0, Firebase, etc.):
|
|
138
149
|
|
|
139
|
-
```
|
|
150
|
+
```ts
|
|
140
151
|
// server/plugins/auth.ts
|
|
141
152
|
import { createAuthPlugin } from "@agent-native/core/server";
|
|
142
153
|
|
|
@@ -191,7 +202,7 @@ unless the app explicitly adds those prefixes to
|
|
|
191
202
|
|
|
192
203
|
The session object returned by `getSession(event)` has this shape:
|
|
193
204
|
|
|
194
|
-
```
|
|
205
|
+
```ts
|
|
195
206
|
interface AuthSession {
|
|
196
207
|
email: string; // User's email (primary identifier)
|
|
197
208
|
userId?: string; // Better Auth user ID
|
|
@@ -205,7 +216,7 @@ interface AuthSession {
|
|
|
205
216
|
|
|
206
217
|
On the client, use the `useSession()` hook:
|
|
207
218
|
|
|
208
|
-
```
|
|
219
|
+
```ts
|
|
209
220
|
import { useSession } from "@agent-native/core/client";
|
|
210
221
|
|
|
211
222
|
function MyComponent() {
|
|
@@ -253,7 +264,7 @@ Both flows (the explicit `/_agent-native/sign-in` entrypoint and the bookmarked-
|
|
|
253
264
|
|
|
254
265
|
If your template wraps `/_agent-native/google/auth-url` directly (e.g. mail and calendar templates do, to widen scopes), accept a `?return=<path>` query and forward it via the options-object form of `encodeOAuthState`:
|
|
255
266
|
|
|
256
|
-
```
|
|
267
|
+
```ts
|
|
257
268
|
const returnUrl = getQuery(event).return;
|
|
258
269
|
const state = encodeOAuthState({
|
|
259
270
|
redirectUri,
|
|
@@ -272,6 +283,11 @@ The default `/_agent-native/google/auth-url` route does this automatically — o
|
|
|
272
283
|
| `AUTH_SKIP_EMAIL_VERIFICATION` | Set to `1` in QA/preview environments to let email/password signups proceed without verification; local dev/test skips by default |
|
|
273
284
|
| `AUTH_DISABLED` | Set to `true` or `1` to skip login/signup; all requests run as one shared user (local dev/preview only — not for production with real users) |
|
|
274
285
|
| `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | Set to `1` to disable localhost auto-sign-in on a fresh dev database |
|
|
286
|
+
| `AUTH_MODE` | `local` resolves CLI/agent identity only (which dev user `pnpm action` runs as); never a browser login bypass |
|
|
287
|
+
| `COOKIE_DOMAIN` | Opt into shared session cookies across same-database subdomains (see [Cookie Realms](#cookie-realms)) |
|
|
288
|
+
| `AGENT_NATIVE_WORKSPACE` | `1` runs in workspace mode — one shared session realm across workspace apps |
|
|
289
|
+
| `AGENT_NATIVE_SHARE_COOKIE_DOMAIN` | Set with `COOKIE_DOMAIN` to share one auth database across first-party subdomains |
|
|
290
|
+
| `OAUTH_STATE_SECRET` | Dedicated HMAC key for OAuth state envelopes (see [Security — OAuth State Signing](/docs/security#oauth-state)) |
|
|
275
291
|
| `GOOGLE_CLIENT_ID` | Enable Google OAuth |
|
|
276
292
|
| `GOOGLE_CLIENT_SECRET` | Google OAuth secret |
|
|
277
293
|
| `GITHUB_CLIENT_ID` | Enable GitHub OAuth |
|