@agent-native/core 0.98.2 → 0.98.4

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.
Files changed (78) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +23 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +2 -2
  5. package/corpus/core/src/client/analytics.ts +12 -0
  6. package/corpus/core/src/client/index.ts +2 -0
  7. package/corpus/core/src/client/session-replay.ts +612 -26
  8. package/corpus/core/src/client/settings/DemoModeSection.tsx +6 -6
  9. package/corpus/core/src/client/settings/SettingsPanel.tsx +31 -211
  10. package/corpus/core/src/client/settings/agent-settings-search.ts +219 -0
  11. package/corpus/core/src/client/settings/index.ts +4 -0
  12. package/corpus/core/src/demo/actions/toggle-demo-mode.ts +2 -2
  13. package/corpus/core/src/demo/config.ts +6 -6
  14. package/corpus/core/src/demo/fetch-interceptor.ts +25 -2
  15. package/corpus/core/src/demo/redact.ts +57 -66
  16. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +65 -6
  17. package/corpus/templates/analytics/AGENTS.md +6 -6
  18. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +429 -244
  19. package/corpus/templates/analytics/app/components/layout/command-palette-search.ts +93 -0
  20. package/corpus/templates/analytics/app/global.css +4 -62
  21. package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +2 -1
  22. package/corpus/templates/analytics/app/lib/demo-chart-trend.ts +46 -33
  23. package/corpus/templates/analytics/app/pages/Settings.tsx +8 -45
  24. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +413 -105
  25. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +32 -16
  26. package/corpus/templates/analytics/app/pages/settings/settings-search.ts +126 -0
  27. package/corpus/templates/analytics/changelog/2026-07-12-command-menu-loading-placeholders-now-stay-below-available-r.md +6 -0
  28. package/corpus/templates/analytics/changelog/2026-07-12-command-menu-search-now-prioritizes-the-best-match.md +6 -0
  29. package/corpus/templates/analytics/changelog/2026-07-12-demo-charts-preserve-source-movement.md +6 -0
  30. package/corpus/templates/analytics/changelog/2026-07-12-fixed-session-replays-that-appeared-ultra-wide-hid-recorded-.md +6 -0
  31. package/corpus/templates/analytics/changelog/2026-07-12-replay-storage-settings-stay-readable-at-narrow-widths.md +6 -0
  32. package/corpus/templates/analytics/changelog/2026-07-12-session-replays-load-faster-in-demo-mode-while-visitor-email.md +6 -0
  33. package/corpus/templates/analytics/changelog/2026-07-12-session-replays-preserve-recorded-styling-and-keep-malformed.md +6 -0
  34. package/corpus/templates/calendar/app/components/calendar/DeleteEventDialog.tsx +11 -2
  35. package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +14 -2
  36. package/corpus/templates/calendar/changelog/2026-07-12-calendar-responses-can-now-be-saved-with-command-enter-or-ct.md +6 -0
  37. package/dist/agent/production-agent.js +2 -2
  38. package/dist/agent/production-agent.js.map +1 -1
  39. package/dist/client/analytics.d.ts.map +1 -1
  40. package/dist/client/analytics.js +11 -0
  41. package/dist/client/analytics.js.map +1 -1
  42. package/dist/client/index.d.ts +1 -1
  43. package/dist/client/index.d.ts.map +1 -1
  44. package/dist/client/index.js +1 -1
  45. package/dist/client/index.js.map +1 -1
  46. package/dist/client/session-replay.d.ts +12 -3
  47. package/dist/client/session-replay.d.ts.map +1 -1
  48. package/dist/client/session-replay.js +488 -23
  49. package/dist/client/session-replay.js.map +1 -1
  50. package/dist/client/settings/DemoModeSection.d.ts +3 -3
  51. package/dist/client/settings/DemoModeSection.js +4 -4
  52. package/dist/client/settings/DemoModeSection.js.map +1 -1
  53. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  54. package/dist/client/settings/SettingsPanel.js +41 -191
  55. package/dist/client/settings/SettingsPanel.js.map +1 -1
  56. package/dist/client/settings/agent-settings-search.d.ts +16 -0
  57. package/dist/client/settings/agent-settings-search.d.ts.map +1 -0
  58. package/dist/client/settings/agent-settings-search.js +178 -0
  59. package/dist/client/settings/agent-settings-search.js.map +1 -0
  60. package/dist/client/settings/index.d.ts +1 -0
  61. package/dist/client/settings/index.d.ts.map +1 -1
  62. package/dist/client/settings/index.js +1 -0
  63. package/dist/client/settings/index.js.map +1 -1
  64. package/dist/collab/routes.d.ts +1 -1
  65. package/dist/demo/actions/toggle-demo-mode.js +2 -2
  66. package/dist/demo/actions/toggle-demo-mode.js.map +1 -1
  67. package/dist/demo/config.js +6 -6
  68. package/dist/demo/config.js.map +1 -1
  69. package/dist/demo/fetch-interceptor.d.ts +1 -0
  70. package/dist/demo/fetch-interceptor.d.ts.map +1 -1
  71. package/dist/demo/fetch-interceptor.js +19 -2
  72. package/dist/demo/fetch-interceptor.js.map +1 -1
  73. package/dist/demo/redact.d.ts +14 -5
  74. package/dist/demo/redact.d.ts.map +1 -1
  75. package/dist/demo/redact.js +30 -56
  76. package/dist/demo/redact.js.map +1 -1
  77. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  78. package/package.json +2 -2
