@agent-native/agentkit 0.1.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/ARCHITECTURE.md +290 -0
- package/README.md +822 -0
- package/dist/adapters/http.d.ts +56 -0
- package/dist/adapters/http.d.ts.map +1 -0
- package/dist/adapters/http.js +950 -0
- package/dist/adapters/http.js.map +1 -0
- package/dist/adapters/index.d.ts +2 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +2 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/client/client.d.ts +240 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +1605 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/state.d.ts +72 -0
- package/dist/client/state.d.ts.map +1 -0
- package/dist/client/state.js +385 -0
- package/dist/client/state.js.map +1 -0
- package/dist/conformance/index.d.ts +41 -0
- package/dist/conformance/index.d.ts.map +1 -0
- package/dist/conformance/index.js +924 -0
- package/dist/conformance/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/agui-codec.d.ts +28 -0
- package/dist/protocol/agui-codec.d.ts.map +1 -0
- package/dist/protocol/agui-codec.js +250 -0
- package/dist/protocol/agui-codec.js.map +1 -0
- package/dist/protocol/agui.d.ts +144 -0
- package/dist/protocol/agui.d.ts.map +1 -0
- package/dist/protocol/agui.js +253 -0
- package/dist/protocol/agui.js.map +1 -0
- package/dist/protocol/compatibility.d.ts +35 -0
- package/dist/protocol/compatibility.d.ts.map +1 -0
- package/dist/protocol/compatibility.js +160 -0
- package/dist/protocol/compatibility.js.map +1 -0
- package/dist/protocol/errors.d.ts +24 -0
- package/dist/protocol/errors.d.ts.map +1 -0
- package/dist/protocol/errors.js +77 -0
- package/dist/protocol/errors.js.map +1 -0
- package/dist/protocol/index.d.ts +982 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/index.js +56 -0
- package/dist/protocol/index.js.map +1 -0
- package/dist/protocol/validation.d.ts +94 -0
- package/dist/protocol/validation.d.ts.map +1 -0
- package/dist/protocol/validation.js +1871 -0
- package/dist/protocol/validation.js.map +1 -0
- package/dist/protocol/version.d.ts +7 -0
- package/dist/protocol/version.d.ts.map +1 -0
- package/dist/protocol/version.js +9 -0
- package/dist/protocol/version.js.map +1 -0
- package/dist/react/chat.d.ts +34 -0
- package/dist/react/chat.d.ts.map +1 -0
- package/dist/react/chat.js +23 -0
- package/dist/react/chat.js.map +1 -0
- package/dist/react/components.d.ts +96 -0
- package/dist/react/components.d.ts.map +1 -0
- package/dist/react/components.js +1300 -0
- package/dist/react/components.js.map +1 -0
- package/dist/react/context.d.ts +259 -0
- package/dist/react/context.d.ts.map +1 -0
- package/dist/react/context.js +359 -0
- package/dist/react/context.js.map +1 -0
- package/dist/react/headless.d.ts +3 -0
- package/dist/react/headless.d.ts.map +1 -0
- package/dist/react/headless.js +3 -0
- package/dist/react/headless.js.map +1 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +6 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/root.d.ts +58 -0
- package/dist/react/root.d.ts.map +1 -0
- package/dist/react/root.js +151 -0
- package/dist/react/root.js.map +1 -0
- package/dist/react/streaming-text.d.ts +19 -0
- package/dist/react/streaming-text.d.ts.map +1 -0
- package/dist/react/streaming-text.js +259 -0
- package/dist/react/streaming-text.js.map +1 -0
- package/dist/react/styles.css +1477 -0
- package/package.json +112 -0
package/README.md
ADDED
|
@@ -0,0 +1,822 @@
|
|
|
1
|
+
# AgentKit
|
|
2
|
+
|
|
3
|
+
Agent-Native is the application framework and execution platform. It owns
|
|
4
|
+
actions, SQL data, application state, agent execution, authentication, access
|
|
5
|
+
control, and deployment. AgentKit is its agent interaction and experience layer:
|
|
6
|
+
the portable conversation protocol, the deterministic headless client,
|
|
7
|
+
transports, React bindings, and composable agent UI. Toolkit supplies the
|
|
8
|
+
semantic design-system and workspace building blocks that AgentKit composes
|
|
9
|
+
with.
|
|
10
|
+
|
|
11
|
+
AgentKit stays provider-neutral. An Agent-Native app uses the first-party Core
|
|
12
|
+
adapter. Another backend implements `AgentTransport` directly or exposes the
|
|
13
|
+
versioned HTTP contract. Persistence, authorization, file storage, and agent
|
|
14
|
+
execution always stay outside this package.
|
|
15
|
+
|
|
16
|
+
See [ARCHITECTURE.md](./ARCHITECTURE.md) for the full ownership, invariant, and
|
|
17
|
+
extension model.
|
|
18
|
+
|
|
19
|
+
## Package layout
|
|
20
|
+
|
|
21
|
+
AgentKit ships as one package with explicit subpaths. Each subpath is a separate
|
|
22
|
+
module graph, so a server, native client, or alternate renderer that imports the
|
|
23
|
+
root or `/protocol` never loads React, Toolkit, or markdown code.
|
|
24
|
+
|
|
25
|
+
| Import | Contents | Loads React |
|
|
26
|
+
| ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
|
27
|
+
| `@agent-native/agentkit` | Headless client and protocol types: deterministic reduction, optimistic mutations, reconnect, replay, approvals, actions, queues | No |
|
|
28
|
+
| `@agent-native/agentkit/protocol` | Wire contract only: versioned types, runtime validators, lifecycle semantics | No |
|
|
29
|
+
| `@agent-native/agentkit/http` | Fetch-compatible HTTP transport and server handler with resumable server-sent events | No |
|
|
30
|
+
| `@agent-native/agentkit/conformance` | Executable transport invariants for custom and remote transports | No |
|
|
31
|
+
| `@agent-native/agentkit/react` | Provider, hooks, control API, slots, registries, composer integration, accessible defaults | Yes |
|
|
32
|
+
| `@agent-native/agentkit/react/{root,chat,components,context,headless,streaming-text}` | Focused React entries | Yes |
|
|
33
|
+
| `@agent-native/agentkit/react/styles.css` | Standalone stylesheet | No |
|
|
34
|
+
|
|
35
|
+
AgentKit previously published six packages. Replace the old specifiers with
|
|
36
|
+
these subpaths: `agentkit-protocol` becomes `agentkit/protocol`,
|
|
37
|
+
`agentkit-adapters` becomes `agentkit/http`, `agentkit-conformance` becomes
|
|
38
|
+
`agentkit/conformance`, `agentkit-react` becomes `agentkit/react`, and
|
|
39
|
+
`agentkit-client` becomes the root `@agent-native/agentkit` import. The root
|
|
40
|
+
also re-exports the protocol, so `/protocol` is reserved for code that must not
|
|
41
|
+
pull in the client.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pnpm add @agent-native/agentkit @agent-native/core
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Generated Chat apps already include a compatible version. Core is needed only
|
|
50
|
+
for the first-party Agent-Native transport. `react` and `react-dom` 19 are
|
|
51
|
+
optional peer dependencies required only by the `/react` entries.
|
|
52
|
+
|
|
53
|
+
## Minimal React integration
|
|
54
|
+
|
|
55
|
+
`AgentChat` owns one AgentKit client, loads the thread, reconnects active work,
|
|
56
|
+
and disposes the client when it unmounts.
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { AgentChat } from "@agent-native/agentkit/react";
|
|
60
|
+
import "@agent-native/agentkit/react/styles.css";
|
|
61
|
+
import { createAgentNativeAgentKitTransport } from "@agent-native/core/client/agent-chat";
|
|
62
|
+
import { useMemo } from "react";
|
|
63
|
+
|
|
64
|
+
export function Conversation({ threadId }: { threadId: string }) {
|
|
65
|
+
const transport = useMemo(
|
|
66
|
+
() => createAgentNativeAgentKitTransport({ threadId, surface: "app" }),
|
|
67
|
+
[threadId],
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<AgentChat
|
|
72
|
+
transport={transport}
|
|
73
|
+
clientOptions={{ transportOwnership: "owned" }}
|
|
74
|
+
threadId={threadId}
|
|
75
|
+
title="Workspace review"
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The ownership option tells the managed client to dispose this exclusively
|
|
82
|
+
created transport on replacement or unmount; omit it for application-level
|
|
83
|
+
shared transports. This adapter uses the built-in `/_agent-native/agent-chat`
|
|
84
|
+
runtime, which restores durable history, streams runs, continues approved tool
|
|
85
|
+
calls, and persists the message queue, so the app adds no second fetch or
|
|
86
|
+
event-stream layer.
|
|
87
|
+
|
|
88
|
+
The reference experience includes a persistent composer, recessed message queue,
|
|
89
|
+
agent-authored suggestions, buffered streaming, progressive task and activity
|
|
90
|
+
disclosure, approval and choice cards, interactive widgets, attachments,
|
|
91
|
+
annotations, feedback, forking, and multi-agent collaboration activity.
|
|
92
|
+
Capability discovery runs before the first command, so unsupported features
|
|
93
|
+
render as absent rather than as broken controls.
|
|
94
|
+
|
|
95
|
+
### Client source and lifecycle
|
|
96
|
+
|
|
97
|
+
`AgentChat` accepts exactly one client source:
|
|
98
|
+
|
|
99
|
+
- **`endpoint`** creates and owns the HTTP transport and the client. The
|
|
100
|
+
optional `http` prop forwards the full transport contract: `fetch`, static or
|
|
101
|
+
async `headers`, `createCorrelationId`, and a lifecycle `signal` whose abort
|
|
102
|
+
releases in-flight commands and run subscriptions owned by the mounted
|
|
103
|
+
surface.
|
|
104
|
+
- **`transport`** leaves the transport host-owned by default and manages only
|
|
105
|
+
the client. Set `clientOptions={{ transportOwnership: "owned" }}` when the
|
|
106
|
+
transport exists solely for this surface.
|
|
107
|
+
- **`client`** is caller-owned, including final disposal.
|
|
108
|
+
|
|
109
|
+
Managed clients are disposed when their endpoint, transport, or mounted surface
|
|
110
|
+
changes; caller-owned clients are never disposed by React. Changing `threadId`
|
|
111
|
+
keeps the managed client and exchanges its active thread lease, so one shell
|
|
112
|
+
preserves cross-thread execution state without rebuilding its controller. Active
|
|
113
|
+
runs are resubscribed when a thread opens, and obsolete loads cannot report
|
|
114
|
+
errors after their lease releases. Set `load="manual"` only when an advanced
|
|
115
|
+
host coordinates loading and leases itself. All modes are safe to server-render
|
|
116
|
+
because network work starts in effects, and React Strict Mode replays share the
|
|
117
|
+
same managed lease rather than duplicating thread loads.
|
|
118
|
+
|
|
119
|
+
Shells that let users navigate away from active work can set
|
|
120
|
+
`clientOptions={{ retainActiveRunsOnThreadRelease: true }}` to keep accepted run
|
|
121
|
+
subscriptions
|
|
122
|
+
alive after the last visible lease releases, ending on the run's terminal event
|
|
123
|
+
or client disposal. Pair it with `useAgentChatRunningThreads()` from
|
|
124
|
+
`@agent-native/core/client/agent-chat` to render per-thread progress in rails or
|
|
125
|
+
tabs: `workingThreadIds` ends at the first visible assistant response, while
|
|
126
|
+
`runningThreadIds` remains active until the transport reaches a terminal event.
|
|
127
|
+
|
|
128
|
+
### Contextual connection requests
|
|
129
|
+
|
|
130
|
+
When an action cannot continue without a workspace integration, the runtime
|
|
131
|
+
emits a typed connection request instead of relying on assistant prose. The
|
|
132
|
+
request identifies only the provider, reason, and blocked run. AgentKit renders
|
|
133
|
+
an inline card, and the host performs setup through its trusted connection
|
|
134
|
+
catalog:
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<AgentChat
|
|
138
|
+
transport={transport}
|
|
139
|
+
threadId={threadId}
|
|
140
|
+
onConnectionRequest={async ({ provider, reason }) => {
|
|
141
|
+
const connection = await workspaceConnections.connect(provider, { reason });
|
|
142
|
+
return connection
|
|
143
|
+
? { status: "connected", connectionId: connection.id }
|
|
144
|
+
: { status: "declined" };
|
|
145
|
+
}}
|
|
146
|
+
/>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Use `slots.connectionRequest` when the product has a richer catalog-native card.
|
|
150
|
+
The slot receives the typed request and its run id, and resolves it through
|
|
151
|
+
`useAgentKitControl().resolveConnectionRequest(...)`. See
|
|
152
|
+
[Connection requests](#connection-requests) for the replay-safe lifecycle, the
|
|
153
|
+
reason taxonomy, and the delegated-agent case.
|
|
154
|
+
|
|
155
|
+
Agent-Native Chat replaces the generic card with Core's MCP connection surface,
|
|
156
|
+
which resolves the provider through the workspace catalog, preserves the exact
|
|
157
|
+
run across OAuth, and resumes it after setup. Agent-authored values never supply
|
|
158
|
+
OAuth URLs, credentials, or scopes, and an existing connection may still require
|
|
159
|
+
a separate human approval before an action runs.
|
|
160
|
+
|
|
161
|
+
### Approvals and activity display
|
|
162
|
+
|
|
163
|
+
Choice approvals render an **Other** option by default, revealing a focused text
|
|
164
|
+
field that submits as `response.other`
|
|
165
|
+
(see [Approval decisions](#approval-decisions)). Localize the affordance through
|
|
166
|
+
the `approvalOther` and `approvalOtherPlaceholder` labels, or replace the
|
|
167
|
+
surface with `slots.approval`.
|
|
168
|
+
|
|
169
|
+
Active execution segments show a quiet `Working for {{duration}}` timer that
|
|
170
|
+
settles to `Worked for {{duration}}`, and consecutive equivalent default
|
|
171
|
+
activities cluster into one counted row that preserves every underlying trace
|
|
172
|
+
record when expanded. Default activity rows use semantic icons for reasoning,
|
|
173
|
+
search, reading, editing, commands, checks, MCP calls, connections, navigation,
|
|
174
|
+
delegation, and approval; adapters should emit an explicit `activity.kind`
|
|
175
|
+
whenever they know the operation; `inferAgentActivityKind()` is the fallback.
|
|
176
|
+
|
|
177
|
+
## Provider-neutral HTTP integration
|
|
178
|
+
|
|
179
|
+
The HTTP adapter uses versioned JSON envelopes for commands and resumable
|
|
180
|
+
server-sent events for run streams. Its server half is a standard Fetch handler,
|
|
181
|
+
so the same contract runs in Node, serverless, and edge hosts. Agent-Native apps
|
|
182
|
+
normally use `createAgentNativeAgentKitTransport()`; use `/http` when another
|
|
183
|
+
backend needs the portable AgentKit boundary, or when a host intentionally
|
|
184
|
+
exposes a separate AgentKit route. In React, `AgentChat`'s `endpoint` mode
|
|
185
|
+
consumes a mounted `createAgentKitHttpHandler()` route directly.
|
|
186
|
+
|
|
187
|
+
### Client transport
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
import { createAgentKitHttpTransport } from "@agent-native/agentkit/http";
|
|
191
|
+
|
|
192
|
+
const transport = createAgentKitHttpTransport({
|
|
193
|
+
baseUrl: "/_agent-native/agentkit",
|
|
194
|
+
headers: async () => ({ Authorization: `Bearer ${await getToken()}` }),
|
|
195
|
+
createCorrelationId: () => tracing.currentRequestId(),
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`createAgentKitHttpTransport()` accepts a base URL, an optional Fetch
|
|
200
|
+
implementation, static or async headers, an optional correlation-id factory, and
|
|
201
|
+
an optional abort signal for the transport lifecycle. Every JSON response is a
|
|
202
|
+
versioned protocol envelope. HTTP failures throw `AgentKitHttpError` with
|
|
203
|
+
status, code, details, retryability, and the correlation id echoed by the
|
|
204
|
+
server; that id is carried in JSON envelopes, request and response headers, and
|
|
205
|
+
SSE event envelopes for end-to-end tracing. Each non-stream operation also
|
|
206
|
+
accepts a request context whose signal cancels that Fetch request independently
|
|
207
|
+
of the transport lifecycle and whose correlation id overrides the factory.
|
|
208
|
+
|
|
209
|
+
### Server handler
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
import { createAgentKitHttpHandler } from "@agent-native/agentkit/http";
|
|
213
|
+
|
|
214
|
+
export const handleAgentKit = createAgentKitHttpHandler({
|
|
215
|
+
basePath: "/_agent-native/agentkit",
|
|
216
|
+
resolveRequestContext: (request) => identity.authorize(request),
|
|
217
|
+
createTransport: ({ trusted }) => agentRuntime.forRequest(trusted),
|
|
218
|
+
onError: (error, request) => telemetry.capture(error, request),
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The returned function accepts a standard `Request` and resolves a standard
|
|
223
|
+
`Response`. Request-scoped hosts pair `resolveRequestContext` with
|
|
224
|
+
`createTransport` so authenticated principal, workspace, access, and audit state
|
|
225
|
+
resolves once and is closed over by a dedicated transport. That trusted value is
|
|
226
|
+
structurally separate from protocol metadata: it is never parsed from the
|
|
227
|
+
client, passed in an operation context, or serialized into a response. Resolver
|
|
228
|
+
failures fail closed with an opaque server error unless the host throws a typed
|
|
229
|
+
`AgentKitHttpError`.
|
|
230
|
+
|
|
231
|
+
A transport returned by `createTransport` is request-owned by default. When it
|
|
232
|
+
implements `dispose()`, the handler calls it exactly once after a JSON request
|
|
233
|
+
succeeds or fails, or after an SSE body completes or its reader cancels; the
|
|
234
|
+
transport stays alive while the SSE body is being consumed. Resolver failures
|
|
235
|
+
neither create nor dispose a transport. Set `transportOwnership: "borrowed"`
|
|
236
|
+
only when `createTransport` deliberately returns a host-managed or shared
|
|
237
|
+
transport. Disposal failures are reported through `onError` without replacing
|
|
238
|
+
the established protocol result. A static `transport` remains available when
|
|
239
|
+
identity and access are genuinely static for the mounted handler; static
|
|
240
|
+
transports are always borrowed, and that mode is wrong for a multi-tenant
|
|
241
|
+
runtime whose scope depends on ambient request state.
|
|
242
|
+
|
|
243
|
+
For non-stream routes the handler passes `Request.signal` and the established
|
|
244
|
+
correlation id to backend work, so a disconnect cancels the in-flight backend
|
|
245
|
+
operation and maps to a typed 499 response when the runtime can still produce
|
|
246
|
+
one. SSE disconnects stop only the subscription iterator and never call
|
|
247
|
+
`cancelRun()`. If the host error observer fails, the request still receives a
|
|
248
|
+
typed opaque error; observer failure is reported separately. Optional routes
|
|
249
|
+
return a typed `operation_unsupported` error with status 501, clients negotiate
|
|
250
|
+
explicit capability state through `POST /capabilities/discover` while
|
|
251
|
+
`GET /capabilities` remains the legacy boolean projection, and run streams
|
|
252
|
+
require `text/event-stream`, validate safe integer cursors and matching SSE ids,
|
|
253
|
+
and accept `afterSequence` only when the transport advertises durable
|
|
254
|
+
resumability.
|
|
255
|
+
|
|
256
|
+
### Host responsibilities
|
|
257
|
+
|
|
258
|
+
- Authenticate before the Fetch handler receives a request.
|
|
259
|
+
- Scope thread and run operations to the current principal and workspace.
|
|
260
|
+
- Validate action payloads and enforce the same access checks used by direct
|
|
261
|
+
application calls.
|
|
262
|
+
- Keep binary uploads in host storage and return portable file references.
|
|
263
|
+
- Advertise only capabilities the mounted transport can complete.
|
|
264
|
+
|
|
265
|
+
Commands are runtime-validated before they reach a backend, and identifiers in
|
|
266
|
+
route paths must match identifiers in versioned request envelopes. The adapter
|
|
267
|
+
validates protocol shape and route identity; it does not turn a thread id,
|
|
268
|
+
action id, widget payload, or smart-object reference into authority.
|
|
269
|
+
|
|
270
|
+
## Compose an advanced product
|
|
271
|
+
|
|
272
|
+
Create a controller when the application needs dependency injection, a native
|
|
273
|
+
transport, custom upload behavior, or more than one coordinated view.
|
|
274
|
+
`AgentKitRoot` owns controller selection and lifecycle, `AgentKitChat` is a
|
|
275
|
+
reference surface rather than a required shell, slots replace broad regions, and
|
|
276
|
+
registries select renderers for domain-specific values.
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
import { createAgentKitClient } from "@agent-native/agentkit";
|
|
280
|
+
import { AgentKitRoot } from "@agent-native/agentkit/react/headless";
|
|
281
|
+
|
|
282
|
+
const controller = createAgentKitClient({ transport });
|
|
283
|
+
|
|
284
|
+
<AgentKitRoot
|
|
285
|
+
controller={controller}
|
|
286
|
+
threadId={threadId}
|
|
287
|
+
labels={localizedLabels}
|
|
288
|
+
slots={{
|
|
289
|
+
emptyState: NewConversation,
|
|
290
|
+
messageSupplement: ProductMessageContext,
|
|
291
|
+
approval: ProductApproval,
|
|
292
|
+
runFailure: ProductRunFailure,
|
|
293
|
+
}}
|
|
294
|
+
registry={{
|
|
295
|
+
agents: { external: ConnectedAgentIdentity },
|
|
296
|
+
agentInteractions: { delegated: DelegationActivity },
|
|
297
|
+
activities: { deploy: DeploymentActivity },
|
|
298
|
+
tasks: { deployment: DeploymentTask },
|
|
299
|
+
tools: { "query-database": QueryActivity },
|
|
300
|
+
widgets: { chart: ChartWidget, picker: RecordPicker },
|
|
301
|
+
messageParts: { "x-workflow": WorkflowPart },
|
|
302
|
+
}}
|
|
303
|
+
onOpenObject={(object) => workspace.open(object)}
|
|
304
|
+
onThreadForked={(thread) => workspace.openThread(thread.id)}
|
|
305
|
+
onRenderError={(failure) => telemetry.capture(failure)}
|
|
306
|
+
onClientEffect={(effect) => effects.dispatch(effect)}
|
|
307
|
+
>
|
|
308
|
+
<ProductConversation />
|
|
309
|
+
</AgentKitRoot>;
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
`AgentKitRoot` accepts `threadId`, children, and exactly one client source:
|
|
313
|
+
`endpoint` creates a managed HTTP transport and controller with optional `http`
|
|
314
|
+
configuration, `transport` creates a managed controller around a host-owned
|
|
315
|
+
transport with optional `clientOptions`, and `controller` uses the host's
|
|
316
|
+
existing `AgentKitController`. In controller mode `AgentKitRoot` opens and
|
|
317
|
+
releases the active thread lease while the host eventually disposes the
|
|
318
|
+
controller; with `load="manual"` the host owns both steps.
|
|
319
|
+
|
|
320
|
+
The `react/headless` entry excludes the reference transcript and rich composer,
|
|
321
|
+
so a custom client bundle loads only the regions it renders. `AgentKitProvider`
|
|
322
|
+
is the lower-level context boundary it exports: it accepts a controller, thread
|
|
323
|
+
id, slots, registry, labels, and host callbacks, but does not load a thread or
|
|
324
|
+
dispose a controller. Prefer `AgentKitRoot` unless the host already owns those
|
|
325
|
+
lifecycle steps.
|
|
326
|
+
|
|
327
|
+
`AgentChat` passes labels, registries, object handlers, renderer slots, and
|
|
328
|
+
`composerProps` through unchanged. Region slots cover the header, toolbar,
|
|
329
|
+
transcript, and footer, plus `messageSupplement`, `messageActions`, and `file`.
|
|
330
|
+
`messageSupplement` adds trusted host-owned contextual UI after a message
|
|
331
|
+
without replacing its content or action behavior. Behavioral queue and
|
|
332
|
+
suggestion slots receive the same client-backed handlers as the defaults, so
|
|
333
|
+
presentation changes without forking behavior. AgentKit injects no default
|
|
334
|
+
commands or skills, upload controls appear only when the backend advertises
|
|
335
|
+
uploads, and uploads always flow through `AgentKitClient.uploadFiles`. Widgets
|
|
336
|
+
call stable framework actions and smart objects ask the host to navigate;
|
|
337
|
+
neither reaches into product routes.
|
|
338
|
+
|
|
339
|
+
Thread forking renders only when the backend advertises the capability and the
|
|
340
|
+
host provides `onThreadForked`, and feedback controls follow the same contract.
|
|
341
|
+
AgentKit never renders an inert control merely because a transport method exists
|
|
342
|
+
in a type. Feedback selection is optimistic and rolls back on transport failure,
|
|
343
|
+
and a fork stays pending until the durable thread exists.
|
|
344
|
+
|
|
345
|
+
### One controller, one stream owner
|
|
346
|
+
|
|
347
|
+
An application must have exactly one behavioral owner for a conversation. Pick a
|
|
348
|
+
single source (`endpoint`, `transport`, or `client` on `AgentChat`, or
|
|
349
|
+
`controller` on `AgentKitRoot` and `AgentKitProvider`) and share that controller
|
|
350
|
+
across every coordinated view. Never create another client for the same live
|
|
351
|
+
thread. When adopting AgentKit inside an existing chat runtime, project that
|
|
352
|
+
runtime through `AgentKitController` instead of opening a second SSE connection
|
|
353
|
+
or maintaining a parallel queue, approval store, or optimistic message list.
|
|
354
|
+
|
|
355
|
+
### Renderer isolation
|
|
356
|
+
|
|
357
|
+
Messages, activity, approvals, headers, connection errors, and composers are
|
|
358
|
+
isolated by `AgentKitErrorBoundary`, so a broken host slot or agent-authored
|
|
359
|
+
widget cannot unmount the rest of the conversation. Users see the localized
|
|
360
|
+
`renderError` label, and `onRenderError` receives the original error, surface,
|
|
361
|
+
thread id, and React component stack. The boundary is public for product-owned
|
|
362
|
+
regions.
|
|
363
|
+
|
|
364
|
+
### Failure and mutation behavior
|
|
365
|
+
|
|
366
|
+
Terminal `run.failed` events render beside the run that failed, and connection
|
|
367
|
+
failures render separately. Approvals, widget actions, queue controls, uploads,
|
|
368
|
+
and sends expose pending and typed error states. The composer preserves its
|
|
369
|
+
draft when submission fails.
|
|
370
|
+
|
|
371
|
+
AgentKit intentionally provides no generic retry button, because replaying agent
|
|
372
|
+
work can duplicate side effects. A product that owns an idempotent recovery
|
|
373
|
+
action renders it explicitly through `slots.runFailure`, using `error.retryable`
|
|
374
|
+
and `error.metadata?.idempotencyKey` to decide, and `useAgentKitMutation()` for
|
|
375
|
+
pending and error state. `control.resubscribe(runId)` only reattaches to an
|
|
376
|
+
existing stream after a connection loss; it never reruns a prompt.
|
|
377
|
+
|
|
378
|
+
### Hooks
|
|
379
|
+
|
|
380
|
+
- `useAgentThread(threadId?)` returns the normalized projection for the context
|
|
381
|
+
thread or an explicitly requested one.
|
|
382
|
+
- `useAgentKitControl(threadId?)` binds conversation commands to the same.
|
|
383
|
+
- `useAgentRun(runId)` returns one run lifecycle.
|
|
384
|
+
- `useAgentCapabilities()` exposes negotiated backend behavior.
|
|
385
|
+
- `useAgentConnection()` exposes connection and typed error state.
|
|
386
|
+
- `useAgentRoster()` and `useAgentParticipant(id)` select agent identity.
|
|
387
|
+
- `useAgentInteractions(filter)` selects append-only collaboration evidence.
|
|
388
|
+
- `useAgentKitSnapshot()` and `useAgentKitSelector()` power custom surfaces.
|
|
389
|
+
- `useAgentKitMutation(fn)` provides race-safe pending and error state for host
|
|
390
|
+
actions.
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
function ProductConversation() {
|
|
394
|
+
const thread = useAgentThread();
|
|
395
|
+
const control = useAgentKitControl();
|
|
396
|
+
|
|
397
|
+
return (
|
|
398
|
+
<ProductTranscript
|
|
399
|
+
messages={thread.messages}
|
|
400
|
+
onSend={(text) => void control.send(text)}
|
|
401
|
+
/>
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
`useAgentKitMutation()` returns `execute()`, `reset()`, `status`, `pending`, and
|
|
407
|
+
`error`; `execute()` takes the same arguments as the supplied async function,
|
|
408
|
+
and only the latest invocation owns the visible status. Use
|
|
409
|
+
`useAgentKitSelector(selector, isEqual?)` for a focused derived value and
|
|
410
|
+
`useAgentKitSnapshot()` only when a surface needs the complete client snapshot.
|
|
411
|
+
`useAgentRun(runId?)` and `useAgentParticipant(agentId?)` return `undefined`
|
|
412
|
+
when no matching value exists.
|
|
413
|
+
|
|
414
|
+
### Streaming and formatting
|
|
415
|
+
|
|
416
|
+
`AgentStreamingText` smooths uneven network chunks per message and preserves
|
|
417
|
+
grapheme clusters. Its reset key prevents a later response from inheriting a
|
|
418
|
+
previous message's buffer. Plain text is the default: a backend must set
|
|
419
|
+
`format: "markdown"`, and a host must intentionally supply a rich-text slot,
|
|
420
|
+
before authored emphasis is interpreted.
|
|
421
|
+
|
|
422
|
+
Reasoning defaults to a compact expandable row and hidden reasoning is never
|
|
423
|
+
rendered. Agents may provide a concise `label` such as "Reviewed release
|
|
424
|
+
boundaries" for completed reasoning, with the localized `reasoning` label as the
|
|
425
|
+
active fallback. Activities describe safe execution evidence instead of exposing
|
|
426
|
+
private chain-of-thought.
|
|
427
|
+
|
|
428
|
+
Agent-authored suggestions replace the suggestion row after each turn, using a
|
|
429
|
+
concise single-line `label` for the pill and an optional longer `prompt` to
|
|
430
|
+
submit. The shared composer exposes a named multiline textbox through
|
|
431
|
+
`labels.composerLabel`; `composerPlaceholder` is visual guidance and does not
|
|
432
|
+
substitute for the accessible name.
|
|
433
|
+
|
|
434
|
+
### Slash discovery
|
|
435
|
+
|
|
436
|
+
AgentKit exposes slash discovery without inventing product semantics. Pass
|
|
437
|
+
`slashCommands`, `slashSkills`, `includeDefaultSlashCommands`,
|
|
438
|
+
`includeDefaultSlashSkills`, and `onSlashCommand` to `AgentKitComposer`. Omit
|
|
439
|
+
unavailable commands and skills; empty integration or skill states are not
|
|
440
|
+
injected into the conversation.
|
|
441
|
+
|
|
442
|
+
### Semantic styling
|
|
443
|
+
|
|
444
|
+
The standalone stylesheet uses semantic host tokens and exposes two focused
|
|
445
|
+
overrides, `--agentkit-chat-background` and `--agentkit-composer-background`.
|
|
446
|
+
Components inherit host foreground, muted, border, primary, destructive,
|
|
447
|
+
success, focus, and radius tokens. Composer, overlay, and control depth use the
|
|
448
|
+
registered `--agent-kit-*-elevation` semantic tokens and fall back to no shadow.
|
|
449
|
+
No product palette is embedded in the package.
|
|
450
|
+
|
|
451
|
+
## Headless client
|
|
452
|
+
|
|
453
|
+
The root import is the framework-agnostic controller. It owns deterministic
|
|
454
|
+
event reduction, optimistic user messages, sequence replay, reconnects,
|
|
455
|
+
approvals, actions, suggestions, and message queues. It does not own agent
|
|
456
|
+
execution, persistence, authentication, authorization, application state, or
|
|
457
|
+
presentation, and it has no React, DOM, storage, or provider dependency, so web,
|
|
458
|
+
native, terminal, and test clients subscribe to the same behavioral source of
|
|
459
|
+
truth through `subscribe()` and `getSnapshot()`.
|
|
460
|
+
|
|
461
|
+
```ts
|
|
462
|
+
import { createAgentKitClient } from "@agent-native/agentkit";
|
|
463
|
+
|
|
464
|
+
const client = createAgentKitClient({ transport });
|
|
465
|
+
const thread = await client.openThread("thread-1");
|
|
466
|
+
const run = await client.sendMessage({
|
|
467
|
+
threadId: "thread-1",
|
|
468
|
+
text: "Review the workspace",
|
|
469
|
+
});
|
|
470
|
+
await run.completed;
|
|
471
|
+
thread.release();
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
`createAgentKitClient()` accepts one options object:
|
|
475
|
+
|
|
476
|
+
- **transport**: the only owner of remote thread and run operations.
|
|
477
|
+
- **transportOwnership**: `"borrowed"` by default; use `"owned"` only when the
|
|
478
|
+
client exclusively owns the transport lifecycle.
|
|
479
|
+
- **upload**: an optional binary upload driver. Binary bodies never enter the
|
|
480
|
+
event protocol.
|
|
481
|
+
- **createId** and **now**: injectable deterministic primitives for tests.
|
|
482
|
+
- **reconnect**: the retry count and delay for reattaching to resumable streams.
|
|
483
|
+
- **retainActiveRunsOnThreadRelease**: keeps accepted run subscriptions alive
|
|
484
|
+
after the last thread lease releases.
|
|
485
|
+
- **onError**: an observer for terminal controller failures.
|
|
486
|
+
|
|
487
|
+
The transport is the only remote owner: do not combine a client with another
|
|
488
|
+
message store, queue reducer, approval store, or stream reader for the same
|
|
489
|
+
conversation. Call `openThread()` before rendering a persisted conversation.
|
|
490
|
+
Concurrent opens share one load and return independent leases. Hydration
|
|
491
|
+
restores durable message and activity projections, fetches missing active-run
|
|
492
|
+
checkpoints, and reattaches every active run once. Releasing the last lease
|
|
493
|
+
aborts those local subscriptions and reconnect waits without cancelling remote
|
|
494
|
+
work. `loadThread()` remains available for hosts that own lifecycle separately,
|
|
495
|
+
and `sendMessage(input)` returns an `AgentRunHandle` with a stable `runId`, a
|
|
496
|
+
`completed` promise, and `cancel()`.
|
|
497
|
+
|
|
498
|
+
Before the first run the controller negotiates protocol and capability status
|
|
499
|
+
through `discoverCapabilities`, or the legacy static capability map. Optional
|
|
500
|
+
operations fail with typed capability or operation errors; unavailable,
|
|
501
|
+
unsupported, and omitted capabilities are never treated as successful no-ops.
|
|
502
|
+
Every mutation is exposed through the controller, including thread, queue,
|
|
503
|
+
approval, action, upload, feedback, cancellation, and deletion operations.
|
|
504
|
+
|
|
505
|
+
Every non-stream controller method takes an optional final request context of
|
|
506
|
+
`{ signal, correlationId }` that propagates through capability preflight and the
|
|
507
|
+
selected transport operation, rejecting with a typed, non-retryable
|
|
508
|
+
`request_aborted` error. Disposing the client aborts its outstanding requests
|
|
509
|
+
and local subscriptions, while ending a subscription never calls `cancelRun()`
|
|
510
|
+
or cancels durable remote work.
|
|
511
|
+
|
|
512
|
+
The client accepts only validated protocol events and reduces them into an
|
|
513
|
+
immutable snapshot preserving tool deltas, actions, upload progress, approval
|
|
514
|
+
ownership, widgets, annotations, task groups, artifacts, agent-authored
|
|
515
|
+
suggestions, the current agent roster, append-only collaboration interactions,
|
|
516
|
+
agent-scoped activity, and queue state. Update and removal events replace or
|
|
517
|
+
delete their stable projection identity, so reconnect replay is idempotent.
|
|
518
|
+
Streams are isolated by thread and run, reconnect after the last accepted
|
|
519
|
+
sequence, and fail if they close without an explicit completed, failed, or
|
|
520
|
+
cancelled event. `resubscribeRun()` retries only the subscription. User messages
|
|
521
|
+
stay visible and are marked `error` when run creation fails; a stream failure
|
|
522
|
+
after run acceptance does not relabel the accepted message. `cancelRun()` waits
|
|
523
|
+
for server acceptance, updates the local run projection, and aborts the live
|
|
524
|
+
subscription or pending reconnect immediately.
|
|
525
|
+
|
|
526
|
+
Call and await `shutdown()` or its `dispose()` alias when a client leaves its
|
|
527
|
+
application lifecycle. Cleanup is idempotent: an owned client awaits transport
|
|
528
|
+
disposal exactly once, a borrowed client never disposes the shared transport,
|
|
529
|
+
and React-managed clients dispose automatically.
|
|
530
|
+
|
|
531
|
+
## Protocol reference
|
|
532
|
+
|
|
533
|
+
`@agent-native/agentkit/protocol` is the dependency-free wire contract between
|
|
534
|
+
an agent backend and AgentKit clients: messages, streamed events, tool calls,
|
|
535
|
+
activities, delegable tasks, approvals, widgets, annotations, artifacts,
|
|
536
|
+
capabilities, runs, threads, queues, and transport operations. Runtime
|
|
537
|
+
validators and versioned envelopes are exported beside the TypeScript types, and
|
|
538
|
+
every network adapter parses commands and events at its trust boundary.
|
|
539
|
+
Compile-time types are not a substitute for protocol validation.
|
|
540
|
+
|
|
541
|
+
Core provides two first-party adapters:
|
|
542
|
+
`createAgentNativeAgentKitTransport()` binds AgentKit to the production
|
|
543
|
+
Agent-Native thread, queue, approval, and streaming runtime, and
|
|
544
|
+
`createAgentKitProtocolAdapter()` adapts a host-owned Core `AgentChatRuntime`.
|
|
545
|
+
|
|
546
|
+
### Design principles
|
|
547
|
+
|
|
548
|
+
- The core event union covers common agent behavior without hiding richer
|
|
549
|
+
backend capabilities, and `x-*` extension events and capability keys carry
|
|
550
|
+
backend-specific features without coupling the base protocol to one provider.
|
|
551
|
+
- IDs and timestamps are strings, so hosts can choose UUIDs, database IDs, or
|
|
552
|
+
another stable format.
|
|
553
|
+
- Widgets carry serializable data and action payloads. The host decides how to
|
|
554
|
+
render them and routes stable action identifiers through `invokeAction`.
|
|
555
|
+
- Activities and smart-object references preserve compact agent progress while
|
|
556
|
+
letting a host open files, records, lines, artifacts, and app views without
|
|
557
|
+
embedding host navigation into the protocol.
|
|
558
|
+
- Tasks expose durable, delegable work with parent relationships, assigned
|
|
559
|
+
agents, progress, and smart objects. Task groups organize stable task ids
|
|
560
|
+
without replacing tasks as the workflow contract, and their canonical create,
|
|
561
|
+
update, complete, and remove events are replay-safe.
|
|
562
|
+
- Participants expose the current roster and lifecycle state for primary,
|
|
563
|
+
delegated, peer, and external agents. Append-only interactions preserve what
|
|
564
|
+
agents did to one another, while agent-scoped activities preserve the work
|
|
565
|
+
performed in the thread, workspace, or an external app, using a shared
|
|
566
|
+
semantic kind taxonomy for status, reasoning, search, reads, writes, commands,
|
|
567
|
+
checks, MCP calls, connections, navigation, delegation, approvals, and tools.
|
|
568
|
+
- Namespaced `x-*` message parts let a host add rich domain UI without forking
|
|
569
|
+
the base union, and `data` parts carry opaque structured content for
|
|
570
|
+
host-owned renderers. The host owns validation and rendering for both.
|
|
571
|
+
- Approval responses support simple confirmation, single or multiple choices,
|
|
572
|
+
and structured input values without a new transport for each card.
|
|
573
|
+
- Thread history, branching, queued messages, and steering are optional
|
|
574
|
+
transport operations, so a small embed stays small without blocking a full
|
|
575
|
+
workbench.
|
|
576
|
+
- Multi-agent activity is capability-negotiated. A backend can start with one
|
|
577
|
+
participant and later register parallel agents without changing message or
|
|
578
|
+
task contracts, and each off-surface source remains a portable smart object
|
|
579
|
+
the host can authorize, render, and open.
|
|
580
|
+
|
|
581
|
+
### Abort and cancellation
|
|
582
|
+
|
|
583
|
+
Every non-stream `AgentTransport` operation accepts an optional trailing
|
|
584
|
+
`AgentRequestContext`. Its `signal` cancels only that request, while its
|
|
585
|
+
`correlationId` gives clients, adapters, and backend work one portable tracing
|
|
586
|
+
identity. The context is ephemeral local control and is never serialized into
|
|
587
|
+
the protocol payload; the argument is optional, so existing transports stay
|
|
588
|
+
source-compatible.
|
|
589
|
+
|
|
590
|
+
`subscribeToRun({ threadId, runId, afterSequence, signal })` accepts an
|
|
591
|
+
`AbortSignal`. Aborting it stops that subscriber and requires the transport to
|
|
592
|
+
close its iterator and release stream resources. It never changes durable run
|
|
593
|
+
state. Call `cancelRun()` only when the caller intends to cancel the remote run.
|
|
594
|
+
|
|
595
|
+
HTTP and streaming adapters map the signal to their request or stream abort
|
|
596
|
+
mechanism. `parseAgentRequestContext()` and `parseSubscribeToRunInput()`
|
|
597
|
+
validate signal shape at local transport boundaries. Aborted non-stream work
|
|
598
|
+
fails with the typed, non-retryable `request_aborted` error and preserves
|
|
599
|
+
correlation identity.
|
|
600
|
+
|
|
601
|
+
### Durable snapshots and replay
|
|
602
|
+
|
|
603
|
+
`AgentThreadSnapshot` remains a backward-compatible partial projection.
|
|
604
|
+
Restart-safe hosts return `AgentDurableThreadSnapshot`, which requires every
|
|
605
|
+
collection even when empty: messages, tools, activities, tasks, task groups,
|
|
606
|
+
approvals, widgets, annotations, agents, interactions, artifacts, suggestions,
|
|
607
|
+
queued messages, runs, active-run ids, and ordered replay events. Annotation and
|
|
608
|
+
widget update and removal events keep these projections complete without
|
|
609
|
+
runtime-specific extension fallbacks.
|
|
610
|
+
|
|
611
|
+
Its `AgentReplayCheckpoint.sequenceByRun` must equal each included run's
|
|
612
|
+
`lastSequence` and cover every run, replayed events cannot advance beyond the
|
|
613
|
+
checkpoint, and active-run ids must resolve to included, non-terminal runs.
|
|
614
|
+
These invariants let clients hydrate each projection once, then subscribe after
|
|
615
|
+
the accepted sequence without dropping durable state or duplicating deltas.
|
|
616
|
+
Parse persisted or remote values with `parseAgentDurableThreadSnapshot()`.
|
|
617
|
+
Before advancing a replay cursor, validate the entire received batch with
|
|
618
|
+
`parseAgentEventSequence()`, which rejects the batch when the first event does
|
|
619
|
+
not follow `afterSequence` or any later event leaves a sequence gap.
|
|
620
|
+
|
|
621
|
+
### Approval decisions
|
|
622
|
+
|
|
623
|
+
Every `AgentApprovalResponse` carries an explicit provider-neutral `decision` of
|
|
624
|
+
`"approve"` or `"deny"`. Option ids and structured input remain payload, never
|
|
625
|
+
authorization signals: transports must not infer approval from labels, localized
|
|
626
|
+
copy, or provider-specific option ids. Resolved approval events and approved or
|
|
627
|
+
denied snapshots preserve the same explicit decision.
|
|
628
|
+
|
|
629
|
+
Choice requests accept a user-authored alternative unless `allowOther` is
|
|
630
|
+
explicitly `false`. The alternative is returned as `response.other`, separate
|
|
631
|
+
from `optionIds`, so runtimes never mistake arbitrary text for a predefined
|
|
632
|
+
choice. Multi-select requests may submit both predefined options and `other`.
|
|
633
|
+
|
|
634
|
+
### Connection requests
|
|
635
|
+
|
|
636
|
+
`AgentConnectionRequest` pauses a run when a concrete integration dependency is
|
|
637
|
+
missing. Its reason distinguishes a new `connect`, an existing connection that
|
|
638
|
+
needs an app `grant`, expired credentials or missing catalog-defined access that
|
|
639
|
+
requires `reauthorize`, and setup that is `admin_required`. This is not an
|
|
640
|
+
approval request: approval authorizes an operation, while a connection request
|
|
641
|
+
establishes the capability required to attempt it.
|
|
642
|
+
|
|
643
|
+
The lifecycle is explicit and replayable. `connection.requested` moves through
|
|
644
|
+
`requested` and `connecting`, then `connection.updated` settles as `connected`,
|
|
645
|
+
`declined`, or `failed`. Clients answer with `resolveConnectionRequest`, and
|
|
646
|
+
transports resume the exact blocked run only after a connected response. Failed
|
|
647
|
+
requests remain visible and retryable.
|
|
648
|
+
|
|
649
|
+
The request intentionally has no URL, credential, token, or scope fields. The
|
|
650
|
+
host resolves `provider` through its authenticated connection catalog and owns
|
|
651
|
+
OAuth, credential storage, grants, and scope policy, which keeps contextual
|
|
652
|
+
cards demand-driven without letting agent-authored data define a setup endpoint
|
|
653
|
+
or permission set. Agent-Native carries this provider-only shape through
|
|
654
|
+
authenticated A2A task metadata too, so a delegated agent pauses the caller's
|
|
655
|
+
visible run instead of degrading the dependency into an opaque remote failure.
|
|
656
|
+
|
|
657
|
+
### Errors, correlation, and metadata
|
|
658
|
+
|
|
659
|
+
`AgentError` is the serializable error base, and capability, operation, and
|
|
660
|
+
version failures have typed refinements and constructors.
|
|
661
|
+
`AgentKitProtocolError` retains the exact wire-safe value on `protocolError`
|
|
662
|
+
when a transport rejects, and both errors and envelopes can carry
|
|
663
|
+
`correlationId`.
|
|
664
|
+
|
|
665
|
+
Every standard metadata field accepts `AgentProtocolMetadata`. Its `actor`,
|
|
666
|
+
`workspace`, `access`, `audit`, `trace`, and `context` fields are portable
|
|
667
|
+
references that the owning host resolves and enforces access for. Existing
|
|
668
|
+
arbitrary metadata stays source-compatible, while new non-standard keys should
|
|
669
|
+
use an `x-*` namespace. Runtime parsing validates the standard reference shapes
|
|
670
|
+
and rejects non-JSON values, cycles, non-finite numbers, and excessive nesting.
|
|
671
|
+
|
|
672
|
+
### Queue steering semantics
|
|
673
|
+
|
|
674
|
+
Steering is a handoff into agent work, not a silent queue deletion. A transport
|
|
675
|
+
can return a `StartRunResult` when promotion starts a new run, or emit
|
|
676
|
+
`message.created` and `queue.updated` on an existing run. The queued item's id
|
|
677
|
+
is preserved so clients render the accepted user message exactly once across
|
|
678
|
+
optimistic state, replay, and remote events. If work rejects the command, the
|
|
679
|
+
transport must reject the operation and leave the queued item unchanged.
|
|
680
|
+
Explicit removal updates only the queue and never creates a conversation
|
|
681
|
+
message.
|
|
682
|
+
|
|
683
|
+
## Transport conformance
|
|
684
|
+
|
|
685
|
+
`@agent-native/agentkit/conformance` is an executable invariant suite for custom
|
|
686
|
+
and remote transports. It checks capability discovery, stable identity, runtime
|
|
687
|
+
validation, unique event identity, contiguous sequence, explicit terminal
|
|
688
|
+
semantics, declared reconnect replay, and run and thread snapshots without tying
|
|
689
|
+
hosts to a test runner. When a stream emits annotation, widget, or task-group
|
|
690
|
+
lifecycle events, it also proves replay idempotency and agreement with the
|
|
691
|
+
thread snapshot.
|
|
692
|
+
|
|
693
|
+
Run it against every first-party adapter and in deployment smoke tests for
|
|
694
|
+
remote implementations:
|
|
695
|
+
|
|
696
|
+
```ts
|
|
697
|
+
import { assertAgentTransportConformance } from "@agent-native/agentkit/conformance";
|
|
698
|
+
|
|
699
|
+
const report = await assertAgentTransportConformance({
|
|
700
|
+
transport,
|
|
701
|
+
threadId: "conformance-thread",
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
console.log(report.checks);
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
`assertAgentTransportConformance()` accepts one options object:
|
|
708
|
+
|
|
709
|
+
- **transport**: an existing `AgentTransport` for the baseline profile. Supply
|
|
710
|
+
this or `createTransport`, never both.
|
|
711
|
+
- **createTransport**: a factory returning an isolated transport per
|
|
712
|
+
full-profile scenario. Conformance owns each one, awaits its optional
|
|
713
|
+
`dispose()`, and disposes it even when a check fails.
|
|
714
|
+
- **threadId**: an optional stable thread id for the run.
|
|
715
|
+
- **messages**: optional seed messages. The default requests a short
|
|
716
|
+
acknowledgement.
|
|
717
|
+
- **timeoutMs**: an optional per-operation timeout. The default is 2,000 ms.
|
|
718
|
+
- **isUnsupportedError**: an optional predicate for a host's typed unsupported
|
|
719
|
+
error.
|
|
720
|
+
|
|
721
|
+
The baseline `transport` form is borrowed and the caller retains lifecycle
|
|
722
|
+
ownership. Use the `createTransport` form for adapter release gates that must
|
|
723
|
+
prove cancellation, abort, reconnect, cross-thread isolation, approval, queue,
|
|
724
|
+
and terminal-failure behavior. The report includes the profile, run id, baseline
|
|
725
|
+
and scenario event counts, negotiated capabilities, and completed checks.
|
|
726
|
+
Optional checks follow declared capabilities, and a transport must not advertise
|
|
727
|
+
a capability it cannot prove.
|
|
728
|
+
|
|
729
|
+
## Ownership and application mapping
|
|
730
|
+
|
|
731
|
+
| Concern | Owner | AgentKit boundary |
|
|
732
|
+
| ---------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
733
|
+
| Agent execution, persistence, auth, and access | Agent-Native or the host backend | Implement `AgentTransport` or use the Core adapter |
|
|
734
|
+
| Conversation state and commands | One `AgentKitController` | Pass one client/source to `AgentChat`, inject a host-owned controller into `AgentKitRoot`, or compose `AgentKitProvider` directly |
|
|
735
|
+
| App operations | Agent-Native `defineAction` actions | Route stable widget action ids through `invokeAction` |
|
|
736
|
+
| Visible app context | Agent-Native application state | Resolve smart objects and client effects in host callbacks |
|
|
737
|
+
| Agent UI semantics | AgentKit | Use components, hooks, slots, and renderer registries |
|
|
738
|
+
| Design system and workspace chrome | Toolkit plus app-owned adapters | Compose around AgentKit without moving runtime ownership |
|
|
739
|
+
|
|
740
|
+
Protocol ids and smart objects are references, not authorization grants. The
|
|
741
|
+
host authenticates the transport, scopes every thread read, checks every action
|
|
742
|
+
invocation, and re-resolves objects before opening them. The generic HTTP
|
|
743
|
+
handler must be mounted behind those controls. The Agent-Native adapter keeps
|
|
744
|
+
the existing Core request and access boundaries.
|
|
745
|
+
|
|
746
|
+
## Configure, compose, then eject
|
|
747
|
+
|
|
748
|
+
Customization follows an ownership ladder: configure `AgentChat` with labels,
|
|
749
|
+
`composerProps`, callbacks, semantic tokens, slots, and registries; compose
|
|
750
|
+
`AgentKitRoot`, hooks, and the visual regions the product needs, using Toolkit
|
|
751
|
+
for semantic controls and workspace UI; then eject only an installed unit listed
|
|
752
|
+
by `agent-native eject --list`, such as
|
|
753
|
+
`agent-native eject toolkit/composer --app <app> --apply`.
|
|
754
|
+
|
|
755
|
+
Ejection transfers presentation source to the app. It does not transfer Core
|
|
756
|
+
auth, persistence, action execution, application state, chat transport, or agent
|
|
757
|
+
execution. AgentKit does not advertise an AgentKit-wide ejection unit, so use
|
|
758
|
+
its public props, slots, registries, provider, client, and hooks instead of
|
|
759
|
+
copying package internals.
|
|
760
|
+
|
|
761
|
+
## Compatibility and versioning
|
|
762
|
+
|
|
763
|
+
Every network envelope carries `AGENTKIT_PROTOCOL_NAME` and a selected version
|
|
764
|
+
from `AGENTKIT_SUPPORTED_PROTOCOL_VERSIONS`. Discovery offers supported versions
|
|
765
|
+
and selects the highest mutual version with
|
|
766
|
+
`negotiateAgentKitProtocolVersion()`. Runtime parsers reject an unsupported
|
|
767
|
+
name, version, event, or command at the trust boundary. They do not coerce an
|
|
768
|
+
unreadable payload into an empty successful value.
|
|
769
|
+
|
|
770
|
+
Optional behavior is added through capability negotiation, which distinguishes
|
|
771
|
+
`available`, `degraded`, `unavailable`, and `unsupported`; omitted capabilities
|
|
772
|
+
remain unknown. The original boolean map is a backward-compatible projection
|
|
773
|
+
where `true` means available, `false` means unsupported, and omission means
|
|
774
|
+
unknown. Breaking required wire changes add a protocol version instead of
|
|
775
|
+
guessing a fallback.
|
|
776
|
+
|
|
777
|
+
Protocol v2 is an explicitly breaking pre-1.0 minor: its AG-UI envelope is not
|
|
778
|
+
wire-compatible with v1. Upgrade AgentKit clients and servers together, then
|
|
779
|
+
rerun transport conformance before deploying a custom adapter. V2-only peers
|
|
780
|
+
reject v1 rather than silently decoding it, and the deprecated
|
|
781
|
+
`resolveApproval` API is only a source-compatibility bridge once both peers use
|
|
782
|
+
v2.
|
|
783
|
+
|
|
784
|
+
New transports implement `discoverCapabilities(input)` and return an
|
|
785
|
+
`AgentCapabilitiesDiscovery` descriptor for every requested capability.
|
|
786
|
+
`degraded` and `unavailable` descriptors carry a typed `capability_unavailable`
|
|
787
|
+
error with explicit retryability, and `unsupported` descriptors carry a
|
|
788
|
+
non-retryable `capability_unsupported` error. Use `getAgentCapabilityStatus()`
|
|
789
|
+
to inspect a descriptor, or `requireAgentCapability()` to fail instead of
|
|
790
|
+
turning missing functionality into a no-op.
|
|
791
|
+
|
|
792
|
+
AgentKit is pre-1.0 and publishes as one compatibility-tested package. Generated
|
|
793
|
+
apps pin it through Core's dependency rather than resolving a `latest` tag. Read
|
|
794
|
+
release notes for minor updates, and run transport conformance after upgrading a
|
|
795
|
+
custom adapter.
|
|
796
|
+
|
|
797
|
+
Approval requests are terminal interrupts on the wire. The interrupted run
|
|
798
|
+
closes after the request; `resumeRun()` returns a distinct replacement run id
|
|
799
|
+
whose stream begins with the approval resolution and carries the continued
|
|
800
|
+
work. Consumers must subscribe to that returned run instead of waiting for more
|
|
801
|
+
events on the interrupted run.
|
|
802
|
+
|
|
803
|
+
Transport conformance requires `resumeRun()` when a transport advertises
|
|
804
|
+
protocol v2. An unversioned compatibility transport may temporarily advertise
|
|
805
|
+
approvals through the deprecated `resolveApproval()` bridge, allowing custom
|
|
806
|
+
adapters to migrate without weakening the v2 lifecycle contract.
|
|
807
|
+
|
|
808
|
+
## Migrate an existing Core chat surface
|
|
809
|
+
|
|
810
|
+
Keep the Core runtime and replace the presentation boundary in one pass:
|
|
811
|
+
|
|
812
|
+
1. Create `createAgentNativeAgentKitTransport()` for the default Agent-Native
|
|
813
|
+
runtime. A custom `AgentChatRuntime` can use
|
|
814
|
+
`createAgentKitProtocolAdapter()` from `@agent-native/core/client/chat`.
|
|
815
|
+
2. Replace the existing Core transcript component with `AgentChat`, or with
|
|
816
|
+
`AgentKitRoot` plus `AgentKitChat` for a composed surface.
|
|
817
|
+
3. Move render overrides to `slots` and kind-specific `registry` entries. Move
|
|
818
|
+
thread commands to `useAgentKitControl()`.
|
|
819
|
+
4. Keep actions, application-state keys, thread routing, auth, and access checks
|
|
820
|
+
unchanged.
|
|
821
|
+
5. Remove the old surface and stream owner. Never run parallel message, queue,
|
|
822
|
+
approval, or SSE state for the same conversation.
|