From 60f9d56e15a8ec1d8e602aeeea37d299ecd49367 Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Thu, 30 Jul 2026 16:35:38 -0700 Subject: [PATCH 1/9] Split getting-started into four focused pages - getting-started: steps 1-2 only (create app + connect AI) - getting-started-actions: steps 3-4 (action + inline rendering) - getting-started-database: step 5 (SQL persistence) - getting-started-pages: steps 6-7 (page + navigation) - Nav gets Getting Started as parent with three children - i18n keys + baselines updated for all locales Co-Authored-By: Claude Sonnet 4.6 --- .../docs/content/getting-started-actions.mdx | 218 ++++++ .../docs/content/getting-started-database.mdx | 236 +++++++ .../docs/content/getting-started-pages.mdx | 176 +++++ .../core/docs/content/getting-started.mdx | 622 +----------------- packages/docs/app/components/docsNavItems.ts | 22 +- packages/docs/app/i18n/ar-SA.ts | 3 + packages/docs/app/i18n/de-DE.ts | 3 + packages/docs/app/i18n/en-US.ts | 3 + packages/docs/app/i18n/es-ES.ts | 3 + packages/docs/app/i18n/fr-FR.ts | 3 + packages/docs/app/i18n/hi-IN.ts | 3 + packages/docs/app/i18n/ja-JP.ts | 3 + packages/docs/app/i18n/ko-KR.ts | 3 + packages/docs/app/i18n/pt-BR.ts | 3 + packages/docs/app/i18n/zh-CN.ts | 3 + packages/docs/app/i18n/zh-TW.ts | 3 + .../i18n-catalog-english-value-baseline.txt | 30 + .../i18n-localized-doc-coverage-baseline.txt | 30 + scripts/i18n-localized-docs-baseline.txt | 118 ---- 19 files changed, 749 insertions(+), 736 deletions(-) create mode 100644 packages/core/docs/content/getting-started-actions.mdx create mode 100644 packages/core/docs/content/getting-started-database.mdx create mode 100644 packages/core/docs/content/getting-started-pages.mdx diff --git a/packages/core/docs/content/getting-started-actions.mdx b/packages/core/docs/content/getting-started-actions.mdx new file mode 100644 index 0000000000..5a40d879e0 --- /dev/null +++ b/packages/core/docs/content/getting-started-actions.mdx @@ -0,0 +1,218 @@ +--- +title: "Add an Action" +description: "Define your first action and render its result as a UI component directly inside the chat transcript." +--- + +# Add an Action + +This is part two of the Getting Started series. In [Getting Started](/docs/getting-started) you created a Chat app and connected an AI engine. Here you'll define your first action and render its result inline in chat. + +## 3. Add an action {#add-an-action} + +An action is a typed operation that both your agent and your UI can call. It's +how the agent does things in your app. Actions live in the `actions/` directory +and can be triggered from chat, from React components, from the CLI, or on a +schedule. You define them once and call them from anywhere. + +### Try the starter action + +The Chat template includes a `hello` action at `actions/hello.ts`: + +```ts filename="actions/hello.ts" +import { defineAction } from "@agent-native/core/action"; +import { z } from "zod"; + +export default defineAction({ + description: "Return a friendly greeting.", + schema: z.object({ + name: z.string().default("world").describe("Name to greet"), + }), + http: { method: "GET" }, + run: async ({ name }) => { + return { message: `Hello, ${name}!` }; + }, +}); +``` + +Run it from the terminal (inside your `my-app/` directory): + +```bash +pnpm action hello --name Alice +``` + +Or open your app at `http://localhost:8080` and ask the agent in the chat there: + +> Use the hello action with the name Alice. + +### Add your own action + +Replace the starter action with the first real operation in your domain. This example +counts words, sentences, and paragraphs in any text you pass it. It computes +everything locally, so there's nothing to configure and no external service to connect. + +Create a new file called `analyze-text.ts` in your `actions/` directory: + +```ts filename="actions/analyze-text.ts" +import { defineAction } from "@agent-native/core/action"; +import { z } from "zod"; + +const textStatsSchema = z.object({ + title: z.string(), + points: z.array(z.object({ label: z.string(), value: z.number() })), +}); + +export default defineAction({ + description: "Count words, sentences, and paragraphs in a block of text.", + schema: z.object({ + text: z + .string() + .default( + "The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs.", + ), + }), + outputSchema: textStatsSchema, + chatUI: { + renderer: "text.stats-chart", + title: "Text stats", + }, + readOnly: true, + run: async ({ text }) => ({ + title: "Text statistics", + points: [ + { label: "Characters", value: text.length }, + { label: "Words", value: text.split(/\s+/).filter(Boolean).length }, + { + label: "Sentences", + value: text.split(/[.!?]+/).filter(Boolean).length, + }, + { + label: "Paragraphs", + value: text.split(/\n\n+/).filter(Boolean).length, + }, + ], + }), +}); +``` + +Try it from the terminal: + +```bash +pnpm action analyze-text --text "Hello world. How are you today?" +``` + +Or open your app at `http://localhost:8080` and ask the agent in the chat there: + +> Run the analyze-text action on "Hello world. How are you today?" + +#### Define once, call from anywhere + +This action is now reachable from chat, React hooks, CLI, HTTP, MCP, A2A, +scheduled jobs, and webhooks. + +TIP: Any time you want the agent to call a specific action without ambiguity, phrasing it as "Run the `` action" is most reliable. Natural-language prompts work well once the agent has enough context about your app's domain. For a brand-new app with no data or context yet, explicit is safer. + +## 4. Render the result inline {#render-inline} + +When the agent runs `analyze-text`, it returns structured data: a title and an +array of counts. By default the agent will describe that data in prose: "The +text has 9 words, 2 sentences..." and so on. That works, but you can +also render the result as a real UI component (a bar chart, a table, a card) +directly inside the chat transcript, right where the agent responded. + +This is what `chatUI.renderer` in the action does. It's a label that says "when +this action's result appears in chat, hand it to this React component instead of +summarizing it in text." The component receives the validated action output as +props and renders whatever you want. + +In the next step, you'll create `app/chat-renderers.tsx`, but first, add one import line +to `app/root.tsx` so it runs on startup: + +```ts filename="app/root.tsx" +import "./chat-renderers"; +``` + +Add it alongside your other imports at the top of the file. That's the only +change to `root.tsx`. The import just ensures the file runs and registers the +renderer. Now create the renderer file: + +```tsx filename="app/chat-renderers.tsx" +import { + registerActionChatRenderer, + type ToolRendererProps, +} from "@agent-native/core/client/chat"; + +type TextStatsResult = { + title: string; + points: Array<{ label: string; value: number }>; +}; + +const MAX_BAR_PX = 80; + +function TextStatsChart({ context }: ToolRendererProps) { + const result = context.resultJson as TextStatsResult; + const max = Math.max(...result.points.map((point) => point.value), 1); + return ( +
+

{result.title}

+
+ {result.points.map((point) => ( +
+
+ {point.label} +
+ ))} +
+
+ ); +} + +registerActionChatRenderer({ + id: "text.stats-chart", + renderer: "text.stats-chart", + Component: TextStatsChart, +}); +``` + +Once the renderer is registered, the agent's response looks like this. Instead +of a paragraph of text, your React component renders directly inside the chat +transcript: + + +
User

Run the analyze-text action on \"Hello world. How are you today?\"

Agent

Rendered with text.stats-chart.

Text statistics

Characters
Words
Sentences
Paragraphs
" + } + /> +
+ +Use this step when the result belongs where the agent is speaking: + +- setup summaries +- short reports +- approvals +- tables or charts small enough to inspect inline +- links into durable app views + +For reusable generic outputs, the framework also ships built-in +`data-chart` and `data-table` renderers, plus `data-insights` for combined +summary/chart/table cards. See [Native Chat UI](/docs/native-chat-ui). For +temporary controls the agent creates at runtime, see +[Generative UI](/docs/generative-ui). + +## What's next {#next} + +Continue to [Persist Data in SQL](/docs/getting-started-database) to save +action results so the agent can reference them later, or jump ahead to: + +- **[Actions](/docs/actions)**: schemas, auth, approvals, hooks, and transport. +- **[Native Chat UI](/docs/native-chat-ui)**: built-in renderers for tables, charts, and cards. +- **[Key Concepts](/docs/key-concepts)**: the architecture underneath this tutorial. diff --git a/packages/core/docs/content/getting-started-database.mdx b/packages/core/docs/content/getting-started-database.mdx new file mode 100644 index 0000000000..d983c77aa1 --- /dev/null +++ b/packages/core/docs/content/getting-started-database.mdx @@ -0,0 +1,236 @@ +--- +title: "Persist Data in SQL" +description: "Save action results to a SQL database so the agent can reference them across conversations." +--- + +# Persist Data in SQL + +This is part three of the Getting Started series. In [Add an Action](/docs/getting-started-actions) you defined the `analyze-text` action and rendered its result inline in chat. Here you'll persist those results to a SQL database. + +## 5. Persist data in SQL {#persist-data} + +Right now, every time the agent runs `analyze-text` the result appears in chat +and then disappears. There's nothing to look back at, nothing the agent can +reference later, and no way to build a page around the data. Persisting to SQL +fixes that: the agent writes results to a table, and both the agent and your UI +can read them back at any time. + +Agent-Native apps have a SQL database available by default: SQLite locally, +and your configured provider (Postgres, Turso/libSQL, Cloudflare D1) in +production. + +### Wire up the database plugin + +The Chat template doesn't include a database plugin by default. Create +`server/plugins/db.ts` to initialize it. This is what runs migrations and +makes the database available to your actions: + +```ts filename="server/plugins/db.ts" +import { runMigrations } from "@agent-native/core/db"; + +export default runMigrations( + [ + { + version: 1, + sql: `CREATE TABLE IF NOT EXISTS text_analyses ( + id TEXT PRIMARY KEY, + input TEXT NOT NULL, + char_count INTEGER NOT NULL, + word_count INTEGER NOT NULL, + sentence_count INTEGER NOT NULL, + created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP + )`, + }, + ], + { table: "text_analyses_migrations" }, +); +``` + +Each entry in the array is an additive migration. When you add new columns or +tables later, append a new version object. Never edit existing ones. + +### Define the schema + +Create `server/db/schema.ts`. The `server/db/` directory may not exist yet, +so create it if needed. This file describes your tables using typed helpers so +your actions get full TypeScript autocomplete: + +```ts filename="server/db/schema.ts" +import { integer, now, table, text } from "@agent-native/core/db/schema"; + +export const textAnalyses = table("text_analyses", { + id: text("id").primaryKey(), + input: text("input").notNull(), + charCount: integer("char_count").notNull(), + wordCount: integer("word_count").notNull(), + sentenceCount: integer("sentence_count").notNull(), + createdAt: text("created_at").notNull().default(now()), +}); +``` + +Use the framework schema helpers (`table`, `text`, `integer`, `now`) rather than +`sqliteTable`, `pgTable`, or dialect-specific imports. They pick the configured +SQL backend automatically, so the same schema runs locally on SQLite and in +production on any supported provider. + +After adding both files, restart the dev server so the migration runs: + +```bash +pnpm dev +``` + +Look for these two lines in the terminal output. They confirm the table was created: + +``` +[db] Applying 1 migration(s) on SQLite/libsql… +[db] Applied migration v1 (1 statement) +``` + +The `NitroViteError` lines, `BETTER_AUTH_SECRET` warning, and +`SECRETS_ENCRYPTION_KEY` warning that also appear are normal for local dev and +can be ignored. + +### Add actions for the table + +Now create the action files that read and write the table. These go in your +`actions/` directory, the same place as `hello.ts` and `analyze-text.ts`. You +create them yourself, one file per operation. The agent and your UI will call +them the same way they call any other action. + +**`actions/save-text-analysis.ts`** writes a result row to the database. +Call this after running `analyze-text` to make the result durable: + +```ts filename="actions/save-text-analysis.ts" +import { defineAction } from "@agent-native/core/action"; +import { getDbExec } from "@agent-native/core/db"; +import { z } from "zod"; + +export default defineAction({ + description: "Save a text analysis result to the database.", + schema: z.object({ + input: z.string(), + charCount: z.number(), + wordCount: z.number(), + sentenceCount: z.number(), + }), + run: async ({ input, charCount, wordCount, sentenceCount }) => { + const id = crypto.randomUUID(); + await getDbExec().execute({ + sql: `INSERT INTO text_analyses (id, input, char_count, word_count, sentence_count) + VALUES (?, ?, ?, ?, ?)`, + args: [id, input, charCount, wordCount, sentenceCount], + }); + return { id }; + }, +}); +``` + +**`actions/list-text-analyses.ts`** reads all saved results. The agent can +call this to summarize past analyses, and your UI can use it to populate a page: + +```ts filename="actions/list-text-analyses.ts" +import { defineAction } from "@agent-native/core/action"; +import { getDbExec } from "@agent-native/core/db"; +import { z } from "zod"; + +export default defineAction({ + description: "List all saved text analyses, newest first.", + schema: z.object({}), + run: async () => { + const result = await getDbExec().execute( + `SELECT id, input, char_count, word_count, sentence_count, created_at + FROM text_analyses + ORDER BY created_at DESC`, + ); + return result.rows; + }, +}); +``` + +**`actions/delete-text-analysis.ts`** removes a row by id: + +```ts filename="actions/delete-text-analysis.ts" +import { defineAction } from "@agent-native/core/action"; +import { getDbExec } from "@agent-native/core/db"; +import { z } from "zod"; + +export default defineAction({ + description: "Delete a saved text analysis by id.", + schema: z.object({ id: z.string() }), + run: async ({ id }) => { + await getDbExec().execute({ + sql: `DELETE FROM text_analyses WHERE id = ?`, + args: [id], + }); + return { deleted: id }; + }, +}); +``` + +Once these files are saved the dev server picks them up automatically. No +restart needed. Try listing analyses from the terminal: + +```bash +pnpm action list-text-analyses +``` + +You should see an empty array. The table exists and the action works; there's +just nothing saved yet: + +``` +[] +``` + +Data is saved to `data/app.db`, a SQLite file in your project directory that +gets created automatically on first run. In production you'd point +`DATABASE_URL` at a hosted database instead, but locally this file is all you +need. + +To save something, first run `analyze-text` to get the counts: + +```bash +pnpm action analyze-text --text "Hello world" +``` + +You'll see output like: + +``` +{ + title: 'Text statistics', + points: [ + { label: 'Characters', value: 11 }, + { label: 'Words', value: 2 }, + { label: 'Sentences', value: 1 }, + { label: 'Paragraphs', value: 1 } + ] +} +``` + +Then pass those values to `save-text-analysis`: + +```bash +pnpm action save-text-analysis \ + --input "Hello world" \ + --charCount 11 \ + --wordCount 2 \ + --sentenceCount 1 +``` + +Now run `list-text-analyses` again and you'll see the saved row: + +```bash +pnpm action list-text-analyses +``` + +Or ask the agent in the chat at `http://localhost:8080` to do both steps at once: + +> Run analyze-text on "Hello world", then save the result. + +## What's next {#next} + +Continue to [Add a Page](/docs/getting-started-pages) to build a UI that +displays your saved data, or jump ahead to: + +- **[Storing Data](/docs/storing-data)**: migrations, schema helpers, and production database setup. +- **[Actions](/docs/actions)**: schemas, auth, approvals, hooks, and transport. +- **[Key Concepts](/docs/key-concepts)**: the architecture underneath this tutorial. diff --git a/packages/core/docs/content/getting-started-pages.mdx b/packages/core/docs/content/getting-started-pages.mdx new file mode 100644 index 0000000000..1cd748c705 --- /dev/null +++ b/packages/core/docs/content/getting-started-pages.mdx @@ -0,0 +1,176 @@ +--- +title: "Add a Page" +description: "Build a React route that displays your saved data and wire it into the sidebar so the agent can navigate to it." +--- + +# Add a Page + +This is part four of the Getting Started series. In [Persist Data in SQL](/docs/getting-started-database) you saved action results to a database. Here you'll build a page that displays that data and connect it to the sidebar. + +## 6. Add a page the agent can open {#add-a-page} + +Chat is great for conversational interaction, but some data is better inspected +in a dedicated UI: a table you can scan, sort, or delete rows from. This step +adds a React route that displays everything saved in `text_analyses`, using the +same `list-text-analyses` and `delete-text-analysis` actions you already wrote. +There's no second data layer. The page is just a view over the same SQL state +the agent reads and writes. + +Create the route file at `app/routes/text-analyses.tsx`. Route files in +`app/routes/` are automatically picked up by the framework. The filename +becomes the URL path, so this page will be available at +`http://localhost:8080/text-analyses`. + +```tsx filename="app/routes/text-analyses.tsx" +import { + useActionMutation, + useActionQuery, +} from "@agent-native/core/client/hooks"; + +export default function TextAnalysesRoute() { + const analyses = useActionQuery("list-text-analyses", {}); + const deleteAnalysis = useActionMutation("delete-text-analysis"); + + return ( +
+
+