@@ -1,7 +1,7 @@
1
1
  /**
2
- * <DemoModeSection /> — toggle that replaces contact/free-text names, emails,
3
- * and numbers with realistic fake data everywhere (UI + what the agent sees)
4
- * while preserving labels, IDs, and structure so the app keeps working.
2
+ * <DemoModeSection /> — toggle that replaces emails and numbers with realistic
3
+ * fake data everywhere (UI + what the agent sees) while preserving names,
4
+ * free text, labels, IDs, and structure so the app keeps working.
5
5
  *
6
6
  * The toggle is stored in application_state under `demo-mode`
7
7
  * (`{ enabled: boolean }`) and written via `PUT
@@ -64,9 +64,9 @@ export function DemoModeSection() {
64
64
  Enable demo mode
65
65
  </div>
66
66
  <p className="text-[10px] text-muted-foreground mt-0.5">
67
- Replace contact/free-text names, emails, and numbers with realistic
68
- fake data everywhere — in the UI and what the agent sees. Labels, IDs,
69
- and structure are preserved so the app keeps working.
67
+ Anonymize emails in the UI and reshape supported dashboard charts for
68
+ presentations. Agent-visible emails and numbers are also anonymized.
69
+ Names, labels, IDs, and structure stay intact.
70
70
  </p>
71
71
  {forced && (
72
72
  <p className="text-[10px] text-muted-foreground mt-0.5">
@@ -50,6 +50,15 @@ import { uploadAvatar, useAvatarUrl } from "../use-avatar.js";
50
50
  import { useDevMode } from "../use-dev-mode.js";
51
51
  import { useSession } from "../use-session.js";
52
52
  import { cn } from "../utils.js";
53
+ import {
54
+ AGENT_SETTINGS_SECTIONS,
55
+ ALL_SETTINGS_SECTIONS,
56
+ CONNECTION_SETTINGS_SECTIONS,
57
+ SETTINGS_SECTION_IDS,
58
+ WORKSPACE_SETTINGS_SECTIONS,
59
+ getAgentSettingsSearchTabs,
60
+ type SettingsSectionId,
61
+ } from "./agent-settings-search.js";
53
62
  import { AgentsSection } from "./AgentsSection.js";
54
63
  import { AutomationsSection } from "./AutomationsSection.js";
55
64
  import { DemoModeSection } from "./DemoModeSection.js";
@@ -60,10 +69,7 @@ import {
60
69
  useSettingsSurface,
61
70
  type SettingsSurface,
62
71
  } from "./SettingsSection.js";
63
- import type {
64
- SettingsSearchEntry,
65
- SettingsTabItem,
66
- } from "./SettingsTabsPage.js";
72
+ import type { SettingsTabItem } from "./SettingsTabsPage.js";
67
73
  import { UsageSection } from "./UsageSection.js";
68
74
  import {
69
75
  type BuilderConnectFlow,
@@ -2299,192 +2305,6 @@ export interface SettingsPanelProps {
2299
2305
  sectionRequestKey?: number;
2300
2306
  }
2301
2307
 
2302
- type SettingsSectionId =
2303
- | "account"
2304
- | "llm"
2305
- | "app-models"
2306
- | "limits"
2307
- | "voice"
2308
- | "demo-mode"
2309
- | "automations"
2310
- | "secrets"
2311
- | "hosting"
2312
- | "database"
2313
- | "uploads"
2314
- | "auth"
2315
- | "email"
2316
- | "browser"
2317
- | "background"
2318
- | "integrations"
2319
- | "usage"
2320
- | "a2a";
2321
-
2322
- const SETTINGS_SECTION_IDS = new Set<SettingsSectionId>([
2323
- "account",
2324
- "llm",
2325
- "app-models",
2326
- "limits",
2327
- "voice",
2328
- "demo-mode",
2329
- "automations",
2330
- "secrets",
2331
- "hosting",
2332
- "database",
2333
- "uploads",
2334
- "auth",
2335
- "email",
2336
- "browser",
2337
- "background",
2338
- "integrations",
2339
- "usage",
2340
- "a2a",
2341
- ]);
2342
-
2343
- const ALL_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [
2344
- "account",
2345
- "llm",
2346
- "app-models",
2347
- "limits",
2348
- "voice",
2349
- "demo-mode",
2350
- "automations",
2351
- "secrets",
2352
- "hosting",
2353
- "database",
2354
- "uploads",
2355
- "auth",
2356
- "email",
2357
- "browser",
2358
- "background",
2359
- "integrations",
2360
- "usage",
2361
- "a2a",
2362
- ];
2363
-
2364
- const AGENT_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [
2365
- "llm",
2366
- "app-models",
2367
- "limits",
2368
- "voice",
2369
- "automations",
2370
- "background",
2371
- "a2a",
2372
- ];
2373
-
2374
- const CONNECTION_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [
2375
- "secrets",
2376
- "integrations",
2377
- "email",
2378
- "browser",
2379
- "usage",
2380
- ];
2381
-
2382
- const WORKSPACE_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [
2383
- "account",
2384
- "demo-mode",
2385
- "hosting",
2386
- "database",
2387
- "uploads",
2388
- "auth",
2389
- ];
2390
-
2391
- // Search metadata for each section so settings search can deep-link straight
2392
- // to a section from any tab. Labels mirror the section headers; keywords add
2393
- // synonyms and provider names the header doesn't spell out.
2394
- const SETTINGS_SECTION_SEARCH_META: Record<
2395
- SettingsSectionId,
2396
- { label: string; keywords: string; description?: string }
2397
- > = {
2398
- account: {
2399
- label: "Account",
2400
- keywords: "profile photo avatar identity signed in email name",
2401
- },
2402
- llm: {
2403
- label: "LLM",
2404
- keywords:
2405
- "model claude gpt openai anthropic gemini api key provider ai engine llm",
2406
- },
2407
- "app-models": {
2408
- label: "App Default Model",
2409
- keywords: "default model provider app template composer",
2410
- },
2411
- limits: {
2412
- label: "Agent Limits",
2413
- keywords: "max iterations budget loop timeout runtime",
2414
- },
2415
- voice: {
2416
- label: "Voice Transcription",
2417
- keywords: "microphone dictation speech to text whisper",
2418
- },
2419
- "demo-mode": {
2420
- label: "Demo mode",
2421
- keywords: "fake data anonymize redact screenshot privacy mask",
2422
- },
2423
- automations: {
2424
- label: "Automations",
2425
- keywords: "triggers scheduled events cron jobs",
2426
- },
2427
- secrets: {
2428
- label: "API Keys & Connections",
2429
- keywords: "secrets credentials tokens api keys environment variables",
2430
- },
2431
- hosting: {
2432
- label: "Hosting",
2433
- keywords: "deploy netlify vercel cloudflare builder nitro",
2434
- },
2435
- database: {
2436
- label: "Database",
2437
- keywords: "postgres sqlite neon supabase turso storage sql pglite",
2438
- },
2439
- uploads: {
2440
- label: "File uploads",
2441
- keywords: "files storage s3 avatars attachments bucket blob",
2442
- },
2443
- auth: {
2444
- label: "Authentication",
2445
- keywords: "login signup oauth google github better auth access sso",
2446
- },
2447
- email: {
2448
- label: "Email",
2449
- keywords: "resend sendgrid smtp transactional notifications reports",
2450
- },
2451
- browser: {
2452
- label: "Browser Automation",
2453
- keywords: "web scraping playwright chrome headless",
2454
- },
2455
- background: {
2456
- label: "Background Agent",
2457
- keywords: "code changes branches builder production async",
2458
- },
2459
- integrations: {
2460
- label: "Integrations",
2461
- keywords: "slack telegram whatsapp discord messaging connect",
2462
- },
2463
- usage: {
2464
- label: "Usage",
2465
- keywords: "tokens cost spend billing consumption",
2466
- },
2467
- a2a: {
2468
- label: "Connected Agents (A2A)",
2469
- keywords: "remote agents protocol a2a connected",
2470
- },
2471
- };
2472
-
2473
- function buildSectionSearchEntries(
2474
- sections: readonly SettingsSectionId[],
2475
- ): SettingsSearchEntry[] {
2476
- return sections.map((section) => {
2477
- const meta = SETTINGS_SECTION_SEARCH_META[section];
2478
- return {
2479
- id: `section:${section}`,
2480
- label: meta.label,
2481
- keywords: meta.keywords,
2482
- description: meta.description,
2483
- hash: section,
2484
- };
2485
- });
2486
- }
2487
-
2488
2308
  function normalizeSettingsSection(
2489
2309
  value?: string | null,
2490
2310
  ): SettingsSectionId | null {
@@ -2970,7 +2790,7 @@ function SettingsPanelContent({
2970
2790
  id={settingsSectionDomId("demo-mode")}
2971
2791
  icon={<IconEyeOff size={14} />}
2972
2792
  title="Demo mode"
2973
- subtitle="Replace contact/free-text names, emails, and numbers with realistic fake data everywhere — in the UI and what the agent sees. Labels, IDs, and structure are preserved so the app keeps working."
2793
+ subtitle="Replace emails and numbers with realistic fake data everywhere — in the UI and what the agent sees. Names, free text, labels, IDs, and structure are preserved so the app keeps working."
2974
2794
  open={openSection === "demo-mode"}
2975
2795
  onToggle={() => toggle("demo-mode")}
2976
2796
  >
@@ -3250,15 +3070,24 @@ export function useAgentSettingsTabs(): SettingsTabItem[] {
3250
3070
  [canToggle, isDevMode, setDevMode],
3251
3071
  );
3252
3072
 
3253
- return useMemo<SettingsTabItem[]>(
3254
- () => [
3073
+ return useMemo<SettingsTabItem[]>(() => {
3074
+ const searchTabs = getAgentSettingsSearchTabs();
3075
+ const searchTab = (
3076
+ id: "agent" | "connections" | "organization" | "workspace",
3077
+ ) => {
3078
+ const tab = searchTabs.find((candidate) => candidate.id === id);
3079
+ if (!tab) throw new Error(`Missing agent settings tab: ${id}`);
3080
+ return tab;
3081
+ };
3082
+ const agent = searchTab("agent");
3083
+ const connections = searchTab("connections");
3084
+ const organization = searchTab("organization");
3085
+ const workspace = searchTab("workspace");
3086
+ return [
3255
3087
  {
3256
- id: "agent",
3257
- label: "Agent",
3088
+ ...agent,
3258
3089
  icon: IconBrain,
3259
3090
  group: "agent",
3260
- keywords: "agent model llm limits voice automations",
3261
- searchEntries: buildSectionSearchEntries(AGENT_SETTINGS_SECTIONS),
3262
3091
  content: (
3263
3092
  <SettingsPanelContent
3264
3093
  {...baseProps}
@@ -3270,12 +3099,9 @@ export function useAgentSettingsTabs(): SettingsTabItem[] {
3270
3099
  ),
3271
3100
  },
3272
3101
  {
3273
- id: "connections",
3274
- label: "Connections",
3102
+ ...connections,
3275
3103
  icon: IconPlugConnected,
3276
3104
  group: "agent",
3277
- keywords: "connections secrets integrations email browser usage",
3278
- searchEntries: buildSectionSearchEntries(CONNECTION_SETTINGS_SECTIONS),
3279
3105
  content: (
3280
3106
  <SettingsPanelContent
3281
3107
  {...baseProps}
@@ -3287,11 +3113,9 @@ export function useAgentSettingsTabs(): SettingsTabItem[] {
3287
3113
  ),
3288
3114
  },
3289
3115
  {
3290
- id: "organization",
3291
- label: "Organization",
3116
+ ...organization,
3292
3117
  icon: IconUsersGroup,
3293
3118
  group: "workspace",
3294
- keywords: "organization org team members invites collaborators",
3295
3119
  content: (
3296
3120
  <div className="mx-auto w-full max-w-2xl">
3297
3121
  <TeamPage showTitle={false} />
@@ -3299,12 +3123,9 @@ export function useAgentSettingsTabs(): SettingsTabItem[] {
3299
3123
  ),
3300
3124
  },
3301
3125
  {
3302
- id: "workspace",
3303
- label: "Workspace",
3126
+ ...workspace,
3304
3127
  icon: IconCloud,
3305
3128
  group: "workspace",
3306
- keywords: "workspace account hosting database uploads auth",
3307
- searchEntries: buildSectionSearchEntries(WORKSPACE_SETTINGS_SECTIONS),
3308
3129
  content: (
3309
3130
  <SettingsPanelContent
3310
3131
  {...baseProps}
@@ -3315,7 +3136,6 @@ export function useAgentSettingsTabs(): SettingsTabItem[] {
3315
3136
  />
3316
3137
  ),
3317
3138
  },
3318
- ],
3319
- [baseProps],
3320
- );
3139
+ ];
3140
+ }, [baseProps]);
3321
3141
  }
@@ -0,0 +1,219 @@
1
+ import type { SettingsSearchEntry } from "./SettingsTabsPage.js";
2
+
3
+ export type SettingsSectionId =
4
+ | "account"
5
+ | "llm"
6
+ | "app-models"
7
+ | "limits"
8
+ | "voice"
9
+ | "demo-mode"
10
+ | "automations"
11
+ | "secrets"
12
+ | "hosting"
13
+ | "database"
14
+ | "uploads"
15
+ | "auth"
16
+ | "email"
17
+ | "browser"
18
+ | "background"
19
+ | "integrations"
20
+ | "usage"
21
+ | "a2a";
22
+
23
+ export const SETTINGS_SECTION_IDS = new Set<SettingsSectionId>([
24
+ "account",
25
+ "llm",
26
+ "app-models",
27
+ "limits",
28
+ "voice",
29
+ "demo-mode",
30
+ "automations",
31
+ "secrets",
32
+ "hosting",
33
+ "database",
34
+ "uploads",
35
+ "auth",
36
+ "email",
37
+ "browser",
38
+ "background",
39
+ "integrations",
40
+ "usage",
41
+ "a2a",
42
+ ]);
43
+
44
+ export const ALL_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [
45
+ "account",
46
+ "llm",
47
+ "app-models",
48
+ "limits",
49
+ "voice",
50
+ "demo-mode",
51
+ "automations",
52
+ "secrets",
53
+ "hosting",
54
+ "database",
55
+ "uploads",
56
+ "auth",
57
+ "email",
58
+ "browser",
59
+ "background",
60
+ "integrations",
61
+ "usage",
62
+ "a2a",
63
+ ];
64
+
65
+ export const AGENT_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [
66
+ "llm",
67
+ "app-models",
68
+ "limits",
69
+ "voice",
70
+ "automations",
71
+ "background",
72
+ "a2a",
73
+ ];
74
+
75
+ export const CONNECTION_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [
76
+ "secrets",
77
+ "integrations",
78
+ "email",
79
+ "browser",
80
+ "usage",
81
+ ];
82
+
83
+ export const WORKSPACE_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [
84
+ "account",
85
+ "demo-mode",
86
+ "hosting",
87
+ "database",
88
+ "uploads",
89
+ "auth",
90
+ ];
91
+
92
+ const SETTINGS_SECTION_SEARCH_META: Record<
93
+ SettingsSectionId,
94
+ { label: string; keywords: string; description?: string }
95
+ > = {
96
+ account: {
97
+ label: "Account",
98
+ keywords: "profile photo avatar identity signed in email name",
99
+ },
100
+ llm: {
101
+ label: "LLM",
102
+ keywords:
103
+ "model claude gpt openai anthropic gemini api key provider ai engine llm",
104
+ },
105
+ "app-models": {
106
+ label: "App Default Model",
107
+ keywords: "default model provider app template composer",
108
+ },
109
+ limits: {
110
+ label: "Agent Limits",
111
+ keywords: "max iterations budget loop timeout runtime",
112
+ },
113
+ voice: {
114
+ label: "Voice Transcription",
115
+ keywords: "microphone dictation speech to text whisper",
116
+ },
117
+ "demo-mode": {
118
+ label: "Demo mode",
119
+ keywords: "fake data anonymize redact screenshot privacy mask",
120
+ },
121
+ automations: {
122
+ label: "Automations",
123
+ keywords: "triggers scheduled events cron jobs",
124
+ },
125
+ secrets: {
126
+ label: "API Keys & Connections",
127
+ keywords: "secrets credentials tokens api keys environment variables",
128
+ },
129
+ hosting: {
130
+ label: "Hosting",
131
+ keywords: "deploy netlify vercel cloudflare builder nitro",
132
+ },
133
+ database: {
134
+ label: "Database",
135
+ keywords: "postgres sqlite neon supabase turso storage sql pglite",
136
+ },
137
+ uploads: {
138
+ label: "File uploads",
139
+ keywords: "files storage s3 avatars attachments bucket blob",
140
+ },
141
+ auth: {
142
+ label: "Authentication",
143
+ keywords: "login signup oauth google github better auth access sso",
144
+ },
145
+ email: {
146
+ label: "Email",
147
+ keywords: "resend sendgrid smtp transactional notifications reports",
148
+ },
149
+ browser: {
150
+ label: "Browser Automation",
151
+ keywords: "web scraping playwright chrome headless",
152
+ },
153
+ background: {
154
+ label: "Background Agent",
155
+ keywords: "code changes branches builder production async",
156
+ },
157
+ integrations: {
158
+ label: "Integrations",
159
+ keywords: "slack telegram whatsapp discord messaging connect",
160
+ },
161
+ usage: {
162
+ label: "Usage",
163
+ keywords: "tokens cost spend billing consumption",
164
+ },
165
+ a2a: {
166
+ label: "Connected Agents (A2A)",
167
+ keywords: "remote agents protocol a2a connected",
168
+ },
169
+ };
170
+
171
+ export function buildSectionSearchEntries(
172
+ sections: readonly SettingsSectionId[],
173
+ ): SettingsSearchEntry[] {
174
+ return sections.map((section) => {
175
+ const meta = SETTINGS_SECTION_SEARCH_META[section];
176
+ return {
177
+ id: `section:${section}`,
178
+ label: meta.label,
179
+ keywords: meta.keywords,
180
+ description: meta.description,
181
+ hash: section,
182
+ };
183
+ });
184
+ }
185
+
186
+ export interface AgentSettingsSearchTab {
187
+ id: string;
188
+ label: string;
189
+ keywords: string;
190
+ searchEntries?: SettingsSearchEntry[];
191
+ }
192
+
193
+ export function getAgentSettingsSearchTabs(): AgentSettingsSearchTab[] {
194
+ return [
195
+ {
196
+ id: "agent",
197
+ label: "Agent",
198
+ keywords: "agent model llm limits voice automations",
199
+ searchEntries: buildSectionSearchEntries(AGENT_SETTINGS_SECTIONS),
200
+ },
201
+ {
202
+ id: "connections",
203
+ label: "Connections",
204
+ keywords: "connections secrets integrations email browser usage",
205
+ searchEntries: buildSectionSearchEntries(CONNECTION_SETTINGS_SECTIONS),
206
+ },
207
+ {
208
+ id: "organization",
209
+ label: "Organization",
210
+ keywords: "organization org team members invites collaborators",
211
+ },
212
+ {
213
+ id: "workspace",
214
+ label: "Workspace",
215
+ keywords: "workspace account hosting database uploads auth",
216
+ searchEntries: buildSectionSearchEntries(WORKSPACE_SETTINGS_SECTIONS),
217
+ },
218
+ ];
219
+ }
@@ -3,6 +3,10 @@ export {
3
3
  useAgentSettingsTabs,
4
4
  type SettingsPanelProps,
5
5
  } from "./SettingsPanel.js";
6
+ export {
7
+ getAgentSettingsSearchTabs,
8
+ type AgentSettingsSearchTab,
9
+ } from "./agent-settings-search.js";
6
10
  export {
7
11
  SettingsTabsPage,
8
12
  type SettingsSearchEntry,
@@ -5,7 +5,7 @@ import { writeAppState } from "../../application-state/script-helpers.js";
5
5
 
6
6
  export default defineAction({
7
7
  description:
8
- "Turn demo mode on or off. When demo mode is on, the app replaces contact/free-text names, email addresses, and numbers with realistic fake data everywhere in the UI and in what you (the agent) see while keeping labels, IDs, dates, and structure intact so everything still works. Use when the user asks to 'hide my data', 'turn on demo mode', 'anonymize this for a screen share / recording', or similar. This is the same toggle as the Demo mode switch in settings.",
8
+ "Turn demo mode on or off. When demo mode is on, the UI replaces email addresses with realistic fake data and supported dashboards reshape chart values for presentations. Agent-visible results replace emails and numbers while keeping names, free text, labels, IDs, dates, and structure intact. Use when the user asks to 'hide my data', 'turn on demo mode', 'anonymize this for a screen share / recording', or similar. This is the same toggle as the Demo mode switch in settings.",
9
9
  schema: z.object({
10
10
  enabled: z
11
11
  .boolean()
@@ -16,7 +16,7 @@ export default defineAction({
16
16
  return {
17
17
  enabled,
18
18
  message: enabled
19
- ? "Demo mode is ON — contact/free-text names, emails, and numbers are now replaced with deterministic fake data everywhere (UI and agent). Labels, IDs, and structure are preserved so everything keeps working."
19
+ ? "Demo mode is ON — UI emails are anonymized and supported dashboard charts are reshaped for presentation. Agent-visible emails and numbers are also anonymized. Names, free text, labels, IDs, and structure are preserved."
20
20
  : "Demo mode is OFF — real data is shown again.",
21
21
  };
22
22
  },
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Demo mode gate.
3
3
  *
4
- * Demo mode replaces contact/free-text names, email addresses, and numbers in every action
5
- * result with deterministic fake data — for both the UI and what the agent
6
- * sees while preserving labels, IDs, dates, URLs, and structure so the app
7
- * keeps working. The redaction WALK (see ./redact.ts) is expensive on large
8
- * payloads, so callers MUST gate it behind this function and only walk when it
9
- * returns true.
4
+ * Demo mode replaces email addresses and numbers in every action result with
5
+ * deterministic fake data — for both the UI and what the agent sees — while
6
+ * preserving names, free text, labels, IDs, dates, URLs, and structure so the
7
+ * app keeps working. The redaction WALK (see ./redact.ts) is expensive on
8
+ * large payloads, so callers MUST gate it behind this function and only walk
9
+ * when it returns true.
10
10
  *
11
11
  * This gate itself is intentionally cheap:
12
12
  * - An env-forced deployment (a hosted demo site) short-circuits with zero
@@ -46,6 +46,23 @@ const SKIP_SUBSTRINGS = [
46
46
  "/_agent-native/runs",
47
47
  ];
48
48
 
49
+ // Raw rrweb payloads are playback data, not ordinary app UI records. Walking
50
+ // and cloning their huge DOM/event trees on the main thread stalls playback
51
+ // and can corrupt replay fidelity. Small list/summary/manifest responses stay
52
+ // eligible so rendered visitor identities are still anonymized.
53
+ const RAW_REPLAY_PAYLOAD_RE =
54
+ /\/api\/session-replay\/recordings\/[^/?#]+\/(?:chunks(?:\/[^/?#]+)?|events)(?:[/?#]|$)/;
55
+ const RAW_AGENT_REPLAY_EVENTS_RE =
56
+ /\/api\/session-replay\/agent-events\.json(?:[?#]|$)/;
57
+
58
+ export function shouldSkipDemoResponseRedaction(url: string): boolean {
59
+ return (
60
+ SKIP_SUBSTRINGS.some((substring) => url.includes(substring)) ||
61
+ RAW_REPLAY_PAYLOAD_RE.test(url) ||
62
+ RAW_AGENT_REPLAY_EVENTS_RE.test(url)
63
+ );
64
+ }
65
+
49
66
  let installed = false;
50
67
  let demoEnabled = false;
51
68
  let originalFetch: typeof fetch | null = null;
@@ -148,7 +165,7 @@ export function ensureDemoModeFetchInterceptor(): void {
148
165
 
149
166
  try {
150
167
  const url = urlOf(input);
151
- if (SKIP_SUBSTRINGS.some((s) => url.includes(s))) return res;
168
+ if (shouldSkipDemoResponseRedaction(url)) return res;
152
169
 
153
170
  // Only buffered, finite JSON. SSE / streaming / chunked-forever bodies
154
171
  // never reach `redactDemoData`: streaming content-types are excluded,
@@ -167,7 +184,13 @@ export function ensureDemoModeFetchInterceptor(): void {
167
184
  if (res.bodyUsed) return res;
168
185
 
169
186
  const data = await withTimeout(res.clone().json(), 3_000);
170
- const redacted = redactDemoData(data);
187
+ // Frontend reads only need identity privacy. Dashboard charts apply
188
+ // their purpose-built demo trend transform at render time, so mutating
189
+ // every numeric field in every JSON response is unnecessary work.
190
+ const redacted = redactDemoData(data, {
191
+ redactNumbers: false,
192
+ redactProtectedEmails: true,
193
+ });
171
194
 
172
195
  const headers = new Headers(res.headers);
173
196
  // Body is re-serialized — these would be wrong now.