@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.
Files changed (88) hide show
  1. package/ARCHITECTURE.md +290 -0
  2. package/README.md +822 -0
  3. package/dist/adapters/http.d.ts +56 -0
  4. package/dist/adapters/http.d.ts.map +1 -0
  5. package/dist/adapters/http.js +950 -0
  6. package/dist/adapters/http.js.map +1 -0
  7. package/dist/adapters/index.d.ts +2 -0
  8. package/dist/adapters/index.d.ts.map +1 -0
  9. package/dist/adapters/index.js +2 -0
  10. package/dist/adapters/index.js.map +1 -0
  11. package/dist/client/client.d.ts +240 -0
  12. package/dist/client/client.d.ts.map +1 -0
  13. package/dist/client/client.js +1605 -0
  14. package/dist/client/client.js.map +1 -0
  15. package/dist/client/index.d.ts +3 -0
  16. package/dist/client/index.d.ts.map +1 -0
  17. package/dist/client/index.js +3 -0
  18. package/dist/client/index.js.map +1 -0
  19. package/dist/client/state.d.ts +72 -0
  20. package/dist/client/state.d.ts.map +1 -0
  21. package/dist/client/state.js +385 -0
  22. package/dist/client/state.js.map +1 -0
  23. package/dist/conformance/index.d.ts +41 -0
  24. package/dist/conformance/index.d.ts.map +1 -0
  25. package/dist/conformance/index.js +924 -0
  26. package/dist/conformance/index.js.map +1 -0
  27. package/dist/index.d.ts +3 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +3 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/protocol/agui-codec.d.ts +28 -0
  32. package/dist/protocol/agui-codec.d.ts.map +1 -0
  33. package/dist/protocol/agui-codec.js +250 -0
  34. package/dist/protocol/agui-codec.js.map +1 -0
  35. package/dist/protocol/agui.d.ts +144 -0
  36. package/dist/protocol/agui.d.ts.map +1 -0
  37. package/dist/protocol/agui.js +253 -0
  38. package/dist/protocol/agui.js.map +1 -0
  39. package/dist/protocol/compatibility.d.ts +35 -0
  40. package/dist/protocol/compatibility.d.ts.map +1 -0
  41. package/dist/protocol/compatibility.js +160 -0
  42. package/dist/protocol/compatibility.js.map +1 -0
  43. package/dist/protocol/errors.d.ts +24 -0
  44. package/dist/protocol/errors.d.ts.map +1 -0
  45. package/dist/protocol/errors.js +77 -0
  46. package/dist/protocol/errors.js.map +1 -0
  47. package/dist/protocol/index.d.ts +982 -0
  48. package/dist/protocol/index.d.ts.map +1 -0
  49. package/dist/protocol/index.js +56 -0
  50. package/dist/protocol/index.js.map +1 -0
  51. package/dist/protocol/validation.d.ts +94 -0
  52. package/dist/protocol/validation.d.ts.map +1 -0
  53. package/dist/protocol/validation.js +1871 -0
  54. package/dist/protocol/validation.js.map +1 -0
  55. package/dist/protocol/version.d.ts +7 -0
  56. package/dist/protocol/version.d.ts.map +1 -0
  57. package/dist/protocol/version.js +9 -0
  58. package/dist/protocol/version.js.map +1 -0
  59. package/dist/react/chat.d.ts +34 -0
  60. package/dist/react/chat.d.ts.map +1 -0
  61. package/dist/react/chat.js +23 -0
  62. package/dist/react/chat.js.map +1 -0
  63. package/dist/react/components.d.ts +96 -0
  64. package/dist/react/components.d.ts.map +1 -0
  65. package/dist/react/components.js +1300 -0
  66. package/dist/react/components.js.map +1 -0
  67. package/dist/react/context.d.ts +259 -0
  68. package/dist/react/context.d.ts.map +1 -0
  69. package/dist/react/context.js +359 -0
  70. package/dist/react/context.js.map +1 -0
  71. package/dist/react/headless.d.ts +3 -0
  72. package/dist/react/headless.d.ts.map +1 -0
  73. package/dist/react/headless.js +3 -0
  74. package/dist/react/headless.js.map +1 -0
  75. package/dist/react/index.d.ts +6 -0
  76. package/dist/react/index.d.ts.map +1 -0
  77. package/dist/react/index.js +6 -0
  78. package/dist/react/index.js.map +1 -0
  79. package/dist/react/root.d.ts +58 -0
  80. package/dist/react/root.d.ts.map +1 -0
  81. package/dist/react/root.js +151 -0
  82. package/dist/react/root.js.map +1 -0
  83. package/dist/react/streaming-text.d.ts +19 -0
  84. package/dist/react/streaming-text.d.ts.map +1 -0
  85. package/dist/react/streaming-text.js +259 -0
  86. package/dist/react/streaming-text.js.map +1 -0
  87. package/dist/react/styles.css +1477 -0
  88. 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.