Text analyses

+

+ Results saved by the agent or triggered manually. +

+
+
+ {analyses.data?.length === 0 && ( +

No analyses saved yet.

+ )} + {analyses.data?.map((row: any) => ( +
+
+

{row.input}

+

+ {row.word_count} words · {row.char_count} characters ·{" "} + {row.sentence_count} sentences +

+
+ +
+ ))} +
+
+ ); +} +``` + +`useActionQuery` calls `list-text-analyses` and keeps the result live. If the +agent saves a new row while the page is open, it appears automatically. +`useActionMutation` calls `delete-text-analysis` when the user clicks Delete, +then invalidates the query so the list refreshes. + +Open `http://localhost:8080/text-analyses` in your browser. If you saved an +analysis in the previous step you'll see it listed. Then ask the agent in chat: + +> Open the text analyses page. + +If you get a 404, try restarting your dev server. + +The agent calls the `navigate` action (already included in the Chat +template) to send the browser to `/text-analyses`. This is what it looks like +with a few saved rows: + + +

Text analyses

Results saved by the agent or triggered manually.

Hello world

2 words · 11 characters · 1 sentence

Delete

The quick brown fox jumps over the lazy dog.

9 words · 44 characters · 1 sentence

Delete

Pack my box with five dozen liquor jugs.

8 words · 40 characters · 1 sentence

Delete
" + } + /> +
+ +## 7. Extend the navigation {#extend-navigation} + +The sidebar's links are a plain array in `app/components/layout/Sidebar.tsx`, +not a separate config file. Open it and add an entry for the Text analyses +page next to the existing Chat entry: + +```tsx filename="app/components/layout/Sidebar.tsx" +import { IconList, IconMessageCircle } from "@tabler/icons-react"; + +const navItems = [ + { + icon: IconMessageCircle, + labelKey: "navigation.chat", + href: "/", + view: "chat", + }, + { + icon: IconList, + labelKey: "navigation.textAnalyses", + href: "/text-analyses", + view: "text-analyses", + }, +]; +``` + +`icon` takes an imported Tabler icon component, not a string name. `labelKey` +looks up a string in the i18n catalog (`app/i18n/en-US.ts` and the other +locale files); an unregistered key still renders — it falls back to a +humanized version of the key (`navigation.textAnalyses` becomes "Text +analyses") — but add it to the catalogs if you want the label translated. See +[Internationalization](/docs/internationalization). + +Save the file. The dev server picks up the change automatically and the sidebar +updates without a restart. + +### Agent navigation + +The sidebar link lets users navigate manually. The agent can also open pages on +its own using two built-in actions that ship with the Chat template: + +- **`view-screen`** reads the current route and returns a compact summary of + what the user is looking at. +- **`navigate`** writes a same-origin path to the browser's history. + +As you add more pages, keep `navigate` updated so the agent knows what +destinations exist. Document available paths in `AGENTS.md` so the model can +reason about them. + +When the app has both a full-page chat route and an app page, use the shared chat +handoff helpers described in [Agent Surfaces](/docs/agent-surfaces#rich-chat): +`AgentChatSurface`, `AgentSidebar`, `useAgentChatHomeHandoff`, +`useAgentChatHomeHandoffLinks`, and `chatViewTransition`. That lets the full +chat slide into the side panel as the page opens, keeping the same thread while +the user inspects durable data. + +## Project structure {#project-structure} + +```text +my-app/ + actions/ # Agent-callable and UI-callable operations + app/ # React routes, pages, and chat surfaces + server/ # Nitro server and SQL schema + AGENTS.md # Always-on instructions for the app agent + .agents/ # Skills the agent loads when relevant + data/app.db # Local SQLite state when DATABASE_URL is unset +``` + +## What's next {#next} + +You've built a complete agentic app: a working chat interface, an action, inline +rendering, a database, and a page the agent can navigate to. From here: + +- **[What Is Agent-Native?](/docs/what-is-agent-native)**: the vision and the case for building this way. +- **[Key Concepts](/docs/key-concepts)**: the architecture underneath this tutorial. +- **[Actions](/docs/actions)**: schemas, auth, approvals, hooks, and transport. +- **[Native Chat UI](/docs/native-chat-ui)**: render action results as tables, charts, and typed cards. +- **[Context Awareness](/docs/context-awareness)**: `view-screen`, `navigate`, route state, and selected objects. +- **[Agent Surfaces](/docs/agent-surfaces)**: chat, inline UI, app pages, embedded sidecars, automation, and external agents. +- **[Deployment](/docs/deployment)**: put your app on your own domain. +- **[FAQ](/docs/faq)**: quick answers on cost, hosting, models, and templates. diff --git a/packages/core/docs/content/getting-started.mdx b/packages/core/docs/content/getting-started.mdx index 14ade79485..fcb550ed67 100644 --- a/packages/core/docs/content/getting-started.mdx +++ b/packages/core/docs/content/getting-started.mdx @@ -1,6 +1,6 @@ --- title: "Getting Started" -description: "Create a chat-first agentic app, add an action, render structured results inline, then grow into a persistent page the agent can open." +description: "Create a Chat app and connect an AI engine so your agent can respond." --- # Getting Started @@ -16,22 +16,6 @@ The quickest way in is the **Chat template**: a minimal app that gives you a working AI chat interface, durable threads, auth, and an `actions/` directory ready to extend. It's the foundation most Agent-Native apps grow from. -The first useful path is: - -1. Create a chat app. -2. Connect an AI engine so the agent can respond. -3. Add one action. -4. Render the action result inline in chat. -5. Persist data in SQL. -6. Add a page the agent can open when visual inspection is better than another - paragraph in the transcript. - -Want a complete domain app instead? Clone a rich template such as -[Mail](/docs/template-mail), [Calendar](/docs/template-calendar), -[Forms](/docs/template-forms), [Analytics](/docs/template-analytics), or -[Plan](/docs/template-plan). Want no browser UI yet? See -[Automation-First Apps](/docs/pure-agent-apps) after this tutorial. - ## 1. Create a chat app {#create-your-app} You'll need [Node.js 22+](https://nodejs.org) and [pnpm](https://pnpm.io). @@ -104,604 +88,16 @@ hides itself and the agent is ready to chat. > the app from rendering needs to be fixed via the environment variable rather than > the UI. -## 3. Add an action {#add-an-action} - -An action is a typed operation that both your agent and your UI can call. It's -how the agent does things in your app. Actions live in the `actions/` directory -and can be triggered from chat, from React components, from the CLI, or on a -schedule. You define them once and call them from anywhere. - -### Try the starter action - -The Chat template includes a `hello` action at `actions/hello.ts`: - -```ts filename="actions/hello.ts" -import { defineAction } from "@agent-native/core/action"; -import { z } from "zod"; - -export default defineAction({ - description: "Return a friendly greeting.", - schema: z.object({ - name: z.string().default("world").describe("Name to greet"), - }), - http: { method: "GET" }, - run: async ({ name }) => { - return { message: `Hello, ${name}!` }; - }, -}); -``` - -Run it from the terminal (inside your `my-app/` directory): - -```bash -pnpm action hello --name Alice -``` - -Or open your app at `http://localhost:8080` and ask the agent in the chat there: - -> Use the hello action with the name Alice. - -### Add your own action - -Replace the starter action with the first real operation in your domain. This example -counts words, sentences, and paragraphs in any text you pass it. It computes -everything locally, so there's nothing to configure and no external service to connect. - -Create a new file called `analyze-text.ts` in your `actions/` directory: - -```ts filename="actions/analyze-text.ts" -import { defineAction } from "@agent-native/core/action"; -import { z } from "zod"; - -const textStatsSchema = z.object({ - title: z.string(), - points: z.array(z.object({ label: z.string(), value: z.number() })), -}); - -export default defineAction({ - description: "Count words, sentences, and paragraphs in a block of text.", - schema: z.object({ - text: z - .string() - .default( - "The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs.", - ), - }), - outputSchema: textStatsSchema, - chatUI: { - renderer: "text.stats-chart", - title: "Text stats", - }, - readOnly: true, - run: async ({ text }) => ({ - title: "Text statistics", - points: [ - { label: "Characters", value: text.length }, - { label: "Words", value: text.split(/\s+/).filter(Boolean).length }, - { - label: "Sentences", - value: text.split(/[.!?]+/).filter(Boolean).length, - }, - { - label: "Paragraphs", - value: text.split(/\n\n+/).filter(Boolean).length, - }, - ], - }), -}); -``` - -Try it from the terminal: - -```bash -pnpm action analyze-text --text "Hello world. How are you today?" -``` - -Or open your app at `http://localhost:8080` and ask the agent in the chat there: - -> Run the analyze-text action on "Hello world. How are you today?" - -#### Define once, call from anywhere - -This action is now reachable from chat, React hooks, CLI, HTTP, MCP, A2A, -scheduled jobs, and webhooks. - -TIP: Any time you want the agent to call a specific action without ambiguity, phrasing it as "Run the `` action" is most reliable. Natural-language prompts work well once the agent has enough context about your app's domain. For a brand-new app with no data or context yet, explicit is safer. - -## 4. Render the result inline {#render-inline} - -When the agent runs `analyze-text`, it returns structured data: a title and an -array of counts. By default the agent will describe that data in prose: "The -text has 9 words, 2 sentences..." and so on. That works, but you can -also render the result as a real UI component (a bar chart, a table, a card) -directly inside the chat transcript, right where the agent responded. - -This is what `chatUI.renderer` in the action does. It's a label that says "when -this action's result appears in chat, hand it to this React component instead of -summarizing it in text." The component receives the validated action output as -props and renders whatever you want. - -In the next step, you'll create `app/chat-renderers.tsx`, but first, add one import line -to `app/root.tsx` so it runs on startup: - -```ts filename="app/root.tsx" -import "./chat-renderers"; -``` - -Add it alongside your other imports at the top of the file. That's the only -change to `root.tsx`. The import just ensures the file runs and registers the -renderer. Now create the renderer file: - -```tsx filename="app/chat-renderers.tsx" -import { - registerActionChatRenderer, - type ToolRendererProps, -} from "@agent-native/core/client/chat"; - -type TextStatsResult = { - title: string; - points: Array<{ label: string; value: number }>; -}; - -const MAX_BAR_PX = 80; - -function TextStatsChart({ context }: ToolRendererProps) { - const result = context.resultJson as TextStatsResult; - const max = Math.max(...result.points.map((point) => point.value), 1); - return ( -
-

