@agent-native/core 0.157.3 → 0.157.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +40 -1
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +3 -1
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/clips/.agents/skills/meetings/SKILL.md +7 -7
- package/corpus/templates/clips/actions/approve-recording-access-request.ts +147 -0
- package/corpus/templates/clips/actions/request-recording-access.ts +121 -23
- package/corpus/templates/clips/actions/view-screen.ts +1 -1
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +34 -53
- package/corpus/templates/clips/app/components/player/request-access-dialog.tsx +104 -0
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +36 -45
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +3 -6
- package/corpus/templates/clips/app/i18n/en-US.ts +26 -1
- package/corpus/templates/clips/app/lib/public-meeting.ts +1 -1
- package/corpus/templates/clips/app/routes/access-request.approve.tsx +250 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +9 -32
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +123 -37
- package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +41 -1
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +1 -0
- package/corpus/templates/clips/server/lib/emails.ts +40 -11
- package/corpus/templates/clips/shared/recording-link.ts +32 -1
- package/corpus/templates/clips/shared/share-attribution.ts +13 -0
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +22 -10
- package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +2 -1
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +245 -9
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +185 -134
- package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +61 -45
- package/corpus/templates/content/app/components/editor/extensions/ImageNode.ts +6 -0
- package/corpus/templates/content/app/components/editor/image-upload.ts +137 -5
- package/corpus/templates/content/app/global.css +8 -0
- package/corpus/templates/content/changelog/2026-08-12-image-uploads-now-confirm-the-image-can-be-displayed-before-.md +6 -0
- package/corpus/templates/content/changelog/2026-08-14-images-fill-the-page-width-by-default-and-remain-visible-whe.md +6 -0
- package/corpus/templates/content/changelog/2026-08-14-images-inserted-from-the-slash-command-stay-saved-after-uplo.md +6 -0
- package/corpus/templates/content/changelog/2026-08-14-svg-files-can-be-selected-reliably-from-the-image-picker.md +6 -0
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +6 -1
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +25 -30
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +21 -0
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +2 -1
- package/corpus/templates/slides/app/components/editor/ShareDialog.tsx +124 -180
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +1 -0
- package/corpus/templates/slides/app/global.css +99 -3
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +21 -0
- package/dist/chat-threads/schema.d.ts +1 -1
- package/dist/cli/code-agent-executor.js +318 -0
- package/dist/client/AgentPanel.d.ts +13 -1
- package/dist/client/AgentPanel.js +41 -3
- package/dist/client/AssistantChat.d.ts +9 -1
- package/dist/client/AssistantChat.js +26 -13
- package/dist/client/MultiTabAssistantChat.js +18 -5
- package/dist/client/agent-chat.d.ts +8 -0
- package/dist/client/agent-chat.js +15 -0
- package/dist/client/app-chat-sidebar.d.ts +23 -0
- package/dist/client/app-chat-sidebar.js +53 -0
- package/dist/client/app-providers.js +31 -2
- package/dist/client/frame-protocol.d.ts +20 -2
- package/dist/client/hooks/index.d.ts +1 -0
- package/dist/client/hooks/index.js +1 -0
- package/dist/client/sharing/AgentShareSection.d.ts +8 -0
- package/dist/client/sharing/AgentShareSection.js +50 -0
- package/dist/client/sharing/ShareButton.js +2 -1
- package/dist/client/sharing/ShareDialog.d.ts +2 -2
- package/dist/client/sharing/ShareDialog.js +21 -29
- package/dist/client/sharing/index.d.ts +1 -0
- package/dist/client/sharing/index.js +1 -0
- package/dist/client/sharing/useShareButtonController.d.ts +1 -0
- package/dist/client/sharing/useShareDialogController.d.ts +3 -0
- package/dist/client/sharing/useShareDialogController.js +2 -1
- package/dist/client/theme.d.ts +21 -0
- package/dist/client/theme.js +60 -0
- package/dist/client/ui/index.d.ts +1 -1
- package/dist/client/ui/index.js +1 -1
- package/dist/client/use-session.js +23 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/dashboard-storage/schema.d.ts +1 -1
- package/dist/data-programs/schema.d.ts +1 -1
- package/dist/extensions/schema.d.ts +1 -1
- package/dist/localization/core-messages/ar-SA.js +6 -0
- package/dist/localization/core-messages/de-DE.js +6 -0
- package/dist/localization/core-messages/en-US.d.ts +6 -0
- package/dist/localization/core-messages/en-US.js +6 -0
- package/dist/localization/core-messages/es-ES.js +6 -0
- package/dist/localization/core-messages/fr-FR.js +6 -0
- package/dist/localization/core-messages/hi-IN.js +6 -0
- package/dist/localization/core-messages/ja-JP.js +6 -0
- package/dist/localization/core-messages/ko-KR.js +6 -0
- package/dist/localization/core-messages/pt-BR.js +6 -0
- package/dist/localization/core-messages/zh-CN.js +6 -0
- package/dist/localization/core-messages/zh-TW.js +6 -0
- package/dist/localization/core-messages.d.ts +6 -0
- package/dist/localization/default-messages.d.ts +1 -0
- package/dist/localization/default-messages.js +1 -0
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
- package/dist/provider-api/actions/provider-api.d.ts +14 -14
- package/dist/server/auth.js +8 -5
- package/dist/server/identity-sso-store.d.ts +6 -1
- package/dist/server/identity-sso-store.js +57 -14
- package/dist/server/identity-sso.d.ts +7 -8
- package/dist/server/identity-sso.js +15 -12
- package/dist/sharing/actions/list-resource-shares.d.ts +2 -0
- package/dist/sharing/actions/list-resource-shares.js +1 -0
- package/dist/sharing/schema.d.ts +1 -1
- package/dist/sharing/schema.js +4 -1
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +21 -0
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/default/.agents/skills/sharing/SKILL.md +21 -0
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +21 -0
- package/docs/content/actions-access-control.mdx +226 -0
- package/docs/content/actions-advanced.mdx +152 -0
- package/docs/content/actions-defining.mdx +275 -0
- package/docs/content/actions-other-surfaces.mdx +167 -0
- package/docs/content/actions-overview.mdx +214 -0
- package/docs/content/actions-run-context.mdx +180 -0
- package/docs/content/agent-surfaces.mdx +1 -1
- package/docs/content/agent-teams.mdx +1 -1
- package/docs/content/agent-web-surfaces.mdx +1 -1
- package/docs/content/audit-log.mdx +1 -1
- package/docs/content/automation-connectors.mdx +1 -1
- package/docs/content/automations.mdx +1 -1
- package/docs/content/blueprint-installer.mdx +1 -1
- package/docs/content/cli-adapters.mdx +1 -1
- package/docs/content/client-agent-chat.mdx +1 -1
- package/docs/content/client-data.mdx +2 -2
- package/docs/content/client-overview.mdx +2 -2
- package/docs/content/components.mdx +1 -1
- package/docs/content/cross-app-sso.mdx +24 -17
- package/docs/content/data-programs.mdx +2 -2
- package/docs/content/database.mdx +1 -1
- package/docs/content/deployment.mdx +1 -1
- package/docs/content/docs-components.mdx +14 -3
- package/docs/content/drop-in-agent.mdx +2 -2
- package/docs/content/durable-resume.mdx +1 -1
- package/docs/content/evals.mdx +1 -1
- package/docs/content/extensions.mdx +1 -1
- package/docs/content/external-agents-catalog.mdx +2 -2
- package/docs/content/external-agents.mdx +1 -1
- package/docs/content/generative-ui.mdx +1 -1
- package/docs/content/getting-started.mdx +1 -1
- package/docs/content/http-api.mdx +4 -4
- package/docs/content/human-approval.mdx +1 -1
- package/docs/content/key-concepts.mdx +1 -1
- package/docs/content/mcp-apps.mdx +1 -1
- package/docs/content/mcp-clients.mdx +1 -1
- package/docs/content/mcp-protocol.mdx +1 -1
- package/docs/content/native-chat-ui.mdx +1 -1
- package/docs/content/observability.mdx +1 -1
- package/docs/content/organizations-teams-permissions.mdx +1 -1
- package/docs/content/processors.mdx +1 -1
- package/docs/content/pure-agent-apps.mdx +1 -1
- package/docs/content/recurring-jobs.mdx +1 -1
- package/docs/content/server-database.mdx +1 -1
- package/docs/content/server-overview.mdx +3 -3
- package/docs/content/server-routes.mdx +2 -2
- package/docs/content/template-analytics-developers.mdx +1 -1
- package/docs/content/template-assets-developers.mdx +1 -1
- package/docs/content/template-brain-developers.mdx +1 -1
- package/docs/content/template-calendar-developers.mdx +1 -1
- package/docs/content/template-chat-first-edits.mdx +1 -1
- package/docs/content/template-chat.mdx +1 -1
- package/docs/content/template-content-developers.mdx +1 -1
- package/docs/content/template-forms-developers.mdx +1 -1
- package/docs/content/template-forms.mdx +1 -1
- package/docs/content/template-mail-developers.mdx +2 -2
- package/docs/content/toolkit-org-team.mdx +1 -1
- package/docs/content/tracking.mdx +1 -1
- package/docs/content/what-is-agent-native.mdx +1 -1
- package/package.json +2 -2
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +21 -0
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/default/.agents/skills/sharing/SKILL.md +21 -0
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +21 -0
- package/docs/content/actions.mdx +0 -750
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Advanced & Legacy"
|
|
3
|
+
description: "Feature-flag gating for actions still rolling out, and the older CLI-only action style (export default async function(args) plus parseArgs) kept for one-off dev scripts."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Advanced & Legacy
|
|
7
|
+
|
|
8
|
+
## Guarding staged features {#feature-flags}
|
|
9
|
+
|
|
10
|
+
Feature flags exist for one specific situation: an action is safe to deploy, but you want to turn it on for a few accounts before everyone gets it. Getting there takes three required steps, plus an optional fourth for the UI.
|
|
11
|
+
|
|
12
|
+
<Steps>
|
|
13
|
+
|
|
14
|
+
### Declare the flag
|
|
15
|
+
|
|
16
|
+
Declare the flag in a module both the server and the client can import, since the same flag key has to reach both sides:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// shared/feature-flags.ts
|
|
20
|
+
import { defineFeatureFlag } from "@agent-native/core/feature-flags";
|
|
21
|
+
|
|
22
|
+
export const FULL_APP_BUILDING = defineFeatureFlag({
|
|
23
|
+
key: "full-app-building",
|
|
24
|
+
displayName: "Full app building",
|
|
25
|
+
description: "Create and edit Fusion-backed applications.",
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`key` is the only field every other piece of code will reference, so it needs to be stable. `displayName` and `description` only show up later, in the operator UI where someone actually turns the flag on. Declaring the flag here doesn't enable anything. Every flag starts out off for every account.
|
|
30
|
+
|
|
31
|
+
### Register it at startup
|
|
32
|
+
|
|
33
|
+
Register the flag with a Nitro plugin so the running server knows it exists:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
// server/plugins/feature-flags.ts
|
|
37
|
+
import { createFeatureFlagsPlugin } from "@agent-native/core/server";
|
|
38
|
+
|
|
39
|
+
import { FULL_APP_BUILDING } from "../../shared/feature-flags.js";
|
|
40
|
+
|
|
41
|
+
export default createFeatureFlagsPlugin({ flags: [FULL_APP_BUILDING] });
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
An unregistered flag always evaluates to `false`, no matter what an operator later sets. This step is what makes the flag real to the server. It still doesn't turn the flag on for anyone. That happens through the operator actions described at the end of this section.
|
|
45
|
+
|
|
46
|
+
### Guard the action
|
|
47
|
+
|
|
48
|
+
This is the check that actually matters, since every caller, whether that's the agent, the frontend, or a script, has to go through it:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// actions/create-fusion-app.ts
|
|
52
|
+
import { isFeatureFlagEnabled } from "@agent-native/core/feature-flags";
|
|
53
|
+
|
|
54
|
+
run: async (args, ctx) => {
|
|
55
|
+
if (!(await isFeatureFlagEnabled(FULL_APP_BUILDING, ctx))) {
|
|
56
|
+
throw new Error("Full app building is not enabled for this account.");
|
|
57
|
+
}
|
|
58
|
+
// Perform the guarded operation.
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`isFeatureFlagEnabled()` reads the caller's identity off `ctx` (see [the ctx argument](/docs/actions-run-context#ctx)) and evaluates the flag for that specific user and org. If the flag isn't on for them, the action throws before doing anything else. This check has to live inside `run()`, because `run()` is the one place every dispatch path is guaranteed to pass through.
|
|
63
|
+
|
|
64
|
+
### Hide it in the UI (optional)
|
|
65
|
+
|
|
66
|
+
Use the same flag on the client to hide the feature from people who can't call it anyway:
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
// app/routes/fusion.tsx
|
|
70
|
+
import { Button } from "@/components/ui/button";
|
|
71
|
+
import { useFeatureFlag } from "@agent-native/core/client";
|
|
72
|
+
|
|
73
|
+
import { FULL_APP_BUILDING } from "../../shared/feature-flags.js";
|
|
74
|
+
|
|
75
|
+
export function CreateFusionAppButton() {
|
|
76
|
+
const enabled = useFeatureFlag(FULL_APP_BUILDING.key);
|
|
77
|
+
if (!enabled) return null;
|
|
78
|
+
return <Button onClick={createFusionApp}>Create Fusion app</Button>;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`useFeatureFlag()` returns a plain boolean, evaluated for the signed-in user the same way the server-side check is. Hiding the button when it's `false` keeps someone from clicking into a feature they can't use yet, but it's presentation only. Nothing about it stops a direct call to the action. That's exactly why the check in `run()` from the previous step still has to be there, regardless of what the UI shows.
|
|
83
|
+
|
|
84
|
+
</Steps>
|
|
85
|
+
|
|
86
|
+
Once a flag is declared and registered, turning it on for real accounts goes through three mounted actions. `get-feature-flags` is the one `useFeatureFlag()` itself calls: it's open to any signed-in caller, since every user needs to check their own flags. `list-feature-flags` and `set-feature-flag` are the two management actions. Both are restricted to an organization's owners and admins (or the no-org administrator), and both are audited.
|
|
87
|
+
|
|
88
|
+
`set-feature-flag` is how an operator actually changes who the flag is on for:
|
|
89
|
+
|
|
90
|
+
| Operation | What it does | Example args |
|
|
91
|
+
| ------------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
92
|
+
| `enable-for-current-user` | Turns the flag on for your own account only. | `{ key: "full-app-building", operation: "enable-for-current-user" }` |
|
|
93
|
+
| `off` | Turns the flag off for everyone, resetting any rules. | `{ key: "full-app-building", operation: "off" }` |
|
|
94
|
+
| `replace-rules`, mode `"on"` | Turns the flag on for everyone. | `{ key: "full-app-building", operation: "replace-rules", rules: { mode: "on" } }` |
|
|
95
|
+
| `replace-rules`, mode `"rules"` with `emails` | Turns it on for a specific list of accounts. | `{ key: "full-app-building", operation: "replace-rules", rules: { mode: "rules", emails: ["a@example.com"] } }` |
|
|
96
|
+
| `replace-rules`, mode `"rules"` with `orgIds` | Turns it on for specific organizations. | `{ key: "full-app-building", operation: "replace-rules", rules: { mode: "rules", orgIds: ["org_123"] } }` |
|
|
97
|
+
| `replace-rules`, mode `"rules"` with `percentage` | Turns it on for a percentage rollout. | `{ key: "full-app-building", operation: "replace-rules", rules: { mode: "rules", percentage: 10 } }` |
|
|
98
|
+
|
|
99
|
+
Fleet operator UIs call these same actions through narrowly scoped A2A delegation instead of a shared login, and Analytics is the sole operator UI for them. Apps should not build their own flag settings panel, and flag writes should never route through generic settings endpoints or raw SQL.
|
|
100
|
+
|
|
101
|
+
<Callout id="doc-block-actions-advanced-1" tone="warning">
|
|
102
|
+
|
|
103
|
+
Never put authentication, authorization, audit, secrets, or SSR cache behavior behind a runtime flag. Those need to be correct unconditionally, not toggled.
|
|
104
|
+
|
|
105
|
+
</Callout>
|
|
106
|
+
|
|
107
|
+
## Legacy CLI-style actions {#legacy-cli-actions}
|
|
108
|
+
|
|
109
|
+
The framework still supports older `export default async function(args)` actions that aren't wrapped in `defineAction()`. These are useful for one-off dev scripts that don't need agent or HTTP exposure. They're CLI-only: they don't appear as agent tools, don't mount HTTP endpoints, and don't get typesafe frontend hooks.
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
// actions/debug-dump.ts (CLI-only)
|
|
113
|
+
import { parseArgs } from "@agent-native/core";
|
|
114
|
+
|
|
115
|
+
export default async function main(args: string[]) {
|
|
116
|
+
const { table } = parseArgs(args);
|
|
117
|
+
// one-off script you wouldn't want the agent to call
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
New code should prefer `defineAction()`. Reach for this pattern only when you deliberately don't want the action exposed to agents or the UI.
|
|
122
|
+
|
|
123
|
+
### `parseArgs(args)` {#parseargs}
|
|
124
|
+
|
|
125
|
+
Helper for legacy-style actions. Parses CLI arguments in `--key value` or `--key=value` format:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { parseArgs } from "@agent-native/core";
|
|
129
|
+
|
|
130
|
+
const args = parseArgs(["--name", "Steve", "--verbose", "--count=3"]);
|
|
131
|
+
// { name: "Steve", verbose: "true", count: "3" }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Utility functions {#utility-functions}
|
|
135
|
+
|
|
136
|
+
These are small helpers for writing scripts, from the same `@agent-native/core` import `parseArgs()` above comes from. They aren't tied to the legacy CLI-style action style specifically. Reach for them in any one-off dev script: loading environment variables, validating a path argument, or aborting with a clear error.
|
|
137
|
+
|
|
138
|
+
| Function | Returns | Description |
|
|
139
|
+
| ----------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
140
|
+
| `loadEnv(path?)` | `void` | Load `.env` (and `.env.local`) from the project root or a custom path. Falls back to the workspace root's `.env` in an enterprise workspace. |
|
|
141
|
+
| `camelCaseArgs(args)` | `Record<string, string>` | Convert kebab-case keys to camelCase. |
|
|
142
|
+
| `isValidPath(p)` | `boolean` | Validate a relative path (no traversal, no absolute). |
|
|
143
|
+
| `isValidProjectPath(p)` | `boolean` | Validate a project slug (e.g. `my-project` or `group/my-project`). |
|
|
144
|
+
| `ensureDir(dir)` | `void` | `mkdir -p` helper. |
|
|
145
|
+
| `fail(message)` | `never` | Throw an error to abort a script. The CLI runner catches it and exits with code 1. In-server callers (agent tools, A2A) get it back as a tool-call error instead. |
|
|
146
|
+
|
|
147
|
+
## What's next
|
|
148
|
+
|
|
149
|
+
- [**Defining Actions**](/docs/actions-defining) — the `defineAction()` pattern this legacy style predates
|
|
150
|
+
- [**Overview**](/docs/actions-overview) — what an action is and the hello-world walkthrough
|
|
151
|
+
- [**Other Surfaces**](/docs/actions-other-surfaces) — the CLI runner these utilities and legacy actions support
|
|
152
|
+
- [**Feature Flags**](/docs/feature-flags) — the full flag lifecycle beyond gating a single action
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Defining Actions"
|
|
3
|
+
description: "The defineAction() anatomy: schema, run, and HTTP config, plus how to keep the action surface small."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Defining Actions
|
|
7
|
+
|
|
8
|
+
Every action starts with a call to `defineAction()`. It bundles a description for the agent, a schema that validates input, and a `run` function that does the work, so the UI and the agent call the exact same code.
|
|
9
|
+
|
|
10
|
+
<AnnotatedCode
|
|
11
|
+
id="doc-block-actions-defining-1"
|
|
12
|
+
title="Anatomy of an action"
|
|
13
|
+
filename="actions/reply-to-email.ts"
|
|
14
|
+
language="ts"
|
|
15
|
+
code={
|
|
16
|
+
'import { defineAction } from "@agent-native/core/action";\nimport { z } from "zod";\n\nimport { getDb, schema } from "../server/db/index.js";\n\nexport default defineAction({\n description: "Reply to an email thread in the user\'s voice.",\n schema: z.object({\n emailId: z.string().describe("The id of the email to reply to."),\n body: z.string().describe("The reply body, in markdown."),\n }),\n run: async ({ emailId, body }) => {\n const db = getDb();\n await db.insert(schema.replies).values({ emailId, body });\n return { ok: true, emailId };\n },\n});'
|
|
17
|
+
}
|
|
18
|
+
annotations={[
|
|
19
|
+
{
|
|
20
|
+
lines: "7",
|
|
21
|
+
label: "Tool surface",
|
|
22
|
+
note: "`description` is what the agent reads to decide when to call this. The per-field `.describe()` calls flow into the JSON Schema too.",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
lines: "8-11",
|
|
26
|
+
label: "Typed contract",
|
|
27
|
+
note: "One schema validates input from **every** surface and is converted to JSON Schema for the model. Invalid inputs never reach `run`.",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
lines: "12-16",
|
|
31
|
+
label: "One implementation",
|
|
32
|
+
note: "The `run` body is the single source of truth. The UI button and the agent tool both execute exactly this. `getDb()` and `schema` come from your app's `server/db/index.ts`. See [Database](/docs/database).",
|
|
33
|
+
},
|
|
34
|
+
]}
|
|
35
|
+
/>
|
|
36
|
+
|
|
37
|
+
The framework auto-discovers every file in `actions/` and mounts it on startup. There's nothing else to register by hand.
|
|
38
|
+
|
|
39
|
+
<Signature
|
|
40
|
+
id="doc-block-actions-defining-2"
|
|
41
|
+
name="defineAction"
|
|
42
|
+
params={[
|
|
43
|
+
{
|
|
44
|
+
name: "config",
|
|
45
|
+
type: "DefineActionConfig<TSchema, TReturn, TOutputSchema>",
|
|
46
|
+
description:
|
|
47
|
+
"Everything below is one config object. Only description, schema, and run are required.",
|
|
48
|
+
fields: [
|
|
49
|
+
{
|
|
50
|
+
name: "description",
|
|
51
|
+
type: "string",
|
|
52
|
+
description:
|
|
53
|
+
"What the agent reads to decide when to call this action.",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "schema",
|
|
57
|
+
type: "StandardSchemaV1",
|
|
58
|
+
description:
|
|
59
|
+
"Validates input on every surface. See Schema options below.",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "run",
|
|
63
|
+
type: "(args, ctx?) => Promise<TReturn> | TReturn",
|
|
64
|
+
description:
|
|
65
|
+
"The single implementation every surface calls. See Run Context for the ctx argument.",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "http",
|
|
69
|
+
type: "ActionHttpConfig | false",
|
|
70
|
+
optional: true,
|
|
71
|
+
description:
|
|
72
|
+
"Overrides the mounted method/path, or disables the HTTP endpoint entirely. See HTTP config below.",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: "readOnly",
|
|
76
|
+
type: "boolean",
|
|
77
|
+
optional: true,
|
|
78
|
+
default: "false",
|
|
79
|
+
description:
|
|
80
|
+
"Auto-true when http.method is GET. Skips the UI poll-refresh and write-auditing. Not access control.",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "outputSchema",
|
|
84
|
+
type: "StandardSchemaV1",
|
|
85
|
+
optional: true,
|
|
86
|
+
description:
|
|
87
|
+
"Validates what run() returns. See Validating the return value below.",
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "outputErrorStrategy",
|
|
91
|
+
type: '"warn" | "strict" | "fallback"',
|
|
92
|
+
optional: true,
|
|
93
|
+
default: '"warn"',
|
|
94
|
+
description: "What happens on an output mismatch.",
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "outputFallback",
|
|
98
|
+
type: "TReturn",
|
|
99
|
+
optional: true,
|
|
100
|
+
description:
|
|
101
|
+
'Returned in place of an invalid result when outputErrorStrategy is "fallback".',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "parallelSafe",
|
|
105
|
+
type: "boolean",
|
|
106
|
+
optional: true,
|
|
107
|
+
description:
|
|
108
|
+
"Allows a mutating action to run concurrently with other same-turn tool calls.",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "agentTool",
|
|
112
|
+
type: "boolean",
|
|
113
|
+
optional: true,
|
|
114
|
+
default: "true",
|
|
115
|
+
description:
|
|
116
|
+
"Set false to hide from every agent tool list. See Access & Authorization.",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: "toolCallable",
|
|
120
|
+
type: "boolean",
|
|
121
|
+
optional: true,
|
|
122
|
+
default: "true",
|
|
123
|
+
description:
|
|
124
|
+
"Set false to block the sandboxed extension iframe bridge. See Access & Authorization.",
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "publicAgent",
|
|
128
|
+
type: "PublicAgentActionConfig",
|
|
129
|
+
optional: true,
|
|
130
|
+
description:
|
|
131
|
+
"{ expose: true } adds the action to public MCP/A2A/OpenAPI surfaces. See Access & Authorization.",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: "needsApproval",
|
|
135
|
+
type: "boolean | ((args, ctx?) => boolean | Promise<boolean>)",
|
|
136
|
+
optional: true,
|
|
137
|
+
default: "false",
|
|
138
|
+
description:
|
|
139
|
+
"Pauses the agent loop for human approval before run(). See Human-in-the-Loop Approvals.",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: "authorize",
|
|
143
|
+
type: "ActionAuthorize<TInput>",
|
|
144
|
+
optional: true,
|
|
145
|
+
description:
|
|
146
|
+
"Guard function deciding whether this caller may run the action at all. See Access & Authorization.",
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: "audit",
|
|
150
|
+
type: "ActionAuditConfig",
|
|
151
|
+
optional: true,
|
|
152
|
+
description:
|
|
153
|
+
"Tunes the automatic audit capture every mutating action already gets. See Audit Log.",
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: "chatUI",
|
|
157
|
+
type: "ActionChatUIConfig",
|
|
158
|
+
optional: true,
|
|
159
|
+
description:
|
|
160
|
+
"Declares a native chat UI renderer for the action's result. See Other Surfaces.",
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
},
|
|
164
|
+
]}
|
|
165
|
+
returns={{
|
|
166
|
+
type: "ActionDefinition<TInput, TReturn>",
|
|
167
|
+
description:
|
|
168
|
+
"The typed action definition. Export it as the file's default export.",
|
|
169
|
+
}}
|
|
170
|
+
/>
|
|
171
|
+
|
|
172
|
+
## Schema options {#schemas}
|
|
173
|
+
|
|
174
|
+
`schema` accepts any [Standard Schema](https://standardschema.dev)-compatible library:
|
|
175
|
+
|
|
176
|
+
- **Zod** (v4): the most common choice, with the best type inference and automatic conversion to JSON Schema.
|
|
177
|
+
- **Valibot**: a good pick when bundle size matters.
|
|
178
|
+
- **ArkType**: a good pick if you prefer its syntax.
|
|
179
|
+
|
|
180
|
+
The schema does two jobs. It converts to JSON Schema for the Claude API tool definition, and it validates input at runtime before `run()` fires. Invalid input never reaches your handler.
|
|
181
|
+
|
|
182
|
+
## Validating the return value {#output-schema}
|
|
183
|
+
|
|
184
|
+
`schema` validates _inputs_. To also validate what an action **returns**, pass an `outputSchema` (any Standard Schema-compatible schema: Zod, Valibot, ArkType, the same surface as `schema`). The framework validates input before `run()` and validates the result after `run()` resolves.
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
export default defineAction({
|
|
188
|
+
description: "Summarize a thread.",
|
|
189
|
+
schema: z.object({ threadId: z.string() }),
|
|
190
|
+
outputSchema: z.object({
|
|
191
|
+
summary: z.string(),
|
|
192
|
+
messageCount: z.number(),
|
|
193
|
+
}),
|
|
194
|
+
outputErrorStrategy: "warn", // default
|
|
195
|
+
run: async ({ threadId }) => {
|
|
196
|
+
/* ...returns { summary, messageCount } ... */
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
`outputErrorStrategy` controls what happens on a mismatch:
|
|
202
|
+
|
|
203
|
+
| Strategy | Behavior on mismatch |
|
|
204
|
+
| ------------ | -------------------------------------------------------------------------------------------------- |
|
|
205
|
+
| `"warn"` | **Default.** `console.warn` the issues and return the **original** result unchanged. Non-breaking. |
|
|
206
|
+
| `"strict"` | Throw a clear error, so a bug in the action is easy to notice. |
|
|
207
|
+
| `"fallback"` | Return the provided `outputFallback` value in place of the invalid result. |
|
|
208
|
+
|
|
209
|
+
When `run()` succeeds, the framework returns the validated value, so any defaults or coercions on `outputSchema` take effect, the same way they do for input. When you don't pass an `outputSchema`, the return value is unchanged.
|
|
210
|
+
|
|
211
|
+
## HTTP config {#http}
|
|
212
|
+
|
|
213
|
+
By default every action is exposed as `POST /_agent-native/actions/<name>`. Override with the `http` option:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
export default defineAction({
|
|
217
|
+
description: "Get details for a lead.",
|
|
218
|
+
schema: z.object({ leadId: z.string() }),
|
|
219
|
+
http: { method: "GET" },
|
|
220
|
+
run: async ({ leadId }) => {
|
|
221
|
+
return await db.select().from(leads).where(eq(leads.id, leadId));
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
For a `GET` action, `leadId` is passed as a query param: `/_agent-native/actions/get-lead?leadId=abc`.
|
|
227
|
+
|
|
228
|
+
<Endpoint id="doc-block-actions-defining-3" title="The auto-mounted action endpoint" method="GET" path="/_agent-native/actions/get-lead" summary={"Every action is mounted here automatically. The filename is the action name."} auth={"Session cookie (frontend calls carry `X-Agent-Native-Frontend: 1`), or `Authorization: Bearer <token>` for external callers"} params={[
|
|
229
|
+
{
|
|
230
|
+
"name": "leadId",
|
|
231
|
+
"in": "query",
|
|
232
|
+
"type": "string",
|
|
233
|
+
"required": true,
|
|
234
|
+
"description": "GET args arrive as query params. POST args arrive in the JSON body."
|
|
235
|
+
}
|
|
236
|
+
]} responses={[
|
|
237
|
+
{
|
|
238
|
+
"status": "200",
|
|
239
|
+
"description": "The action's return value as JSON."
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"status": "400",
|
|
243
|
+
"description": "Input failed schema validation before run() fired."
|
|
244
|
+
}
|
|
245
|
+
]}>
|
|
246
|
+
|
|
247
|
+
POST is the default, and `http: { method: "GET" }` makes it a GET. The React hooks and `callAction()` always call this path by name, regardless of any `http.path` override. External systems can call the same route with a long-lived bearer token. See [HTTP API](/docs/http-api).
|
|
248
|
+
|
|
249
|
+
</Endpoint>
|
|
250
|
+
|
|
251
|
+
- **`http: { method: "GET" | "POST" | "PUT" | "DELETE" }`**: defaults to `POST`. `GET` actions are auto-marked `readOnly`, so a successful call doesn't trigger a UI poll-refresh.
|
|
252
|
+
- **`http: { path: "..." }`**: overrides the mounted URL under `/_agent-native/actions/`. It defaults to the filename. This override only changes the URL for direct HTTP callers. `useActionQuery()`, `useActionMutation()`, and `callAction()` always call `/_agent-native/actions/<name>`, regardless of this override, so overriding the path makes those hooks 404. Use a path override only for external HTTP callers. Also note that `:param` route segments in the override path are not parsed into `run()` args. Only query-string params and JSON body fields are.
|
|
253
|
+
- **`http: false`**: disables the HTTP endpoint entirely. Only the agent and CLI can call the action.
|
|
254
|
+
- **`readOnly: true`**: explicitly skips the poll-refresh, even for POST actions that don't mutate anything. This is not access control. It doesn't restrict who may call the action, and it doesn't affect `useActionQuery()`, `useActionMutation()`, or any client hook. Its only effects are suppressing the post-call refresh event and opting the action out of write-auditing. To hide an action from the model, use `agentTool: false`. To gate who can call it, use the auth and access options on [Access & Authorization](/docs/actions-access-control).
|
|
255
|
+
- **`parallelSafe: true`**: allows a mutating action to run at the same time as other tool calls in the same turn. Only set this when the action is safe to run concurrently and doesn't depend on order. Mutating actions serialize by default.
|
|
256
|
+
|
|
257
|
+
## Keep the action surface small {#small-surface}
|
|
258
|
+
|
|
259
|
+
Every action the agent can see takes up a slot in the model's tool list, and a long, overlapping list makes it harder for the model to pick the right tool. Design the action surface like an API you maintain, not one action per button in the UI:
|
|
260
|
+
|
|
261
|
+
- Prefer **one CRUD-style `update` action** that takes a patch of optional fields, over many per-field actions like `update-name`, `update-order`, and `update-color`. The caller only sends the fields that changed.
|
|
262
|
+
- Before adding a new read action for every query or filter, consider a more general option first: the [provider API trio](/docs/template-dispatch-vault-integrations#provider-api) (`provider-api-catalog`, `provider-api-docs`, and `provider-api-request`) for provider data, or the dev `db-query` tool for app data.
|
|
263
|
+
- Mark UI-only or programmatic actions [`agentTool: false`](/docs/actions-access-control#agent-tool). They stay callable from the frontend or over HTTP, without taking a slot in the model's tool list.
|
|
264
|
+
- Delete or hide actions the UI no longer uses, instead of leaving them exposed to the model.
|
|
265
|
+
|
|
266
|
+
The repo includes an advisory helper, `node scripts/audit-template-actions.mjs [template ...]` (alias `pnpm actions:audit`). It scans a template's `actions/` folder and flags actions the UI may no longer use, along with groups of per-field actions that could be combined into one. It always exits with code 0 and never fails CI, and its heuristics are conservative, so treat its output as a suggestion, not an error.
|
|
267
|
+
|
|
268
|
+
## What's next
|
|
269
|
+
|
|
270
|
+
- [**Overview**](/docs/actions-overview) — what an action is and the hello-world walkthrough
|
|
271
|
+
- [**Access & Authorization**](/docs/actions-access-control) — `agentTool`, `toolCallable`, `authorize`, and `ctx` scoping
|
|
272
|
+
- [**Run Context**](/docs/actions-run-context) — the full `ctx` field table
|
|
273
|
+
- [**Other Surfaces**](/docs/actions-other-surfaces) — native chat UI, CLI, A2A, MCP, and standard actions
|
|
274
|
+
- [**Database**](/docs/database) — `getDb()`/`schema` used inside `run()`
|
|
275
|
+
- [**Data & Sync**](/docs/client-data) — calling this action from the UI
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Other Surfaces"
|
|
3
|
+
description: "Everything that calls an action beyond the UI hooks: native chat UI widget results, the CLI, A2A, MCP, and the two standard actions every template ships."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Other Surfaces
|
|
7
|
+
|
|
8
|
+
The UI-hook surface is covered on [Data & Sync](/docs/client-data): `useActionQuery()`, `useActionMutation()`, and `callAction()`. This page covers everything else that can call, or be driven by, an action.
|
|
9
|
+
|
|
10
|
+
## Rendering native chat UI {#native-chat-ui}
|
|
11
|
+
|
|
12
|
+
Actions can return structured widget data that the in-app chat renders
|
|
13
|
+
natively. This is the first-party chat path for reusable tables, charts, setup
|
|
14
|
+
summaries, and insight cards. Use [Generative UI](/docs/generative-ui) when the
|
|
15
|
+
agent needs to generate arbitrary interactive controls inside the in-app chat,
|
|
16
|
+
and use [MCP Apps](/docs/mcp-apps) for inline UI in external MCP hosts.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { defineAction } from "@agent-native/core/action";
|
|
20
|
+
import { ACTION_CHAT_UI_DATA_CHART_RENDERER } from "@agent-native/core/action-ui";
|
|
21
|
+
import {
|
|
22
|
+
createDataChartWidgetResult,
|
|
23
|
+
dataChartWidgetResultSchema,
|
|
24
|
+
} from "@agent-native/core/data-widgets";
|
|
25
|
+
|
|
26
|
+
export default defineAction({
|
|
27
|
+
description: "Summarize response trends.",
|
|
28
|
+
readOnly: true,
|
|
29
|
+
outputSchema: dataChartWidgetResultSchema,
|
|
30
|
+
chatUI: { renderer: ACTION_CHAT_UI_DATA_CHART_RENDERER },
|
|
31
|
+
run: async () =>
|
|
32
|
+
createDataChartWidgetResult({
|
|
33
|
+
title: "Response trends",
|
|
34
|
+
chartSeries: {
|
|
35
|
+
type: "line",
|
|
36
|
+
xKey: "day",
|
|
37
|
+
series: [{ key: "responses", label: "Responses" }],
|
|
38
|
+
data: [
|
|
39
|
+
{ day: "Mon", responses: 12 },
|
|
40
|
+
{ day: "Tue", responses: 18 },
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The built-in discriminants are `"data-table"`, `"data-chart"`, and
|
|
48
|
+
`"data-insights"`, with server-safe builders and schemas in
|
|
49
|
+
`@agent-native/core/data-widgets`. Use `data-chart` for chart-only answers,
|
|
50
|
+
`data-table` for SQL/list results, and `data-insights` only when a combined
|
|
51
|
+
summary/chart/table card is the right output. See
|
|
52
|
+
[Native Chat UI](/docs/native-chat-ui) for the full result contract, or
|
|
53
|
+
[BYO agent runtimes](/docs/native-chat-ui#byo-agent-runtimes) if you're
|
|
54
|
+
wiring a custom agent runtime instead of the built-in chat loop. See
|
|
55
|
+
[Agent Surfaces](/docs/agent-surfaces) for how the same action can stay
|
|
56
|
+
automation-friendly, render in chat, or grow into a full screen.
|
|
57
|
+
|
|
58
|
+
## Calling it from the CLI {#cli}
|
|
59
|
+
|
|
60
|
+
Every action is runnable via `pnpm action`:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pnpm action reply-to-email '{"emailId":"thread-123","body":"Thanks!"}'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
JSON input is the preferred shape for agents and complex objects. Flags work
|
|
67
|
+
the same way for simple manual runs and existing scripts:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pnpm action reply-to-email --emailId thread-123 --body "Thanks!"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This is useful for agent-dev loops, scripts, and cron jobs.
|
|
74
|
+
|
|
75
|
+
## Calling it from another agent (A2A) {#a2a}
|
|
76
|
+
|
|
77
|
+
If your app is an [A2A](/docs/a2a-protocol) peer, other agent-native apps discover your actions automatically and can call them by name. Same-origin deploys skip JWT signing. Cross-origin deploys use a shared `A2A_SECRET` instead.
|
|
78
|
+
|
|
79
|
+
## Exposing it over MCP {#mcp}
|
|
80
|
+
|
|
81
|
+
With MCP enabled, your actions show up in the framework's MCP server at `/mcp`. Every caller gets a compact catalog by default (app-facing builtins plus the template-declared app actions), and `tool-search` is always present so any other tool stays reachable on demand. The full action surface is served only on explicit opt-in (`--full-catalog` token or `AGENT_NATIVE_MCP_FULL_CATALOG=1`), and [`publicAgent.expose`](/docs/actions-access-control#public-agent) opts a safe read/ingest tool onto the public surface. See [MCP Protocol](/docs/mcp-protocol) for catalog tiers, auth, and the `mcpApp` resource details.
|
|
82
|
+
|
|
83
|
+
For UI-capable MCP hosts, an action can declare an optional MCP Apps resource via the `mcpApp` field (plus a matching `link`) so capable hosts render the result inline. When `link` and `mcpApp` should point at the same route, `embedRoute()` builds both from one pure path builder:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { embedRoute } from "@agent-native/core";
|
|
87
|
+
|
|
88
|
+
export default defineAction({
|
|
89
|
+
description: "Create an email draft for review.",
|
|
90
|
+
schema: z.object({ body: z.string() }),
|
|
91
|
+
run: async ({ body }) => ({ body }),
|
|
92
|
+
...embedRoute({
|
|
93
|
+
title: "Review draft",
|
|
94
|
+
openLabel: "Open in Mail",
|
|
95
|
+
path: ({ result }) => ({
|
|
96
|
+
label: "Open draft in Mail",
|
|
97
|
+
url: "/_agent-native/open?app=mail&view=inbox",
|
|
98
|
+
}),
|
|
99
|
+
}),
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Keep `link` as the fallback for CLI and non-UI MCP hosts. It is also the embed's launch target. The embed bridge (the signed embed-start session, transplant vs. controlled-frame rendering, the `ui/*` host bridge, CSP, and height clamping) is owned by [External Agents](/docs/external-agents#mcp-app-bridge).
|
|
104
|
+
|
|
105
|
+
## Standard actions {#standard-actions}
|
|
106
|
+
|
|
107
|
+
Every template should include these two for [context awareness](/docs/context-awareness).
|
|
108
|
+
|
|
109
|
+
### view-screen {#view-screen}
|
|
110
|
+
|
|
111
|
+
Reads the current navigation state, fetches contextual data, and returns a snapshot of what the user sees. The agent calls this when it needs a fresh look at the screen.
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
// actions/view-screen.ts
|
|
115
|
+
import { defineAction } from "@agent-native/core/action";
|
|
116
|
+
import { readAppState } from "@agent-native/core/application-state";
|
|
117
|
+
import { z } from "zod";
|
|
118
|
+
|
|
119
|
+
export default defineAction({
|
|
120
|
+
description: "Read the current screen state for context.",
|
|
121
|
+
schema: z.object({}),
|
|
122
|
+
http: { method: "GET" },
|
|
123
|
+
run: async () => {
|
|
124
|
+
const navigation = await readAppState("navigation");
|
|
125
|
+
const screen: Record<string, unknown> = { navigation };
|
|
126
|
+
|
|
127
|
+
if (navigation?.view === "inbox") {
|
|
128
|
+
screen.emailList = await listEmailsForLabel(navigation.label);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return screen;
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### navigate {#navigate}
|
|
137
|
+
|
|
138
|
+
Writes a one-shot navigation command to application state. The UI reads it, navigates, and deletes the entry.
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
// actions/navigate.ts
|
|
142
|
+
import { defineAction } from "@agent-native/core/action";
|
|
143
|
+
import { writeAppState } from "@agent-native/core/application-state";
|
|
144
|
+
import { z } from "zod";
|
|
145
|
+
|
|
146
|
+
export default defineAction({
|
|
147
|
+
description: "Navigate the user to a view.",
|
|
148
|
+
schema: z.object({
|
|
149
|
+
view: z.string(),
|
|
150
|
+
threadId: z.string().optional(),
|
|
151
|
+
}),
|
|
152
|
+
run: async (args) => {
|
|
153
|
+
await writeAppState("navigate", args);
|
|
154
|
+
return { ok: true };
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## What's next
|
|
160
|
+
|
|
161
|
+
- [**Data & Sync**](/docs/client-data) — `useActionQuery`, `useActionMutation`, and `callAction` from the UI
|
|
162
|
+
- [**Overview**](/docs/actions-overview) — what an action is and the hello-world walkthrough
|
|
163
|
+
- [**Context Awareness**](/docs/context-awareness) — the `view-screen` + `navigate` pattern in depth
|
|
164
|
+
- [**A2A Protocol**](/docs/a2a-protocol) — how other agents discover and call your actions
|
|
165
|
+
- [**MCP Protocol**](/docs/mcp-protocol) — catalog tiers, auth, and `mcpApp` resources
|
|
166
|
+
- [**Generative UI**](/docs/generative-ui) — rendering transient or persisted generated UI inline in chat
|
|
167
|
+
- [**Native Chat UI**](/docs/native-chat-ui) — the full widget result contract
|