@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.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +23 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +2 -2
- package/corpus/core/src/client/analytics.ts +12 -0
- package/corpus/core/src/client/index.ts +2 -0
- package/corpus/core/src/client/session-replay.ts +612 -26
- package/corpus/core/src/client/settings/DemoModeSection.tsx +6 -6
- package/corpus/core/src/client/settings/SettingsPanel.tsx +31 -211
- package/corpus/core/src/client/settings/agent-settings-search.ts +219 -0
- package/corpus/core/src/client/settings/index.ts +4 -0
- package/corpus/core/src/demo/actions/toggle-demo-mode.ts +2 -2
- package/corpus/core/src/demo/config.ts +6 -6
- package/corpus/core/src/demo/fetch-interceptor.ts +25 -2
- package/corpus/core/src/demo/redact.ts +57 -66
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +65 -6
- package/corpus/templates/analytics/AGENTS.md +6 -6
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +429 -244
- package/corpus/templates/analytics/app/components/layout/command-palette-search.ts +93 -0
- package/corpus/templates/analytics/app/global.css +4 -62
- package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +2 -1
- package/corpus/templates/analytics/app/lib/demo-chart-trend.ts +46 -33
- package/corpus/templates/analytics/app/pages/Settings.tsx +8 -45
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +413 -105
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +32 -16
- package/corpus/templates/analytics/app/pages/settings/settings-search.ts +126 -0
- package/corpus/templates/analytics/changelog/2026-07-12-command-menu-loading-placeholders-now-stay-below-available-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-command-menu-search-now-prioritizes-the-best-match.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-demo-charts-preserve-source-movement.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-fixed-session-replays-that-appeared-ultra-wide-hid-recorded-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-replay-storage-settings-stay-readable-at-narrow-widths.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-session-replays-load-faster-in-demo-mode-while-visitor-email.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-session-replays-preserve-recorded-styling-and-keep-malformed.md +6 -0
- package/corpus/templates/calendar/app/components/calendar/DeleteEventDialog.tsx +11 -2
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +14 -2
- package/corpus/templates/calendar/changelog/2026-07-12-calendar-responses-can-now-be-saved-with-command-enter-or-ct.md +6 -0
- package/dist/agent/production-agent.js +2 -2
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +11 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/session-replay.d.ts +12 -3
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +488 -23
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/DemoModeSection.d.ts +3 -3
- package/dist/client/settings/DemoModeSection.js +4 -4
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +41 -191
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/agent-settings-search.d.ts +16 -0
- package/dist/client/settings/agent-settings-search.d.ts.map +1 -0
- package/dist/client/settings/agent-settings-search.js +178 -0
- package/dist/client/settings/agent-settings-search.js.map +1 -0
- package/dist/client/settings/index.d.ts +1 -0
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js +1 -0
- package/dist/client/settings/index.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/demo/actions/toggle-demo-mode.js +2 -2
- package/dist/demo/actions/toggle-demo-mode.js.map +1 -1
- package/dist/demo/config.js +6 -6
- package/dist/demo/config.js.map +1 -1
- package/dist/demo/fetch-interceptor.d.ts +1 -0
- package/dist/demo/fetch-interceptor.d.ts.map +1 -1
- package/dist/demo/fetch-interceptor.js +19 -2
- package/dist/demo/fetch-interceptor.js.map +1 -1
- package/dist/demo/redact.d.ts +14 -5
- package/dist/demo/redact.d.ts.map +1 -1
- package/dist/demo/redact.js +30 -56
- package/dist/demo/redact.js.map +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/package.json +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* <DemoModeSection /> — toggle that replaces
|
|
3
|
-
*
|
|
4
|
-
*
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 —
|
|
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
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* keeps working. The redaction WALK (see ./redact.ts) is expensive on
|
|
8
|
-
* payloads, so callers MUST gate it behind this function and only walk
|
|
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 (
|
|
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
|
-
|
|
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.
|