@agent-native/core 0.175.1 → 0.175.2-nightly-20260826165737
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/corpus/README.md +1 -1
- package/corpus/templates/clips/app/components/player/video-player.tsx +5 -3
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1 -1
- package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +3 -2
- package/corpus/templates/design/.generated/bridge/zoom.generated.ts +8 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +46 -10
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +89 -63
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +3 -1
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +8 -2
- package/corpus/templates/design/app/components/design/bridge/zoom.bridge.ts +11 -2
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -4
- package/corpus/templates/design/app/components/design/multi-screen/zoom-gesture.ts +19 -63
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +2 -1
- package/corpus/templates/design/shared/canvas-math.ts +11 -1
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +44 -18
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +44 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +77 -63
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +3 -1
- package/corpus/templates/slides/changelog/2026-08-26-thumbnail-arrow-keys-now-navigate-slides-after-selection.md +6 -0
- package/dist/client/embed-auth.js +4 -2
- package/dist/client/hooks/index.d.ts +1 -0
- package/dist/client/hooks/index.js +1 -0
- package/dist/client/use-pinch-zoom.js +17 -4
- package/dist/client/zoom-gesture.d.ts +74 -0
- package/dist/client/zoom-gesture.js +100 -0
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +5 -5
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/builder-browser.d.ts +13 -13
- package/dist/server/builder-browser.js +46 -15
- package/dist/server/builder-oauth.d.ts +12 -0
- package/dist/server/builder-oauth.js +13 -2
- package/dist/server/core-routes-plugin.js +54 -19
- package/dist/server/embed-session.js +1 -1
- package/dist/server/security-headers.d.ts +3 -0
- package/dist/server/security-headers.js +10 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/vite/client.js +2 -0
- package/docs/content/template-chat-developers.mdx +100 -13
- package/docs/content/template-chat-first-edits.mdx +5 -5
- package/docs/content/template-chat.mdx +84 -36
- package/package.json +3 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assertBodySize, defineEventHandler, setResponseStatus, setResponseHeader, getMethod, getHeader, getRequestURL, getRequestIP, readRawBody, } from "h3";
|
|
1
|
+
import { assertBodySize, defineEventHandler, setResponseStatus, setResponseHeader, getMethod, getHeader, getRequestURL, getRequestIP, readRawBody, getCookie, setCookie, deleteCookie, } from "h3";
|
|
2
2
|
import { readMultipartFormData } from "h3";
|
|
3
3
|
import { DEFAULT_MODEL } from "../agent/default-model.js";
|
|
4
4
|
import { registerBuiltinEngines } from "../agent/engine/builtin.js";
|
|
@@ -41,8 +41,8 @@ import { createAgentEngineApiKeyHandler } from "./agent-engine-api-key-route.js"
|
|
|
41
41
|
import { readAnalyticsClientPlatformHeader, readBrowserSessionIdHeader, } from "./agent-run-context.js";
|
|
42
42
|
import { getConfiguredAppBasePath, stripAppBasePath } from "./app-base-path.js";
|
|
43
43
|
import { getSession } from "./auth.js";
|
|
44
|
-
import { BUILDER_CONNECT_PARAM, BUILDER_ENV_KEYS, BUILDER_OPENER_PARAM, BUILDER_RELAY_FLOW_HEADER, BUILDER_RELAY_SIGNATURE_HEADER, BUILDER_RELAY_STATE_PARAM, BUILDER_RELAY_TIMESTAMP_HEADER, appendBuilderConnectToken, builderConnectTrackingProperties, createBuilderConnectState, createBuilderBrowserCallbackErrorPage, createBuilderBrowserCallbackPage, createBuilderRelayRequest, getBuilderConnectTrackingParams, getBuilderBrowserOriginForEvent, getBuilderBrowserStatusForEvent, isBuilderConnectCallbackUrlAllowed, isSignedBuilderConnectState, normalizeBuilderAgentContext, resolveBuilderBranchProjectId, resolveBuilderConnectCallbackUrl, resolveBuilderPreviewRelayParentOrigin, runBuilderAgent, verifyBuilderRelayRequest, verifyBuilderPreviewRelayStateForCallback, verifyBuilderConnectTokenAndGetOwner, } from "./builder-browser.js";
|
|
45
|
-
import { BUILDER_OAUTH_SCOPE, deleteBuilderOAuthSession,
|
|
44
|
+
import { BUILDER_CONNECT_PARAM, BUILDER_CONNECT_STATE_COOKIE, BUILDER_ENV_KEYS, BUILDER_OPENER_PARAM, BUILDER_RELAY_FLOW_HEADER, BUILDER_RELAY_SIGNATURE_HEADER, BUILDER_RELAY_STATE_PARAM, BUILDER_RELAY_TIMESTAMP_HEADER, appendBuilderConnectToken, appendBuilderConnectStateCookie, builderConnectTrackingProperties, createBuilderConnectState, createBuilderBrowserCallbackErrorPage, createBuilderBrowserCallbackPage, createBuilderRelayRequest, getBuilderConnectTrackingParams, getBuilderBrowserOriginForEvent, getBuilderBrowserStatusForEvent, isBuilderConnectCallbackUrlAllowed, isSignedBuilderConnectState, normalizeBuilderAgentContext, resolveBuilderBranchProjectId, resolveBuilderConnectCallbackUrl, resolveBuilderConnectCallbackState, resolveBuilderPreviewRelayParentOrigin, removeBuilderConnectStateCookie, runBuilderAgent, verifyBuilderRelayRequest, verifyBuilderPreviewRelayStateForCallback, verifyBuilderConnectTokenAndGetOwner, } from "./builder-browser.js";
|
|
45
|
+
import { BUILDER_OAUTH_SCOPE, deleteBuilderOAuthSession, exchangeBuilderOAuthAuthorization, hasBuilderOAuthSession, resolveBuilderOAuthRequestAccess, saveBuilderOAuthCredentials, startBuilderOAuthAuthorization, } from "./builder-oauth.js";
|
|
46
46
|
import { captureError, registerErrorCaptureProvider } from "./capture-error.js";
|
|
47
47
|
import { resolveCoreRoutesMcpOptions, } from "./core-routes/mcp-connect-options.js";
|
|
48
48
|
import { getAllowedCorsOrigin, readCorsAllowedOrigins, } from "./cors-origins.js";
|
|
@@ -1837,12 +1837,10 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
1837
1837
|
// request with the navigation context. We allow `same-origin` or
|
|
1838
1838
|
// `none` (typed/bookmark/extension); cross-site / same-site without
|
|
1839
1839
|
// a valid connect token are rejected.
|
|
1840
|
-
// 3. Pending row keyed by signed OAuth state
|
|
1841
|
-
//
|
|
1842
|
-
//
|
|
1843
|
-
//
|
|
1844
|
-
// cross-site and then trick the victim into completing an
|
|
1845
|
-
// attacker-initiated authorization flow.
|
|
1840
|
+
// 3. Pending row keyed by signed OAuth state plus a host-only cookie —
|
|
1841
|
+
// Builder can omit the callback query, but it cannot read or forge
|
|
1842
|
+
// the cookie. The callback still requires the matching session,
|
|
1843
|
+
// pending row, and a successful PKCE exchange before persistence.
|
|
1846
1844
|
getH3App(nitroApp).use(`${P}/builder/connect`, defineEventHandler(async (event) => {
|
|
1847
1845
|
const ownerContext = await resolveBuilderOwnerContext(event, "connect");
|
|
1848
1846
|
const ownerEmail = ownerContext.email;
|
|
@@ -1913,7 +1911,8 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
1913
1911
|
catch {
|
|
1914
1912
|
// No prior error row — fine
|
|
1915
1913
|
}
|
|
1916
|
-
const
|
|
1914
|
+
const state = createBuilderConnectState();
|
|
1915
|
+
const callbackUrl = resolveBuilderConnectCallbackUrl(event, state);
|
|
1917
1916
|
if (!callbackUrl ||
|
|
1918
1917
|
!isBuilderConnectCallbackUrlAllowed(callbackUrl, event)) {
|
|
1919
1918
|
const msg = "This deployment cannot start Builder OAuth from the current origin.";
|
|
@@ -1940,7 +1939,6 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
1940
1939
|
parentOrigin: getBuilderBrowserOriginForEvent(event),
|
|
1941
1940
|
});
|
|
1942
1941
|
}
|
|
1943
|
-
const state = createBuilderConnectState();
|
|
1944
1942
|
// The standard OAuth client discovers Builder's protected-resource
|
|
1945
1943
|
// metadata, dynamically registers, and creates its S256 verifier.
|
|
1946
1944
|
// Persist that opaque protocol state encrypted and consume it once.
|
|
@@ -1964,6 +1962,13 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
1964
1962
|
tracking: connectTracking,
|
|
1965
1963
|
});
|
|
1966
1964
|
await purgeExpiredBuilderConnectPendingStates().catch(() => 0); // coercion-ok: connect already persisted the new pending row; purge of abandoned rows must not fail OAuth start
|
|
1965
|
+
setCookie(event, BUILDER_CONNECT_STATE_COOKIE, appendBuilderConnectStateCookie(getCookie(event, BUILDER_CONNECT_STATE_COOKIE), state), {
|
|
1966
|
+
httpOnly: true,
|
|
1967
|
+
secure: callbackUrl.startsWith("https://"),
|
|
1968
|
+
sameSite: "lax",
|
|
1969
|
+
path: "/",
|
|
1970
|
+
maxAge: Math.ceil(BUILDER_CONNECT_PENDING_TTL_MS / 1_000),
|
|
1971
|
+
});
|
|
1967
1972
|
}
|
|
1968
1973
|
catch (err) {
|
|
1969
1974
|
await trackBuilderLifecycle(event, "builder connect failed", ownerEmail, {
|
|
@@ -2243,7 +2248,11 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
2243
2248
|
setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
|
|
2244
2249
|
return createBuilderBrowserCallbackPage(`${relayParentOrigin}${relayPayload.basePath || "/"}`, { parentOrigin: relayParentOrigin });
|
|
2245
2250
|
}
|
|
2246
|
-
|
|
2251
|
+
// Builder sometimes drops the top-level OAuth state. Recover it
|
|
2252
|
+
// from the host-only cookie set by /builder/connect; the pending row
|
|
2253
|
+
// and authenticated session still bind it to this account.
|
|
2254
|
+
const queryState = requestUrl.searchParams.get("state");
|
|
2255
|
+
const state = resolveBuilderConnectCallbackState(queryState, getCookie(event, BUILDER_CONNECT_STATE_COOKIE));
|
|
2247
2256
|
const parentOrigin = getBuilderBrowserOriginForEvent(event);
|
|
2248
2257
|
const fail = async (status, message, ownerEmail, reason, tracking = {}) => {
|
|
2249
2258
|
if (ownerEmail) {
|
|
@@ -2282,7 +2291,7 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
2282
2291
|
const redirectUri = typeof pending.redirectUri === "string"
|
|
2283
2292
|
? pending.redirectUri
|
|
2284
2293
|
: null;
|
|
2285
|
-
const expectedRedirectUri = resolveBuilderConnectCallbackUrl(event);
|
|
2294
|
+
const expectedRedirectUri = resolveBuilderConnectCallbackUrl(event, state);
|
|
2286
2295
|
if (!ownerEmail ||
|
|
2287
2296
|
!isBuilderConnectCallbackOwner(ownerEmail, session?.email) ||
|
|
2288
2297
|
Date.now() >= expiresAt ||
|
|
@@ -2296,10 +2305,6 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
2296
2305
|
}
|
|
2297
2306
|
return fail(403, "Builder connect callback could not be verified. Restart the connection.", ownerEmail ?? undefined, "callback_verification_failed", tracking);
|
|
2298
2307
|
}
|
|
2299
|
-
const consumed = await consumeBuilderConnectPendingState(state);
|
|
2300
|
-
if (!consumed) {
|
|
2301
|
-
return fail(403, "No active Builder connect flow found. Restart the connection from Settings.", ownerEmail, "callback_verification_failed", tracking);
|
|
2302
|
-
}
|
|
2303
2308
|
const denied = requestUrl.searchParams.get("error");
|
|
2304
2309
|
const code = requestUrl.searchParams.get("code");
|
|
2305
2310
|
const iss = requestUrl.searchParams.get("iss") ?? undefined;
|
|
@@ -2308,11 +2313,11 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
2308
2313
|
? "Builder connection was cancelled."
|
|
2309
2314
|
: "Builder did not return an authorization code.", ownerEmail, denied ? "authorization_denied" : "missing_code", tracking);
|
|
2310
2315
|
}
|
|
2316
|
+
let credentials;
|
|
2311
2317
|
try {
|
|
2312
2318
|
const oauthFlow = JSON.parse(decryptSecretValue(encryptedOAuthFlow));
|
|
2313
|
-
await
|
|
2319
|
+
credentials = await exchangeBuilderOAuthAuthorization({
|
|
2314
2320
|
ownerEmail,
|
|
2315
|
-
orgId: typeof consumed.orgId === "string" ? consumed.orgId : undefined,
|
|
2316
2321
|
code,
|
|
2317
2322
|
iss,
|
|
2318
2323
|
pending: oauthFlow,
|
|
@@ -2321,6 +2326,36 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
2321
2326
|
catch {
|
|
2322
2327
|
return fail(502, "Builder could not exchange the authorization code. Restart the connection.", ownerEmail, "code_exchange_failed", tracking);
|
|
2323
2328
|
}
|
|
2329
|
+
// PKCE proves the callback belongs to this flow before its pending
|
|
2330
|
+
// row is consumed. Persist first so a transient credential-store
|
|
2331
|
+
// failure does not strand an otherwise valid pending flow.
|
|
2332
|
+
try {
|
|
2333
|
+
await saveBuilderOAuthCredentials({
|
|
2334
|
+
ownerEmail,
|
|
2335
|
+
orgId: typeof pending.orgId === "string" ? pending.orgId : undefined,
|
|
2336
|
+
credentials,
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
catch {
|
|
2340
|
+
return fail(500, "Builder credentials could not be saved. Restart the connection.", ownerEmail, "credential_write_failed", tracking);
|
|
2341
|
+
}
|
|
2342
|
+
const consumed = await consumeBuilderConnectPendingState(state);
|
|
2343
|
+
if (!consumed) {
|
|
2344
|
+
return fail(403, "No active Builder connect flow found. Restart the connection from Settings.", ownerEmail, "callback_verification_failed", tracking);
|
|
2345
|
+
}
|
|
2346
|
+
const remainingStates = removeBuilderConnectStateCookie(getCookie(event, BUILDER_CONNECT_STATE_COOKIE), state);
|
|
2347
|
+
if (remainingStates) {
|
|
2348
|
+
setCookie(event, BUILDER_CONNECT_STATE_COOKIE, remainingStates, {
|
|
2349
|
+
httpOnly: true,
|
|
2350
|
+
secure: expectedRedirectUri.startsWith("https://"),
|
|
2351
|
+
sameSite: "lax",
|
|
2352
|
+
path: "/",
|
|
2353
|
+
maxAge: Math.ceil(BUILDER_CONNECT_PENDING_TTL_MS / 1_000),
|
|
2354
|
+
});
|
|
2355
|
+
}
|
|
2356
|
+
else {
|
|
2357
|
+
deleteCookie(event, BUILDER_CONNECT_STATE_COOKIE, { path: "/" });
|
|
2358
|
+
}
|
|
2324
2359
|
try {
|
|
2325
2360
|
await Promise.all([
|
|
2326
2361
|
deleteSetting("builder-disconnected").catch(() => false), // coercion-ok: best-effort cleanup after successful OAuth save
|
|
@@ -761,7 +761,7 @@ export async function resolveEmbedSessionFromRequest(event) {
|
|
|
761
761
|
if (candidate.source === "query" && candidate.token) {
|
|
762
762
|
try {
|
|
763
763
|
setEmbedSessionCookie(event, candidate.token);
|
|
764
|
-
setResponseHeader(event, "Referrer-Policy", "
|
|
764
|
+
setResponseHeader(event, "Referrer-Policy", "same-origin");
|
|
765
765
|
}
|
|
766
766
|
catch {
|
|
767
767
|
// Some tests and edge runtimes expose read-only request shims. The
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
* - `Referrer-Policy: strict-origin-when-cross-origin` — strips path/query
|
|
20
20
|
* from outbound Referer headers when the request crosses origin, so a
|
|
21
21
|
* public-share viewer's outbound link clicks never leak the share token.
|
|
22
|
+
* Validated embed-session responses tighten this to `same-origin`, which
|
|
23
|
+
* sends nothing cross-origin at all while keeping the same-origin Referer
|
|
24
|
+
* that parent-vs-child app checks depend on.
|
|
22
25
|
* - `Permissions-Policy: camera=*, microphone=(self), geolocation=(),
|
|
23
26
|
* screen-wake-lock=()` — allows microphone access for composer dictation
|
|
24
27
|
* and camera access for media-capture UI (the Clips recorder, and the
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
* - `Referrer-Policy: strict-origin-when-cross-origin` — strips path/query
|
|
20
20
|
* from outbound Referer headers when the request crosses origin, so a
|
|
21
21
|
* public-share viewer's outbound link clicks never leak the share token.
|
|
22
|
+
* Validated embed-session responses tighten this to `same-origin`, which
|
|
23
|
+
* sends nothing cross-origin at all while keeping the same-origin Referer
|
|
24
|
+
* that parent-vs-child app checks depend on.
|
|
22
25
|
* - `Permissions-Policy: camera=*, microphone=(self), geolocation=(),
|
|
23
26
|
* screen-wake-lock=()` — allows microphone access for composer dictation
|
|
24
27
|
* and camera access for media-capture UI (the Clips recorder, and the
|
|
@@ -112,7 +115,13 @@ export function createSecurityHeadersMiddleware() {
|
|
|
112
115
|
const iframeNavigationRequest = isIframeNavigationRequest(event);
|
|
113
116
|
const requestOrigin = getHeader(event, "origin");
|
|
114
117
|
setResponseHeader(event, "X-Content-Type-Options", "nosniff");
|
|
115
|
-
setResponseHeader(event, "Referrer-Policy",
|
|
118
|
+
setResponseHeader(event, "Referrer-Policy",
|
|
119
|
+
/**
|
|
120
|
+
* Dispatch is served as an embed, and the parent page's path cannot be forged by a
|
|
121
|
+
* same-origin child app, so stripping it made minting an app session from Dispatch
|
|
122
|
+
* impossible.
|
|
123
|
+
*/
|
|
124
|
+
embedFrameRequest ? "same-origin" : "strict-origin-when-cross-origin");
|
|
116
125
|
setResponseHeader(event, "Permissions-Policy", PERMISSIONS_POLICY);
|
|
117
126
|
setResponseHeader(event, "Cross-Origin-Opener-Policy", "same-origin");
|
|
118
127
|
if (embedFrameRequest || iframeNavigationRequest) {
|
package/dist/vite/client.js
CHANGED
|
@@ -917,6 +917,7 @@ const CORE_CLIENT_SUBPATHS = [
|
|
|
917
917
|
// (and its transitive ~650-700 KB gzip chat stack) onto the critical path.
|
|
918
918
|
"@agent-native/core/client/api-path",
|
|
919
919
|
"@agent-native/core/client/clipboard",
|
|
920
|
+
"@agent-native/core/client/zoom-gesture",
|
|
920
921
|
"@agent-native/core/blocks",
|
|
921
922
|
"@agent-native/core/blocks/server",
|
|
922
923
|
"@agent-native/core/client/extensions",
|
|
@@ -1216,6 +1217,7 @@ function getCoreSourceAliases(cwd) {
|
|
|
1216
1217
|
// Dedicated thin subpath — only the URL helpers, no chat stack in the closure.
|
|
1217
1218
|
"@agent-native/core/client/api-path": path.join(coreSrc, "client/api-path.ts"),
|
|
1218
1219
|
"@agent-native/core/client/clipboard": path.join(coreSrc, "client/clipboard.ts"),
|
|
1220
|
+
"@agent-native/core/client/zoom-gesture": path.join(coreSrc, "client/zoom-gesture.ts"),
|
|
1219
1221
|
"@agent-native/core/blocks": path.join(coreSrc, "client/blocks/index.ts"),
|
|
1220
1222
|
"@agent-native/core/blocks/server": path.join(coreSrc, "client/blocks/server.ts"),
|
|
1221
1223
|
"@agent-native/core/client/extensions": path.join(coreSrc, "client/extensions/index.ts"),
|
|
@@ -1,19 +1,81 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Chat
|
|
3
|
-
description: "
|
|
2
|
+
title: "Chat: Developer Guide"
|
|
3
|
+
description: "Quick start, the action inventory, core tables, auth, and the Database/Observability/Extensions admin pages that ship by default with the Chat template."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Developer Guide
|
|
7
7
|
|
|
8
|
-
This page is for developers
|
|
8
|
+
This page is for developers running or extending the Chat template: the
|
|
9
|
+
quick start, every built-in action, the core tables it runs on, how auth is
|
|
10
|
+
configured, and the admin pages — Database, Observability, and Extensions —
|
|
11
|
+
that ship by default whether or not you ever open them. See
|
|
12
|
+
[Chat](/docs/template-chat) for what the app does.
|
|
9
13
|
|
|
10
|
-
##
|
|
14
|
+
## Quick start {#quick-start}
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
This walks through running Chat from nothing installed to a live
|
|
17
|
+
conversation with the agent. The commands are identical whether you're in
|
|
18
|
+
Terminal on macOS or PowerShell/Command Prompt on Windows, they're plain
|
|
19
|
+
Node.js tooling.
|
|
13
20
|
|
|
14
|
-
|
|
21
|
+
<Steps>
|
|
22
|
+
|
|
23
|
+
### Create the app
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx @agent-native/core@latest create my-chat-app --standalone --template chat
|
|
27
|
+
cd my-chat-app
|
|
28
|
+
pnpm install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This needs [Node.js](https://nodejs.org) 22 or later and
|
|
32
|
+
[pnpm](https://pnpm.io) installed first. See [Getting
|
|
33
|
+
started](/docs/getting-started) if you haven't installed either yet.
|
|
34
|
+
|
|
35
|
+
### Start the dev server
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pnpm dev
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The app opens at `http://localhost:8080`. If it doesn't open automatically,
|
|
42
|
+
visit that URL in your browser.
|
|
43
|
+
|
|
44
|
+
### Sign in and connect an LLM
|
|
45
|
+
|
|
46
|
+
On the Welcome screen, select **Continue as local dev** — no email or
|
|
47
|
+
password needed for local development. Then connect an LLM: select
|
|
48
|
+
**Connect Builder.io** for free credits, or **Custom keys** to add an
|
|
49
|
+
Anthropic/OpenAI key or a local Ollama model. Chat ships with no domain data
|
|
50
|
+
to seed, so once an LLM is connected there's nothing else to set up before
|
|
51
|
+
you can start chatting.
|
|
52
|
+
|
|
53
|
+
</Steps>
|
|
54
|
+
|
|
55
|
+
## Action inventory {#actions}
|
|
15
56
|
|
|
16
|
-
|
|
57
|
+
Every operation is a TypeScript file in `actions/`, auto-mounted at
|
|
58
|
+
`POST /_agent-native/actions/:name`.
|
|
59
|
+
|
|
60
|
+
| Action | What it does |
|
|
61
|
+
| ------------- | ----------------------------------------------------------------------- |
|
|
62
|
+
| `hello` | Example action; returns a greeting. Replace it or add actions beside it |
|
|
63
|
+
| `view-screen` | Standard context action; reads the current view back for the agent |
|
|
64
|
+
| `navigate` | Standard navigation action; moves the UI to a route |
|
|
65
|
+
|
|
66
|
+
`server/plugins/agent-chat.ts` is where the chat runtime itself is
|
|
67
|
+
configured: it registers every action in `actions/` as a callable tool
|
|
68
|
+
(`loadActionsFromStaticRegistry`), resolves the current org for scoping
|
|
69
|
+
(`resolveOrgId`), sets the system prompt, and declares which tools the model
|
|
70
|
+
sees on the very first turn (`initialToolNames`) — see [Your First Feature in
|
|
71
|
+
Chat](/docs/template-chat-first-edits#first-edits) for what that last part
|
|
72
|
+
means when you add a new action.
|
|
73
|
+
|
|
74
|
+
## Core tables and live sync {#tables}
|
|
75
|
+
|
|
76
|
+
Chat adds no domain tables of its own (see [What ships](/docs/template-chat#what-ships)). It runs entirely on the framework's core tables: chat threads and messages, `application_state`, `settings`, sessions, resources, and run history.
|
|
77
|
+
|
|
78
|
+
`useDbSync()` is already wired into the app shell: when the agent (or anyone else) writes to SQL, the client receives the change over SSE, or the 2-second polling fallback, and invalidates the matching React Query caches — no manual refresh, no websocket you have to manage yourself. See [`useDbSync`](/docs/client-data#usedbsync) for the full hook API.
|
|
17
79
|
|
|
18
80
|
## Auth {#auth}
|
|
19
81
|
|
|
@@ -78,11 +140,36 @@ Three routes are mounted whether or not your app ever links to them:
|
|
|
78
140
|
|
|
79
141
|
**Extensions** are sandboxed Alpine.js mini-apps your users can ask the agent to build inside the running app — a custom widget or checklist, no deploy required. Chat mounts the routes that view and run them (`/extensions/:id`) by default, even before you or your users create one; `/extensions` itself just redirects into the Extensions tab of Settings rather than showing its own list. See [Extensions](/docs/extensions) for what they can and cannot do.
|
|
80
142
|
|
|
143
|
+
## Customizing it {#customizing}
|
|
144
|
+
|
|
145
|
+
Every part of the app is editable source. Start here:
|
|
146
|
+
|
|
147
|
+
- `actions/` — add a new file with `defineAction` to expose new capability
|
|
148
|
+
to both the agent and the frontend.
|
|
149
|
+
- `app/routes/` — the UI. The app uses file-system routing (`flatRoutes()`
|
|
150
|
+
in `app/routes.ts`), so adding a route file is enough to mount it.
|
|
151
|
+
- `server/db/schema.ts` — add your own tables with Drizzle once you outgrow
|
|
152
|
+
the core tables above. Keep the code dialect-agnostic so the app runs on
|
|
153
|
+
SQLite, Postgres, Turso, D1, and Neon.
|
|
154
|
+
- `AGENTS.md` — agent instructions. Update this when you teach the agent new
|
|
155
|
+
capabilities or conventions.
|
|
156
|
+
- `.agents/skills/` — detailed patterns the agent follows.
|
|
157
|
+
|
|
158
|
+
If you add a feature, remember to update all four areas: UI, action, skill
|
|
159
|
+
or AGENTS.md entry, and any application state the agent needs to see. That
|
|
160
|
+
is what keeps the agent and the UI in parity.
|
|
161
|
+
|
|
81
162
|
## What's next
|
|
82
163
|
|
|
83
|
-
- [**Chat
|
|
84
|
-
- [**Your
|
|
85
|
-
|
|
86
|
-
- [**
|
|
164
|
+
- [**Chat**](/docs/template-chat) — what ships by default and when to pick it
|
|
165
|
+
- [**Your First Feature in Chat**](/docs/template-chat-first-edits) — the
|
|
166
|
+
starter chat route, annotated, plus a full feature walkthrough
|
|
167
|
+
- [**Actions**](/docs/actions-overview) — the action system this template is
|
|
168
|
+
built on
|
|
169
|
+
- [**Database**](/docs/server-database) — connecting a real database and the
|
|
170
|
+
portable-SQL model
|
|
171
|
+
- [**Agent Observability**](/docs/observability) — what the dashboard tracks
|
|
172
|
+
and how
|
|
87
173
|
- [**Extensions**](/docs/extensions) — building mini-apps inside a template
|
|
88
|
-
- [**Authentication**](/docs/authentication) — sessions, organizations, and
|
|
174
|
+
- [**Authentication**](/docs/authentication) — sessions, organizations, and
|
|
175
|
+
protected routes
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Your
|
|
2
|
+
title: "Chat: Your First Feature"
|
|
3
3
|
description: "The one file that renders Chat's starter screen, what its real props do, and a full walkthrough of adding a feature end to end."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Your
|
|
6
|
+
# Your First Feature
|
|
7
7
|
|
|
8
8
|
This page is for developers extending the [Chat template](/docs/template-chat). It covers the single file that renders the starter chat screen, then walks through everything the agent typically touches when you ask for a real feature.
|
|
9
9
|
|
|
@@ -96,7 +96,7 @@ Most first features follow the same shape: a table, one or two actions, a route,
|
|
|
96
96
|
|
|
97
97
|
> Add a data model for `notes`. A note has an id, title, body, and owner. Render a notes page at `/notes`, add create/list actions, and keep chat able to create notes.
|
|
98
98
|
|
|
99
|
-
Chat ships with no `server/db/schema.ts` at all (see [What
|
|
99
|
+
Chat ships with no `server/db/schema.ts` at all (see [What ships](/docs/template-chat#what-ships)), so the first change is a new file, following the same `table`/`text`/`ownableColumns` shape every other template uses:
|
|
100
100
|
|
|
101
101
|
<Diff
|
|
102
102
|
id="doc-block-chat5"
|
|
@@ -139,7 +139,7 @@ Use this when your model orchestration already lives elsewhere, but you still wa
|
|
|
139
139
|
|
|
140
140
|
## What's next
|
|
141
141
|
|
|
142
|
-
- [**Chat
|
|
143
|
-
- [**Chat
|
|
142
|
+
- [**Chat**](/docs/template-chat) — what ships by default and when to pick it
|
|
143
|
+
- [**Chat: Developer Guide**](/docs/template-chat-developers) — quick start, actions, core tables, auth, and the admin pages
|
|
144
144
|
- [**Actions**](/docs/actions-overview) — the action system chat and UI both call
|
|
145
145
|
- [**Native Chat UI**](/docs/native-chat-ui) — chat surface primitives and runtime options
|
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Chat
|
|
2
|
+
title: "Chat"
|
|
3
3
|
description: "A minimal chat-first agent-native app: durable chat threads, actions, application state, live sync, auth, and room to add your own UI."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Chat
|
|
6
|
+
# Chat
|
|
7
7
|
|
|
8
|
-
Chat is the plainest agent-native starting point: a ChatGPT-style shell with
|
|
8
|
+
Chat is the plainest agent-native starting point: a ChatGPT-style shell with
|
|
9
|
+
chat at the center, a thread list, auth, and one example action, nothing
|
|
10
|
+
domain-specific. It's for developers who want a real, deployable app to build
|
|
11
|
+
their own agent and screens on top of, not a finished product for a specific
|
|
12
|
+
job.
|
|
9
13
|
|
|
10
|
-
If you want a finished domain product shape, start from
|
|
14
|
+
If you want a finished domain product shape, start from
|
|
15
|
+
[Calendar](/docs/template-calendar), [Mail](/docs/template-mail),
|
|
16
|
+
[Content](/docs/template-content), [Forms](/docs/template-forms),
|
|
17
|
+
[Analytics](/docs/template-analytics), or another domain template. If you
|
|
18
|
+
truly do not need a browser UI yet, see [Automation-First
|
|
19
|
+
Apps](/docs/pure-agent-apps).
|
|
20
|
+
|
|
21
|
+
<Cards columns={1}>
|
|
22
|
+
|
|
23
|
+
### [Try it out now →](https://chat.agent-native.com)
|
|
24
|
+
|
|
25
|
+
See Chat live: start a real conversation with the agent, no setup required.
|
|
26
|
+
|
|
27
|
+
</Cards>
|
|
11
28
|
|
|
12
29
|
<WireframeBlock id="doc-block-chat1">
|
|
13
30
|
<Screen
|
|
@@ -18,25 +35,40 @@ If you want a finished domain product shape, start from [Calendar](/docs/templat
|
|
|
18
35
|
/>
|
|
19
36
|
</WireframeBlock>
|
|
20
37
|
|
|
21
|
-
## What
|
|
38
|
+
## What ships {#what-ships}
|
|
22
39
|
|
|
23
|
-
|
|
24
|
-
- **Thread list in the app sidebar** so users can create, reopen, rename, pin, and archive chats.
|
|
25
|
-
- **Agent chat plugin** pre-configured so the chat talks to the built-in app-agent loop once your agent credentials are set.
|
|
26
|
-
- **Auth** via Better Auth — login, signup, sessions, organizations. See [Chat — runtime and admin surfaces](/docs/template-chat-developers#auth) for how sessions, orgs, and dev-mode email verification are configured.
|
|
27
|
-
- **Actions directory** with one example (`actions/hello.ts`) plus the standard `view-screen` and `navigate` actions.
|
|
28
|
-
- **The framework's core tables** for chat threads, application state, settings, sessions, resources, and run history — plus a Database admin page and an Observability dashboard mounted by default, whether or not you ever open them. See [Chat — runtime and admin surfaces](/docs/template-chat-developers).
|
|
29
|
-
- **Live sync** (`useDbSync`) already wired so UI auto-refreshes when the agent writes to SQL.
|
|
30
|
-
- **Extensions** routes mounted by default too, for sandboxed mini-apps your users build inside the chat later. See [Extensions](/docs/extensions).
|
|
31
|
-
- **AGENTS.md** with chat-first guidance for adding actions, routes, skills, and application state.
|
|
40
|
+
<Comparison>
|
|
32
41
|
|
|
33
|
-
|
|
42
|
+
### :green: Included
|
|
34
43
|
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
-
|
|
44
|
+
- Full-page chat on `/` using the framework chat surface and durable chat
|
|
45
|
+
threads
|
|
46
|
+
- Thread list in the app sidebar to create, reopen, rename, pin, and archive
|
|
47
|
+
chats
|
|
48
|
+
- The built-in app-agent loop, pre-configured for the chat plugin
|
|
49
|
+
- Auth via Better Auth: login, signup, sessions, organizations
|
|
50
|
+
- An actions directory with one example (`actions/hello.ts`) plus the
|
|
51
|
+
standard `view-screen` and `navigate` actions
|
|
52
|
+
- The framework's core tables for chat threads, application state, settings,
|
|
53
|
+
sessions, resources, and run history, plus a Database admin page and an
|
|
54
|
+
Observability dashboard, mounted whether or not you ever open them
|
|
55
|
+
- Live sync (`useDbSync`) already wired so the UI refreshes when the agent
|
|
56
|
+
writes to SQL
|
|
57
|
+
- Extensions routes mounted by default, for sandboxed mini-apps your users
|
|
58
|
+
build inside chat later
|
|
59
|
+
- AGENTS.md with chat-first guidance for adding actions, routes, skills, and
|
|
60
|
+
application state
|
|
38
61
|
|
|
39
|
-
|
|
62
|
+
### :red: Not included
|
|
63
|
+
|
|
64
|
+
- Domain tables or seed data
|
|
65
|
+
- Dashboards, lists, charts, forms, or provider integrations
|
|
66
|
+
- Domain-specific actions beyond the example stub
|
|
67
|
+
|
|
68
|
+
</Comparison>
|
|
69
|
+
|
|
70
|
+
That's the point. Chat is a thin, useful default shell for your own agent, not
|
|
71
|
+
a domain product pretending to be generic.
|
|
40
72
|
|
|
41
73
|
<Diagram id="doc-block-chat2" title="What ships in the Chat shell" summary={"A thin chat surface over the framework's standard runtime — actions, durable threads, live sync, and auth — with room to add your own UI."}>
|
|
42
74
|
|
|
@@ -104,34 +136,50 @@ That's the point. Chat is a thin, useful default shell for your own agent, not a
|
|
|
104
136
|
|
|
105
137
|
## When to pick it {#when-to-pick}
|
|
106
138
|
|
|
107
|
-
- **You want a basic app users can talk to immediately** and then extend with
|
|
108
|
-
|
|
109
|
-
- **You want
|
|
110
|
-
|
|
139
|
+
- **You want a basic app users can talk to immediately** and then extend with
|
|
140
|
+
actions and UI.
|
|
141
|
+
- **You want the default Agent-Native on-ramp**: chat first, then actions,
|
|
142
|
+
native results, and app pages.
|
|
143
|
+
- **You want to plug your own agent backend into a familiar chat UI** while
|
|
144
|
+
keeping Agent-Native's actions, state, auth, and deployment shape.
|
|
145
|
+
- **You are prototyping a custom internal tool** that does not match a domain
|
|
146
|
+
template.
|
|
111
147
|
|
|
112
|
-
##
|
|
148
|
+
## Get started {#get-started}
|
|
113
149
|
|
|
114
150
|
```bash
|
|
115
151
|
npx @agent-native/core@latest create my-chat-app --standalone --template chat
|
|
116
152
|
```
|
|
117
153
|
|
|
118
|
-
See [
|
|
119
|
-
|
|
120
|
-
|
|
154
|
+
See [Chat: Developer Guide](/docs/template-chat-developers#quick-start) for
|
|
155
|
+
install, first run, and connecting an LLM. For automation-first work with no
|
|
156
|
+
browser UI at all, scaffold with `--headless` instead:
|
|
121
157
|
|
|
122
158
|
```bash
|
|
123
159
|
npx @agent-native/core@latest create my-agent --headless
|
|
124
160
|
```
|
|
125
161
|
|
|
126
|
-
Use it for scheduled jobs, queues, CLI loops, or external-agent workflows
|
|
162
|
+
Use it for scheduled jobs, queues, CLI loops, or external-agent workflows
|
|
163
|
+
where chat and app pages are not useful yet. The key invariant stays the
|
|
164
|
+
same: actions are the shared surface for chat, UI, HTTP, MCP, A2A, and CLI.
|
|
165
|
+
See [Automation-First Apps](/docs/pure-agent-apps) for that path in depth.
|
|
127
166
|
|
|
128
167
|
## What's next
|
|
129
168
|
|
|
130
|
-
- [**Your
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
- [**
|
|
134
|
-
|
|
135
|
-
- [**
|
|
136
|
-
|
|
137
|
-
- [**
|
|
169
|
+
- [**Your First Feature in Chat**](/docs/template-chat-first-edits) — the
|
|
170
|
+
starter chat route, annotated, plus a full walkthrough of adding a real
|
|
171
|
+
feature
|
|
172
|
+
- [**Chat: Developer Guide**](/docs/template-chat-developers) — quick start,
|
|
173
|
+
actions, core tables, auth, and the admin pages that ship by default
|
|
174
|
+
- [**Getting Started**](/docs/getting-started) — build the chat-first path
|
|
175
|
+
from action to inline result to app page
|
|
176
|
+
- [**Templates**](/docs/cloneable-saas) — the Cloneable SaaS model, and every
|
|
177
|
+
domain template to start from instead
|
|
178
|
+
- [**Agent Surfaces**](/docs/agent-surfaces) — chat, inline UI, app pages,
|
|
179
|
+
embedded, automation, and external-agent patterns
|
|
180
|
+
- [**Actions**](/docs/actions-overview) — the action system chat and UI both
|
|
181
|
+
call
|
|
182
|
+
- [**Native Chat UI**](/docs/native-chat-ui) — chat surface primitives and
|
|
183
|
+
runtime options
|
|
184
|
+
- [**Automation-First Apps**](/docs/pure-agent-apps) — no-browser workflows
|
|
185
|
+
for jobs, queues, scripts, and external agents
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.175.
|
|
3
|
+
"version": "0.175.2-nightly-20260826165737",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -134,6 +134,7 @@
|
|
|
134
134
|
"./client/route-chunk-recovery": "./dist/client/route-chunk-recovery/index.js",
|
|
135
135
|
"./client/settings": "./dist/client/settings/index.js",
|
|
136
136
|
"./client/use-db-sync": "./dist/client/use-db-sync.js",
|
|
137
|
+
"./client/zoom-gesture": "./dist/client/zoom-gesture.js",
|
|
137
138
|
"./client/ui": "./dist/client/ui/index.js",
|
|
138
139
|
"./client/uploads": "./dist/client/uploads/index.js",
|
|
139
140
|
"./client/widgets": "./dist/client/widgets/index.js",
|
|
@@ -432,7 +433,7 @@
|
|
|
432
433
|
"yjs": "^13.6.32",
|
|
433
434
|
"zod": "^4.3.6",
|
|
434
435
|
"@agent-native/recap-cli": "0.5.15",
|
|
435
|
-
"@agent-native/toolkit": "^0.17.
|
|
436
|
+
"@agent-native/toolkit": "^0.17.2-nightly-20260826165737"
|
|
436
437
|
},
|
|
437
438
|
"devDependencies": {
|
|
438
439
|
"@ai-sdk/anthropic": "^3.0.71",
|