{result.title}

-
- {result.points.map((point) => ( -
-
- {point.label} -
- ))} -
-
- ); -} - -registerActionChatRenderer({ - id: "text.stats-chart", - renderer: "text.stats-chart", - Component: TextStatsChart, -}); -``` - -Once the renderer is registered, the agent's response looks like this. Instead -of a paragraph of text, your React component renders directly inside the chat -transcript: - - -
User

Run the analyze-text action on \"Hello world. How are you today?\"

Agent

Rendered with text.stats-chart.

Text statistics

Characters
Words
Sentences
Paragraphs
" - } - /> -
- -Use this step when the result belongs where the agent is speaking: - -- setup summaries -- short reports -- approvals -- tables or charts small enough to inspect inline -- links into durable app views - -For reusable generic outputs, the framework also ships built-in -`data-chart` and `data-table` renderers, plus `data-insights` for combined -summary/chart/table cards. See [Native Chat UI](/docs/native-chat-ui). For -temporary controls the agent creates at runtime, see -[Generative UI](/docs/generative-ui). - -## 5. Persist data in SQL {#persist-data} - -Right now, every time the agent runs `analyze-text` the result appears in chat -and then disappears. There's nothing to look back at, nothing the agent can -reference later, and no way to build a page around the data. Persisting to SQL -fixes that: the agent writes results to a table, and both the agent and your UI -can read them back at any time. - -Agent-Native apps have a SQL database available by default: SQLite locally, -and your configured provider (Postgres, Turso/libSQL, Cloudflare D1) in -production. - -### Wire up the database plugin - -The Chat template doesn't include a database plugin by default. Create -`server/plugins/db.ts` to initialize it. This is what runs migrations and -makes the database available to your actions: - -```ts filename="server/plugins/db.ts" -import { runMigrations } from "@agent-native/core/db"; - -export default runMigrations( - [ - { - version: 1, - sql: `CREATE TABLE IF NOT EXISTS text_analyses ( - id TEXT PRIMARY KEY, - input TEXT NOT NULL, - char_count INTEGER NOT NULL, - word_count INTEGER NOT NULL, - sentence_count INTEGER NOT NULL, - created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP - )`, - }, - ], - { table: "text_analyses_migrations" }, -); -``` - -Each entry in the array is an additive migration. When you add new columns or -tables later, append a new version object. Never edit existing ones. - -### Define the schema - -Create `server/db/schema.ts`. The `server/db/` directory may not exist yet, -so create it if needed. This file describes your tables using typed helpers so -your actions get full TypeScript autocomplete: - -```ts filename="server/db/schema.ts" -import { integer, now, table, text } from "@agent-native/core/db/schema"; - -export const textAnalyses = table("text_analyses", { - id: text("id").primaryKey(), - input: text("input").notNull(), - charCount: integer("char_count").notNull(), - wordCount: integer("word_count").notNull(), - sentenceCount: integer("sentence_count").notNull(), - createdAt: text("created_at").notNull().default(now()), -}); -``` - -Use the framework schema helpers (`table`, `text`, `integer`, `now`) rather than -`sqliteTable`, `pgTable`, or dialect-specific imports. They pick the configured -SQL backend automatically, so the same schema runs locally on SQLite and in -production on any supported provider. - -After adding both files, restart the dev server so the migration runs: - -```bash -pnpm dev -``` - -Look for these two lines in the terminal output. They confirm the table was created: - -``` -[db] Applying 1 migration(s) on SQLite/libsql… -[db] Applied migration v1 (1 statement) -``` - -The `NitroViteError` lines, `BETTER_AUTH_SECRET` warning, and -`SECRETS_ENCRYPTION_KEY` warning that also appear are normal for local dev and -can be ignored. - -### Add actions for the table - -Now create the action files that read and write the table. These go in your -`actions/` directory, the same place as `hello.ts` and `analyze-text.ts`. You -create them yourself, one file per operation. The agent and your UI will call -them the same way they call any other action. - -**`actions/save-text-analysis.ts`** writes a result row to the database. -Call this after running `analyze-text` to make the result durable: - -```ts filename="actions/save-text-analysis.ts" -import { defineAction } from "@agent-native/core/action"; -import { getDbExec } from "@agent-native/core/db"; -import { z } from "zod"; - -export default defineAction({ - description: "Save a text analysis result to the database.", - schema: z.object({ - input: z.string(), - charCount: z.number(), - wordCount: z.number(), - sentenceCount: z.number(), - }), - run: async ({ input, charCount, wordCount, sentenceCount }) => { - const id = crypto.randomUUID(); - await getDbExec().execute({ - sql: `INSERT INTO text_analyses (id, input, char_count, word_count, sentence_count) - VALUES (?, ?, ?, ?, ?)`, - args: [id, input, charCount, wordCount, sentenceCount], - }); - return { id }; - }, -}); -``` - -**`actions/list-text-analyses.ts`** reads all saved results. The agent can -call this to summarize past analyses, and your UI can use it to populate a page: - -```ts filename="actions/list-text-analyses.ts" -import { defineAction } from "@agent-native/core/action"; -import { getDbExec } from "@agent-native/core/db"; -import { z } from "zod"; - -export default defineAction({ - description: "List all saved text analyses, newest first.", - schema: z.object({}), - run: async () => { - const result = await getDbExec().execute( - `SELECT id, input, char_count, word_count, sentence_count, created_at - FROM text_analyses - ORDER BY created_at DESC`, - ); - return result.rows; - }, -}); -``` - -**`actions/delete-text-analysis.ts`** removes a row by id: - -```ts filename="actions/delete-text-analysis.ts" -import { defineAction } from "@agent-native/core/action"; -import { getDbExec } from "@agent-native/core/db"; -import { z } from "zod"; - -export default defineAction({ - description: "Delete a saved text analysis by id.", - schema: z.object({ id: z.string() }), - run: async ({ id }) => { - await getDbExec().execute({ - sql: `DELETE FROM text_analyses WHERE id = ?`, - args: [id], - }); - return { deleted: id }; - }, -}); -``` - -Once these files are saved the dev server picks them up automatically. No -restart needed. Try listing analyses from the terminal: - -```bash -pnpm action list-text-analyses -``` - -You should see an empty array. The table exists and the action works; there's -just nothing saved yet: - -``` -[] -``` - -Data is saved to `data/app.db`, a SQLite file in your project directory that -gets created automatically on first run. In production you'd point -`DATABASE_URL` at a hosted database instead, but locally this file is all you -need. - -To save something, first run `analyze-text` to get the counts: - -```bash -pnpm action analyze-text --text "Hello world" -``` - -You'll see output like: - -``` -{ - title: 'Text statistics', - points: [ - { label: 'Characters', value: 11 }, - { label: 'Words', value: 2 }, - { label: 'Sentences', value: 1 }, - { label: 'Paragraphs', value: 1 } - ] -} -``` - -Then pass those values to `save-text-analysis`: - -```bash -pnpm action save-text-analysis \ - --input "Hello world" \ - --charCount 11 \ - --wordCount 2 \ - --sentenceCount 1 -``` - -Now run `list-text-analyses` again and you'll see the saved row: - -```bash -pnpm action list-text-analyses -``` - -Or ask the agent in the chat at `http://localhost:8080` to do both steps at once: - -> Run analyze-text on "Hello world", then save the result. - -## 6. Add a page the agent can open {#add-a-page} - -Chat is great for conversational interaction, but some data is better inspected -in a dedicated UI: a table you can scan, sort, or delete rows from. This step -adds a React route that displays everything saved in `text_analyses`, using the -same `list-text-analyses` and `delete-text-analysis` actions you already wrote. -There's no second data layer. The page is just a view over the same SQL state -the agent reads and writes. - -Create the route file at `app/routes/text-analyses.tsx`. Route files in -`app/routes/` are automatically picked up by the framework. The filename -becomes the URL path, so this page will be available at -`http://localhost:8080/text-analyses`. - -```tsx filename="app/routes/text-analyses.tsx" -import { - useActionMutation, - useActionQuery, -} from "@agent-native/core/client/hooks"; - -export default function TextAnalysesRoute() { - const analyses = useActionQuery("list-text-analyses", {}); - const deleteAnalysis = useActionMutation("delete-text-analysis"); - - return ( -
-
-

Text analyses

-

- Results saved by the agent or triggered manually. -

-
-
- {analyses.data?.length === 0 && ( -

No analyses saved yet.

- )} - {analyses.data?.map((row: any) => ( -
-
-

{row.input}

-

- {row.word_count} words · {row.char_count} characters ·{" "} - {row.sentence_count} sentences -

-
- -
- ))} -
-
- ); -} -``` - -`useActionQuery` calls `list-text-analyses` and keeps the result live. If the -agent saves a new row while the page is open, it appears automatically. -`useActionMutation` calls `delete-text-analysis` when the user clicks Delete, -then invalidates the query so the list refreshes. - -Open `http://localhost:8080/text-analyses` in your browser. If you saved an -analysis in the previous step you'll see it listed. Then ask the agent in chat: - -> Open the text analyses page. - -If you get a 404, try restarting your dev server. - -The agent calls the `navigate` action (already included in the Chat -template) to send the browser to `/text-analyses`. This is what it looks like -with a few saved rows: - - -

