@agent-native/core 0.164.1 → 0.164.4
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/analytics/app/components/agents/FeatureFlagsFleetPanel.tsx +78 -19
- package/corpus/templates/analytics/app/lib/use-auto-focus-select.ts +4 -4
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +6 -0
- package/corpus/templates/analytics/app/routes/_index.tsx +3 -2
- package/corpus/templates/analytics/app/routes/adhoc.$id.tsx +7 -2
- package/corpus/templates/analytics/app/routes/dashboard.tsx +3 -2
- package/corpus/templates/analytics/app/routes/overview.tsx +3 -2
- package/corpus/templates/analytics/app/routes/traffic.tsx +3 -2
- package/corpus/templates/analytics/changelog/2026-08-18-verify-cross-app-feature-flag-changes.md +6 -0
- package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +196 -48
- package/corpus/templates/analytics/server/plugins/feature-flags.ts +5 -0
- package/corpus/templates/analytics/shared/feature-flags.ts +10 -0
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +5 -1
- package/corpus/templates/assets/app/routes/brand-kits._index.tsx +4 -1
- package/corpus/templates/assets/app/routes/libraries.tsx +4 -1
- package/corpus/templates/assets/app/routes/picker.tsx +4 -1
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +1 -1
- package/corpus/templates/clips/app/routes/_app.wispr.tsx +2 -1
- package/corpus/templates/clips/app/routes/_index.tsx +7 -11
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +3 -0
- package/corpus/templates/clips/changelog/2026-08-19-social-preview-video-frames.md +5 -0
- package/corpus/templates/clips/server/lib/slack-unfurls.ts +7 -13
- package/corpus/templates/clips/shared/share-meta.ts +67 -3
- package/corpus/templates/content/actions/list-content-databases.ts +95 -1
- package/corpus/templates/content/changelog/2026-08-11-content-mutations-delegated-from-verified-slack-dms-now-use-.md +6 -0
- package/corpus/templates/content/shared/api.ts +11 -0
- package/corpus/templates/design/app/routes/examples.tsx +2 -1
- package/corpus/templates/forms/app/routes/_index.tsx +3 -2
- package/corpus/templates/mail/app/routes/_index.tsx +3 -2
- package/corpus/templates/tasks/app/routes/_index.tsx +2 -1
- package/dist/a2a/artifact-response.d.ts +50 -0
- package/dist/a2a/artifact-response.js +266 -39
- package/dist/a2a/index.d.ts +2 -0
- package/dist/a2a/index.js +1 -0
- package/dist/cli/code-agent-executor.js +1 -1
- package/dist/deploy/build.js +10 -4
- package/dist/integrations/adapters/slack.js +58 -7
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-chat/action-filters-a2a.d.ts +2 -1
- package/dist/server/agent-chat/action-filters-a2a.js +10 -2
- package/dist/server/agent-chat-plugin.js +33 -11
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/ssr-handler.js +13 -4
- package/dist/shared/cache-control.d.ts +22 -0
- package/dist/shared/cache-control.js +25 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/docs/content/drop-in-agent.mdx +4 -4
- package/docs/content/faq.mdx +15 -15
- package/docs/content/getting-started.mdx +173 -41
- package/docs/content/key-concepts.mdx +10 -10
- package/docs/content/using-your-agent.mdx +2 -2
- package/docs/content/what-is-agent-native.mdx +79 -228
- package/package.json +1 -1
|
@@ -199,17 +199,19 @@ export function createSerializedA2ATaskStatusWriter(taskId, writeStatus = update
|
|
|
199
199
|
const A2A_ACTIVITY_CHECKPOINT_MIN_INTERVAL_MS = 2_000;
|
|
200
200
|
export async function resolveA2ARecoverableArtifactSecret(orgId = getRequestOrgId()) {
|
|
201
201
|
const globalSecret = process.env.A2A_SECRET?.trim();
|
|
202
|
-
if (
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
202
|
+
if (orgId) {
|
|
203
|
+
try {
|
|
204
|
+
const { getOrgA2ASecret } = await import("../org/context.js");
|
|
205
|
+
const orgSecret = (await getOrgA2ASecret(orgId))?.trim();
|
|
206
|
+
if (orgSecret)
|
|
207
|
+
return orgSecret;
|
|
208
|
+
// coercion-ok: undefined is the fail-closed result when organization secret lookup throws
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
212
213
|
}
|
|
214
|
+
return globalSecret || undefined;
|
|
213
215
|
}
|
|
214
216
|
export function buildLeanRunPolicyPrompt(codeEditingSurfaceRestriction, prodCodeExecPromptNote) {
|
|
215
217
|
return codeEditingSurfaceRestriction + prodCodeExecPromptNote;
|
|
@@ -1619,6 +1621,7 @@ export function createAgentChatPlugin(options) {
|
|
|
1619
1621
|
baseUrl: artifactBaseUrl,
|
|
1620
1622
|
includePersistedArtifactMarker: true,
|
|
1621
1623
|
persistedArtifactSecret: recoverableArtifactSecret,
|
|
1624
|
+
delegatedTaskId: context.taskId,
|
|
1622
1625
|
})
|
|
1623
1626
|
: null;
|
|
1624
1627
|
if (recoverableArtifactText &&
|
|
@@ -1723,7 +1726,12 @@ export function createAgentChatPlugin(options) {
|
|
|
1723
1726
|
};
|
|
1724
1727
|
return;
|
|
1725
1728
|
}
|
|
1726
|
-
const { responseText, finalText } = assembleA2AFinalResponse(a2aEvents, a2aToolResults, {
|
|
1729
|
+
const { responseText, finalText, mutationReceipts } = assembleA2AFinalResponse(a2aEvents, a2aToolResults, {
|
|
1730
|
+
event: context.event,
|
|
1731
|
+
outcome: a2aOutcome,
|
|
1732
|
+
persistedArtifactSecret: recoverableArtifactSecret,
|
|
1733
|
+
delegatedTaskId: context.taskId,
|
|
1734
|
+
});
|
|
1727
1735
|
console.log(`[A2A] Loop complete. Text: ${responseText.slice(0, 100)}...`);
|
|
1728
1736
|
// Yield the final accumulated text
|
|
1729
1737
|
yield {
|
|
@@ -1734,6 +1742,18 @@ export function createAgentChatPlugin(options) {
|
|
|
1734
1742
|
type: "text",
|
|
1735
1743
|
text: finalText,
|
|
1736
1744
|
},
|
|
1745
|
+
...(mutationReceipts.length > 0
|
|
1746
|
+
? [
|
|
1747
|
+
{
|
|
1748
|
+
type: "data",
|
|
1749
|
+
data: {
|
|
1750
|
+
kind: "agent-native/mutation-receipts",
|
|
1751
|
+
version: 1,
|
|
1752
|
+
receipts: mutationReceipts,
|
|
1753
|
+
},
|
|
1754
|
+
},
|
|
1755
|
+
]
|
|
1756
|
+
: []),
|
|
1737
1757
|
],
|
|
1738
1758
|
};
|
|
1739
1759
|
},
|
|
@@ -2000,8 +2020,10 @@ export function createAgentChatPlugin(options) {
|
|
|
2000
2020
|
delegation: { protocol: "mcp" },
|
|
2001
2021
|
},
|
|
2002
2022
|
});
|
|
2023
|
+
const persistedArtifactSecret = await resolveA2ARecoverableArtifactSecret();
|
|
2003
2024
|
return assembleA2AFinalResponse(mcpEvents, mcpToolResults, {
|
|
2004
2025
|
outcome: mcpOutcome,
|
|
2026
|
+
persistedArtifactSecret,
|
|
2005
2027
|
}).finalText;
|
|
2006
2028
|
},
|
|
2007
2029
|
});
|
|
@@ -26,8 +26,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
expiresAt?: undefined;
|
|
27
27
|
ttlSeconds?: undefined;
|
|
28
28
|
} | {
|
|
29
|
-
error?: undefined;
|
|
30
29
|
token: string;
|
|
31
30
|
expiresAt: string;
|
|
32
31
|
ttlSeconds: number;
|
|
32
|
+
error?: undefined;
|
|
33
33
|
}>>;
|
|
@@ -18,7 +18,7 @@ import { defineEventHandler } from "h3";
|
|
|
18
18
|
*/
|
|
19
19
|
import { createRequestHandler } from "react-router";
|
|
20
20
|
import { isMcpPublicPath } from "../mcp/route-paths.js";
|
|
21
|
-
import { DEFAULT_SPECULATION_RULES_PATH, resolveSsrCacheHeaders, resolveSsrCacheKeyHeaders, } from "../shared/cache-control.js";
|
|
21
|
+
import { DEFAULT_SPECULATION_RULES_PATH, resolveSsrCacheHeaders, resolveSsrCacheKeyHeaders, SSR_QUERY_CACHE_KEY_HEADER, } from "../shared/cache-control.js";
|
|
22
22
|
import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, withAgentNativeSocialImageCacheBuster, } from "../shared/social-meta.js";
|
|
23
23
|
import { getAppBasePathFromViteEnv, stripAppBasePath as canonicalStripAppBasePath, } from "./app-base-path.js";
|
|
24
24
|
import { getAppOriginClientConfigScript } from "./app-origin-config.js";
|
|
@@ -204,6 +204,8 @@ function isSsrHtmlOrDataResponse(headers, status, pathname) {
|
|
|
204
204
|
* that contradicts that.
|
|
205
205
|
*/
|
|
206
206
|
function applyDefaultSsrCacheHeader(headers, status, pathname) {
|
|
207
|
+
const varyByQuery = headers.get(SSR_QUERY_CACHE_KEY_HEADER)?.trim().toLowerCase() === "query";
|
|
208
|
+
headers.delete(SSR_QUERY_CACHE_KEY_HEADER);
|
|
207
209
|
if (!isSsrHtmlOrDataResponse(headers, status, pathname))
|
|
208
210
|
return;
|
|
209
211
|
// A public shell must never set a viewer cookie or vary by credentials.
|
|
@@ -234,9 +236,16 @@ function applyDefaultSsrCacheHeader(headers, status, pathname) {
|
|
|
234
236
|
for (const [name, value] of Object.entries(resolveSsrCacheHeaders())) {
|
|
235
237
|
headers.set(name, value);
|
|
236
238
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
239
|
+
const cacheKeyHeaders = resolveSsrCacheKeyHeaders();
|
|
240
|
+
const netlifyVary = varyByQuery
|
|
241
|
+
? cacheKeyHeaders["netlify-vary"]
|
|
242
|
+
? "query"
|
|
243
|
+
: undefined
|
|
244
|
+
: cacheKeyHeaders["netlify-vary"];
|
|
245
|
+
if (netlifyVary)
|
|
246
|
+
headers.set("netlify-vary", netlifyVary);
|
|
247
|
+
else
|
|
248
|
+
headers.delete("netlify-vary");
|
|
240
249
|
}
|
|
241
250
|
function applyDefaultSpeculationRulesHeader(headers, status, basePath) {
|
|
242
251
|
if (status < 200 || status >= 400)
|
|
@@ -7,6 +7,28 @@ export declare const DEFAULT_SSR_CACHE_HEADERS: {
|
|
|
7
7
|
readonly "cdn-cache-control": "public, max-age=600, stale-while-revalidate=604800, stale-if-error=3600";
|
|
8
8
|
readonly "netlify-cdn-cache-control": "public, durable, s-maxage=31536000, stale-while-revalidate=604800, stale-if-error=3600";
|
|
9
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* Content type used by impersonal HTML redirects that should enter the
|
|
12
|
+
* deployment adapter's shared SSR cache path.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SSR_HTML_CONTENT_TYPE = "text/html; charset=utf-8";
|
|
15
|
+
/**
|
|
16
|
+
* Internal response marker for public HTML whose redirect target preserves
|
|
17
|
+
* request query parameters. The SSR adapters consume this marker and emit a
|
|
18
|
+
* provider-specific full-query cache key only where the provider supports it.
|
|
19
|
+
*/
|
|
20
|
+
export declare const SSR_QUERY_CACHE_KEY_HEADER = "x-agent-native-ssr-key";
|
|
21
|
+
export type SsrHtmlContentTypeOptions = {
|
|
22
|
+
varyByQuery?: boolean;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Mark an already-built HTML response as HTML without changing its redirect
|
|
26
|
+
* status, location, or other headers. Only use this for redirects whose
|
|
27
|
+
* target is independent of the viewer and request credentials. Set
|
|
28
|
+
* `varyByQuery` when the target preserves request query parameters so the SSR
|
|
29
|
+
* adapter can request a full-query cache key on providers that support it.
|
|
30
|
+
*/
|
|
31
|
+
export declare function withSsrHtmlContentType<T extends Response>(response: T, options?: SsrHtmlContentTypeOptions): T;
|
|
10
32
|
/**
|
|
11
33
|
* Deployment-wide override for the SSR shell cache policy.
|
|
12
34
|
*
|
|
@@ -7,6 +7,31 @@ export const DEFAULT_SSR_CACHE_HEADERS = {
|
|
|
7
7
|
"cdn-cache-control": DEFAULT_SSR_CDN_CACHE_CONTROL,
|
|
8
8
|
"netlify-cdn-cache-control": DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL,
|
|
9
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* Content type used by impersonal HTML redirects that should enter the
|
|
12
|
+
* deployment adapter's shared SSR cache path.
|
|
13
|
+
*/
|
|
14
|
+
export const SSR_HTML_CONTENT_TYPE = "text/html; charset=utf-8";
|
|
15
|
+
/**
|
|
16
|
+
* Internal response marker for public HTML whose redirect target preserves
|
|
17
|
+
* request query parameters. The SSR adapters consume this marker and emit a
|
|
18
|
+
* provider-specific full-query cache key only where the provider supports it.
|
|
19
|
+
*/
|
|
20
|
+
export const SSR_QUERY_CACHE_KEY_HEADER = "x-agent-native-ssr-key";
|
|
21
|
+
/**
|
|
22
|
+
* Mark an already-built HTML response as HTML without changing its redirect
|
|
23
|
+
* status, location, or other headers. Only use this for redirects whose
|
|
24
|
+
* target is independent of the viewer and request credentials. Set
|
|
25
|
+
* `varyByQuery` when the target preserves request query parameters so the SSR
|
|
26
|
+
* adapter can request a full-query cache key on providers that support it.
|
|
27
|
+
*/
|
|
28
|
+
export function withSsrHtmlContentType(response, options = {}) {
|
|
29
|
+
response.headers.set("content-type", SSR_HTML_CONTENT_TYPE);
|
|
30
|
+
if (options.varyByQuery) {
|
|
31
|
+
response.headers.set(SSR_QUERY_CACHE_KEY_HEADER, "query");
|
|
32
|
+
}
|
|
33
|
+
return response;
|
|
34
|
+
}
|
|
10
35
|
/**
|
|
11
36
|
* Deployment-wide override for the SSR shell cache policy.
|
|
12
37
|
*
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { truncate } from "./truncate.js";
|
|
|
6
6
|
export { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "./document-title.js";
|
|
7
7
|
export { injectDocumentMarkup } from "./html-document.js";
|
|
8
8
|
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
9
|
+
export { SSR_HTML_CONTENT_TYPE, SSR_QUERY_CACHE_KEY_HEADER, type SsrHtmlContentTypeOptions, withSsrHtmlContentType, } from "./cache-control.js";
|
|
9
10
|
export { AGENT_NATIVE_DOCS_ORIGIN, docsUrl, type DocsUrlOptions, } from "./docs-url.js";
|
|
10
11
|
export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, type RuntimeConfigEnvironment, type RuntimeConfigIssue, type RuntimeConfigIssueCode, type RuntimeConfigIssueSeverity, type RuntimeConfigPhase, type RuntimeConfigReport, type RuntimeConfigRequirements, } from "./runtime-config.js";
|
|
11
12
|
export { llmConnectionTrackingProperties, normalizeLlmConnection, type LlmConnectionStatus, } from "./llm-connection.js";
|
package/dist/shared/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export { truncate } from "./truncate.js";
|
|
|
6
6
|
export { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "./document-title.js";
|
|
7
7
|
export { injectDocumentMarkup } from "./html-document.js";
|
|
8
8
|
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
9
|
+
export { SSR_HTML_CONTENT_TYPE, SSR_QUERY_CACHE_KEY_HEADER, withSsrHtmlContentType, } from "./cache-control.js";
|
|
9
10
|
export { AGENT_NATIVE_DOCS_ORIGIN, docsUrl, } from "./docs-url.js";
|
|
10
11
|
export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, } from "./runtime-config.js";
|
|
11
12
|
export { llmConnectionTrackingProperties, normalizeLlmConnection, } from "./llm-connection.js";
|
|
@@ -11,7 +11,7 @@ description: "Mount the agent chat + resources into any React app with <AgentPan
|
|
|
11
11
|
|
|
12
12
|
</Callout>
|
|
13
13
|
|
|
14
|
-
You don't need to build
|
|
14
|
+
You don't need to build Agent-Native from scratch. The agent chat, resources tab, CLI terminal, voice input, and all the related infrastructure ship as a handful of React components you drop into any app.
|
|
15
15
|
|
|
16
16
|
<Callout tone="info">
|
|
17
17
|
|
|
@@ -184,7 +184,7 @@ Full props: `AgentPanelProps` in `@agent-native/core/client`.
|
|
|
184
184
|
|
|
185
185
|
## Programmatic messages: `sendToAgentChat()` {#send}
|
|
186
186
|
|
|
187
|
-
A button that hands work off to the agent
|
|
187
|
+
A button that hands work off to the agent instead of creating a separate AI path with an inline `llm()` call. See [Why build apps this way](/docs/what-is-agent-native#why-build-apps-this-way) for why that distinction matters. For visible, user-initiated AI work, open the sidebar explicitly so the user can see, steer, and continue the same thread:
|
|
188
188
|
|
|
189
189
|
```tsx
|
|
190
190
|
import { sendToAgentChat } from "@agent-native/core/client/agent-chat";
|
|
@@ -283,7 +283,7 @@ AI-shaped workflow inside one opaque action.
|
|
|
283
283
|
|
|
284
284
|
## Typesafe actions from the UI: `useActionMutation()` {#use-action-mutation}
|
|
285
285
|
|
|
286
|
-
When the UI needs to run the same operation an agent tool would run
|
|
286
|
+
When the UI needs to run the same operation an agent tool would run, use [`useActionMutation`](/docs/client-data#use-action-mutation):
|
|
287
287
|
|
|
288
288
|
```tsx
|
|
289
289
|
import { useActionMutation } from "@agent-native/core/client/hooks";
|
|
@@ -298,7 +298,7 @@ Type-safe arguments come from the zod schema in your `defineAction()`. See [Acti
|
|
|
298
298
|
|
|
299
299
|
<Callout id="doc-block-1757zi5" tone="decision">
|
|
300
300
|
|
|
301
|
-
**`useActionMutation` vs `sendToAgentChat`.** Run the operation directly with `useActionMutation` when the user clicked a deterministic button ("Send reply"). Hand it to `sendToAgentChat` when the work needs the agent's reasoning, tools, or multi-step planning. Never call an inline `llm()` from UI
|
|
301
|
+
**`useActionMutation` vs `sendToAgentChat`.** Run the operation directly with `useActionMutation` when the user clicked a deterministic button ("Send reply"). Hand it to `sendToAgentChat` when the work needs the agent's reasoning, tools, or multi-step planning. Never call an inline `llm()` from UI; that creates a separate AI path instead of using the shared agent loop.
|
|
302
302
|
|
|
303
303
|
</Callout>
|
|
304
304
|
|
package/docs/content/faq.mdx
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "FAQ"
|
|
3
|
-
description: "Common questions about
|
|
3
|
+
description: "Common questions about Agent-Native — what it is, who it's for, what you can build, and how it works."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# FAQ
|
|
7
7
|
|
|
8
|
-
Common questions about
|
|
8
|
+
Common questions about Agent-Native, organized from "I'm just looking" to "I'm wiring up auth right now."
|
|
9
9
|
|
|
10
10
|
## The basics {#general}
|
|
11
11
|
|
|
12
|
-
### What is
|
|
12
|
+
### What is Agent-Native? {#what-is-agent-native}
|
|
13
13
|
|
|
14
|
-
Agent-
|
|
14
|
+
Agent-Native is a framework for building apps where the AI agent and the product surface around it are equal partners. The usual path starts with chat, adds typed actions, renders structured results inline, and grows into durable pages around the same SQL state. The invariant is that agents and humans share the same actions, database, and state. See [What is Agent-Native?](/docs/what-is-agent-native) for the full explanation.
|
|
15
15
|
|
|
16
16
|
### Who is this for? {#who-is-this-for}
|
|
17
17
|
|
|
18
|
-
Agent-
|
|
18
|
+
Agent-Native is for people who want a real app and an AI agent to work from the same data and actions. The common paths are:
|
|
19
19
|
|
|
20
20
|
- **Use a hosted app** if you want Mail, Calendar, Forms, Plan, or another finished template with no setup — start at the [template gallery](/templates).
|
|
21
21
|
- **Start with Chat** if you want the default from-scratch path: users can talk to the agent immediately, then you extend with actions, native results, and screens — start with [Getting Started](/docs/getting-started) or [Chat](/docs/template-chat).
|
|
22
22
|
- **Start automation-first** if you are building scheduled jobs, queues, scripts, integration workers, or external-agent workflows with no browser UI yet — start with [Automation-First Apps](/docs/pure-agent-apps).
|
|
23
23
|
- **Start from a template and customize it** if you want your own SaaS product with auth, database, UI, and agent actions already wired — see [Templates](/docs/cloneable-saas).
|
|
24
24
|
- **Build from scratch** if you want the framework primitives for a new agent-driven product — start with [Getting Started](/docs/getting-started).
|
|
25
|
-
- **Connect another agent or code tool** if you want Claude, ChatGPT, Codex, Cursor, or GitHub Copilot / VS Code to use an
|
|
25
|
+
- **Connect another agent or code tool** if you want Claude, ChatGPT, Codex, Cursor, or GitHub Copilot / VS Code to use an Agent-Native app — see [External Agents](/docs/external-agents) and [Skills Guide](/docs/skills-guide).
|
|
26
26
|
|
|
27
27
|
### How is this different from adding AI to an existing app? {#how-is-this-different}
|
|
28
28
|
|
|
29
|
-
Most apps bolt AI on as an afterthought that can't actually _do_ things in the app. In an
|
|
29
|
+
Most apps bolt AI on as an afterthought that can't actually _do_ things in the app. In an Agent-Native app the agent is a first-class citizen that shares the same actions, database, and state as the UI, so it can do anything the buttons can. See [Why build apps this way](/docs/what-is-agent-native#why-build-apps-this-way).
|
|
30
30
|
|
|
31
|
-
<Diagram id="doc-block-1s6b04" title="Bolted-on AI vs.
|
|
31
|
+
<Diagram id="doc-block-1s6b04" title="Bolted-on AI vs. Agent-Native" summary="A bolted-on chat sidebar lives in its own world. An Agent-Native agent shares the same actions, database, and state as the UI.">
|
|
32
32
|
|
|
33
33
|
```html
|
|
34
34
|
<div class="diagram-vs">
|
|
@@ -45,7 +45,7 @@ Most apps bolt AI on as an afterthought that can't actually _do_ things in the a
|
|
|
45
45
|
</div>
|
|
46
46
|
<div class="diagram-divider" aria-hidden="true"></div>
|
|
47
47
|
<div class="diagram-col">
|
|
48
|
-
<span class="diagram-pill ok">Agent-
|
|
48
|
+
<span class="diagram-pill ok">Agent-Native</span>
|
|
49
49
|
<div class="diagram-row2">
|
|
50
50
|
<div class="diagram-node">UI</div>
|
|
51
51
|
<div class="diagram-node">Agent</div>
|
|
@@ -114,9 +114,9 @@ Anthropic Claude, OpenAI (GPT-5 family), Google Gemini, and any provider that sp
|
|
|
114
114
|
|
|
115
115
|
No. You don't train models, fine-tune, or deal with embeddings. You build a regular web app — and on the hosted version, you barely build anything at all. The framework handles the agent integration: routing messages, running actions, syncing state.
|
|
116
116
|
|
|
117
|
-
### Can I migrate an existing app to
|
|
117
|
+
### Can I migrate an existing app to Agent-Native? {#can-i-use-existing-code}
|
|
118
118
|
|
|
119
|
-
You can, but
|
|
119
|
+
You can, but Agent-Native works best when built from the ground up. The architecture — shared database, polling sync, actions, application state — needs to be integrated throughout. Starting from an app and customizing it is the recommended path. Think of it like the shift from desktop-first to mobile-first: you _can_ retrofit, but building native is better.
|
|
120
120
|
|
|
121
121
|
## Templates and what you can build {#templates}
|
|
122
122
|
|
|
@@ -148,7 +148,7 @@ Yes. The same agent runs in your web UI, in Slack, in Telegram, over email, and
|
|
|
148
148
|
|
|
149
149
|
### Can agents talk to each other? {#can-agents-talk-to-each-other}
|
|
150
150
|
|
|
151
|
-
Yes, via the [A2A (Agent-to-Agent) protocol](/docs/a2a-protocol). Every
|
|
151
|
+
Yes, via the [A2A (Agent-to-Agent) protocol](/docs/a2a-protocol). Every Agent-Native app automatically gets an A2A endpoint. From the mail app, you can tag the analytics agent to query data. An agent discovers what other agents are available, calls them over the protocol, and shows results in the UI. No configuration needed — the agent card is auto-generated from your template's actions.
|
|
152
152
|
|
|
153
153
|
### What can the agent see in the app? {#what-can-the-agent-see}
|
|
154
154
|
|
|
@@ -156,7 +156,7 @@ The agent always knows what the user is currently viewing. The UI writes navigat
|
|
|
156
156
|
|
|
157
157
|
## Development questions {#development}
|
|
158
158
|
|
|
159
|
-
### Which AI coding tools work with
|
|
159
|
+
### Which AI coding tools work with Agent-Native? {#which-ai-tools-work}
|
|
160
160
|
|
|
161
161
|
Any AI coding tool that reads project instructions. The framework uses AGENTS.md as the universal standard:
|
|
162
162
|
|
|
@@ -227,7 +227,7 @@ SSE gives same-process writes an immediate path to the browser, and a lightweigh
|
|
|
227
227
|
|
|
228
228
|
AI is non-deterministic, so you need conversation flow to give feedback and iterate — not one-shot buttons — and the agent already has your codebase, instructions, skills, and history that an inline call lacks. Routing everything through the agent is also what lets the app be driven from Slack, Telegram, or another agent. See [Key Concepts — Agent chat bridge](/docs/key-concepts#agent-chat-bridge).
|
|
229
229
|
|
|
230
|
-
### How do I upgrade an older Agent
|
|
230
|
+
### How do I upgrade an older Agent-Native app? {#upgrade-older-app}
|
|
231
231
|
|
|
232
232
|
Run the supported upgrade path from the app or workspace root:
|
|
233
233
|
|
|
@@ -251,7 +251,7 @@ The shared database, live sync, actions system, and application state only work
|
|
|
251
251
|
## What's next
|
|
252
252
|
|
|
253
253
|
- [**Getting Started**](/docs/getting-started) — build your first action and render it inline in chat
|
|
254
|
-
- [**What
|
|
254
|
+
- [**What is Agent-Native?**](/docs/what-is-agent-native) — the full explanation behind the answers above
|
|
255
255
|
- [**Templates**](/docs/cloneable-saas) — start from a complete SaaS product instead of starting from scratch
|
|
256
256
|
- [**Key Concepts**](/docs/key-concepts) — the architecture: SQL, actions, polling sync, and portability
|
|
257
257
|
- [**Deployment**](/docs/deployment) — host on your own domain or any Nitro-compatible provider
|
|
@@ -1,69 +1,201 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Getting Started"
|
|
3
|
-
description: "Create
|
|
3
|
+
description: "Create an Agent-Native app and call the same action from the agent and the UI."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Getting Started
|
|
7
7
|
|
|
8
|
-
Agent-Native
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
Agent-Native is an open-source TypeScript framework for building apps that
|
|
9
|
+
serve both people and AI agents. You define your app's functionality once as
|
|
10
|
+
[actions](/docs/actions-overview)—typed functions that your React UI calls
|
|
11
|
+
from code and agents use as tools.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
In this guide, you'll create a Chat app and call its included `hello` action
|
|
14
|
+
from the agent and the UI.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
## Prerequisites
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
- [Node.js](https://nodejs.org) 22 or later
|
|
19
|
+
- [pnpm](https://pnpm.io)
|
|
20
|
+
- An LLM connection for the agent: Builder.io, an Anthropic or OpenAI API key,
|
|
21
|
+
or a local Ollama model
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
## Create an app
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
In a new directory, create a Chat app:
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
```bash
|
|
28
|
+
npx @agent-native/core@latest create my-app --standalone --template chat
|
|
29
|
+
cd my-app
|
|
30
|
+
pnpm install
|
|
31
|
+
```
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
The template includes a browser app, authentication, durable conversations,
|
|
34
|
+
live sync, application context, and an `actions/` directory. It also includes a
|
|
35
|
+
small `hello` action that you'll use throughout this guide.
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
## Start the development server
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
Start the app:
|
|
36
40
|
|
|
37
41
|
```bash
|
|
38
|
-
npx @agent-native/core@latest create my-app --template chat
|
|
39
|
-
cd my-app
|
|
40
|
-
pnpm install
|
|
41
42
|
pnpm dev
|
|
42
43
|
```
|
|
43
44
|
|
|
44
|
-
The app opens at `http://localhost:8080`. If
|
|
45
|
-
|
|
45
|
+
The app opens at `http://localhost:8080`. If it doesn't open automatically,
|
|
46
|
+
visit that URL in your browser.
|
|
47
|
+
|
|
48
|
+
<Callout tone="info">
|
|
49
|
+
|
|
50
|
+
On the Welcome screen, select **Continue as local dev**. You don't need to
|
|
51
|
+
enter an email or password for local development.
|
|
52
|
+
|
|
53
|
+
</Callout>
|
|
54
|
+
|
|
55
|
+
Next, connect an LLM. Select **Connect Builder.io** to use free credits, or
|
|
56
|
+
select **Custom keys**, choose a provider, and enter the requested connection
|
|
57
|
+
details.
|
|
58
|
+
|
|
59
|
+
## Run the action from the agent
|
|
60
|
+
|
|
61
|
+
An action is a typed function that your React UI can call from code and agents
|
|
62
|
+
can use as a tool. The Chat template includes a simple `hello` action so you
|
|
63
|
+
can try the pattern before writing one yourself.
|
|
64
|
+
|
|
65
|
+
In the app, ask:
|
|
66
|
+
|
|
67
|
+
> Call the hello action for Alex.
|
|
68
|
+
|
|
69
|
+
The agent finds `hello` from its description and input schema, passes `Alex` as
|
|
70
|
+
the `name` input, and responds:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
Hello, Alex!
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Inspect the action
|
|
77
|
+
|
|
78
|
+
Open `actions/hello.ts`:
|
|
79
|
+
|
|
80
|
+
```ts filename="actions/hello.ts"
|
|
81
|
+
import { defineAction } from "@agent-native/core/action";
|
|
82
|
+
import { z } from "zod";
|
|
83
|
+
|
|
84
|
+
export default defineAction({
|
|
85
|
+
description: "Return a friendly greeting.",
|
|
86
|
+
schema: z.object({
|
|
87
|
+
name: z.string().default("world").describe("Name to greet"),
|
|
88
|
+
}),
|
|
89
|
+
http: { method: "GET" },
|
|
90
|
+
run: async ({ name }) => {
|
|
91
|
+
return { message: `Hello, ${name}!` };
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
For now, focus on four parts:
|
|
97
|
+
|
|
98
|
+
- `description` tells the agent when to use the action.
|
|
99
|
+
- `schema` validates the input and gives the agent a typed tool definition.
|
|
100
|
+
- `http` exposes this read-only action through `GET`, which lets
|
|
101
|
+
`useActionQuery` call it from React.
|
|
102
|
+
- `run` contains the application logic shared by the agent and the UI.
|
|
103
|
+
|
|
104
|
+
Read [Defining Actions](/docs/actions-defining) for the complete API.
|
|
105
|
+
|
|
106
|
+
## Call the action from React
|
|
107
|
+
|
|
108
|
+
Add a route at `app/routes/hello.tsx`:
|
|
109
|
+
|
|
110
|
+
```tsx filename="app/routes/hello.tsx"
|
|
111
|
+
import { useActionQuery } from "@agent-native/core/client/hooks";
|
|
112
|
+
import { useState } from "react";
|
|
113
|
+
|
|
114
|
+
import { Input } from "@/components/ui/input";
|
|
115
|
+
import { Label } from "@/components/ui/label";
|
|
116
|
+
|
|
117
|
+
export default function HelloRoute() {
|
|
118
|
+
const [name, setName] = useState("Alex");
|
|
119
|
+
const { data } = useActionQuery("hello", { name });
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<main className="mx-auto grid w-full max-w-xl gap-6 p-6">
|
|
123
|
+
<h1 className="text-2xl font-semibold">Hello action</h1>
|
|
124
|
+
<div className="grid gap-2">
|
|
125
|
+
<Label htmlFor="name">Name</Label>
|
|
126
|
+
<Input
|
|
127
|
+
id="name"
|
|
128
|
+
value={name}
|
|
129
|
+
onChange={(event) => setName(event.target.value)}
|
|
130
|
+
/>
|
|
131
|
+
</div>
|
|
132
|
+
<p className="text-xl font-medium">{data?.message}</p>
|
|
133
|
+
</main>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
<Callout tone="warning">
|
|
139
|
+
|
|
140
|
+
Restart the development server so it discovers the new route, then open
|
|
141
|
+
`http://localhost:8080/hello`.
|
|
142
|
+
|
|
143
|
+
</Callout>
|
|
144
|
+
|
|
145
|
+
As you type a name, `useActionQuery` calls `hello` and renders the result. It
|
|
146
|
+
infers the action's input and result types, so the page doesn't need a custom
|
|
147
|
+
API route or a second implementation of the greeting.
|
|
148
|
+
|
|
149
|
+
## Change the action
|
|
150
|
+
|
|
151
|
+
In `actions/hello.ts`, change the return value:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
return { message: `Welcome, ${name}.` };
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Refresh `/hello`, then ask the agent to call `hello` again. Both return the
|
|
158
|
+
updated greeting because they call the same action.
|
|
159
|
+
|
|
160
|
+
## Call actions in other ways
|
|
161
|
+
|
|
162
|
+
You called the same action from the agent and UI. The same action can also be
|
|
163
|
+
called from:
|
|
164
|
+
|
|
165
|
+
| Call from | Use it to |
|
|
166
|
+
| --------------------------------------- | ------------------------------------------------------------- |
|
|
167
|
+
| [HTTP API](/docs/http-api) | Call an action from a script, backend, or integration. |
|
|
168
|
+
| [CLI](/docs/actions-other-surfaces#cli) | Run or test an action from a terminal. |
|
|
169
|
+
| [MCP](/docs/actions-other-surfaces#mcp) | Let an external AI client discover and call actions as tools. |
|
|
170
|
+
| [A2A](/docs/actions-other-surfaces#a2a) | Let another Agent-Native app ask this app to do work. |
|
|
171
|
+
|
|
172
|
+
Every caller uses the same action definition. You do not need a separate
|
|
173
|
+
implementation for each one. This shared action model is central to
|
|
174
|
+
Agent-Native: behavior, validation, and permissions stay aligned across the
|
|
175
|
+
UI, agents, and integrations as the app changes.
|
|
176
|
+
|
|
177
|
+
## What you built
|
|
178
|
+
|
|
179
|
+
You created an Agent-Native app, called its `hello` action from the agent and a
|
|
180
|
+
React UI, then changed the greeting once and watched both update. Every action
|
|
181
|
+
you write from here follows that same pattern.
|
|
182
|
+
|
|
183
|
+
## Next steps
|
|
46
184
|
|
|
47
|
-
|
|
48
|
-
`actions/` directory, and the standard `view-screen` and `navigate` actions.
|
|
185
|
+
<Cards>
|
|
49
186
|
|
|
50
|
-
###
|
|
187
|
+
### [What is Agent-Native?](/docs/what-is-agent-native)
|
|
51
188
|
|
|
52
|
-
|
|
53
|
-
choose another option in the CLI. See [Creating Templates](/docs/creating-templates)
|
|
54
|
-
for the other paths.
|
|
189
|
+
Understand why the UI and agent share actions, data, and context.
|
|
55
190
|
|
|
56
|
-
|
|
191
|
+
### [Key Concepts](/docs/key-concepts)
|
|
57
192
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
to configure a model and provider.
|
|
193
|
+
Learn how actions, SQL data, application context, access, and live sync fit
|
|
194
|
+
together.
|
|
61
195
|
|
|
62
|
-
|
|
196
|
+
### [Actions](/docs/actions-overview)
|
|
63
197
|
|
|
64
|
-
|
|
198
|
+
Define actions for reads, writes, and approvals, then call them from the UI,
|
|
199
|
+
agents, and external clients.
|
|
65
200
|
|
|
66
|
-
|
|
67
|
-
- [Chat Template](/docs/template-chat): what the starter app includes.
|
|
68
|
-
- [Database](/docs/database): add app-owned tables when your app needs domain data.
|
|
69
|
-
- [FAQ](/docs/faq): answers about models, hosting, and templates.
|
|
201
|
+
</Cards>
|