@agent-native/core 0.149.6 → 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/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/brain/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/calendar/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/clips/.agents/skills/delegate-to-agent/SKILL.md +28 -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/app/components/editor/CommentsSidebar.tsx +2 -1
- package/corpus/templates/design/.agents/skills/delegate-to-agent/SKILL.md +28 -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/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/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/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/mail/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/plan/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/slides/.agents/skills/delegate-to-agent/SKILL.md +28 -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/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/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- 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/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +6 -6
- package/dist/observability/routes.d.ts +3 -3
- 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/secrets/routes.d.ts +3 -3
- package/dist/server/agent-chat/browser-team-tools.js +20 -0
- package/dist/server/agent-chat-plugin.js +12 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- 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/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +28 -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/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/default/.agents/skills/delegate-to-agent/SKILL.md +28 -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/generative-ui/SKILL.md +3 -1
|
@@ -31,6 +31,11 @@ let lastCheckStartedAt = 0;
|
|
|
31
31
|
|
|
32
32
|
const UPDATE_CHECK_INTERVAL_MS = 60 * 60 * 1000;
|
|
33
33
|
const UPDATE_FOCUS_CHECK_MIN_INTERVAL_MS = 15 * 60 * 1000;
|
|
34
|
+
const UPDATE_RETRY_DELAYS_MS = [1000, 3000];
|
|
35
|
+
|
|
36
|
+
function waitForRetry(delayMs: number) {
|
|
37
|
+
return new Promise<void>((resolve) => setTimeout(resolve, delayMs));
|
|
38
|
+
}
|
|
34
39
|
|
|
35
40
|
function canRunUpdateChecks() {
|
|
36
41
|
// Dev and local release builds are for testing the current checkout. Do not
|
|
@@ -43,6 +48,44 @@ function setStatus(next: UpdateStatus) {
|
|
|
43
48
|
for (const l of listeners) l(next);
|
|
44
49
|
}
|
|
45
50
|
|
|
51
|
+
async function runCheckAttempt(staged: string | null) {
|
|
52
|
+
if (!staged) setStatus({ state: "checking" });
|
|
53
|
+
const update = await check();
|
|
54
|
+
if (!update) {
|
|
55
|
+
// The endpoint answering "current" while a newer bundle sits staged is a
|
|
56
|
+
// contradiction, not a reason to drop the download. Keep it staged.
|
|
57
|
+
if (!staged) setStatus({ state: "not-available" });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (staged && update.version === staged) return;
|
|
61
|
+
const version = update.version;
|
|
62
|
+
const notes = update.body ?? undefined;
|
|
63
|
+
setStatus({ state: "available", version, notes });
|
|
64
|
+
|
|
65
|
+
// Download ONLY — do not install here. On macOS `install` swaps the .app
|
|
66
|
+
// bundle on disk while this process keeps running, which invalidates the
|
|
67
|
+
// running process's Screen Recording (TCC) grant and breaks capture until
|
|
68
|
+
// relaunch. We defer the swap to `installAndRestart()` so a downloaded-but-
|
|
69
|
+
// not-yet-installed update leaves the running app fully functional; the
|
|
70
|
+
// user records normally until they choose to restart.
|
|
71
|
+
let total = 0;
|
|
72
|
+
let downloaded = 0;
|
|
73
|
+
await update.download((event) => {
|
|
74
|
+
if (event.event === "Started") {
|
|
75
|
+
total = event.data.contentLength ?? 0;
|
|
76
|
+
downloaded = 0;
|
|
77
|
+
setStatus({ state: "downloading", version, notes, percent: 0 });
|
|
78
|
+
} else if (event.event === "Progress") {
|
|
79
|
+
downloaded += event.data.chunkLength;
|
|
80
|
+
const percent =
|
|
81
|
+
total > 0 ? Math.min(100, Math.round((downloaded / total) * 100)) : 0;
|
|
82
|
+
setStatus({ state: "downloading", version, notes, percent });
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
pendingUpdate = update;
|
|
86
|
+
setStatus({ state: "downloaded", version, notes });
|
|
87
|
+
}
|
|
88
|
+
|
|
46
89
|
async function runCheck() {
|
|
47
90
|
if (checkInFlight) return checkInFlight;
|
|
48
91
|
|
|
@@ -56,44 +99,16 @@ async function runCheck() {
|
|
|
56
99
|
lastCheckStartedAt = Date.now();
|
|
57
100
|
checkInFlight = (async () => {
|
|
58
101
|
try {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (staged && update.version === staged) return;
|
|
68
|
-
pendingUpdate = update;
|
|
69
|
-
const version = update.version;
|
|
70
|
-
const notes = update.body ?? undefined;
|
|
71
|
-
setStatus({ state: "available", version, notes });
|
|
72
|
-
|
|
73
|
-
// Download ONLY — do not install here. On macOS `install` swaps the .app
|
|
74
|
-
// bundle on disk while this process keeps running, which invalidates the
|
|
75
|
-
// running process's Screen Recording (TCC) grant and breaks capture until
|
|
76
|
-
// relaunch. We defer the swap to `installAndRestart()` so a downloaded-but-
|
|
77
|
-
// not-yet-installed update leaves the running app fully functional; the
|
|
78
|
-
// user records normally until they choose to restart.
|
|
79
|
-
let total = 0;
|
|
80
|
-
let downloaded = 0;
|
|
81
|
-
await update.download((event) => {
|
|
82
|
-
if (event.event === "Started") {
|
|
83
|
-
total = event.data.contentLength ?? 0;
|
|
84
|
-
downloaded = 0;
|
|
85
|
-
setStatus({ state: "downloading", version, notes, percent: 0 });
|
|
86
|
-
} else if (event.event === "Progress") {
|
|
87
|
-
downloaded += event.data.chunkLength;
|
|
88
|
-
const percent =
|
|
89
|
-
total > 0
|
|
90
|
-
? Math.min(100, Math.round((downloaded / total) * 100))
|
|
91
|
-
: 0;
|
|
92
|
-
setStatus({ state: "downloading", version, notes, percent });
|
|
93
|
-
} else if (event.event === "Finished") {
|
|
94
|
-
setStatus({ state: "downloaded", version, notes });
|
|
102
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
103
|
+
try {
|
|
104
|
+
await runCheckAttempt(staged);
|
|
105
|
+
return;
|
|
106
|
+
} catch (err) {
|
|
107
|
+
const delay = UPDATE_RETRY_DELAYS_MS[attempt];
|
|
108
|
+
if (delay === undefined) throw err;
|
|
109
|
+
await waitForRetry(delay);
|
|
95
110
|
}
|
|
96
|
-
}
|
|
111
|
+
}
|
|
97
112
|
} catch (err) {
|
|
98
113
|
const message = err instanceof Error ? err.message : String(err);
|
|
99
114
|
setStatus({ state: "error", message });
|
|
@@ -1010,8 +1010,7 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
1010
1010
|
line-height: 1;
|
|
1011
1011
|
}
|
|
1012
1012
|
|
|
1013
|
-
.readiness-action svg
|
|
1014
|
-
.rewind-home-state svg {
|
|
1013
|
+
.readiness-action svg {
|
|
1015
1014
|
width: 11px;
|
|
1016
1015
|
height: 11px;
|
|
1017
1016
|
}
|
|
@@ -1386,110 +1385,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
1386
1385
|
font-size: 11px;
|
|
1387
1386
|
}
|
|
1388
1387
|
|
|
1389
|
-
/* Rewind is a calm everyday status first; configuration is a drill-in. */
|
|
1390
|
-
.rewind-home-card {
|
|
1391
|
-
display: grid;
|
|
1392
|
-
gap: 0;
|
|
1393
|
-
padding: 0;
|
|
1394
|
-
border: none;
|
|
1395
|
-
border-radius: 0;
|
|
1396
|
-
background: transparent;
|
|
1397
|
-
}
|
|
1398
|
-
|
|
1399
|
-
.rewind-home-summary {
|
|
1400
|
-
display: grid;
|
|
1401
|
-
grid-template-columns: minmax(0, 1fr) auto;
|
|
1402
|
-
align-items: center;
|
|
1403
|
-
gap: 8px;
|
|
1404
|
-
width: 100%;
|
|
1405
|
-
min-height: 36px;
|
|
1406
|
-
padding: 7px 12px;
|
|
1407
|
-
border: none;
|
|
1408
|
-
border-radius: var(--radius-sm);
|
|
1409
|
-
background: transparent;
|
|
1410
|
-
color: var(--fg-muted);
|
|
1411
|
-
cursor: pointer;
|
|
1412
|
-
text-align: left;
|
|
1413
|
-
transition: color 120ms;
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
.rewind-home-summary:hover,
|
|
1417
|
-
.rewind-home-summary:focus-visible {
|
|
1418
|
-
color: var(--fg);
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
|
-
.rewind-home-summary:focus-visible {
|
|
1422
|
-
outline: none;
|
|
1423
|
-
box-shadow: 0 0 0 3px var(--brand-ring);
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
.rewind-home-title {
|
|
1427
|
-
font-size: 13px;
|
|
1428
|
-
font-weight: 500;
|
|
1429
|
-
line-height: 1;
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
.rewind-home-state {
|
|
1433
|
-
display: inline-flex;
|
|
1434
|
-
align-items: center;
|
|
1435
|
-
gap: 4px;
|
|
1436
|
-
color: inherit;
|
|
1437
|
-
font-size: 11px;
|
|
1438
|
-
font-weight: 600;
|
|
1439
|
-
line-height: 1;
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
.rewind-home-details {
|
|
1443
|
-
display: grid;
|
|
1444
|
-
gap: 10px;
|
|
1445
|
-
padding: 0 12px 10px;
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
.rewind-home-details p {
|
|
1449
|
-
margin: 0;
|
|
1450
|
-
color: var(--fg-muted);
|
|
1451
|
-
font-size: 11px;
|
|
1452
|
-
line-height: 1.4;
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
.rewind-home-detail-actions {
|
|
1456
|
-
display: flex;
|
|
1457
|
-
align-items: center;
|
|
1458
|
-
justify-content: space-between;
|
|
1459
|
-
gap: 10px;
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
.rewind-home-controls {
|
|
1463
|
-
display: inline-flex;
|
|
1464
|
-
align-items: center;
|
|
1465
|
-
gap: 8px;
|
|
1466
|
-
margin-left: auto;
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
.rewind-docs-link {
|
|
1470
|
-
display: inline-flex;
|
|
1471
|
-
align-items: center;
|
|
1472
|
-
gap: 4px;
|
|
1473
|
-
padding: 0;
|
|
1474
|
-
border: none;
|
|
1475
|
-
background: transparent;
|
|
1476
|
-
color: var(--fg-muted);
|
|
1477
|
-
cursor: pointer;
|
|
1478
|
-
font-size: 11px;
|
|
1479
|
-
font-weight: 600;
|
|
1480
|
-
white-space: nowrap;
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
.rewind-docs-link:hover {
|
|
1484
|
-
color: var(--fg);
|
|
1485
|
-
}
|
|
1486
|
-
|
|
1487
|
-
.rewind-docs-link:focus-visible {
|
|
1488
|
-
outline: none;
|
|
1489
|
-
box-shadow: 0 0 0 3px var(--brand-ring);
|
|
1490
|
-
border-radius: 4px;
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
1388
|
.rewind-settings-entry-main {
|
|
1494
1389
|
display: grid;
|
|
1495
1390
|
grid-template-columns: auto minmax(0, 1fr);
|
|
@@ -1497,7 +1392,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
1497
1392
|
gap: 9px;
|
|
1498
1393
|
}
|
|
1499
1394
|
|
|
1500
|
-
.rewind-home-lock-note,
|
|
1501
1395
|
.rewind-capture-lock-note {
|
|
1502
1396
|
margin: 0;
|
|
1503
1397
|
color: var(--fg-muted);
|
|
@@ -1511,28 +1405,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
1511
1405
|
background: var(--surface);
|
|
1512
1406
|
}
|
|
1513
1407
|
|
|
1514
|
-
.rewind-agent-prompt-copy {
|
|
1515
|
-
width: 28px;
|
|
1516
|
-
height: 28px;
|
|
1517
|
-
display: grid;
|
|
1518
|
-
place-items: center;
|
|
1519
|
-
padding: 0;
|
|
1520
|
-
border: none;
|
|
1521
|
-
border-radius: 7px;
|
|
1522
|
-
background: transparent;
|
|
1523
|
-
color: var(--fg-muted);
|
|
1524
|
-
cursor: pointer;
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
.rewind-agent-prompt-copy:hover {
|
|
1528
|
-
color: var(--fg);
|
|
1529
|
-
}
|
|
1530
|
-
|
|
1531
|
-
.rewind-agent-prompt-copy:focus-visible {
|
|
1532
|
-
outline: none;
|
|
1533
|
-
box-shadow: 0 0 0 3px var(--brand-ring);
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
1408
|
.rewind-home-dot {
|
|
1537
1409
|
width: 9px;
|
|
1538
1410
|
height: 9px;
|
|
@@ -1548,38 +1420,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
1548
1420
|
box-shadow: 0 0 0 4px color-mix(in srgb, var(--status-ok) 15%, transparent);
|
|
1549
1421
|
}
|
|
1550
1422
|
|
|
1551
|
-
.rewind-home-actions {
|
|
1552
|
-
display: grid;
|
|
1553
|
-
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
1554
|
-
gap: 6px;
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
.rewind-home-actions button {
|
|
1558
|
-
min-width: 0;
|
|
1559
|
-
min-height: 31px;
|
|
1560
|
-
display: inline-flex;
|
|
1561
|
-
align-items: center;
|
|
1562
|
-
justify-content: center;
|
|
1563
|
-
gap: 5px;
|
|
1564
|
-
border: 1px solid var(--border-strong);
|
|
1565
|
-
border-radius: var(--radius-sm);
|
|
1566
|
-
background: var(--bg);
|
|
1567
|
-
color: var(--fg);
|
|
1568
|
-
cursor: pointer;
|
|
1569
|
-
font-size: 10.5px;
|
|
1570
|
-
font-weight: 600;
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
.rewind-home-actions button:hover:not(:disabled) {
|
|
1574
|
-
background: var(--surface-hover);
|
|
1575
|
-
}
|
|
1576
|
-
|
|
1577
|
-
.rewind-home-actions button:disabled {
|
|
1578
|
-
opacity: 0.42;
|
|
1579
|
-
cursor: default;
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
.rewind-home-actions button:focus-visible,
|
|
1583
1423
|
.rewind-consent-choices button:focus-visible,
|
|
1584
1424
|
.rewind-consent-primary:focus-visible,
|
|
1585
1425
|
.rewind-quiet-button:focus-visible,
|
|
@@ -1594,11 +1434,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
1594
1434
|
box-shadow: 0 0 0 3px var(--brand-ring);
|
|
1595
1435
|
}
|
|
1596
1436
|
|
|
1597
|
-
.rewind-home-actions .icon {
|
|
1598
|
-
width: 14px;
|
|
1599
|
-
height: 14px;
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
1437
|
.rewind-consent {
|
|
1603
1438
|
min-height: 430px;
|
|
1604
1439
|
align-items: center;
|
|
@@ -99,6 +99,8 @@ unicode-segmentation = "1.13"
|
|
|
99
99
|
# Powers the "browser" voice-dictation provider (free, instant, no API
|
|
100
100
|
# key, no server round-trip — same engine WisprFlow uses for offline).
|
|
101
101
|
objc2-foundation = { version = "0.3", features = [
|
|
102
|
+
"NSBundle",
|
|
103
|
+
"NSDictionary",
|
|
102
104
|
"NSString",
|
|
103
105
|
"NSError",
|
|
104
106
|
"NSLocale",
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
<string>Clips uses your microphone to record audio with screen recordings.</string>
|
|
9
9
|
<key>NSScreenCaptureUsageDescription</key>
|
|
10
10
|
<string>Clips records your screen and system audio when you start a Clip.</string>
|
|
11
|
+
<key>NSCalendarsUsageDescription</key>
|
|
12
|
+
<string>Clips uses your calendars to show upcoming meetings and offer meeting capture.</string>
|
|
13
|
+
<key>NSCalendarsFullAccessUsageDescription</key>
|
|
14
|
+
<string>Clips uses your calendars to show upcoming meetings and offer meeting capture.</string>
|
|
11
15
|
<key>NSSpeechRecognitionUsageDescription</key>
|
|
12
16
|
<string>Clips uses speech recognition for on-device voice dictation.</string>
|
|
13
17
|
<key>NSAccessibilityUsageDescription</key>
|
|
@@ -73,13 +73,38 @@ mod macos {
|
|
|
73
73
|
use objc2::rc::Retained;
|
|
74
74
|
use objc2::runtime::{AnyClass, AnyObject, Bool};
|
|
75
75
|
use objc2::{class, msg_send};
|
|
76
|
-
use objc2_foundation::{NSArray, NSString};
|
|
76
|
+
use objc2_foundation::{NSArray, NSBundle, NSString};
|
|
77
77
|
use tauri::AppHandle;
|
|
78
78
|
|
|
79
79
|
use super::EventKitEvent;
|
|
80
80
|
|
|
81
81
|
/// EKEntityType::Event == 0
|
|
82
82
|
const EK_ENTITY_TYPE_EVENT: usize = 0;
|
|
83
|
+
const CALENDAR_USAGE_DESCRIPTION_KEYS: [&str; 2] = [
|
|
84
|
+
"NSCalendarsUsageDescription",
|
|
85
|
+
"NSCalendarsFullAccessUsageDescription",
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
fn has_calendar_usage_descriptions() -> bool {
|
|
89
|
+
let bundle = NSBundle::mainBundle();
|
|
90
|
+
let Some(info) = bundle.infoDictionary() else {
|
|
91
|
+
return false;
|
|
92
|
+
};
|
|
93
|
+
CALENDAR_USAGE_DESCRIPTION_KEYS.iter().all(|key| {
|
|
94
|
+
let key = NSString::from_str(key);
|
|
95
|
+
info.objectForKey(&*key)
|
|
96
|
+
.and_then(|value| value.downcast::<NSString>().ok())
|
|
97
|
+
.is_some_and(|value| !value.is_empty())
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
fn ensure_calendar_usage_descriptions() -> Result<(), String> {
|
|
102
|
+
if has_calendar_usage_descriptions() {
|
|
103
|
+
Ok(())
|
|
104
|
+
} else {
|
|
105
|
+
Err("Clips cannot access macOS calendars because the app bundle is missing calendar usage descriptions.".into())
|
|
106
|
+
}
|
|
107
|
+
}
|
|
83
108
|
|
|
84
109
|
/// Returns Some(NSObject*) for the given class name, or None if the
|
|
85
110
|
/// runtime doesn't know about it (e.g. the EventKit framework is not
|
|
@@ -104,6 +129,7 @@ mod macos {
|
|
|
104
129
|
}
|
|
105
130
|
|
|
106
131
|
pub async fn request_access_impl(_app: AppHandle) -> Result<bool, String> {
|
|
132
|
+
ensure_calendar_usage_descriptions()?;
|
|
107
133
|
let store =
|
|
108
134
|
unsafe { new_event_store() }.ok_or_else(|| "EventKit not available".to_string())?;
|
|
109
135
|
let (tx, rx) = mpsc::sync_channel::<bool>(1);
|
|
@@ -141,6 +167,7 @@ mod macos {
|
|
|
141
167
|
_app: AppHandle,
|
|
142
168
|
within_hours: u32,
|
|
143
169
|
) -> Result<Vec<EventKitEvent>, String> {
|
|
170
|
+
ensure_calendar_usage_descriptions()?;
|
|
144
171
|
unsafe {
|
|
145
172
|
let store = new_event_store().ok_or_else(|| "EventKit not available".to_string())?;
|
|
146
173
|
|
|
@@ -553,6 +553,8 @@ pub fn run() {
|
|
|
553
553
|
// otherwise skips Rust destructors — make sure a live
|
|
554
554
|
// `screencapture` fallback child doesn't survive us.
|
|
555
555
|
if let tauri::RunEvent::Exit = _event {
|
|
556
|
+
whisper_speech::shutdown(_app_handle);
|
|
557
|
+
native_speech::shutdown();
|
|
556
558
|
let state = _app_handle.state::<native_screen::NativeFullscreenRecordingState>();
|
|
557
559
|
native_screen::kill_active_screencapture_child(&state);
|
|
558
560
|
}
|
|
@@ -144,7 +144,7 @@ pub(crate) mod macos {
|
|
|
144
144
|
kAudioObjectPropertyElementMain, kAudioObjectPropertyScopeGlobal, kAudioObjectSystemObject,
|
|
145
145
|
AudioObjectGetPropertyData, AudioObjectID, AudioObjectPropertyAddress,
|
|
146
146
|
};
|
|
147
|
-
use objc2_foundation::{NSArray, NSError, NSLocale, NSString};
|
|
147
|
+
use objc2_foundation::{NSArray, NSBundle, NSError, NSLocale, NSString};
|
|
148
148
|
use objc2_speech::{
|
|
149
149
|
SFSpeechAudioBufferRecognitionRequest, SFSpeechRecognitionResult, SFSpeechRecognitionTask,
|
|
150
150
|
SFSpeechRecognizer, SFSpeechRecognizerAuthorizationStatus,
|
|
@@ -154,6 +154,29 @@ pub(crate) mod macos {
|
|
|
154
154
|
|
|
155
155
|
use screencapturekit::audio_devices::AudioInputDevice;
|
|
156
156
|
|
|
157
|
+
const SPEECH_USAGE_DESCRIPTION_KEY: &str = "NSSpeechRecognitionUsageDescription";
|
|
158
|
+
const SPEECH_USAGE_DESCRIPTION_ERROR: &str =
|
|
159
|
+
"Clips cannot start macOS speech recognition because the app bundle is missing NSSpeechRecognitionUsageDescription.";
|
|
160
|
+
|
|
161
|
+
pub(crate) fn has_speech_usage_description() -> bool {
|
|
162
|
+
let bundle = NSBundle::mainBundle();
|
|
163
|
+
let Some(info) = bundle.infoDictionary() else {
|
|
164
|
+
return false;
|
|
165
|
+
};
|
|
166
|
+
let key = NSString::from_str(SPEECH_USAGE_DESCRIPTION_KEY);
|
|
167
|
+
info.objectForKey(&*key)
|
|
168
|
+
.and_then(|value| value.downcast::<NSString>().ok())
|
|
169
|
+
.is_some_and(|value| !value.is_empty())
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
fn ensure_speech_usage_description() -> Result<(), String> {
|
|
173
|
+
if has_speech_usage_description() {
|
|
174
|
+
Ok(())
|
|
175
|
+
} else {
|
|
176
|
+
Err(SPEECH_USAGE_DESCRIPTION_ERROR.into())
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
157
180
|
/// Who owns an in-flight `SpeechSession`. Meetings fall back to this
|
|
158
181
|
/// mic-only engine when whisper fails; a Fn/dictation press must not be
|
|
159
182
|
/// able to silently kill a meeting's live capture (D10). Priority rule:
|
|
@@ -416,6 +439,11 @@ pub(crate) mod macos {
|
|
|
416
439
|
/// system has an answer. The handler itself only sends a value on a
|
|
417
440
|
/// channel; no ObjC interop, no UI work.
|
|
418
441
|
fn ensure_authorized() -> Result<(), String> {
|
|
442
|
+
// macOS aborts the process, rather than returning an error, when
|
|
443
|
+
// Speech.framework is touched without this usage description. This
|
|
444
|
+
// guard keeps `tauri dev` and malformed bundles recoverable.
|
|
445
|
+
ensure_speech_usage_description()?;
|
|
446
|
+
|
|
419
447
|
// Fast path: already known.
|
|
420
448
|
let current = unsafe { SFSpeechRecognizer::authorizationStatus() };
|
|
421
449
|
if current == SFSpeechRecognizerAuthorizationStatus::Authorized {
|
|
@@ -1548,6 +1576,20 @@ pub(crate) mod macos {
|
|
|
1548
1576
|
Ok(())
|
|
1549
1577
|
}
|
|
1550
1578
|
|
|
1579
|
+
pub fn shutdown() {
|
|
1580
|
+
let session = match session_slot().lock() {
|
|
1581
|
+
Ok(mut slot) => slot.take(),
|
|
1582
|
+
Err(poisoned) => poisoned.into_inner().take(),
|
|
1583
|
+
};
|
|
1584
|
+
if let Some(session) = session {
|
|
1585
|
+
session.cancelled.store(true, Ordering::SeqCst);
|
|
1586
|
+
session.stopped.store(true, Ordering::SeqCst);
|
|
1587
|
+
unsafe { session.task.cancel() };
|
|
1588
|
+
stop_engine_and_remove_tap(&session);
|
|
1589
|
+
}
|
|
1590
|
+
clear_warmed_raw_mic_engine();
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1551
1593
|
#[cfg(test)]
|
|
1552
1594
|
mod tests {
|
|
1553
1595
|
use super::{native_speech_voice_processing_mode, MicVoiceProcessingMode, SessionOwner};
|
|
@@ -1569,3 +1611,8 @@ pub(crate) mod macos {
|
|
|
1569
1611
|
}
|
|
1570
1612
|
}
|
|
1571
1613
|
}
|
|
1614
|
+
|
|
1615
|
+
pub fn shutdown() {
|
|
1616
|
+
#[cfg(target_os = "macos")]
|
|
1617
|
+
macos::shutdown();
|
|
1618
|
+
}
|
|
@@ -123,6 +123,11 @@ pub async fn whisper_transcription_stop(app: AppHandle) -> Result<(), String> {
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
pub fn shutdown(app: &AppHandle) {
|
|
127
|
+
#[cfg(target_os = "macos")]
|
|
128
|
+
macos::stop(app);
|
|
129
|
+
}
|
|
130
|
+
|
|
126
131
|
#[tauri::command]
|
|
127
132
|
pub async fn whisper_transcription_reset_timeline() -> Result<(), String> {
|
|
128
133
|
#[cfg(target_os = "macos")]
|
|
@@ -5,6 +5,9 @@ import { PRERENDERED_PUBLIC_PAGE_PATHS } from "../../shared/prerendered-public-p
|
|
|
5
5
|
// Clips has public share pages, embeds, and view-event tracking that must
|
|
6
6
|
// reach unauthenticated viewers. Everything else sits behind auth.
|
|
7
7
|
export default createAuthPlugin({
|
|
8
|
+
// Keep the native tray token and the Better Auth cookie useful between
|
|
9
|
+
// infrequent recording sessions without making them permanent.
|
|
10
|
+
maxAge: 60 * 60 * 24 * 90,
|
|
8
11
|
// Clips owns `/_agent-native/google/*` so the same registered Google
|
|
9
12
|
// callback can handle both normal sign-in and the Calendar connect flow.
|
|
10
13
|
mountGoogleOAuthRoutes: false,
|
|
@@ -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
|
|
@@ -435,7 +435,8 @@ export function CommentsSidebar({
|
|
|
435
435
|
? `${t("comments.agentRegardingText", { text: thread.quotedText })}\n\n`
|
|
436
436
|
: "";
|
|
437
437
|
sendToAgentChat({
|
|
438
|
-
message:
|
|
438
|
+
message: t("comments.agentHelp"),
|
|
439
|
+
context: `${context}${t("comments.agentThreadHeader")}\n${commentTexts}`,
|
|
439
440
|
});
|
|
440
441
|
};
|
|
441
442
|
|
|
@@ -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
|
|
@@ -555,9 +555,13 @@ export default function DesignSystemSetup() {
|
|
|
555
555
|
}. Present a summary for review.`,
|
|
556
556
|
);
|
|
557
557
|
|
|
558
|
+
const message =
|
|
559
|
+
parts[0] ?? "Set up a design system from the selected sources.";
|
|
560
|
+
const context = parts.slice(1).join("\n");
|
|
558
561
|
openAgentSidebar();
|
|
559
562
|
sendToDesignAgentChat({
|
|
560
|
-
message
|
|
563
|
+
message,
|
|
564
|
+
context,
|
|
561
565
|
submit: true,
|
|
562
566
|
newTab: true,
|
|
563
567
|
});
|
|
@@ -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
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
--ring: 0 0% 40%;
|
|
30
30
|
--radius: 0.5rem;
|
|
31
31
|
--sidebar-background: 0 0% 97%;
|
|
32
|
-
--sidebar-foreground: 0 0%
|
|
32
|
+
--sidebar-foreground: 0 0% 43%;
|
|
33
33
|
--sidebar-primary: 0 0% 15%;
|
|
34
34
|
--sidebar-primary-foreground: 0 0% 100%;
|
|
35
35
|
--sidebar-accent: 0 0% 95%;
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
--ring: 0 0% 60%;
|
|
61
61
|
--radius: 0.5rem;
|
|
62
62
|
--sidebar-background: 0 0% 10%;
|
|
63
|
-
--sidebar-foreground: 0 0%
|
|
63
|
+
--sidebar-foreground: 0 0% 62%;
|
|
64
64
|
--sidebar-primary: 0 0% 75%;
|
|
65
65
|
--sidebar-primary-foreground: 0 0% 10%;
|
|
66
66
|
--sidebar-accent: 0 0% 16%;
|