Text analyses

Results saved by the agent or triggered manually.

Hello world

2 words · 11 characters · 1 sentence

Delete

The quick brown fox jumps over the lazy dog.

9 words · 44 characters · 1 sentence

Delete

Pack my box with five dozen liquor jugs.

8 words · 40 characters · 1 sentence

Delete
" - } - /> -
- -## 7. Extend the navigation {#extend-navigation} - -The sidebar's links are a plain array in `app/components/layout/Sidebar.tsx`, -not a separate config file. Open it and add an entry for the Text analyses -page next to the existing Chat entry: - -```tsx filename="app/components/layout/Sidebar.tsx" -import { IconList, IconMessageCircle } from "@tabler/icons-react"; - -const navItems = [ - { - icon: IconMessageCircle, - labelKey: "navigation.chat", - href: "/", - view: "chat", - }, - { - icon: IconList, - labelKey: "navigation.textAnalyses", - href: "/text-analyses", - view: "text-analyses", - }, -]; -``` - -`icon` takes an imported Tabler icon component, not a string name. `labelKey` -looks up a string in the i18n catalog (`app/i18n/en-US.ts` and the other -locale files); an unregistered key still renders — it falls back to a -humanized version of the key (`navigation.textAnalyses` becomes "Text -analyses") — but add it to the catalogs if you want the label translated. See -[Internationalization](/docs/internationalization). - -Save the file. The dev server picks up the change automatically and the sidebar -updates without a restart. - -### Agent navigation - -The sidebar link lets users navigate manually. The agent can also open pages on -its own using two built-in actions that ship with the Chat template: - -- **`view-screen`** reads the current route and returns a compact summary of - what the user is looking at. -- **`navigate`** writes a same-origin path to the browser's history. - -As you add more pages, keep `navigate` updated so the agent knows what -destinations exist. Document available paths in `AGENTS.md` so the model can -reason about them. - -When the app has both a full-page chat route and an app page, use the shared chat -handoff helpers described in [Agent Surfaces](/docs/agent-surfaces#rich-chat): -`AgentChatSurface`, `AgentSidebar`, `useAgentChatHomeHandoff`, -`useAgentChatHomeHandoffLinks`, and `chatViewTransition`. That lets the full -chat slide into the side panel as the page opens, keeping the same thread while -the user inspects durable data. - -## Project structure {#project-structure} - -```text -my-app/ - actions/ # Agent-callable and UI-callable operations - app/ # React routes, pages, and chat surfaces - server/ # Nitro server and SQL schema - AGENTS.md # Always-on instructions for the app agent - .agents/ # Skills the agent loads when relevant - data/app.db # Local SQLite state when DATABASE_URL is unset -``` +## What's next {#next} -## Want a full analytics starting point? {#analytics-starting-point} +Your app is running and the agent can respond. Continue the series to build it out: -The text-analyses example above is intentionally small so you can see the -framework pieces. If you are building a real analytics product, start from -[Analytics](/docs/template-analytics) instead. It is the robust starting point: -connect your providers, use the existing dashboards and agent actions, then -customize the app from there. +- **[Add an Action](/docs/getting-started-actions)**: define your first action and render its result inline in chat. +- **[Persist Data in SQL](/docs/getting-started-database)**: save action results so the agent can reference them later. +- **[Add a Page](/docs/getting-started-pages)**: build a React route and wire it into the sidebar. -## What's next {#next} +Or jump to a specific topic: -- **[What Is Agent-Native?](/docs/what-is-agent-native)**: the vision and the - case for building this way. -- **[Key Concepts](/docs/key-concepts)**: the architecture underneath this - tutorial — SQL, actions, live sync, context awareness. -- **[Actions](/docs/actions)**: schemas, auth, approvals, hooks, and transport. -- **[Native Chat UI](/docs/native-chat-ui)**: render action results as tables, - charts, and typed cards. -- **[Chat Template](/docs/template-chat)**: the minimal chat-first app you just - created. -- **[Analytics Template](/docs/template-analytics)**: a robust analytics app - starting point; connect providers and customize from there. -- **[Context Awareness](/docs/context-awareness)**: `view-screen`, `navigate`, - route state, and selected objects. -- **[Agent Surfaces](/docs/agent-surfaces)**: chat, inline UI, app pages, - embedded sidecars, automation, and external agents. -- **[Deployment](/docs/deployment)**: put your app on your own domain. +- **[What Is Agent-Native?](/docs/what-is-agent-native)**: the vision and case for building this way. +- **[Chat Template](/docs/template-chat)**: the minimal chat-first app you just created. - **[FAQ](/docs/faq)**: quick answers on cost, hosting, models, and templates. diff --git a/packages/docs/app/components/docsNavItems.ts b/packages/docs/app/components/docsNavItems.ts index a5fde2db6b..bd31f7138a 100644 --- a/packages/docs/app/components/docsNavItems.ts +++ b/packages/docs/app/components/docsNavItems.ts @@ -37,6 +37,23 @@ const NAV_SECTION_CONFIG: NavSectionConfig[] = [ id: "getting-started", labelKey: "gettingStarted", slug: "getting-started", + children: [ + { + id: "getting-started-actions", + labelKey: "gettingStartedActions", + slug: "getting-started-actions", + }, + { + id: "getting-started-database", + labelKey: "gettingStartedDatabase", + slug: "getting-started-database", + }, + { + id: "getting-started-pages", + labelKey: "gettingStartedPages", + slug: "getting-started-pages", + }, + ], }, { id: "what-is-agent-native", @@ -295,11 +312,6 @@ const NAV_SECTION_CONFIG: NavSectionConfig[] = [ }, { id: "embedding-sdk", labelKey: "embeddingSdk", slug: "embedding-sdk" }, { id: "frames", labelKey: "frames", slug: "frames" }, - { - id: "docs-components", - labelKey: "docsComponents", - slug: "docs-components", - }, ], }, { diff --git a/packages/docs/app/i18n/ar-SA.ts b/packages/docs/app/i18n/ar-SA.ts index bc146d333e..38fa519a40 100644 --- a/packages/docs/app/i18n/ar-SA.ts +++ b/packages/docs/app/i18n/ar-SA.ts @@ -1475,6 +1475,9 @@ const arSA = { advancedRuntime: "متقدم: توسيع runtime", templatesSection: "التطبيقات", gettingStarted: "البدء", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "ما هو Agent-Native؟", agentSurfaces: "واجهات Agent", keyConcepts: "المفاهيم الأساسية", diff --git a/packages/docs/app/i18n/de-DE.ts b/packages/docs/app/i18n/de-DE.ts index 327e19f6b5..1b87c971db 100644 --- a/packages/docs/app/i18n/de-DE.ts +++ b/packages/docs/app/i18n/de-DE.ts @@ -1487,6 +1487,9 @@ const deDE = { advancedRuntime: "Fortgeschritten: Runtime erweitern", templatesSection: "Apps", gettingStarted: "Erste Schritte", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "Was ist Agent-Native?", agentSurfaces: "Agent-Oberflächen", keyConcepts: "Schlüsselkonzepte", diff --git a/packages/docs/app/i18n/en-US.ts b/packages/docs/app/i18n/en-US.ts index 9674273a13..f86dd2ad5e 100644 --- a/packages/docs/app/i18n/en-US.ts +++ b/packages/docs/app/i18n/en-US.ts @@ -1477,6 +1477,9 @@ const enUS = { advancedRuntime: "Advanced: Extend the Runtime", templatesSection: "Apps", gettingStarted: "Getting Started", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "What Is Agent-Native?", agentSurfaces: "Agent Surfaces", keyConcepts: "Key Concepts", diff --git a/packages/docs/app/i18n/es-ES.ts b/packages/docs/app/i18n/es-ES.ts index 0e30c1a443..717b1d7210 100644 --- a/packages/docs/app/i18n/es-ES.ts +++ b/packages/docs/app/i18n/es-ES.ts @@ -1487,6 +1487,9 @@ const esES = { advancedRuntime: "Avanzado: extender el runtime", templatesSection: "Apps", gettingStarted: "Primeros pasos", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "¿Qué es Agent-Native?", agentSurfaces: "Superficies del Agent", keyConcepts: "Conceptos clave", diff --git a/packages/docs/app/i18n/fr-FR.ts b/packages/docs/app/i18n/fr-FR.ts index 110f7c4539..ffc188f270 100644 --- a/packages/docs/app/i18n/fr-FR.ts +++ b/packages/docs/app/i18n/fr-FR.ts @@ -1488,6 +1488,9 @@ const frFR = { advancedRuntime: "Avancé : étendre le runtime", templatesSection: "Apps", gettingStarted: "Bien démarrer", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "Qu'est-ce qu'Agent-Native ?", agentSurfaces: "Surfaces Agent", keyConcepts: "Concepts clés", diff --git a/packages/docs/app/i18n/hi-IN.ts b/packages/docs/app/i18n/hi-IN.ts index 489c7d753c..293be8ff1e 100644 --- a/packages/docs/app/i18n/hi-IN.ts +++ b/packages/docs/app/i18n/hi-IN.ts @@ -1477,6 +1477,9 @@ const hiIN = { advancedRuntime: "उन्नत: runtime बढ़ाएं", templatesSection: "ऐप्स", gettingStarted: "शुरुआत", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "Agent-Native क्या है?", agentSurfaces: "Agent surfaces", keyConcepts: "मुख्य अवधारणाएं", diff --git a/packages/docs/app/i18n/ja-JP.ts b/packages/docs/app/i18n/ja-JP.ts index 8088a02da4..021b431a08 100644 --- a/packages/docs/app/i18n/ja-JP.ts +++ b/packages/docs/app/i18n/ja-JP.ts @@ -1484,6 +1484,9 @@ const jaJP = { advancedRuntime: "高度: ランタイムを拡張", templatesSection: "アプリ", gettingStarted: "はじめに", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "Agent-Native とは?", agentSurfaces: "Agent サーフェス", keyConcepts: "主要概念", diff --git a/packages/docs/app/i18n/ko-KR.ts b/packages/docs/app/i18n/ko-KR.ts index de9d01bcfe..779cb1c213 100644 --- a/packages/docs/app/i18n/ko-KR.ts +++ b/packages/docs/app/i18n/ko-KR.ts @@ -1480,6 +1480,9 @@ const koKR = { advancedRuntime: "고급: 런타임 확장", templatesSection: "앱", gettingStarted: "시작하기", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "Agent-Native란?", agentSurfaces: "Agent 표면", keyConcepts: "핵심 개념", diff --git a/packages/docs/app/i18n/pt-BR.ts b/packages/docs/app/i18n/pt-BR.ts index eb2ec7ec7b..2f5dd807cd 100644 --- a/packages/docs/app/i18n/pt-BR.ts +++ b/packages/docs/app/i18n/pt-BR.ts @@ -1483,6 +1483,9 @@ const ptBR = { advancedRuntime: "Avançado: estender o runtime", templatesSection: "Apps", gettingStarted: "Primeiros passos", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "O que é Agent-Native?", agentSurfaces: "Superfícies do Agent", keyConcepts: "Conceitos principais", diff --git a/packages/docs/app/i18n/zh-CN.ts b/packages/docs/app/i18n/zh-CN.ts index 1681566700..27da19bf14 100644 --- a/packages/docs/app/i18n/zh-CN.ts +++ b/packages/docs/app/i18n/zh-CN.ts @@ -1460,6 +1460,9 @@ const zhCN = { advancedRuntime: "高级:扩展运行时", templatesSection: "应用", gettingStarted: "入门", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "什么是 Agent-Native?", agentSurfaces: "Agent 界面", keyConcepts: "核心概念", diff --git a/packages/docs/app/i18n/zh-TW.ts b/packages/docs/app/i18n/zh-TW.ts index 37a339a2bb..42bcf57854 100644 --- a/packages/docs/app/i18n/zh-TW.ts +++ b/packages/docs/app/i18n/zh-TW.ts @@ -1458,6 +1458,9 @@ const messages = { advancedRuntime: "進階:擴充功能執行時", templatesSection: "應用程式", gettingStarted: "入門", + gettingStartedActions: "Add an Action", + gettingStartedDatabase: "Persist Data in SQL", + gettingStartedPages: "Add a Page", whatIsAgentNative: "什麼是 Agent-Native?", agentSurfaces: "Agent 介面", keyConcepts: "核心概念", diff --git a/scripts/i18n-catalog-english-value-baseline.txt b/scripts/i18n-catalog-english-value-baseline.txt index cfee6977d1..8221e874f5 100644 --- a/scripts/i18n-catalog-english-value-baseline.txt +++ b/scripts/i18n-catalog-english-value-baseline.txt @@ -1,6 +1,36 @@ # Existing non-English catalog values that still exactly match English. # Keep this file sorted. Remove entries as catalogs get translated. # Format: relative/catalog/locale|key|English source string +packages/docs/app/i18n/ar-SA|nav.gettingStartedActions|Add an Action +packages/docs/app/i18n/ar-SA|nav.gettingStartedDatabase|Persist Data in SQL +packages/docs/app/i18n/ar-SA|nav.gettingStartedPages|Add a Page +packages/docs/app/i18n/de-DE|nav.gettingStartedActions|Add an Action +packages/docs/app/i18n/de-DE|nav.gettingStartedDatabase|Persist Data in SQL +packages/docs/app/i18n/de-DE|nav.gettingStartedPages|Add a Page +packages/docs/app/i18n/es-ES|nav.gettingStartedActions|Add an Action +packages/docs/app/i18n/es-ES|nav.gettingStartedDatabase|Persist Data in SQL +packages/docs/app/i18n/es-ES|nav.gettingStartedPages|Add a Page +packages/docs/app/i18n/fr-FR|nav.gettingStartedActions|Add an Action +packages/docs/app/i18n/fr-FR|nav.gettingStartedDatabase|Persist Data in SQL +packages/docs/app/i18n/fr-FR|nav.gettingStartedPages|Add a Page +packages/docs/app/i18n/hi-IN|nav.gettingStartedActions|Add an Action +packages/docs/app/i18n/hi-IN|nav.gettingStartedDatabase|Persist Data in SQL +packages/docs/app/i18n/hi-IN|nav.gettingStartedPages|Add a Page +packages/docs/app/i18n/ja-JP|nav.gettingStartedActions|Add an Action +packages/docs/app/i18n/ja-JP|nav.gettingStartedDatabase|Persist Data in SQL +packages/docs/app/i18n/ja-JP|nav.gettingStartedPages|Add a Page +packages/docs/app/i18n/ko-KR|nav.gettingStartedActions|Add an Action +packages/docs/app/i18n/ko-KR|nav.gettingStartedDatabase|Persist Data in SQL +packages/docs/app/i18n/ko-KR|nav.gettingStartedPages|Add a Page +packages/docs/app/i18n/pt-BR|nav.gettingStartedActions|Add an Action +packages/docs/app/i18n/pt-BR|nav.gettingStartedDatabase|Persist Data in SQL +packages/docs/app/i18n/pt-BR|nav.gettingStartedPages|Add a Page +packages/docs/app/i18n/zh-CN|nav.gettingStartedActions|Add an Action +packages/docs/app/i18n/zh-CN|nav.gettingStartedDatabase|Persist Data in SQL +packages/docs/app/i18n/zh-CN|nav.gettingStartedPages|Add a Page +packages/docs/app/i18n/zh-TW|nav.gettingStartedActions|Add an Action +packages/docs/app/i18n/zh-TW|nav.gettingStartedDatabase|Persist Data in SQL +packages/docs/app/i18n/zh-TW|nav.gettingStartedPages|Add a Page templates/assets/app/i18n/ar-SA|brandKitDetail.addReference|Add reference templates/assets/app/i18n/ar-SA|brandKitDetail.chooseReferenceImage|Choose from library templates/assets/app/i18n/ar-SA|brandKitDetail.couldNotUploadReferenceImage|Could not upload reference image. diff --git a/scripts/i18n-localized-doc-coverage-baseline.txt b/scripts/i18n-localized-doc-coverage-baseline.txt index 2e4df97304..2349da029c 100644 --- a/scripts/i18n-localized-doc-coverage-baseline.txt +++ b/scripts/i18n-localized-doc-coverage-baseline.txt @@ -6,6 +6,9 @@ ar-SA|docs-components ar-SA|durable-background-runs ar-SA|external-agents-catalog ar-SA|generative-ui +ar-SA|getting-started-actions +ar-SA|getting-started-database +ar-SA|getting-started-pages ar-SA|http-api ar-SA|integrations ar-SA|messaging-internals @@ -76,6 +79,9 @@ de-DE|docs-components de-DE|durable-background-runs de-DE|external-agents-catalog de-DE|generative-ui +de-DE|getting-started-actions +de-DE|getting-started-database +de-DE|getting-started-pages de-DE|http-api de-DE|integrations de-DE|messaging-internals @@ -146,6 +152,9 @@ es-ES|docs-components es-ES|durable-background-runs es-ES|external-agents-catalog es-ES|generative-ui +es-ES|getting-started-actions +es-ES|getting-started-database +es-ES|getting-started-pages es-ES|http-api es-ES|integrations es-ES|messaging-internals @@ -216,6 +225,9 @@ fr-FR|docs-components fr-FR|durable-background-runs fr-FR|external-agents-catalog fr-FR|generative-ui +fr-FR|getting-started-actions +fr-FR|getting-started-database +fr-FR|getting-started-pages fr-FR|http-api fr-FR|integrations fr-FR|messaging-internals @@ -286,6 +298,9 @@ hi-IN|docs-components hi-IN|durable-background-runs hi-IN|external-agents-catalog hi-IN|generative-ui +hi-IN|getting-started-actions +hi-IN|getting-started-database +hi-IN|getting-started-pages hi-IN|http-api hi-IN|integrations hi-IN|messaging-internals @@ -356,6 +371,9 @@ ja-JP|docs-components ja-JP|durable-background-runs ja-JP|external-agents-catalog ja-JP|generative-ui +ja-JP|getting-started-actions +ja-JP|getting-started-database +ja-JP|getting-started-pages ja-JP|http-api ja-JP|integrations ja-JP|messaging-internals @@ -426,6 +444,9 @@ ko-KR|docs-components ko-KR|durable-background-runs ko-KR|external-agents-catalog ko-KR|generative-ui +ko-KR|getting-started-actions +ko-KR|getting-started-database +ko-KR|getting-started-pages ko-KR|http-api ko-KR|integrations ko-KR|messaging-internals @@ -496,6 +517,9 @@ pt-BR|docs-components pt-BR|durable-background-runs pt-BR|external-agents-catalog pt-BR|generative-ui +pt-BR|getting-started-actions +pt-BR|getting-started-database +pt-BR|getting-started-pages pt-BR|http-api pt-BR|integrations pt-BR|messaging-internals @@ -566,6 +590,9 @@ zh-CN|docs-components zh-CN|durable-background-runs zh-CN|external-agents-catalog zh-CN|generative-ui +zh-CN|getting-started-actions +zh-CN|getting-started-database +zh-CN|getting-started-pages zh-CN|http-api zh-CN|integrations zh-CN|messaging-internals @@ -635,6 +662,9 @@ zh-TW|automation-connectors zh-TW|docs-components zh-TW|external-agents-catalog zh-TW|generative-ui +zh-TW|getting-started-actions +zh-TW|getting-started-database +zh-TW|getting-started-pages zh-TW|http-api zh-TW|integrations zh-TW|messaging-internals diff --git a/scripts/i18n-localized-docs-baseline.txt b/scripts/i18n-localized-docs-baseline.txt index 83bf7b368d..61b67d67e3 100644 --- a/scripts/i18n-localized-docs-baseline.txt +++ b/scripts/i18n-localized-docs-baseline.txt @@ -3,19 +3,6 @@ # Format: relative/localized/path.md|English source string packages/core/docs/content/locales/ar-SA/dispatch.mdx|"summarize last week's signups" packages/core/docs/content/locales/ar-SA/frames.mdx|type: \"code\" -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Agent-callable and UI-callable operations -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Always-on instructions for the app agent -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Hello world -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Local SQLite state when DATABASE_URL is unset -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Nitro server and SQL schema -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Pack my box with five dozen liquor jugs. -packages/core/docs/content/locales/ar-SA/getting-started.mdx|React routes, pages, and chat surfaces -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Results saved by the agent or triggered manually. -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Run the analyze-text action on "Hello world. How are you today?" -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Skills the agent loads when relevant -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Text analyses -packages/core/docs/content/locales/ar-SA/getting-started.mdx|Text statistics -packages/core/docs/content/locales/ar-SA/getting-started.mdx|The quick brown fox jumps over the lazy dog. packages/core/docs/content/locales/ar-SA/messaging.mdx|Microsoft Teams packages/core/docs/content/locales/ar-SA/progress.mdx|Ingest 1M rows packages/core/docs/content/locales/ar-SA/progress.mdx|Triage 128 unread emails @@ -29,19 +16,6 @@ packages/core/docs/content/locales/ar-SA/toolkit-context-knowledge.mdx|Context X packages/core/docs/content/locales/ar-SA/using-your-agent.mdx|**Shared awareness is two-way.** You and the agent both read and write `application_state`, so "reply to this" or "summarize the selection" just works — and when the agent navigates, the real UI moves with it. packages/core/docs/content/locales/de-DE/dispatch.mdx|"summarize last week's signups" packages/core/docs/content/locales/de-DE/frames.mdx|type: \"code\" -packages/core/docs/content/locales/de-DE/getting-started.mdx|Agent-callable and UI-callable operations -packages/core/docs/content/locales/de-DE/getting-started.mdx|Always-on instructions for the app agent -packages/core/docs/content/locales/de-DE/getting-started.mdx|Hello world -packages/core/docs/content/locales/de-DE/getting-started.mdx|Local SQLite state when DATABASE_URL is unset -packages/core/docs/content/locales/de-DE/getting-started.mdx|Nitro server and SQL schema -packages/core/docs/content/locales/de-DE/getting-started.mdx|Pack my box with five dozen liquor jugs. -packages/core/docs/content/locales/de-DE/getting-started.mdx|React routes, pages, and chat surfaces -packages/core/docs/content/locales/de-DE/getting-started.mdx|Results saved by the agent or triggered manually. -packages/core/docs/content/locales/de-DE/getting-started.mdx|Run the analyze-text action on "Hello world. How are you today?" -packages/core/docs/content/locales/de-DE/getting-started.mdx|Skills the agent loads when relevant -packages/core/docs/content/locales/de-DE/getting-started.mdx|Text analyses -packages/core/docs/content/locales/de-DE/getting-started.mdx|Text statistics -packages/core/docs/content/locales/de-DE/getting-started.mdx|The quick brown fox jumps over the lazy dog. packages/core/docs/content/locales/de-DE/messaging.mdx|Microsoft Teams packages/core/docs/content/locales/de-DE/progress.mdx|Ingest 1M rows packages/core/docs/content/locales/de-DE/progress.mdx|Triage 128 unread emails @@ -54,13 +28,6 @@ packages/core/docs/content/locales/de-DE/toolkit-capability-packages.mdx|Creativ packages/core/docs/content/locales/de-DE/using-your-agent.mdx|**Shared awareness is two-way.** You and the agent both read and write `application_state`, so "reply to this" or "summarize the selection" just works — and when the agent navigates, the real UI moves with it. packages/core/docs/content/locales/es-ES/dispatch.mdx|"summarize last week's signups" packages/core/docs/content/locales/es-ES/frames.mdx|type: \"code\" -packages/core/docs/content/locales/es-ES/getting-started.mdx|Hello world -packages/core/docs/content/locales/es-ES/getting-started.mdx|Pack my box with five dozen liquor jugs. -packages/core/docs/content/locales/es-ES/getting-started.mdx|Results saved by the agent or triggered manually. -packages/core/docs/content/locales/es-ES/getting-started.mdx|Run the analyze-text action on "Hello world. How are you today?" -packages/core/docs/content/locales/es-ES/getting-started.mdx|Text analyses -packages/core/docs/content/locales/es-ES/getting-started.mdx|Text statistics -packages/core/docs/content/locales/es-ES/getting-started.mdx|The quick brown fox jumps over the lazy dog. packages/core/docs/content/locales/es-ES/messaging.mdx|Microsoft Teams packages/core/docs/content/locales/es-ES/progress.mdx|Ingest 1M rows packages/core/docs/content/locales/es-ES/progress.mdx|Triage 128 unread emails @@ -74,19 +41,6 @@ packages/core/docs/content/locales/es-ES/toolkit-context-knowledge.mdx|Context X packages/core/docs/content/locales/es-ES/using-your-agent.mdx|**Shared awareness is two-way.** You and the agent both read and write `application_state`, so "reply to this" or "summarize the selection" just works — and when the agent navigates, the real UI moves with it. packages/core/docs/content/locales/fr-FR/dispatch.mdx|"summarize last week's signups" packages/core/docs/content/locales/fr-FR/frames.mdx|type: \"code\" -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Agent-callable and UI-callable operations -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Always-on instructions for the app agent -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Hello world -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Local SQLite state when DATABASE_URL is unset -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Nitro server and SQL schema -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Pack my box with five dozen liquor jugs. -packages/core/docs/content/locales/fr-FR/getting-started.mdx|React routes, pages, and chat surfaces -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Results saved by the agent or triggered manually. -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Run the analyze-text action on "Hello world. How are you today?" -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Skills the agent loads when relevant -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Text analyses -packages/core/docs/content/locales/fr-FR/getting-started.mdx|Text statistics -packages/core/docs/content/locales/fr-FR/getting-started.mdx|The quick brown fox jumps over the lazy dog. packages/core/docs/content/locales/fr-FR/messaging.mdx|Microsoft Teams packages/core/docs/content/locales/fr-FR/progress.mdx|Ingest 1M rows packages/core/docs/content/locales/fr-FR/progress.mdx|Triage 128 unread emails @@ -100,19 +54,6 @@ packages/core/docs/content/locales/fr-FR/toolkit-context-knowledge.mdx|Context X packages/core/docs/content/locales/fr-FR/using-your-agent.mdx|**Shared awareness is two-way.** You and the agent both read and write `application_state`, so "reply to this" or "summarize the selection" just works — and when the agent navigates, the real UI moves with it. packages/core/docs/content/locales/hi-IN/dispatch.mdx|"summarize last week's signups" packages/core/docs/content/locales/hi-IN/frames.mdx|type: \"code\" -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Agent-callable and UI-callable operations -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Always-on instructions for the app agent -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Hello world -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Local SQLite state when DATABASE_URL is unset -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Nitro server and SQL schema -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Pack my box with five dozen liquor jugs. -packages/core/docs/content/locales/hi-IN/getting-started.mdx|React routes, pages, and chat surfaces -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Results saved by the agent or triggered manually. -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Run the analyze-text action on "Hello world. How are you today?" -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Skills the agent loads when relevant -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Text analyses -packages/core/docs/content/locales/hi-IN/getting-started.mdx|Text statistics -packages/core/docs/content/locales/hi-IN/getting-started.mdx|The quick brown fox jumps over the lazy dog. packages/core/docs/content/locales/hi-IN/messaging.mdx|Microsoft Teams packages/core/docs/content/locales/hi-IN/progress.mdx|Ingest 1M rows packages/core/docs/content/locales/hi-IN/progress.mdx|Triage 128 unread emails @@ -126,19 +67,6 @@ packages/core/docs/content/locales/hi-IN/toolkit-context-knowledge.mdx|Context X packages/core/docs/content/locales/hi-IN/using-your-agent.mdx|**Shared awareness is two-way.** You and the agent both read and write `application_state`, so "reply to this" or "summarize the selection" just works — and when the agent navigates, the real UI moves with it. packages/core/docs/content/locales/ja-JP/dispatch.mdx|"summarize last week's signups" packages/core/docs/content/locales/ja-JP/frames.mdx|type: \"code\" -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Agent-callable and UI-callable operations -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Always-on instructions for the app agent -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Hello world -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Local SQLite state when DATABASE_URL is unset -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Nitro server and SQL schema -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Pack my box with five dozen liquor jugs. -packages/core/docs/content/locales/ja-JP/getting-started.mdx|React routes, pages, and chat surfaces -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Results saved by the agent or triggered manually. -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Run the analyze-text action on "Hello world. How are you today?" -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Skills the agent loads when relevant -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Text analyses -packages/core/docs/content/locales/ja-JP/getting-started.mdx|Text statistics -packages/core/docs/content/locales/ja-JP/getting-started.mdx|The quick brown fox jumps over the lazy dog. packages/core/docs/content/locales/ja-JP/messaging.mdx|Microsoft Teams packages/core/docs/content/locales/ja-JP/progress.mdx|Ingest 1M rows packages/core/docs/content/locales/ja-JP/progress.mdx|Triage 128 unread emails @@ -152,19 +80,6 @@ packages/core/docs/content/locales/ja-JP/toolkit-context-knowledge.mdx|Context X packages/core/docs/content/locales/ja-JP/using-your-agent.mdx|**Shared awareness is two-way.** You and the agent both read and write `application_state`, so "reply to this" or "summarize the selection" just works — and when the agent navigates, the real UI moves with it. packages/core/docs/content/locales/ko-KR/dispatch.mdx|"summarize last week's signups" packages/core/docs/content/locales/ko-KR/frames.mdx|type: \"code\" -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Agent-callable and UI-callable operations -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Always-on instructions for the app agent -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Hello world -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Local SQLite state when DATABASE_URL is unset -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Nitro server and SQL schema -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Pack my box with five dozen liquor jugs. -packages/core/docs/content/locales/ko-KR/getting-started.mdx|React routes, pages, and chat surfaces -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Results saved by the agent or triggered manually. -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Run the analyze-text action on "Hello world. How are you today?" -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Skills the agent loads when relevant -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Text analyses -packages/core/docs/content/locales/ko-KR/getting-started.mdx|Text statistics -packages/core/docs/content/locales/ko-KR/getting-started.mdx|The quick brown fox jumps over the lazy dog. packages/core/docs/content/locales/ko-KR/messaging.mdx|Microsoft Teams packages/core/docs/content/locales/ko-KR/onboarding.mdx|Hide setup packages/core/docs/content/locales/ko-KR/progress.mdx|Ingest 1M rows @@ -179,13 +94,6 @@ packages/core/docs/content/locales/ko-KR/toolkit-context-knowledge.mdx|Context X packages/core/docs/content/locales/ko-KR/using-your-agent.mdx|**Shared awareness is two-way.** You and the agent both read and write `application_state`, so "reply to this" or "summarize the selection" just works — and when the agent navigates, the real UI moves with it. packages/core/docs/content/locales/pt-BR/dispatch.mdx|"summarize last week's signups" packages/core/docs/content/locales/pt-BR/frames.mdx|type: \"code\" -packages/core/docs/content/locales/pt-BR/getting-started.mdx|Hello world -packages/core/docs/content/locales/pt-BR/getting-started.mdx|Pack my box with five dozen liquor jugs. -packages/core/docs/content/locales/pt-BR/getting-started.mdx|Results saved by the agent or triggered manually. -packages/core/docs/content/locales/pt-BR/getting-started.mdx|Run the analyze-text action on "Hello world. How are you today?" -packages/core/docs/content/locales/pt-BR/getting-started.mdx|Text analyses -packages/core/docs/content/locales/pt-BR/getting-started.mdx|Text statistics -packages/core/docs/content/locales/pt-BR/getting-started.mdx|The quick brown fox jumps over the lazy dog. packages/core/docs/content/locales/pt-BR/messaging.mdx|Microsoft Teams packages/core/docs/content/locales/pt-BR/progress.mdx|Ingest 1M rows packages/core/docs/content/locales/pt-BR/progress.mdx|Triage 128 unread emails @@ -199,19 +107,6 @@ packages/core/docs/content/locales/pt-BR/toolkit-context-knowledge.mdx|Context X packages/core/docs/content/locales/pt-BR/using-your-agent.mdx|**Shared awareness is two-way.** You and the agent both read and write `application_state`, so "reply to this" or "summarize the selection" just works — and when the agent navigates, the real UI moves with it. packages/core/docs/content/locales/zh-CN/dispatch.mdx|"summarize last week's signups" packages/core/docs/content/locales/zh-CN/frames.mdx|type: \"code\" -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Agent-callable and UI-callable operations -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Always-on instructions for the app agent -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Hello world -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Local SQLite state when DATABASE_URL is unset -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Nitro server and SQL schema -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Pack my box with five dozen liquor jugs. -packages/core/docs/content/locales/zh-CN/getting-started.mdx|React routes, pages, and chat surfaces -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Results saved by the agent or triggered manually. -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Run the analyze-text action on "Hello world. How are you today?" -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Skills the agent loads when relevant -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Text analyses -packages/core/docs/content/locales/zh-CN/getting-started.mdx|Text statistics -packages/core/docs/content/locales/zh-CN/getting-started.mdx|The quick brown fox jumps over the lazy dog. packages/core/docs/content/locales/zh-CN/messaging.mdx|Microsoft Teams packages/core/docs/content/locales/zh-CN/progress.mdx|Ingest 1M rows packages/core/docs/content/locales/zh-CN/progress.mdx|Triage 128 unread emails @@ -225,19 +120,6 @@ packages/core/docs/content/locales/zh-CN/toolkit-context-knowledge.mdx|Context X packages/core/docs/content/locales/zh-CN/using-your-agent.mdx|**Shared awareness is two-way.** You and the agent both read and write `application_state`, so "reply to this" or "summarize the selection" just works — and when the agent navigates, the real UI moves with it. packages/core/docs/content/locales/zh-TW/dispatch.mdx|"summarize last week's signups" packages/core/docs/content/locales/zh-TW/frames.mdx|type: \"code\" -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Agent-callable and UI-callable operations -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Always-on instructions for the app agent -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Hello world -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Local SQLite state when DATABASE_URL is unset -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Nitro server and SQL schema -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Pack my box with five dozen liquor jugs. -packages/core/docs/content/locales/zh-TW/getting-started.mdx|React routes, pages, and chat surfaces -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Results saved by the agent or triggered manually. -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Run the analyze-text action on "Hello world. How are you today?" -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Skills the agent loads when relevant -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Text analyses -packages/core/docs/content/locales/zh-TW/getting-started.mdx|Text statistics -packages/core/docs/content/locales/zh-TW/getting-started.mdx|The quick brown fox jumps over the lazy dog. packages/core/docs/content/locales/zh-TW/messaging.mdx|Microsoft Teams packages/core/docs/content/locales/zh-TW/progress.mdx|Ingest 1M rows packages/core/docs/content/locales/zh-TW/progress.mdx|Triage 128 unread emails From cd94d762cb8813c4c9157149c7b8e74e21d0d7f1 Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Thu, 30 Jul 2026 16:45:34 -0700 Subject: [PATCH 2/9] Improve getting-started visuals and clean up step numbering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Steps series-overview block to getting-started page 1 - Convert blockquote tips to Callout components (info + warning) - Replace What's next bullet list with Cards - Remove step numbers (3–7) from headings on pages 2–4 Co-Authored-By: Claude Sonnet 4.6 --- .../docs/content/getting-started-actions.mdx | 4 +- .../docs/content/getting-started-database.mdx | 2 +- .../docs/content/getting-started-pages.mdx | 4 +- .../core/docs/content/getting-started.mdx | 78 +++++++++++++++---- 4 files changed, 68 insertions(+), 20 deletions(-) diff --git a/packages/core/docs/content/getting-started-actions.mdx b/packages/core/docs/content/getting-started-actions.mdx index 5a40d879e0..5db05af0a8 100644 --- a/packages/core/docs/content/getting-started-actions.mdx +++ b/packages/core/docs/content/getting-started-actions.mdx @@ -7,7 +7,7 @@ description: "Define your first action and render its result as a UI component d This is part two of the Getting Started series. In [Getting Started](/docs/getting-started) you created a Chat app and connected an AI engine. Here you'll define your first action and render its result inline in chat. -## 3. Add an action {#add-an-action} +## Add an action {#add-an-action} An action is a typed operation that both your agent and your UI can call. It's how the agent does things in your app. Actions live in the `actions/` directory @@ -111,7 +111,7 @@ scheduled jobs, and webhooks. TIP: Any time you want the agent to call a specific action without ambiguity, phrasing it as "Run the `` action" is most reliable. Natural-language prompts work well once the agent has enough context about your app's domain. For a brand-new app with no data or context yet, explicit is safer. -## 4. Render the result inline {#render-inline} +## Render the result inline {#render-inline} When the agent runs `analyze-text`, it returns structured data: a title and an array of counts. By default the agent will describe that data in prose: "The diff --git a/packages/core/docs/content/getting-started-database.mdx b/packages/core/docs/content/getting-started-database.mdx index d983c77aa1..5411ed852c 100644 --- a/packages/core/docs/content/getting-started-database.mdx +++ b/packages/core/docs/content/getting-started-database.mdx @@ -7,7 +7,7 @@ description: "Save action results to a SQL database so the agent can reference t This is part three of the Getting Started series. In [Add an Action](/docs/getting-started-actions) you defined the `analyze-text` action and rendered its result inline in chat. Here you'll persist those results to a SQL database. -## 5. Persist data in SQL {#persist-data} +## Persist data in SQL {#persist-data} Right now, every time the agent runs `analyze-text` the result appears in chat and then disappears. There's nothing to look back at, nothing the agent can diff --git a/packages/core/docs/content/getting-started-pages.mdx b/packages/core/docs/content/getting-started-pages.mdx index 1cd748c705..e4e4cfe173 100644 --- a/packages/core/docs/content/getting-started-pages.mdx +++ b/packages/core/docs/content/getting-started-pages.mdx @@ -7,7 +7,7 @@ description: "Build a React route that displays your saved data and wire it into This is part four of the Getting Started series. In [Persist Data in SQL](/docs/getting-started-database) you saved action results to a database. Here you'll build a page that displays that data and connect it to the sidebar. -## 6. Add a page the agent can open {#add-a-page} +## Add a page the agent can open {#add-a-page} Chat is great for conversational interaction, but some data is better inspected in a dedicated UI: a table you can scan, sort, or delete rows from. This step @@ -94,7 +94,7 @@ with a few saved rows: /> -## 7. Extend the navigation {#extend-navigation} +## Extend the navigation {#extend-navigation} The sidebar's links are a plain array in `app/components/layout/Sidebar.tsx`, not a separate config file. Open it and add an entry for the Text analyses diff --git a/packages/core/docs/content/getting-started.mdx b/packages/core/docs/content/getting-started.mdx index fcb550ed67..937c887dab 100644 --- a/packages/core/docs/content/getting-started.mdx +++ b/packages/core/docs/content/getting-started.mdx @@ -14,7 +14,34 @@ hands-on build path. The quickest way in is the **Chat template**: a minimal app that gives you a working AI chat interface, durable threads, auth, and an `actions/` directory -ready to extend. It's the foundation most Agent-Native apps grow from. +ready to extend. This guide is split into four short pages so you can stop at +any point with a working app. + + + +### Create a chat app and connect AI + +Scaffold the Chat template, install dependencies, start the dev server, and +connect an AI engine. You'll have a working agent chat in under five minutes. +**You are here.** + +### Add an action + +Define your first typed action — a text analyzer — and register a React +renderer so the result appears as a bar chart directly inside the chat +transcript. + +### Persist data in SQL + +Wire up a database plugin, define a schema, and add read/write actions so the +agent can save and recall results across conversations. + +### Add a page + +Build a React route that lists saved analyses, then extend the sidebar so users +and the agent can navigate to it. + + ## 1. Create a chat app {#create-your-app} @@ -39,13 +66,16 @@ unavailable`. These are a normal race condition during the initial boot and resolve on their own. The app is ready once **VITE ready** displays in the terminal output. -When the app starts, you might find yourself on the login screen rather than in the app. In this case, just sign up with a made up login to satisfy the login screen. -For local development, no email verification is actually required. +When the app starts, you might find yourself on the login screen rather than in the app. In this case, just sign up with a made-up login to satisfy the login screen. For local development, no email verification is actually required. + + -> **Want to attach a real debugger?** Run `agent-native dev --inspect` (or -> `--inspect-brk[=]`) instead of `pnpm dev` to attach the Node inspector -> to the dev server, on port `9229` by default. Override the dev runner with -> the `NITRO_DEV_RUNNER` env var if your setup needs a different one. +**Want to attach a real debugger?** Run `agent-native dev --inspect` (or +`--inspect-brk[=]`) instead of `pnpm dev` to attach the Node inspector +to the dev server, on port `9229` by default. Override the dev runner with +the `NITRO_DEV_RUNNER` env var if your setup needs a different one. + + ### If you want a different type of app @@ -82,19 +112,37 @@ echo "ANTHROPIC_API_KEY=sk-ant-..." >> .env Restart the dev server. Once an AI engine is connected, the Setup panel hides itself and the agent is ready to chat. -> **Blank screen?** Create a `.env` file in your `my-app/` directory with -> `ANTHROPIC_API_KEY=sk-ant-...`, then restart `pnpm dev`. The in-app Setup -> panel only appears once the app has loaded, so a missing key that prevents -> the app from rendering needs to be fixed via the environment variable rather than -> the UI. + + +**Blank screen?** Create a `.env` file in your `my-app/` directory with +`ANTHROPIC_API_KEY=sk-ant-...`, then restart `pnpm dev`. The in-app Setup +panel only appears once the app has loaded, so a missing key that prevents +the app from rendering needs to be fixed via the environment variable rather than +the UI. + + ## What's next {#next} Your app is running and the agent can respond. Continue the series to build it out: -- **[Add an Action](/docs/getting-started-actions)**: define your first action and render its result inline in chat. -- **[Persist Data in SQL](/docs/getting-started-database)**: save action results so the agent can reference them later. -- **[Add a Page](/docs/getting-started-pages)**: build a React route and wire it into the sidebar. + + +### [Add an Action](/docs/getting-started-actions) + +Define your first typed action and render its result as a chart directly inside +the chat transcript. + +### [Persist Data in SQL](/docs/getting-started-database) + +Save action results to a database so the agent can reference them across +conversations. + +### [Add a Page](/docs/getting-started-pages) + +Build a React route that displays your saved data and wire it into the sidebar. + + Or jump to a specific topic: From d8c85aa12bc8fbbc735ad9da18b7926db424936d Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Thu, 30 Jul 2026 16:54:50 -0700 Subject: [PATCH 3/9] =?UTF-8?q?Convert=20What's=20next=20bullet=20lists=20?= =?UTF-8?q?to=20Cards=20on=20getting-started=20pages=202=E2=80=934?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../docs/content/getting-started-actions.mdx | 27 +++++++++++++---- .../docs/content/getting-started-database.mdx | 27 +++++++++++++---- .../docs/content/getting-started-pages.mdx | 30 ++++++++++++++----- 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/packages/core/docs/content/getting-started-actions.mdx b/packages/core/docs/content/getting-started-actions.mdx index 5db05af0a8..06a0f927d9 100644 --- a/packages/core/docs/content/getting-started-actions.mdx +++ b/packages/core/docs/content/getting-started-actions.mdx @@ -210,9 +210,26 @@ temporary controls the agent creates at runtime, see ## What's next {#next} -Continue to [Persist Data in SQL](/docs/getting-started-database) to save -action results so the agent can reference them later, or jump ahead to: + -- **[Actions](/docs/actions)**: schemas, auth, approvals, hooks, and transport. -- **[Native Chat UI](/docs/native-chat-ui)**: built-in renderers for tables, charts, and cards. -- **[Key Concepts](/docs/key-concepts)**: the architecture underneath this tutorial. +### [Persist Data in SQL](/docs/getting-started-database) + +Save action results to a database so the agent can reference them across +conversations. Next in the series. + +### [Actions](/docs/actions) + +Schemas, auth, approvals, hooks, and transport — the full reference for what +actions can do. + +### [Native Chat UI](/docs/native-chat-ui) + +Built-in renderers for tables, charts, and typed cards — beyond the custom +renderer you just built. + +### [Key Concepts](/docs/key-concepts) + +The architecture underneath this tutorial: SQL, actions, live sync, and context +awareness. + + diff --git a/packages/core/docs/content/getting-started-database.mdx b/packages/core/docs/content/getting-started-database.mdx index 5411ed852c..7f27b8c454 100644 --- a/packages/core/docs/content/getting-started-database.mdx +++ b/packages/core/docs/content/getting-started-database.mdx @@ -228,9 +228,26 @@ Or ask the agent in the chat at `http://localhost:8080` to do both steps at once ## What's next {#next} -Continue to [Add a Page](/docs/getting-started-pages) to build a UI that -displays your saved data, or jump ahead to: + -- **[Storing Data](/docs/storing-data)**: migrations, schema helpers, and production database setup. -- **[Actions](/docs/actions)**: schemas, auth, approvals, hooks, and transport. -- **[Key Concepts](/docs/key-concepts)**: the architecture underneath this tutorial. +### [Add a Page](/docs/getting-started-pages) + +Build a React route that displays your saved analyses and wire it into the +sidebar. Next in the series. + +### [Storing Data](/docs/storing-data) + +Migrations, schema helpers, and production database setup — the full reference +beyond this tutorial. + +### [Actions](/docs/actions) + +Schemas, auth, approvals, hooks, and transport — the full reference for what +actions can do. + +### [Key Concepts](/docs/key-concepts) + +The architecture underneath this tutorial: SQL, actions, live sync, and context +awareness. + + diff --git a/packages/core/docs/content/getting-started-pages.mdx b/packages/core/docs/content/getting-started-pages.mdx index e4e4cfe173..cbb9c7756e 100644 --- a/packages/core/docs/content/getting-started-pages.mdx +++ b/packages/core/docs/content/getting-started-pages.mdx @@ -166,11 +166,25 @@ my-app/ You've built a complete agentic app: a working chat interface, an action, inline rendering, a database, and a page the agent can navigate to. From here: -- **[What Is Agent-Native?](/docs/what-is-agent-native)**: the vision and the case for building this way. -- **[Key Concepts](/docs/key-concepts)**: the architecture underneath this tutorial. -- **[Actions](/docs/actions)**: schemas, auth, approvals, hooks, and transport. -- **[Native Chat UI](/docs/native-chat-ui)**: render action results as tables, charts, and typed cards. -- **[Context Awareness](/docs/context-awareness)**: `view-screen`, `navigate`, route state, and selected objects. -- **[Agent Surfaces](/docs/agent-surfaces)**: chat, inline UI, app pages, embedded sidecars, automation, and external agents. -- **[Deployment](/docs/deployment)**: put your app on your own domain. -- **[FAQ](/docs/faq)**: quick answers on cost, hosting, models, and templates. + + +### [Key Concepts](/docs/key-concepts) + +The architecture underneath this tutorial: SQL, actions, live sync, and context +awareness. + +### [Agent Surfaces](/docs/agent-surfaces) + +Chat, inline UI, app pages, embedded sidecars, automation, and external agents — +all the ways your app can surface the agent. + +### [Context Awareness](/docs/context-awareness) + +`view-screen`, `navigate`, route state, and selected objects — how the agent +knows what the user is looking at. + +### [Deployment](/docs/deployment) + +Put your app on your own domain. + + From 840f048485c87d8a029522448e3354c7d55f7a88 Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Thu, 30 Jul 2026 17:03:07 -0700 Subject: [PATCH 4/9] Truncate code blocks at 17 lines; exclude MDX block headings from TOC - Lower DEFAULT_CODE_MAX_LINES from 30 to 17 - Skip headings inside MDX block components (Cards, Steps, Comparison, etc.) in extractHeadings so card titles don't appear in the right-side TOC Co-Authored-By: Claude Sonnet 4.6 --- packages/docs/app/components/MarkdownRenderer.tsx | 2 +- packages/docs/app/components/docs-content.ts | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/docs/app/components/MarkdownRenderer.tsx b/packages/docs/app/components/MarkdownRenderer.tsx index c3e349ce16..f8934148af 100644 --- a/packages/docs/app/components/MarkdownRenderer.tsx +++ b/packages/docs/app/components/MarkdownRenderer.tsx @@ -22,7 +22,7 @@ interface ImageDimensions { height: number; } -const DEFAULT_CODE_MAX_LINES = 30; +const DEFAULT_CODE_MAX_LINES = 17; const MAX_CONFIGURED_CODE_LINES = 2000; const DOCS_IMAGE_DIMENSIONS: Record = { diff --git a/packages/docs/app/components/docs-content.ts b/packages/docs/app/components/docs-content.ts index cfa5c495b0..bcd092350b 100644 --- a/packages/docs/app/components/docs-content.ts +++ b/packages/docs/app/components/docs-content.ts @@ -107,7 +107,17 @@ function extractHeadings( ): { id: string; label: string; level: number }[] { const headings: { id: string; label: string; level: number }[] = []; const pattern = /^(#{2,4})\s+(.+?)(?:\s+\{#([\w-]+)\})?\s*$/; + let inMdxBlock = false; for (const line of nonFencedMarkdownLines(body)) { + if (/^<[A-Z][A-Za-z]*[\s>]/.test(line.text)) { + inMdxBlock = true; + continue; + } + if (/^<\/[A-Z][A-Za-z]*>/.test(line.text)) { + inMdxBlock = false; + continue; + } + if (inMdxBlock) continue; const match = line.text.match(pattern); if (!match) continue; const level = match[1].length; // 2, 3, or 4 From 890056bf1617d3a5c2af5afca15b136035701a3a Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Fri, 31 Jul 2026 09:15:43 -0700 Subject: [PATCH 5/9] Update MarkdownRenderer test to match new 17-line truncation default Co-Authored-By: Claude Sonnet 4.6 --- packages/docs/app/components/MarkdownRenderer.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/docs/app/components/MarkdownRenderer.test.ts b/packages/docs/app/components/MarkdownRenderer.test.ts index ff718ff27f..aca36b02dd 100644 --- a/packages/docs/app/components/MarkdownRenderer.test.ts +++ b/packages/docs/app/components/MarkdownRenderer.test.ts @@ -87,8 +87,8 @@ describe("renderMarkdownToHtml", () => { const html = renderMarkdownToHtml(`\`\`\`text\n${code}\n\`\`\``); expect(html).toContain('data-collapsed="true"'); - expect(html).toContain('data-code-max-lines="30"'); - expect(html).toContain("Show 2 more lines"); + expect(html).toContain('data-code-max-lines="17"'); + expect(html).toContain("Show 15 more lines"); }); it("renders a filename label bar for fences with a filename attribute", () => { From 30040d800f173157f7e25b6d8737241a4579d24b Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Fri, 31 Jul 2026 09:44:45 -0700 Subject: [PATCH 6/9] Raise timeout on buildSearchIndex tests to 15s The three new getting-started docs pushed index build time past the default 5000ms on two tests that were missing an explicit timeout. Co-Authored-By: Claude Sonnet 4.6 --- .../docs/app/components/docs-content.test.ts | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/packages/docs/app/components/docs-content.test.ts b/packages/docs/app/components/docs-content.test.ts index db625e9935..02810598c2 100644 --- a/packages/docs/app/components/docs-content.test.ts +++ b/packages/docs/app/components/docs-content.test.ts @@ -28,26 +28,34 @@ describe("docs content parsing", () => { ); }); - it("keeps fenced markdown headings out of the search section index", async () => { - const sections = (await buildSearchIndex()).filter( - (entry) => entry.path === "/docs/creating-templates", - ); - - expect(sections.some((entry) => entry.section === "Actions")).toBe(false); - expect( - sections.some((entry) => entry.section === "Application State"), - ).toBe(false); - }); - - it("indexes markdown mirror text instead of raw MDX component source", async () => { - const indexText = (await buildSearchIndex()) - .map((entry) => `${entry.section}\n${entry.text}`) - .join("\n"); - - expect(indexText).not.toMatch( - /<(?:AnnotatedCode|Callout|Checklist|Columns|DataModel|Diff|Endpoint|FileTree|JsonExplorer|OpenApiSpec|Table|Tabs|Wireframe)\b/, - ); - expect(indexText).not.toContain("doc-block-"); - expect(indexText).not.toContain("params={["); - }); + it( + "keeps fenced markdown headings out of the search section index", + async () => { + const sections = (await buildSearchIndex()).filter( + (entry) => entry.path === "/docs/creating-templates", + ); + + expect(sections.some((entry) => entry.section === "Actions")).toBe(false); + expect( + sections.some((entry) => entry.section === "Application State"), + ).toBe(false); + }, + 15_000, + ); + + it( + "indexes markdown mirror text instead of raw MDX component source", + async () => { + const indexText = (await buildSearchIndex()) + .map((entry) => `${entry.section}\n${entry.text}`) + .join("\n"); + + expect(indexText).not.toMatch( + /<(?:AnnotatedCode|Callout|Checklist|Columns|DataModel|Diff|Endpoint|FileTree|JsonExplorer|OpenApiSpec|Table|Tabs|Wireframe)\b/, + ); + expect(indexText).not.toContain("doc-block-"); + expect(indexText).not.toContain("params={["); + }, + 15_000, + ); }); From c9127b23edbd91c4946528133ec1dc97ccda06af Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Fri, 31 Jul 2026 09:59:29 -0700 Subject: [PATCH 7/9] Fix formatting and add changeset Co-Authored-By: Claude Sonnet 4.6 --- .changeset/quick-get-started.md | 5 ++ .../docs/app/components/docs-content.test.ts | 52 ++++++++----------- 2 files changed, 27 insertions(+), 30 deletions(-) create mode 100644 .changeset/quick-get-started.md diff --git a/.changeset/quick-get-started.md b/.changeset/quick-get-started.md new file mode 100644 index 0000000000..94de9c8b4a --- /dev/null +++ b/.changeset/quick-get-started.md @@ -0,0 +1,5 @@ +--- +"@agent-native/core": patch +--- + +Split Getting Started into a focused four-page series with visual improvements diff --git a/packages/docs/app/components/docs-content.test.ts b/packages/docs/app/components/docs-content.test.ts index 02810598c2..00b24305ff 100644 --- a/packages/docs/app/components/docs-content.test.ts +++ b/packages/docs/app/components/docs-content.test.ts @@ -28,34 +28,26 @@ describe("docs content parsing", () => { ); }); - it( - "keeps fenced markdown headings out of the search section index", - async () => { - const sections = (await buildSearchIndex()).filter( - (entry) => entry.path === "/docs/creating-templates", - ); - - expect(sections.some((entry) => entry.section === "Actions")).toBe(false); - expect( - sections.some((entry) => entry.section === "Application State"), - ).toBe(false); - }, - 15_000, - ); - - it( - "indexes markdown mirror text instead of raw MDX component source", - async () => { - const indexText = (await buildSearchIndex()) - .map((entry) => `${entry.section}\n${entry.text}`) - .join("\n"); - - expect(indexText).not.toMatch( - /<(?:AnnotatedCode|Callout|Checklist|Columns|DataModel|Diff|Endpoint|FileTree|JsonExplorer|OpenApiSpec|Table|Tabs|Wireframe)\b/, - ); - expect(indexText).not.toContain("doc-block-"); - expect(indexText).not.toContain("params={["); - }, - 15_000, - ); + it("keeps fenced markdown headings out of the search section index", async () => { + const sections = (await buildSearchIndex()).filter( + (entry) => entry.path === "/docs/creating-templates", + ); + + expect(sections.some((entry) => entry.section === "Actions")).toBe(false); + expect( + sections.some((entry) => entry.section === "Application State"), + ).toBe(false); + }, 15_000); + + it("indexes markdown mirror text instead of raw MDX component source", async () => { + const indexText = (await buildSearchIndex()) + .map((entry) => `${entry.section}\n${entry.text}`) + .join("\n"); + + expect(indexText).not.toMatch( + /<(?:AnnotatedCode|Callout|Checklist|Columns|DataModel|Diff|Endpoint|FileTree|JsonExplorer|OpenApiSpec|Table|Tabs|Wireframe)\b/, + ); + expect(indexText).not.toContain("doc-block-"); + expect(indexText).not.toContain("params={["); + }, 15_000); }); From 87b8c5727afeacebe49200457a4a91f46412b06d Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Fri, 31 Jul 2026 10:02:12 -0700 Subject: [PATCH 8/9] Fix TOC heading loss after self-closing MDX components Single-line self-closing tags () no longer enter block mode. Standalone /> lines (end of multi-line self-closing) now clear block mode. Regression test added using recurring-jobs.mdx / ## Frontmatter. Co-Authored-By: Claude Sonnet 4.6 --- packages/docs/app/components/docs-content.test.ts | 8 ++++++++ packages/docs/app/components/docs-content.ts | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/docs/app/components/docs-content.test.ts b/packages/docs/app/components/docs-content.test.ts index 00b24305ff..8ddb902007 100644 --- a/packages/docs/app/components/docs-content.test.ts +++ b/packages/docs/app/components/docs-content.test.ts @@ -14,6 +14,14 @@ describe("docs content parsing", () => { expect(paths).not.toContain("/docs/workspace"); }, 15_000); + it("keeps headings after self-closing MDX components in the TOC", async () => { + const doc = await loadDoc("recurring-jobs"); + + expect(doc).toBeDefined(); + const ids = doc!.headings.map((h) => h.id); + expect(ids).toContain("frontmatter"); + }); + it("ignores fenced markdown headings when extracting page headings", async () => { const doc = await loadDoc("creating-templates"); diff --git a/packages/docs/app/components/docs-content.ts b/packages/docs/app/components/docs-content.ts index bcd092350b..5421b0c688 100644 --- a/packages/docs/app/components/docs-content.ts +++ b/packages/docs/app/components/docs-content.ts @@ -110,10 +110,12 @@ function extractHeadings( let inMdxBlock = false; for (const line of nonFencedMarkdownLines(body)) { if (/^<[A-Z][A-Za-z]*[\s>]/.test(line.text)) { - inMdxBlock = true; + // Self-closing on one line () — don't enter block mode + if (!line.text.trimEnd().endsWith("/>")) inMdxBlock = true; continue; } - if (/^<\/[A-Z][A-Za-z]*>/.test(line.text)) { + // Closing tag or standalone /> (end of multi-line self-closing tag) + if (/^<\/[A-Z][A-Za-z]*>/.test(line.text) || /^\s*\/>/.test(line.text)) { inMdxBlock = false; continue; } From d287b4c30b0f64bafa024f7112ae7d7c4762e7be Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Fri, 31 Jul 2026 13:05:53 -0700 Subject: [PATCH 9/9] =?UTF-8?q?Fix=20broken=20/docs/storing-data=20link=20?= =?UTF-8?q?=E2=86=92=20/docs/database?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- packages/core/docs/content/getting-started-database.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/docs/content/getting-started-database.mdx b/packages/core/docs/content/getting-started-database.mdx index 7f27b8c454..4b0ce1f3ce 100644 --- a/packages/core/docs/content/getting-started-database.mdx +++ b/packages/core/docs/content/getting-started-database.mdx @@ -235,10 +235,10 @@ Or ask the agent in the chat at `http://localhost:8080` to do both steps at once Build a React route that displays your saved analyses and wire it into the sidebar. Next in the series. -### [Storing Data](/docs/storing-data) +### [Database](/docs/database) Migrations, schema helpers, and production database setup — the full reference -beyond this tutorial. +for SQL in Agent Native. ### [Actions](/docs/actions)