@agent-native/core 0.149.5 → 0.151.0
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/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +83 -45
- package/corpus/templates/analytics/changelog/2026-08-11-analytics-dashboards-keep-the-selected-tab-when-reopened.md +6 -0
- package/corpus/templates/assets/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/brain/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/calendar/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/clips/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/clips/changelog/2026-08-11-clips-recovers-from-transient-updates-and-avoids-macos-priva.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +32 -176
- package/corpus/templates/clips/desktop/src/lib/updater.ts +52 -37
- package/corpus/templates/clips/desktop/src/styles.css +1 -166
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +2 -0
- package/corpus/templates/clips/desktop/src-tauri/Info.plist +4 -0
- package/corpus/templates/clips/desktop/src-tauri/src/eventkit.rs +28 -1
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +48 -1
- package/corpus/templates/clips/desktop/src-tauri/src/permission_status.rs +3 -0
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +5 -0
- package/corpus/templates/clips/server/plugins/auth.ts +3 -0
- package/corpus/templates/content/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/content/actions/_document-discovery-query.ts +127 -0
- package/corpus/templates/content/actions/list-documents.ts +189 -198
- package/corpus/templates/content/actions/search-documents.ts +95 -24
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +2 -1
- package/corpus/templates/content/app/hooks/use-documents.ts +84 -6
- package/corpus/templates/content/shared/api.ts +10 -0
- package/corpus/templates/design/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +5 -1
- package/corpus/templates/design/changelog/2026-08-11-design-agent-prompts-copy-successfully-in-the-desktop-app.md +6 -0
- package/corpus/templates/dispatch/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/dispatch/app/global.css +2 -2
- package/corpus/templates/dispatch/changelog/2026-08-10-desktop-workspace-sign-in.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-no-longer-shows-the-generic-chat-starter-among-defa.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-integrations-and-scheduled-work-open-as-first-class-electron-pages.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-sidebar-text-is-slightly-easier-to-read-in-light-and-dark-mo.md +6 -0
- package/corpus/templates/dispatch/server/lib/identity-sso.ts +57 -31
- package/corpus/templates/dispatch/server/plugins/feature-flags.ts +5 -0
- package/corpus/templates/dispatch/server/plugins/identity-sso.ts +82 -33
- package/corpus/templates/dispatch/server/plugins/org-apps-directory.ts +7 -15
- package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +9 -1
- package/corpus/templates/dispatch/shared/feature-flags.ts +15 -0
- package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/forms/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +8 -7
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/forms/app/hooks/use-forms.ts +8 -1
- package/corpus/templates/forms/changelog/2026-08-11-fixed-public-forms-so-conditional-questions-stay-hidden-unti.md +6 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +2 -1
- package/corpus/templates/forms/server/lib/public-form-ssr.ts +37 -2
- package/corpus/templates/forms/shared/page-url.ts +54 -0
- package/corpus/templates/forms/shared/types.ts +4 -4
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/mail/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/plan/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/slides/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/slides/actions/add-slide.ts +0 -27
- package/corpus/templates/slides/actions/import-file.ts +28 -9
- package/corpus/templates/slides/actions/view-screen.ts +4 -4
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +8 -1
- package/corpus/templates/slides/app/components/editor/AiEditingMarker.tsx +25 -0
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +43 -48
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +9 -6
- package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +1 -9
- package/corpus/templates/slides/app/components/editor/ImageDropPromptPopover.tsx +2 -0
- package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +0 -26
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +904 -217
- package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
- package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +11 -0
- package/corpus/templates/slides/app/components/editor/inline-edit-session.ts +16 -0
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +22 -6
- package/corpus/templates/slides/app/components/editor/style-clipboard.ts +61 -0
- package/corpus/templates/slides/app/components/layout/Layout.tsx +26 -2
- package/corpus/templates/slides/app/components/ui/context-menu.tsx +1 -0
- package/corpus/templates/slides/app/context/DeckContext.tsx +75 -25
- package/corpus/templates/slides/app/global.css +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +6 -1
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -1
- package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +12 -12
- package/corpus/templates/slides/app/lib/slide-agent-context.ts +52 -0
- package/corpus/templates/slides/app/lib/slide-image-replacement.ts +61 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +55 -116
- package/corpus/templates/slides/app/pages/Index.tsx +28 -3
- package/corpus/templates/slides/changelog/2026-08-11-agent-chat-now-follows-the-current-slide-and-selection.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-deck-titles-now-use-slide-content-instead-of-placeholder-filenames.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-history-now-opens-from-the-deck-overflow-menu.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-images-can-be-dropped-directly-onto-slides-and-resized-or-re.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-new-decks-now-transition-directly-to-a-full-page-editor-load.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-selected-slide-layers-can-be-nudged-precisely-with-arrow-key.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slides-can-copy-and-paste-element-styles-with-cmd-option-c-v.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slides-shows-one-compact-ai-marker-and-keeps-your-current-sl.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-text-edits-preserve-slide-layout-when-no-changes-are-made.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-the-style-toolbar-now-uses-the-full-available-width.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-undo-and-redo-now-move-one-visible-slide-state-at-a-time.md +6 -0
- package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -2
- package/corpus/templates/slides/shared/deck-title.ts +56 -0
- package/corpus/templates/tasks/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/agent/run-store.js +6 -1
- package/dist/agent/thread-data-builder.js +19 -44
- package/dist/agent/types.d.ts +13 -0
- package/dist/catalog.json +1 -0
- package/dist/cli/create.js +1 -1
- package/dist/client/AssistantChat.js +58 -10
- package/dist/client/FileStorageSetupCard.d.ts +6 -0
- package/dist/client/FileStorageSetupCard.js +18 -0
- package/dist/client/NewWorkspaceAppFlow.js +10 -0
- package/dist/client/agent-chat-adapter.js +87 -11
- package/dist/client/agent-chat.d.ts +1 -1
- package/dist/client/agent-chat.js +8 -3
- package/dist/client/chat/attachment-adapters.js +10 -0
- package/dist/client/chat/message-components.d.ts +4 -1
- package/dist/client/chat/message-components.js +37 -13
- package/dist/client/chat/tool-call-display.js +14 -0
- package/dist/client/chat-first/apps-rail.d.ts +1 -1
- package/dist/client/chat-first/apps-rail.js +6 -6
- package/dist/client/chat-first/copy.js +1 -0
- package/dist/client/chat-first/types.d.ts +1 -0
- package/dist/client/extensions/EmbeddedExtension.js +1 -1
- package/dist/client/extensions/ExtensionViewer.js +1 -1
- package/dist/client/extensions/InlineExtensionFrame.js +1 -1
- package/dist/client/onboarding/FirstRunOnboarding.js +17 -2
- package/dist/client/settings/FileStorageSettingsForm.d.ts +2 -0
- package/dist/client/settings/FileStorageSettingsForm.js +113 -0
- package/dist/client/settings/SettingsPanel.js +2 -1
- package/dist/client/sse-event-processor.js +21 -0
- package/dist/extensions/actions.js +2 -2
- package/dist/extensions/html-shell.js +3 -1
- package/dist/file-upload/pre-upload-attachments.d.ts +15 -10
- package/dist/file-upload/pre-upload-attachments.js +68 -24
- package/dist/file-upload/registry.d.ts +4 -5
- package/dist/file-upload/registry.js +7 -14
- package/dist/file-upload/s3.d.ts +9 -0
- package/dist/file-upload/s3.js +168 -0
- package/dist/file-upload/types.d.ts +3 -3
- package/dist/file-upload/types.js +2 -2
- package/dist/onboarding/app-profile.js +23 -1
- package/dist/onboarding/default-steps.js +69 -0
- package/dist/onboarding/types.d.ts +2 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-chat/browser-team-tools.js +20 -0
- package/dist/server/agent-chat-plugin.js +12 -3
- package/dist/server/auth.js +45 -21
- package/dist/server/better-auth-instance.d.ts +2 -0
- package/dist/server/better-auth-instance.js +2 -2
- package/dist/server/core-routes-plugin.d.ts +1 -0
- package/dist/server/core-routes-plugin.js +26 -16
- package/dist/server/identity-sso-store.d.ts +3 -0
- package/dist/server/identity-sso-store.js +45 -0
- package/dist/server/identity-sso.d.ts +20 -10
- package/dist/server/identity-sso.js +79 -31
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +24 -1
- package/dist/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -2
- package/dist/templates/workspace-core/.agents/skills/extensions/references/api.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +3 -1
- package/docs/content/authentication.mdx +27 -0
- package/docs/content/cross-app-sso.mdx +38 -8
- package/docs/content/extensions.mdx +15 -15
- package/docs/content/file-uploads.mdx +10 -12
- package/docs/content/generative-ui.mdx +6 -1
- package/package.json +2 -2
- package/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
- package/src/templates/default/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +24 -1
- package/src/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -2
- package/src/templates/workspace-core/.agents/skills/extensions/references/api.md +1 -1
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +3 -1
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
* Auth-guard reachability: `/_agent-native/*` is 401'd by the core auth
|
|
38
38
|
* guard when there is no session. This route is authenticated by the A2A
|
|
39
39
|
* JWT, not a cookie, so — exactly like the identity-sso plugin's authorize
|
|
40
|
-
* route —
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* route — Dispatch's primary auth plugin receives its exact `publicPath`
|
|
41
|
+
* from `setupDispatch`. "Public path" only means "the guard does not pre-empt
|
|
42
|
+
* with a 401"; the handler still performs
|
|
43
43
|
* the full A2A JWT + same-org check itself (defense in depth). The path is
|
|
44
44
|
* matched exactly, so no other `/_agent-native/org/*` route is affected.
|
|
45
45
|
*
|
|
@@ -51,11 +51,7 @@ import {
|
|
|
51
51
|
getOrgDomain,
|
|
52
52
|
resolveOrgByDomain,
|
|
53
53
|
} from "@agent-native/core/org";
|
|
54
|
-
import {
|
|
55
|
-
createAuthPlugin,
|
|
56
|
-
getH3App,
|
|
57
|
-
runWithRequestContext,
|
|
58
|
-
} from "@agent-native/core/server";
|
|
54
|
+
import { getH3App, runWithRequestContext } from "@agent-native/core/server";
|
|
59
55
|
import { discoverAgents } from "@agent-native/core/server/agent-discovery";
|
|
60
56
|
import { defineEventHandler, getMethod, getRequestHeader } from "h3";
|
|
61
57
|
import type { H3Event } from "h3";
|
|
@@ -181,14 +177,10 @@ const orgAppsHandler = defineEventHandler(
|
|
|
181
177
|
);
|
|
182
178
|
|
|
183
179
|
/**
|
|
184
|
-
* Dispatch org-app-directory plugin.
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* `createAuthPlugin({ publicPaths })` call is additive — it appends to the
|
|
188
|
-
* live guard config without disturbing Dispatch's primary auth plugin
|
|
189
|
-
* (same mechanism the identity-sso plugin relies on).
|
|
180
|
+
* Dispatch org-app-directory plugin. The primary Dispatch auth plugin owns
|
|
181
|
+
* the exact public-path registration so this handler can perform its own JWT
|
|
182
|
+
* and same-org checks without racing a second auth initializer.
|
|
190
183
|
*/
|
|
191
184
|
export default async (nitroApp: any) => {
|
|
192
185
|
getH3App(nitroApp).use(ORG_APPS_PATH, orgAppsHandler);
|
|
193
|
-
return createAuthPlugin({ publicPaths: [ORG_APPS_PATH] })(nitroApp);
|
|
194
186
|
};
|
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import { setupDispatch } from "@agent-native/dispatch/server";
|
|
2
2
|
|
|
3
|
-
export default setupDispatch(
|
|
3
|
+
export default setupDispatch({
|
|
4
|
+
auth: {
|
|
5
|
+
publicPaths: [
|
|
6
|
+
"/_agent-native/identity/availability",
|
|
7
|
+
"/_agent-native/identity/authorize",
|
|
8
|
+
"/_agent-native/org/apps",
|
|
9
|
+
],
|
|
10
|
+
},
|
|
11
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineFeatureFlag,
|
|
3
|
+
defineFeatureFlags,
|
|
4
|
+
} from "@agent-native/core/feature-flags";
|
|
5
|
+
|
|
6
|
+
export const DESKTOP_WORKSPACE_SSO_FLAG = defineFeatureFlag({
|
|
7
|
+
key: "desktop.workspace-sso",
|
|
8
|
+
displayName: "Desktop workspace sign-in",
|
|
9
|
+
description:
|
|
10
|
+
"Let the signed Agent Native Desktop broker workspace identity across first-party apps.",
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const DISPATCH_FEATURE_FLAGS = defineFeatureFlags([
|
|
14
|
+
DESKTOP_WORKSPACE_SSO_FLAG,
|
|
15
|
+
]);
|
|
@@ -49,6 +49,34 @@ sendToAgentChat({
|
|
|
49
49
|
});
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
### Keep user text separate from injected context
|
|
53
|
+
|
|
54
|
+
Treat the visible `message` as the user's request or the shortest clear
|
|
55
|
+
description of an app-initiated operation. Put context the user did not type —
|
|
56
|
+
IDs, URLs, filenames, current selection or screen state, serialized records,
|
|
57
|
+
upload instructions, and bounded source excerpts — in the `context` field.
|
|
58
|
+
`context` is model input carried through the agent turn; it is stripped from
|
|
59
|
+
the rendered user message, so do not concatenate it into `message` with labels,
|
|
60
|
+
blank-line sections, or `<context>` tags yourself.
|
|
61
|
+
|
|
62
|
+
Use the related surface for each kind of supporting input:
|
|
63
|
+
|
|
64
|
+
| Surface | Use for |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `message` | User-authored intent or a concise app action description |
|
|
67
|
+
| `context` | Derived metadata and bounded text needed to carry out that intent |
|
|
68
|
+
| `setAgentChatContextItem` | Context staged for a later user-submitted prompt; keep it keyed so updates replace stale context |
|
|
69
|
+
| `images`, `referenceImagePaths`, attachments | Binary or visual inputs; describe only the handling instructions in `context` |
|
|
70
|
+
|
|
71
|
+
If an app builds a prompt from a form, selection, upload, or editor state, keep
|
|
72
|
+
the visible message short and pass the assembled details as `context`. Preserve
|
|
73
|
+
the user's actual freeform text in `message` when it is the request; do not
|
|
74
|
+
restate it as metadata in `context` unless the agent needs a structured copy.
|
|
75
|
+
|
|
76
|
+
This boundary applies to auto-submitted turns and prefills. A hidden context
|
|
77
|
+
field is not a license to send unbounded records or secrets: cap excerpts,
|
|
78
|
+
prefer stable IDs and URLs, and use an action or resource lookup for full data.
|
|
79
|
+
|
|
52
80
|
**From the UI, in the background:**
|
|
53
81
|
|
|
54
82
|
```ts
|
|
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
|
|
|
168
168
|
- Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
|
|
169
169
|
- Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
|
|
170
170
|
- Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
|
|
171
|
+
- Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
|
|
172
|
+
plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
|
|
173
|
+
an icon you haven't used elsewhere in this app, confirm it exists by grepping
|
|
174
|
+
`node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
|
|
175
|
+
for the exact name, and pick the closest real match if your first guess isn't there.
|
|
171
176
|
- Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
|
|
172
177
|
- Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
|
|
173
178
|
- Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
|
|
@@ -49,6 +49,34 @@ sendToAgentChat({
|
|
|
49
49
|
});
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
### Keep user text separate from injected context
|
|
53
|
+
|
|
54
|
+
Treat the visible `message` as the user's request or the shortest clear
|
|
55
|
+
description of an app-initiated operation. Put context the user did not type —
|
|
56
|
+
IDs, URLs, filenames, current selection or screen state, serialized records,
|
|
57
|
+
upload instructions, and bounded source excerpts — in the `context` field.
|
|
58
|
+
`context` is model input carried through the agent turn; it is stripped from
|
|
59
|
+
the rendered user message, so do not concatenate it into `message` with labels,
|
|
60
|
+
blank-line sections, or `<context>` tags yourself.
|
|
61
|
+
|
|
62
|
+
Use the related surface for each kind of supporting input:
|
|
63
|
+
|
|
64
|
+
| Surface | Use for |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `message` | User-authored intent or a concise app action description |
|
|
67
|
+
| `context` | Derived metadata and bounded text needed to carry out that intent |
|
|
68
|
+
| `setAgentChatContextItem` | Context staged for a later user-submitted prompt; keep it keyed so updates replace stale context |
|
|
69
|
+
| `images`, `referenceImagePaths`, attachments | Binary or visual inputs; describe only the handling instructions in `context` |
|
|
70
|
+
|
|
71
|
+
If an app builds a prompt from a form, selection, upload, or editor state, keep
|
|
72
|
+
the visible message short and pass the assembled details as `context`. Preserve
|
|
73
|
+
the user's actual freeform text in `message` when it is the request; do not
|
|
74
|
+
restate it as metadata in `context` unless the agent needs a structured copy.
|
|
75
|
+
|
|
76
|
+
This boundary applies to auto-submitted turns and prefills. A hidden context
|
|
77
|
+
field is not a license to send unbounded records or secrets: cap excerpts,
|
|
78
|
+
prefer stable IDs and URLs, and use an action or resource lookup for full data.
|
|
79
|
+
|
|
52
80
|
**From the UI, in the background:**
|
|
53
81
|
|
|
54
82
|
```ts
|
|
@@ -80,13 +80,14 @@ Each response is stored in the `responses` SQL table:
|
|
|
80
80
|
`submitterEmail` may come from the logged-in Forms session or from trusted
|
|
81
81
|
feedback clients that pass the logged-in user email as submission metadata.
|
|
82
82
|
|
|
83
|
-
`pageUrl` and `clientSurface` are hidden pass-through fields
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
from.
|
|
88
|
-
is allowlisted server-side (unknown values are dropped)
|
|
89
|
-
surfaces them as "Page" and "Source"
|
|
83
|
+
`pageUrl` and `clientSurface` are hidden pass-through fields. Direct public
|
|
84
|
+
fills record the current form URL, while trusted embeds (e.g. the framework
|
|
85
|
+
FeedbackButton) forward the respondent's source page and runtime shell (`web`,
|
|
86
|
+
`electron`, or `tauri`) so owners can see which screen and app feedback came
|
|
87
|
+
from. Sensitive URL query keys are scrubbed before persistence, `clientSurface`
|
|
88
|
+
is allowlisted server-side (unknown values are dropped), and anonymous forms
|
|
89
|
+
suppress both fields. The responses table surfaces them as "Page" and "Source"
|
|
90
|
+
columns when any response carries them.
|
|
90
91
|
|
|
91
92
|
The `data` JSON maps field IDs to values:
|
|
92
93
|
|
|
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
|
|
|
168
168
|
- Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
|
|
169
169
|
- Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
|
|
170
170
|
- Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
|
|
171
|
+
- Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
|
|
172
|
+
plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
|
|
173
|
+
an icon you haven't used elsewhere in this app, confirm it exists by grepping
|
|
174
|
+
`node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
|
|
175
|
+
for the exact name, and pick the closest real match if your first guess isn't there.
|
|
171
176
|
- Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
|
|
172
177
|
- Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
|
|
173
178
|
- Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
useActionMutation,
|
|
5
5
|
} from "@agent-native/core/client/hooks";
|
|
6
6
|
import { useT } from "@agent-native/core/client/i18n";
|
|
7
|
+
import { scrubPageUrl } from "@shared/page-url";
|
|
7
8
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
8
9
|
import { toast } from "sonner";
|
|
9
10
|
|
|
@@ -189,7 +190,13 @@ export function useSubmitForm() {
|
|
|
189
190
|
fetch(appApiPath(`/api/submit/${formId}`), {
|
|
190
191
|
method: "POST",
|
|
191
192
|
headers: { "Content-Type": "application/json" },
|
|
192
|
-
body: JSON.stringify({
|
|
193
|
+
body: JSON.stringify({
|
|
194
|
+
data,
|
|
195
|
+
captchaToken,
|
|
196
|
+
_hp,
|
|
197
|
+
_t,
|
|
198
|
+
_meta: { pageUrl: scrubPageUrl(window.location.href) },
|
|
199
|
+
}),
|
|
193
200
|
}).then((r) => {
|
|
194
201
|
if (!r.ok) return r.json().then((e: any) => Promise.reject(e));
|
|
195
202
|
return r.json();
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
isConditionalFieldVisible,
|
|
22
22
|
sanitizeConditionalValues as sanitizeVisibleValues,
|
|
23
23
|
} from "../../shared/conditional.js";
|
|
24
|
+
import { scrubPageUrl } from "../../shared/page-url.js";
|
|
24
25
|
import {
|
|
25
26
|
cleanSubmitterEmail,
|
|
26
27
|
publicSubmitterEmail,
|
|
@@ -226,7 +227,7 @@ export const submitForm = defineEventHandler(async (event: H3Event) => {
|
|
|
226
227
|
meta?.chatSessionIds,
|
|
227
228
|
]);
|
|
228
229
|
const activeRunId = cleanMetaText(meta?.activeRunId);
|
|
229
|
-
const pageUrl =
|
|
230
|
+
const pageUrl = scrubPageUrl(meta?.pageUrl);
|
|
230
231
|
const clientSurface = cleanClientSurface(meta?.clientSurface);
|
|
231
232
|
|
|
232
233
|
await db.insert(schema.responses).values({
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
import { eq } from "drizzle-orm";
|
|
11
11
|
import { getMethod, getRequestURL, type H3Event } from "h3";
|
|
12
12
|
|
|
13
|
+
import { isConditionalFieldVisible } from "../../shared/conditional.js";
|
|
14
|
+
import { SENSITIVE_QUERY_PARAMS } from "../../shared/page-url.js";
|
|
13
15
|
import {
|
|
14
16
|
toPublicFormSettings,
|
|
15
17
|
type FormField,
|
|
@@ -200,6 +202,10 @@ function renderField(field: FormField): string {
|
|
|
200
202
|
? ` data-cond-field="${escapeHtml(field.conditional.fieldId)}" data-cond-op="${escapeHtml(field.conditional.operator)}" data-cond-val="${escapeHtml(field.conditional.value)}"`
|
|
201
203
|
: "";
|
|
202
204
|
const widthClass = field.width === "half" ? " field-half" : "";
|
|
205
|
+
const initiallyVisible = isConditionalFieldVisible(field, {});
|
|
206
|
+
const initialVisibility = initiallyVisible
|
|
207
|
+
? ""
|
|
208
|
+
: ' style="display:none" data-hidden="1"';
|
|
203
209
|
|
|
204
210
|
let input = "";
|
|
205
211
|
|
|
@@ -265,7 +271,7 @@ function renderField(field: FormField): string {
|
|
|
265
271
|
break;
|
|
266
272
|
}
|
|
267
273
|
|
|
268
|
-
return `<div class="field${widthClass}" data-field-id="${id}"${cond}>
|
|
274
|
+
return `<div class="field${widthClass}" data-field-id="${id}"${cond}${initialVisibility}>
|
|
269
275
|
<label class="field-label">${escapeHtml(field.label)}${field.required ? '<span class="req">*</span>' : ""}</label>
|
|
270
276
|
${desc}${input}</div>`;
|
|
271
277
|
}
|
|
@@ -435,6 +441,34 @@ function renderFormPage(
|
|
|
435
441
|
var REDIRECT = ${JSON.stringify(safeRedirectUrl(settings.redirectUrl))};
|
|
436
442
|
var TURNSTILE_KEY = ${JSON.stringify(turnstileSiteKey)};
|
|
437
443
|
var FIELDS = ${JSON.stringify(fields.map((f) => ({ id: f.id, type: f.type, required: f.required, validation: f.validation, label: f.label, conditional: f.conditional })))};
|
|
444
|
+
var SENSITIVE_QUERY_PARAMS = ${JSON.stringify(SENSITIVE_QUERY_PARAMS)};
|
|
445
|
+
|
|
446
|
+
function scrubPageUrl(value) {
|
|
447
|
+
try {
|
|
448
|
+
var url = new URL(value);
|
|
449
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
450
|
+
url.username = "";
|
|
451
|
+
url.password = "";
|
|
452
|
+
scrubParams(url.searchParams);
|
|
453
|
+
if (url.hash.indexOf("=") >= 0) {
|
|
454
|
+
var hashParams = new URLSearchParams(url.hash.slice(1));
|
|
455
|
+
scrubParams(hashParams);
|
|
456
|
+
url.hash = hashParams.toString();
|
|
457
|
+
}
|
|
458
|
+
return url.toString();
|
|
459
|
+
// coercion-ok: an invalid browser URL is absent page context, not a valid submission value
|
|
460
|
+
} catch (_) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function scrubParams(params) {
|
|
466
|
+
Array.from(params.keys()).forEach(function(key) {
|
|
467
|
+
if (SENSITIVE_QUERY_PARAMS.indexOf(key.toLowerCase()) >= 0) {
|
|
468
|
+
params.set(key, "<redacted>");
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
}
|
|
438
472
|
|
|
439
473
|
function revalidateFormVersion() {
|
|
440
474
|
fetch(PUBLIC_FORM_API, { cache: "no-store" })
|
|
@@ -631,11 +665,12 @@ function renderFormPage(
|
|
|
631
665
|
btn.textContent = "Submitting...";
|
|
632
666
|
btn.disabled = true;
|
|
633
667
|
var hp = (document.getElementById("_hp") || {}).value || "";
|
|
668
|
+
var pageUrl = scrubPageUrl(window.location.href);
|
|
634
669
|
|
|
635
670
|
fetch(${JSON.stringify(submitPath)} + FORM_ID, {
|
|
636
671
|
method: "POST",
|
|
637
672
|
headers: { "Content-Type": "application/json" },
|
|
638
|
-
body: JSON.stringify({ data: data, captchaToken: captchaToken, _hp: hp, _t: PAGE_LOAD_T }),
|
|
673
|
+
body: JSON.stringify({ data: data, captchaToken: captchaToken, _hp: hp, _t: PAGE_LOAD_T, _meta: { pageUrl: pageUrl } }),
|
|
639
674
|
})
|
|
640
675
|
.then(function(r) { return r.json().then(function(d) { return { ok: r.ok, data: d }; }); })
|
|
641
676
|
.then(function(res) {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export const SENSITIVE_QUERY_PARAMS = [
|
|
2
|
+
"password",
|
|
3
|
+
"p",
|
|
4
|
+
"token",
|
|
5
|
+
"state",
|
|
6
|
+
"code",
|
|
7
|
+
"share",
|
|
8
|
+
"share_token",
|
|
9
|
+
"bridge",
|
|
10
|
+
"access_token",
|
|
11
|
+
"id_token",
|
|
12
|
+
"refresh_token",
|
|
13
|
+
"authorization",
|
|
14
|
+
"api_key",
|
|
15
|
+
"key",
|
|
16
|
+
"secret",
|
|
17
|
+
"session",
|
|
18
|
+
] as const;
|
|
19
|
+
|
|
20
|
+
const SENSITIVE_QUERY_PARAM_SET = new Set<string>(SENSITIVE_QUERY_PARAMS);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Keep response page context useful while never retaining URL-bar secrets.
|
|
24
|
+
* This mirrors the framework feedback URL scrubber for Forms-owned public
|
|
25
|
+
* submissions and re-checks metadata supplied by embeds on the server.
|
|
26
|
+
*/
|
|
27
|
+
export function scrubPageUrl(value: unknown): string | null {
|
|
28
|
+
if (typeof value !== "string") return null;
|
|
29
|
+
const trimmed = value.trim();
|
|
30
|
+
if (!trimmed) return null;
|
|
31
|
+
if (!URL.canParse(trimmed)) return null;
|
|
32
|
+
|
|
33
|
+
const url = new URL(trimmed);
|
|
34
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
35
|
+
url.username = "";
|
|
36
|
+
url.password = "";
|
|
37
|
+
scrubParams(url.searchParams);
|
|
38
|
+
|
|
39
|
+
if (url.hash.includes("=")) {
|
|
40
|
+
const hashParams = new URLSearchParams(url.hash.slice(1));
|
|
41
|
+
scrubParams(hashParams);
|
|
42
|
+
url.hash = hashParams.toString();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return url.toString();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function scrubParams(params: URLSearchParams) {
|
|
49
|
+
for (const key of params.keys()) {
|
|
50
|
+
if (SENSITIVE_QUERY_PARAM_SET.has(key.toLowerCase())) {
|
|
51
|
+
params.set(key, "<redacted>");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -155,15 +155,15 @@ export interface FormResponse {
|
|
|
155
155
|
/** Real submitter email when known; synthetic anonymous-owner ids are hidden. */
|
|
156
156
|
submitterEmail?: string | null;
|
|
157
157
|
/**
|
|
158
|
-
* URL of the
|
|
159
|
-
*
|
|
160
|
-
*
|
|
158
|
+
* URL of the direct public form or trusted embed source page. Sensitive URL
|
|
159
|
+
* query keys are scrubbed before it is stored; null when no page context is
|
|
160
|
+
* available or anonymous mode suppresses response metadata.
|
|
161
161
|
*/
|
|
162
162
|
pageUrl?: string | null;
|
|
163
163
|
/**
|
|
164
164
|
* Runtime shell the feedback was sent from — "web", "electron", or "tauri" —
|
|
165
165
|
* forwarded by trusted embeds as a hidden pass-through field. Null when
|
|
166
|
-
* unknown
|
|
166
|
+
* unknown or anonymous mode suppresses response metadata.
|
|
167
167
|
*/
|
|
168
168
|
clientSurface?: string | null;
|
|
169
169
|
}
|
|
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
|
|
|
168
168
|
- Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
|
|
169
169
|
- Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
|
|
170
170
|
- Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
|
|
171
|
+
- Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
|
|
172
|
+
plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
|
|
173
|
+
an icon you haven't used elsewhere in this app, confirm it exists by grepping
|
|
174
|
+
`node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
|
|
175
|
+
for the exact name, and pick the closest real match if your first guess isn't there.
|
|
171
176
|
- Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
|
|
172
177
|
- Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
|
|
173
178
|
- Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
|
|
@@ -49,6 +49,34 @@ sendToAgentChat({
|
|
|
49
49
|
});
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
### Keep user text separate from injected context
|
|
53
|
+
|
|
54
|
+
Treat the visible `message` as the user's request or the shortest clear
|
|
55
|
+
description of an app-initiated operation. Put context the user did not type —
|
|
56
|
+
IDs, URLs, filenames, current selection or screen state, serialized records,
|
|
57
|
+
upload instructions, and bounded source excerpts — in the `context` field.
|
|
58
|
+
`context` is model input carried through the agent turn; it is stripped from
|
|
59
|
+
the rendered user message, so do not concatenate it into `message` with labels,
|
|
60
|
+
blank-line sections, or `<context>` tags yourself.
|
|
61
|
+
|
|
62
|
+
Use the related surface for each kind of supporting input:
|
|
63
|
+
|
|
64
|
+
| Surface | Use for |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `message` | User-authored intent or a concise app action description |
|
|
67
|
+
| `context` | Derived metadata and bounded text needed to carry out that intent |
|
|
68
|
+
| `setAgentChatContextItem` | Context staged for a later user-submitted prompt; keep it keyed so updates replace stale context |
|
|
69
|
+
| `images`, `referenceImagePaths`, attachments | Binary or visual inputs; describe only the handling instructions in `context` |
|
|
70
|
+
|
|
71
|
+
If an app builds a prompt from a form, selection, upload, or editor state, keep
|
|
72
|
+
the visible message short and pass the assembled details as `context`. Preserve
|
|
73
|
+
the user's actual freeform text in `message` when it is the request; do not
|
|
74
|
+
restate it as metadata in `context` unless the agent needs a structured copy.
|
|
75
|
+
|
|
76
|
+
This boundary applies to auto-submitted turns and prefills. A hidden context
|
|
77
|
+
field is not a license to send unbounded records or secrets: cap excerpts,
|
|
78
|
+
prefer stable IDs and URLs, and use an action or resource lookup for full data.
|
|
79
|
+
|
|
52
80
|
**From the UI, in the background:**
|
|
53
81
|
|
|
54
82
|
```ts
|
|
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
|
|
|
168
168
|
- Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
|
|
169
169
|
- Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
|
|
170
170
|
- Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
|
|
171
|
+
- Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
|
|
172
|
+
plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
|
|
173
|
+
an icon you haven't used elsewhere in this app, confirm it exists by grepping
|
|
174
|
+
`node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
|
|
175
|
+
for the exact name, and pick the closest real match if your first guess isn't there.
|
|
171
176
|
- Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
|
|
172
177
|
- Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
|
|
173
178
|
- Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
|
|
@@ -49,6 +49,34 @@ sendToAgentChat({
|
|
|
49
49
|
});
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
### Keep user text separate from injected context
|
|
53
|
+
|
|
54
|
+
Treat the visible `message` as the user's request or the shortest clear
|
|
55
|
+
description of an app-initiated operation. Put context the user did not type —
|
|
56
|
+
IDs, URLs, filenames, current selection or screen state, serialized records,
|
|
57
|
+
upload instructions, and bounded source excerpts — in the `context` field.
|
|
58
|
+
`context` is model input carried through the agent turn; it is stripped from
|
|
59
|
+
the rendered user message, so do not concatenate it into `message` with labels,
|
|
60
|
+
blank-line sections, or `<context>` tags yourself.
|
|
61
|
+
|
|
62
|
+
Use the related surface for each kind of supporting input:
|
|
63
|
+
|
|
64
|
+
| Surface | Use for |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `message` | User-authored intent or a concise app action description |
|
|
67
|
+
| `context` | Derived metadata and bounded text needed to carry out that intent |
|
|
68
|
+
| `setAgentChatContextItem` | Context staged for a later user-submitted prompt; keep it keyed so updates replace stale context |
|
|
69
|
+
| `images`, `referenceImagePaths`, attachments | Binary or visual inputs; describe only the handling instructions in `context` |
|
|
70
|
+
|
|
71
|
+
If an app builds a prompt from a form, selection, upload, or editor state, keep
|
|
72
|
+
the visible message short and pass the assembled details as `context`. Preserve
|
|
73
|
+
the user's actual freeform text in `message` when it is the request; do not
|
|
74
|
+
restate it as metadata in `context` unless the agent needs a structured copy.
|
|
75
|
+
|
|
76
|
+
This boundary applies to auto-submitted turns and prefills. A hidden context
|
|
77
|
+
field is not a license to send unbounded records or secrets: cap excerpts,
|
|
78
|
+
prefer stable IDs and URLs, and use an action or resource lookup for full data.
|
|
79
|
+
|
|
52
80
|
**From the UI, in the background:**
|
|
53
81
|
|
|
54
82
|
```ts
|
|
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
|
|
|
168
168
|
- Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
|
|
169
169
|
- Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
|
|
170
170
|
- Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
|
|
171
|
+
- Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
|
|
172
|
+
plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
|
|
173
|
+
an icon you haven't used elsewhere in this app, confirm it exists by grepping
|
|
174
|
+
`node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
|
|
175
|
+
for the exact name, and pick the closest real match if your first guess isn't there.
|
|
171
176
|
- Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
|
|
172
177
|
- Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
|
|
173
178
|
- Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
|
|
@@ -49,6 +49,34 @@ sendToAgentChat({
|
|
|
49
49
|
});
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
### Keep user text separate from injected context
|
|
53
|
+
|
|
54
|
+
Treat the visible `message` as the user's request or the shortest clear
|
|
55
|
+
description of an app-initiated operation. Put context the user did not type —
|
|
56
|
+
IDs, URLs, filenames, current selection or screen state, serialized records,
|
|
57
|
+
upload instructions, and bounded source excerpts — in the `context` field.
|
|
58
|
+
`context` is model input carried through the agent turn; it is stripped from
|
|
59
|
+
the rendered user message, so do not concatenate it into `message` with labels,
|
|
60
|
+
blank-line sections, or `<context>` tags yourself.
|
|
61
|
+
|
|
62
|
+
Use the related surface for each kind of supporting input:
|
|
63
|
+
|
|
64
|
+
| Surface | Use for |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `message` | User-authored intent or a concise app action description |
|
|
67
|
+
| `context` | Derived metadata and bounded text needed to carry out that intent |
|
|
68
|
+
| `setAgentChatContextItem` | Context staged for a later user-submitted prompt; keep it keyed so updates replace stale context |
|
|
69
|
+
| `images`, `referenceImagePaths`, attachments | Binary or visual inputs; describe only the handling instructions in `context` |
|
|
70
|
+
|
|
71
|
+
If an app builds a prompt from a form, selection, upload, or editor state, keep
|
|
72
|
+
the visible message short and pass the assembled details as `context`. Preserve
|
|
73
|
+
the user's actual freeform text in `message` when it is the request; do not
|
|
74
|
+
restate it as metadata in `context` unless the agent needs a structured copy.
|
|
75
|
+
|
|
76
|
+
This boundary applies to auto-submitted turns and prefills. A hidden context
|
|
77
|
+
field is not a license to send unbounded records or secrets: cap excerpts,
|
|
78
|
+
prefer stable IDs and URLs, and use an action or resource lookup for full data.
|
|
79
|
+
|
|
52
80
|
**From the UI, in the background:**
|
|
53
81
|
|
|
54
82
|
```ts
|
|
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
|
|
|
168
168
|
- Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
|
|
169
169
|
- Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
|
|
170
170
|
- Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
|
|
171
|
+
- Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
|
|
172
|
+
plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
|
|
173
|
+
an icon you haven't used elsewhere in this app, confirm it exists by grepping
|
|
174
|
+
`node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
|
|
175
|
+
for the exact name, and pick the closest real match if your first guess isn't there.
|
|
171
176
|
- Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
|
|
172
177
|
- Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
|
|
173
178
|
- Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
|
|
@@ -24,10 +24,6 @@ import {
|
|
|
24
24
|
awaitLayoutFitCheck,
|
|
25
25
|
formatOverflowForTool,
|
|
26
26
|
} from "./_await-fit-check.js";
|
|
27
|
-
import {
|
|
28
|
-
readAppStateForCurrentTab,
|
|
29
|
-
writeAppStateForCurrentTab,
|
|
30
|
-
} from "./_tab-state.js";
|
|
31
27
|
// Use the shared, globalThis-pinned per-deck lock so add-slide, update-slide,
|
|
32
28
|
// and the browser's patch-deck all serialise against the SAME lock — writes to
|
|
33
29
|
// different slides of the same deck can never clobber each other.
|
|
@@ -383,29 +379,6 @@ export default defineAction({
|
|
|
383
379
|
// Include the new slideId + agent actor (backwards-compatible payload).
|
|
384
380
|
notifyClients(deckId, { slideId: newSlideId, actor: "agent" });
|
|
385
381
|
|
|
386
|
-
// Nudge any open editor onto the new slide so the renderer measures
|
|
387
|
-
// IT (not whichever slide was previously selected). Only fires when an
|
|
388
|
-
// editor is open on this deck; navigation state is a no-op if nobody
|
|
389
|
-
// is watching.
|
|
390
|
-
const nav = (await readAppStateForCurrentTab("navigation", {
|
|
391
|
-
fallbackToGlobal: false,
|
|
392
|
-
}).catch(() => null)) as {
|
|
393
|
-
view?: string;
|
|
394
|
-
deckId?: string;
|
|
395
|
-
} | null;
|
|
396
|
-
if (nav?.view === "editor" && nav.deckId === deckId) {
|
|
397
|
-
await writeAppStateForCurrentTab("navigate", {
|
|
398
|
-
deckId,
|
|
399
|
-
slideIndex: insertIndex,
|
|
400
|
-
// Unique-per-write token. The UI's `use-navigation-state` hook
|
|
401
|
-
// dedups by this so a race between the GET and the consume-DELETE
|
|
402
|
-
// doesn't cause the same command to be re-applied repeatedly
|
|
403
|
-
// (which previously bounced the editor between slides whenever the
|
|
404
|
-
// agent path errored partway through a turn).
|
|
405
|
-
_writeId: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
406
|
-
}).catch(() => {});
|
|
407
|
-
}
|
|
408
|
-
|
|
409
382
|
// Wait briefly for the editor to render the new slide and report its
|
|
410
383
|
// measured fit. If we get an "overflows" signal, append the auto-fix
|
|
411
384
|
// hint so the agent can make one bounded structural repair. Timeout = no
|