@agent-native/core 0.153.8 → 0.153.10
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/templates/analytics/app/pages/DataSources.tsx +2 -1
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +4 -2
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +4 -2
- package/corpus/templates/clips/app/root.tsx +4 -1
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -2
- package/corpus/templates/clips/desktop/src/app.tsx +1 -1
- package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +2 -1
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +5 -2
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +5 -3
- package/dist/cli/skills-content/help.d.ts +1 -1
- package/dist/cli/skills-content/help.js +2 -1
- package/dist/cli/skills.js +2 -1
- package/dist/client/NewWorkspaceAppFlow.js +4 -1
- package/dist/client/agent-page/AgentTabsPage.d.ts +2 -2
- package/dist/client/agent-page/AgentTabsPage.js +12 -9
- package/dist/client/extensions/ExtensionsSidebarSection.js +2 -1
- package/dist/client/hooks/index.d.ts +1 -1
- package/dist/client/hooks/index.js +1 -1
- package/dist/client/onboarding/FirstRunOnboarding.js +2 -1
- package/dist/client/org/TeamPage.js +14 -3
- package/dist/client/settings/SettingsPanel.js +26 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/integrations/catalog.js +9 -8
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/server/agent-chat-plugin.js +2 -2
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/onboarding-html.js +2 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/shared/docs-url.d.ts +24 -0
- package/dist/shared/docs-url.js +39 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/templates/default/app/routes/_index.tsx +2 -1
- package/docs/content/client-advanced.mdx +200 -0
- package/docs/content/client-agent-chat.mdx +313 -0
- package/docs/content/client-data.mdx +432 -0
- package/docs/content/client-entry-points.mdx +27 -0
- package/docs/content/client-overview.mdx +206 -0
- package/docs/content/client-routing.mdx +121 -0
- package/docs/content/client-sync-internals.mdx +124 -0
- package/docs/content/context-awareness.mdx +1 -1
- package/docs/content/docs-components.mdx +201 -0
- package/docs/content/drop-in-agent.mdx +1 -1
- package/docs/content/internationalization.mdx +1 -1
- package/docs/content/key-concepts.mdx +4 -0
- package/docs/content/notifications.mdx +1 -1
- package/docs/content/progress.mdx +2 -2
- package/docs/content/real-time-collaboration.mdx +2 -2
- package/docs/content/template-chat-developers.mdx +1 -1
- package/docs/content/toolkit-command-navigation.mdx +1 -1
- package/package.json +3 -3
- package/src/templates/default/app/routes/_index.tsx +2 -1
- package/docs/content/client.mdx +0 -486
- package/docs/content/routing.mdx +0 -119
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Runtime behavior stays in adapters and plugins; consumers must use
|
|
6
6
|
* availability and support maturity before offering a connection flow.
|
|
7
7
|
*/
|
|
8
|
+
import { docsUrl } from "../shared/docs-url.js";
|
|
8
9
|
export const INTEGRATION_CATEGORIES = [
|
|
9
10
|
"channel",
|
|
10
11
|
"provider",
|
|
@@ -26,7 +27,7 @@ const BUILT_IN_CHANNEL_CATALOG = [
|
|
|
26
27
|
"Managed installations select encrypted credentials by workspace; legacy manual installs should use SLACK_ALLOWED_TEAM_IDS.",
|
|
27
28
|
],
|
|
28
29
|
documentation: {
|
|
29
|
-
href: "
|
|
30
|
+
href: docsUrl("messaging", { hash: "slack" }),
|
|
30
31
|
externalHref: "https://api.slack.com/apps",
|
|
31
32
|
externalLabel: "Open Slack apps",
|
|
32
33
|
},
|
|
@@ -88,7 +89,7 @@ const BUILT_IN_CHANNEL_CATALOG = [
|
|
|
88
89
|
"Production deployments must allowlist Microsoft Entra tenant IDs; proactive messaging without an inbound conversation reference is not implemented.",
|
|
89
90
|
],
|
|
90
91
|
documentation: {
|
|
91
|
-
href: "
|
|
92
|
+
href: docsUrl("messaging", { hash: "microsoft-teams" }),
|
|
92
93
|
externalHref: "https://dev.botframework.com/",
|
|
93
94
|
externalLabel: "Open Bot Framework",
|
|
94
95
|
},
|
|
@@ -148,7 +149,7 @@ const BUILT_IN_CHANNEL_CATALOG = [
|
|
|
148
149
|
"Interaction tokens are retained only while the queued task is active and normally expire after 15 minutes.",
|
|
149
150
|
],
|
|
150
151
|
documentation: {
|
|
151
|
-
href: "
|
|
152
|
+
href: docsUrl("messaging", { hash: "discord" }),
|
|
152
153
|
externalHref: "https://discord.com/developers/applications",
|
|
153
154
|
externalLabel: "Open Discord applications",
|
|
154
155
|
},
|
|
@@ -197,7 +198,7 @@ const BUILT_IN_CHANNEL_CATALOG = [
|
|
|
197
198
|
"Webhook verification requires TELEGRAM_WEBHOOK_SECRET for production-safe setup.",
|
|
198
199
|
],
|
|
199
200
|
documentation: {
|
|
200
|
-
href: "
|
|
201
|
+
href: docsUrl("messaging", { hash: "telegram" }),
|
|
201
202
|
externalHref: "https://t.me/BotFather",
|
|
202
203
|
externalLabel: "Open BotFather",
|
|
203
204
|
},
|
|
@@ -246,7 +247,7 @@ const BUILT_IN_CHANNEL_CATALOG = [
|
|
|
246
247
|
"Meta pricing and the customer-service conversation window can limit replies; template-message flows are not implemented by this adapter.",
|
|
247
248
|
],
|
|
248
249
|
documentation: {
|
|
249
|
-
href: "
|
|
250
|
+
href: docsUrl("messaging", { hash: "whatsapp" }),
|
|
250
251
|
externalHref: "https://developers.facebook.com/apps",
|
|
251
252
|
externalLabel: "Open Meta developer console",
|
|
252
253
|
},
|
|
@@ -303,7 +304,7 @@ const BUILT_IN_CHANNEL_CATALOG = [
|
|
|
303
304
|
"Email replies preserve RFC email threads and reply-all when the agent was CC'd.",
|
|
304
305
|
],
|
|
305
306
|
documentation: {
|
|
306
|
-
href: "
|
|
307
|
+
href: docsUrl("messaging", { hash: "email" }),
|
|
307
308
|
externalHref: "https://resend.com/webhooks",
|
|
308
309
|
externalLabel: "Open Resend webhooks",
|
|
309
310
|
},
|
|
@@ -363,7 +364,7 @@ const AUTOMATION_CATALOG = [
|
|
|
363
364
|
"Use a configured webhook URL or n8n credential; never put an n8n URL or credential in an agent prompt.",
|
|
364
365
|
],
|
|
365
366
|
documentation: {
|
|
366
|
-
href: "
|
|
367
|
+
href: docsUrl("automation-connectors", { hash: "n8n" }),
|
|
367
368
|
externalHref: "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/",
|
|
368
369
|
externalLabel: "Open n8n Webhook docs",
|
|
369
370
|
},
|
|
@@ -405,7 +406,7 @@ const AUTOMATION_CATALOG = [
|
|
|
405
406
|
"Zapier MCP is a separately configured remote MCP connection with its own account and authorization flow.",
|
|
406
407
|
],
|
|
407
408
|
documentation: {
|
|
408
|
-
href: "
|
|
409
|
+
href: docsUrl("automation-connectors", { hash: "zapier" }),
|
|
409
410
|
externalHref: "https://docs.zapier.com/mcp/home",
|
|
410
411
|
externalLabel: "Open Zapier MCP docs",
|
|
411
412
|
},
|
|
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
+
error?: undefined;
|
|
44
45
|
summary: import("./types.js").TraceSummary;
|
|
45
46
|
spans: import("./types.js").TraceSpan[];
|
|
46
47
|
id?: undefined;
|
|
47
|
-
error?: undefined;
|
|
48
48
|
ok?: undefined;
|
|
49
49
|
} | {
|
|
50
|
+
error?: undefined;
|
|
50
51
|
summary?: undefined;
|
|
51
52
|
spans?: undefined;
|
|
52
53
|
id: string;
|
|
53
|
-
error?: undefined;
|
|
54
54
|
ok?: undefined;
|
|
55
55
|
} | {
|
|
56
56
|
summary?: undefined;
|
|
@@ -59,9 +59,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
59
59
|
error: any;
|
|
60
60
|
ok?: undefined;
|
|
61
61
|
} | {
|
|
62
|
+
error?: undefined;
|
|
62
63
|
summary?: undefined;
|
|
63
64
|
spans?: undefined;
|
|
64
65
|
id?: undefined;
|
|
65
66
|
ok: boolean;
|
|
66
|
-
error?: undefined;
|
|
67
67
|
}>>;
|
|
@@ -34,6 +34,7 @@ import { getSkillNameFromPath } from "../resources/metadata.js";
|
|
|
34
34
|
import { resourceList, resourceListAccessible, resourceGet, ensurePersonalDefaults, SHARED_OWNER, WORKSPACE_OWNER, } from "../resources/store.js";
|
|
35
35
|
import { normalizeDatabaseToolsMode } from "../scripts/db/tool-mode.js";
|
|
36
36
|
import { getSetting, putSetting } from "../settings/store.js";
|
|
37
|
+
import { docsUrl } from "../shared/docs-url.js";
|
|
37
38
|
import { handleSharedThreadRequest, } from "./agent-chat/shared-thread.js";
|
|
38
39
|
import { discoverAgents } from "./agent-discovery.js";
|
|
39
40
|
import { resolveAgentRunOwnerContext, runWithAgentRunContext, seedBackgroundAgentRunOwnerContext, } from "./agent-run-context.js";
|
|
@@ -3510,8 +3511,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
3510
3511
|
}
|
|
3511
3512
|
const result = { skills };
|
|
3512
3513
|
if (skills.length === 0) {
|
|
3513
|
-
result.hint =
|
|
3514
|
-
"No skills found. Add skill files under skills/ in Resources. Learn more: https://agent-native.com/docs/resources#skills";
|
|
3514
|
+
result.hint = `No skills found. Add skill files under skills/ in Resources. Learn more: ${docsUrl("agent-resources", { hash: "skills" })}`;
|
|
3515
3515
|
}
|
|
3516
3516
|
return result;
|
|
3517
3517
|
}));
|
|
@@ -27,10 +27,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
|
|
|
27
27
|
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
28
28
|
error: any;
|
|
29
29
|
} | {
|
|
30
|
+
error?: undefined;
|
|
30
31
|
ok: boolean;
|
|
31
32
|
key: string;
|
|
32
33
|
baseUrlKey?: string;
|
|
33
34
|
scope: AgentEngineApiKeyScope;
|
|
34
|
-
error?: undefined;
|
|
35
35
|
}>>;
|
|
36
36
|
export {};
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { getLocaleInitScript } from "../localization/server.js";
|
|
10
10
|
import { DEFAULT_LOCALE, LOCALE_METADATA, LOCALE_STORAGE_KEY, SUPPORTED_LOCALES, } from "../localization/shared.js";
|
|
11
|
+
import { docsUrl } from "../shared/docs-url.js";
|
|
11
12
|
import { PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, } from "../shared/password-policy.js";
|
|
12
13
|
import { signInJourneyInlineScript } from "../shared/sign-in-journey.js";
|
|
13
14
|
import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, withAgentNativeSocialImageCacheBuster, } from "../shared/social-meta.js";
|
|
@@ -1424,7 +1425,7 @@ ${localeMenuItemsHtml}
|
|
|
1424
1425
|
<button type="button" class="btn-local-dev btn-primary" id="local-dev-btn" title="${esc(t("localDevDescription"))}"${i18nAttr("localDevButton")} data-i18n-title="localDevDescription" aria-describedby="local-dev-description">${esc(t("localDevButton"))}</button>
|
|
1425
1426
|
<p class="local-dev-description" id="local-dev-description">
|
|
1426
1427
|
<span${i18nAttr("localDevDescription")}>${esc(t("localDevDescription"))}</span>
|
|
1427
|
-
<a class="local-dev-help" id="local-dev-help" href="
|
|
1428
|
+
<a class="local-dev-help" id="local-dev-help" href="${docsUrl("authentication", { hash: "local-development-sign-in" })}" target="_blank" rel="noreferrer" aria-label="${esc(t("localDevHelp"))}" title="${esc(t("localDevHelp"))}" data-i18n-title="localDevHelp"${i18nAriaAttr("localDevHelp")}><span class="local-dev-help-glyph" aria-hidden="true">?</span></a>
|
|
1428
1429
|
</p>
|
|
1429
1430
|
<button type="button" class="local-dev-full-options" id="local-dev-full-options" hidden${i18nAttr("localDevFullOptions")}>${esc(t("localDevFullOptions"))}</button>
|
|
1430
1431
|
<p class="msg error" id="local-dev-msg" role="status" aria-live="polite"></p>
|
|
@@ -26,8 +26,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
expiresAt?: undefined;
|
|
27
27
|
ttlSeconds?: undefined;
|
|
28
28
|
} | {
|
|
29
|
+
error?: undefined;
|
|
29
30
|
token: string;
|
|
30
31
|
expiresAt: string;
|
|
31
32
|
ttlSeconds: number;
|
|
32
|
-
error?: undefined;
|
|
33
33
|
}>>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Absolute links into the public Agent-Native docs site.
|
|
3
|
+
*
|
|
4
|
+
* Call `docsUrl("content-slug")` at call sites so the path is visible inline
|
|
5
|
+
* (`docsUrl("template-design")` → `/docs/template-design`). Relative
|
|
6
|
+
* `/docs/...` paths resolve against the app origin and 404 — always use this
|
|
7
|
+
* helper for outbound docs links.
|
|
8
|
+
*/
|
|
9
|
+
export declare const AGENT_NATIVE_DOCS_ORIGIN = "https://www.agent-native.com";
|
|
10
|
+
export type DocsUrlOptions = {
|
|
11
|
+
hash?: string;
|
|
12
|
+
/** UTM medium; defaults to `product` when any UTM field is set. */
|
|
13
|
+
medium?: string;
|
|
14
|
+
/** UTM campaign; defaults to `docs` when any UTM field is set. */
|
|
15
|
+
campaign?: string;
|
|
16
|
+
content?: string | null;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Build an absolute docs URL for a content slug (the MDX stem under
|
|
20
|
+
* `packages/core/docs/content/`).
|
|
21
|
+
*
|
|
22
|
+
* `getting-started` maps to `/docs` (the docs home).
|
|
23
|
+
*/
|
|
24
|
+
export declare function docsUrl(slug: string, options?: DocsUrlOptions): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Absolute links into the public Agent-Native docs site.
|
|
3
|
+
*
|
|
4
|
+
* Call `docsUrl("content-slug")` at call sites so the path is visible inline
|
|
5
|
+
* (`docsUrl("template-design")` → `/docs/template-design`). Relative
|
|
6
|
+
* `/docs/...` paths resolve against the app origin and 404 — always use this
|
|
7
|
+
* helper for outbound docs links.
|
|
8
|
+
*/
|
|
9
|
+
export const AGENT_NATIVE_DOCS_ORIGIN = "https://www.agent-native.com";
|
|
10
|
+
function applyDocsUtm(params, options) {
|
|
11
|
+
const wantsUtm = options.medium != null ||
|
|
12
|
+
options.campaign != null ||
|
|
13
|
+
options.content != null;
|
|
14
|
+
if (!wantsUtm)
|
|
15
|
+
return;
|
|
16
|
+
params.set("utm_source", "agent-native");
|
|
17
|
+
params.set("utm_medium", options.medium ?? "product");
|
|
18
|
+
params.set("utm_campaign", options.campaign ?? "docs");
|
|
19
|
+
if (options.content)
|
|
20
|
+
params.set("utm_content", options.content);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build an absolute docs URL for a content slug (the MDX stem under
|
|
24
|
+
* `packages/core/docs/content/`).
|
|
25
|
+
*
|
|
26
|
+
* `getting-started` maps to `/docs` (the docs home).
|
|
27
|
+
*/
|
|
28
|
+
export function docsUrl(slug, options = {}) {
|
|
29
|
+
const normalized = slug.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
30
|
+
const path = normalized === "" || normalized === "getting-started"
|
|
31
|
+
? "/docs"
|
|
32
|
+
: `/docs/${normalized}`;
|
|
33
|
+
const url = new URL(path, AGENT_NATIVE_DOCS_ORIGIN);
|
|
34
|
+
applyDocsUtm(url.searchParams, options);
|
|
35
|
+
if (options.hash) {
|
|
36
|
+
url.hash = options.hash.replace(/^#/, "");
|
|
37
|
+
}
|
|
38
|
+
return url.toString();
|
|
39
|
+
}
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { truncate } from "./truncate.js";
|
|
|
6
6
|
export { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "./document-title.js";
|
|
7
7
|
export { injectDocumentMarkup } from "./html-document.js";
|
|
8
8
|
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
9
|
+
export { AGENT_NATIVE_DOCS_ORIGIN, docsUrl, type DocsUrlOptions, } from "./docs-url.js";
|
|
9
10
|
export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, type RuntimeConfigEnvironment, type RuntimeConfigIssue, type RuntimeConfigIssueCode, type RuntimeConfigIssueSeverity, type RuntimeConfigPhase, type RuntimeConfigReport, type RuntimeConfigRequirements, } from "./runtime-config.js";
|
|
10
11
|
export { llmConnectionTrackingProperties, normalizeLlmConnection, type LlmConnectionStatus, } from "./llm-connection.js";
|
|
11
12
|
export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, normalizeWorkspaceAppId, } from "./workspace-app-id.js";
|
package/dist/shared/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export { truncate } from "./truncate.js";
|
|
|
6
6
|
export { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "./document-title.js";
|
|
7
7
|
export { injectDocumentMarkup } from "./html-document.js";
|
|
8
8
|
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
9
|
+
export { AGENT_NATIVE_DOCS_ORIGIN, docsUrl, } from "./docs-url.js";
|
|
9
10
|
export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, } from "./runtime-config.js";
|
|
10
11
|
export { llmConnectionTrackingProperties, normalizeLlmConnection, } from "./llm-connection.js";
|
|
11
12
|
export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, normalizeWorkspaceAppId, } from "./workspace-app-id.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useActionQuery } from "@agent-native/core/client/hooks";
|
|
2
2
|
import { useT } from "@agent-native/core/client/i18n";
|
|
3
|
+
import { docsUrl } from "@agent-native/core/shared";
|
|
3
4
|
import { useTheme } from "next-themes";
|
|
4
5
|
import { Link } from "react-router";
|
|
5
6
|
|
|
@@ -41,7 +42,7 @@ export default function IndexPage() {
|
|
|
41
42
|
|
|
42
43
|
<div className="grid grid-cols-2 gap-3 text-left">
|
|
43
44
|
<a
|
|
44
|
-
href="
|
|
45
|
+
href={docsUrl("getting-started")}
|
|
45
46
|
target="_blank"
|
|
46
47
|
rel="noopener noreferrer"
|
|
47
48
|
className="group rounded-lg border border-border/50 px-4 py-3 hover:bg-accent/50 transition-colors"
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Advanced"
|
|
3
|
+
description: "Lower-level app/ primitives and escape hatches: direct application-state access, background chat sends, custom suggestion chips, and the MCP App host bridge."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Advanced
|
|
7
|
+
|
|
8
|
+
Overview, Data & Sync, Agent Chat, and Routing cover the typical case: the hooks and helpers most pages need. This page covers the lower-level primitives and narrower escape hatches underneath them. Most apps never touch these directly. Reach for one when you're building something more custom than the default hooks support, such as a custom selection sync or an embedded MCP App. For syncing a raw `useQuery` with a hand-rolled key, see [Sync Internals](/docs/client-sync-internals) instead.
|
|
9
|
+
|
|
10
|
+
## Application State {#application-state}
|
|
11
|
+
|
|
12
|
+
`application_state` is the SQL-backed key/value store the agent reads to know what the UI is currently looking at, including navigation, selection, and other focused-object context (see [Context Awareness](/docs/context-awareness)). `useAgentRouteState` and `useSemanticNavigationState` (also covered in Context Awareness) already wrap these for the common navigation case. Reach for the primitives below directly when you're syncing something they don't cover, such as a custom selection, or writing from outside a component's render.
|
|
13
|
+
|
|
14
|
+
### readClientAppState {#read-client-app-state}
|
|
15
|
+
|
|
16
|
+
Read the current value for a key. Resolves to whatever was last written for that key, or `null` if the key has never been written.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { readClientAppState } from "@agent-native/core/client/hooks";
|
|
20
|
+
|
|
21
|
+
const selection = await readClientAppState("selection");
|
|
22
|
+
// selection is exactly what was last written to that key, e.g.:
|
|
23
|
+
// { kind: "tickets.rows", ids: ["tik_182", "tik_209"] }
|
|
24
|
+
//
|
|
25
|
+
// or, if nothing has written "selection" yet:
|
|
26
|
+
// null
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### writeClientAppState {#write-client-app-state}
|
|
30
|
+
|
|
31
|
+
Write a value for a key. Unlike `setClientAppState` below, it always writes, even if you pass `null`. Passing `undefined` throws instead, since `undefined` isn't valid JSON. Use `setClientAppState(key, undefined)` or `deleteClientAppState()` to clear a key.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { writeClientAppState } from "@agent-native/core/client/hooks";
|
|
35
|
+
|
|
36
|
+
await writeClientAppState(
|
|
37
|
+
"selection",
|
|
38
|
+
{ id: recordId },
|
|
39
|
+
{ requestSource: TAB_ID },
|
|
40
|
+
);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### setClientAppState {#set-client-app-state}
|
|
44
|
+
|
|
45
|
+
The convenience wrapper most UI code should reach for: writes the value, or deletes the key when you pass `null`/`undefined`. Use this instead of `writeClientAppState` unless a call site genuinely needs "always write, never delete."
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { setClientAppState } from "@agent-native/core/client/hooks";
|
|
49
|
+
|
|
50
|
+
await setClientAppState(
|
|
51
|
+
"selection",
|
|
52
|
+
{ id: recordId },
|
|
53
|
+
{ requestSource: TAB_ID },
|
|
54
|
+
);
|
|
55
|
+
await setClientAppState("selection", null); // clears the key, same as deleteClientAppState
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### deleteClientAppState {#delete-client-app-state}
|
|
59
|
+
|
|
60
|
+
Remove a key entirely.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { deleteClientAppState } from "@agent-native/core/client/hooks";
|
|
64
|
+
|
|
65
|
+
await deleteClientAppState("pending-selection-context");
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### readClientAppStateMany {#read-client-app-state-many}
|
|
69
|
+
|
|
70
|
+
Read several keys in one request. Returns `{ values, missing }`. `values` holds an entry for every key the server has a row for, including a key that was explicitly written as `null`. `missing` lists the keys that have never been written at all. This is how "never written" stays distinguishable from "written as null."
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { readClientAppStateMany } from "@agent-native/core/client/hooks";
|
|
74
|
+
|
|
75
|
+
const { values, missing } = await readClientAppStateMany([
|
|
76
|
+
"selection",
|
|
77
|
+
"pending-selection-context",
|
|
78
|
+
]);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Requests over 100 keys are chunked automatically. `readClientAppState()` itself is built on this: calls issued in the same tick are coalesced into one batched request behind the scenes, so calling it many times in a single render pass costs one round trip, not one per call.
|
|
82
|
+
|
|
83
|
+
### Options {#application-state-options}
|
|
84
|
+
|
|
85
|
+
`signal` is accepted by all five functions above, to cancel an in-flight call. `requestSource` and `keepalive` only apply to the three write functions, since they don't mean anything for a read.
|
|
86
|
+
|
|
87
|
+
| Option | Type | Applies to | Description |
|
|
88
|
+
| --------------- | -------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
|
|
89
|
+
| `requestSource` | `string?` | `writeClientAppState`, `setClientAppState`, `deleteClientAppState` | Tags the write with an id so a matching `useDbSync({ ignoreSource })` can skip refetching it |
|
|
90
|
+
| `keepalive` | `boolean?` | `writeClientAppState`, `setClientAppState`, `deleteClientAppState` | Lets the request outlive page unload. Use for cleanup writes like clearing selection |
|
|
91
|
+
| `signal` | `AbortSignal?` | all five functions | Cancels the request |
|
|
92
|
+
|
|
93
|
+
### Failure behavior {#failure-behavior}
|
|
94
|
+
|
|
95
|
+
All five functions throw on a failed request, a non-2xx response, or a body that can't be parsed. The thrown `Error` carries a `.status` property when the server responded, so a caller can branch on the HTTP status if needed. Wrap a call in `try`/`catch`, or let it propagate to an error boundary, the same as any other network call.
|
|
96
|
+
|
|
97
|
+
### What TAB_ID is {#tab-id}
|
|
98
|
+
|
|
99
|
+
`requestSource` is commonly set to `TAB_ID`, a plain constant every template exports from `app/lib/tab-id.ts`: a short random string that stays the same for the life of a tab and differs between tabs. Pairing `requestSource: TAB_ID` on a write with `useDbSync({ ignoreSource: TAB_ID })` on the read side is how a tab avoids refetching its own write while still reacting to everyone else. See [Context Awareness](/docs/context-awareness#jitter-prevention) for the full walkthrough.
|
|
100
|
+
|
|
101
|
+
## sendToAgentChat: Background Sends {#background-send}
|
|
102
|
+
|
|
103
|
+
Use `background: true` when a UI action should kick off real agent work without
|
|
104
|
+
opening or focusing the sidebar. This still creates a normal chat thread/run,
|
|
105
|
+
uses the agent's tools/actions/context, and keeps the work observable through
|
|
106
|
+
the runs tray. It is not a raw one-shot model call.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { sendToAgentChat } from "@agent-native/core/client/agent-chat";
|
|
110
|
+
|
|
111
|
+
const tabId = sendToAgentChat({
|
|
112
|
+
message: "Analyze this import and create any missing records",
|
|
113
|
+
context: `Import batch id: ${batchId}`,
|
|
114
|
+
submit: true,
|
|
115
|
+
newTab: true,
|
|
116
|
+
background: true,
|
|
117
|
+
openSidebar: false,
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`background` is intended to be paired with `newTab` so the hidden work does not
|
|
122
|
+
overwrite the user's active conversation. Use the returned `tabId` if the UI
|
|
123
|
+
needs to correlate follow-up status or deep-link into the run later.
|
|
124
|
+
|
|
125
|
+
A few more `AgentChatMessage` options exist beyond the ones covered in [Agent Chat](/docs/client-agent-chat#agentchatmessage), mostly for embedded or downstream-integration cases:
|
|
126
|
+
|
|
127
|
+
| Option | Type | Description |
|
|
128
|
+
| --------------------- | ----------- | -------------------------------------------------------------------------- |
|
|
129
|
+
| `background` | `boolean?` | With `newTab`, run without focusing the tab and show the run in `RunsTray` |
|
|
130
|
+
| `projectSlug` | `string?` | Optional project slug for structured context |
|
|
131
|
+
| `preset` | `string?` | Optional preset name for downstream consumers |
|
|
132
|
+
| `referenceImagePaths` | `string[]?` | Optional reference image paths |
|
|
133
|
+
|
|
134
|
+
## MCP App Host Bridge {#mcp-app-host-bridge}
|
|
135
|
+
|
|
136
|
+
Routes embedded as MCP Apps should be URL-first: load the current artifact from
|
|
137
|
+
path/query params, render the real React route or a focused shared component,
|
|
138
|
+
and use the host bridge only for host-owned behavior. `@agent-native/core/client`
|
|
139
|
+
exports the helpers embedded routes call:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import {
|
|
143
|
+
getMcpAppHostContext,
|
|
144
|
+
openMcpAppHostLink,
|
|
145
|
+
requestMcpAppDisplayMode,
|
|
146
|
+
updateMcpAppModelContext,
|
|
147
|
+
useMcpAppHostContext,
|
|
148
|
+
} from "@agent-native/core/client/agent-chat";
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`getMcpAppHostContext()` reads the latest pushed host context snapshot.
|
|
152
|
+
`useMcpAppHostContext()` subscribes React components to changes. The request
|
|
153
|
+
helpers (`openMcpAppHostLink`, `requestMcpAppDisplayMode`,
|
|
154
|
+
`updateMcpAppModelContext`) return `false` outside an embedded MCP App frame, or
|
|
155
|
+
`Promise<boolean>` inside a frame.
|
|
156
|
+
|
|
157
|
+
`sendToAgentChat()` (see [Agent Chat](/docs/client-agent-chat#sendtoagentchat)) uses the same bridge for auto-submitted prompts from embedded routes. Inside an MCP App embed created with `embedApp()`, auto-submitted messages (`submit` omitted or `true`) are forwarded to the bridge, which asks the containing host to add hidden context and send the visible user turn. `context` stays model-visible without being posted as user-facing chat. `submit: false` keeps the local prefill/review behavior because MCP Apps do not define a standard draft-prefill API. Internally this is the submitted-chat path sometimes surfaced as `agentNative.submitChat`. App code should still call `sendToAgentChat()` rather than posting that event directly.
|
|
158
|
+
|
|
159
|
+
The bridge itself, the `ui/*` JSON-RPC messages, the `agentNative.mcpHost.*`
|
|
160
|
+
wrapper relay, transplant vs. controlled-frame rendering, host context, and
|
|
161
|
+
display-mode requests, is owned by
|
|
162
|
+
[External Agents](/docs/external-agents#mcp-app-bridge). See [MCP Apps](/docs/mcp-apps) for the full protocol.
|
|
163
|
+
|
|
164
|
+
## Custom Suggestion Chips {#custom-suggestions}
|
|
165
|
+
|
|
166
|
+
`<AgentSidebar>`'s `dynamicSuggestions` (see [Agent Chat](/docs/client-agent-chat#dynamic-suggestions)) already merges static `suggestions` with the framework's own context-aware heuristic. Pass a `getSuggestions` function inside `dynamicSuggestions` instead when an app wants deterministic, domain-specific chips computed from the same `application_state` context rather than the framework's default heuristic.
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
<AgentSidebar
|
|
170
|
+
suggestions={["Summarize my inbox"]}
|
|
171
|
+
dynamicSuggestions={{
|
|
172
|
+
getSuggestions: ({ navigation }) => {
|
|
173
|
+
if (
|
|
174
|
+
typeof navigation !== "object" ||
|
|
175
|
+
navigation === null ||
|
|
176
|
+
(navigation as { view?: unknown }).view !== "inbox"
|
|
177
|
+
) {
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
const label = (navigation as { label?: unknown }).label;
|
|
181
|
+
return [`Summarize ${typeof label === "string" ? label : "this"} label`];
|
|
182
|
+
},
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
<App />
|
|
186
|
+
</AgentSidebar>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`getSuggestions` receives the same `navigation`/`selection`/`pendingSelection` snapshot the built-in heuristic reads, typed as `unknown` since its shape is app-defined, so narrow it before reading fields. A custom implementation can react to exactly the state the default one does, just with app-specific rules instead of generic ones.
|
|
190
|
+
|
|
191
|
+
## What's next
|
|
192
|
+
|
|
193
|
+
- [**Overview**](/docs/client-overview) — the `app/` and `public/` directory layout these primitives live in
|
|
194
|
+
- [**Data & Sync**](/docs/client-data) — the default action hooks and `useDbSync` most pages should use instead
|
|
195
|
+
- [**Sync Internals**](/docs/client-sync-internals) — `useChangeVersion`/`useChangeVersions` and the two latency paths a refetch can take
|
|
196
|
+
- [**Agent Chat**](/docs/client-agent-chat) — the default `sendToAgentChat`/`askUserQuestion` helpers most UI should use instead, and the staged agent chat context-state APIs
|
|
197
|
+
- [**Entry Points**](/docs/client-entry-points) — `app/entry.client.tsx`/`app/entry.server.tsx` and SSR streaming customization
|
|
198
|
+
- [**Context Awareness**](/docs/context-awareness) — the `navigation`/`selection` semantics built on `application_state`, and the `TAB_ID`/jitter-prevention walkthrough
|
|
199
|
+
- [**Generative UI**](/docs/generative-ui) — richer inline chat controls beyond `askUserQuestion`
|
|
200
|
+
- [**External Agents**](/docs/external-agents#mcp-app-bridge) — the full MCP App host bridge internals
|