@agent-native/core 0.98.3 → 0.98.5
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 +29 -0
- package/corpus/core/docs/content/durable-background-runs.mdx +37 -0
- package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/de-DE/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/es-ES/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +4 -2
- package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-TW/durable-background-runs.mdx +14 -0
- package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +2 -0
- package/corpus/core/docs/content/tracking.mdx +2 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/durable-background.ts +16 -16
- package/corpus/core/src/agent/engine/ai-sdk-engine.ts +25 -8
- package/corpus/core/src/agent/engine/anthropic-engine.ts +17 -3
- package/corpus/core/src/agent/engine/output-tokens.ts +6 -6
- package/corpus/core/src/agent/production-agent.ts +200 -27
- package/corpus/core/src/agent/run-manager.ts +81 -1
- package/corpus/core/src/agent/run-store.ts +301 -41
- package/corpus/core/src/client/AgentPanel.tsx +6 -2
- package/corpus/core/src/client/AssistantChat.tsx +364 -69
- package/corpus/core/src/client/agent-chat-adapter.ts +169 -1
- package/corpus/core/src/client/analytics.ts +12 -0
- package/corpus/core/src/client/chat/message-components.tsx +3 -0
- package/corpus/core/src/client/chat/tool-call-display.tsx +20 -36
- package/corpus/core/src/client/conversation/use-near-bottom-autoscroll.ts +7 -0
- package/corpus/core/src/client/extensions/AgentNativeExtensionFrame.tsx +2 -0
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +2 -0
- package/corpus/core/src/client/extensions/ExtensionEditor.tsx +9 -2
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +2 -0
- package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +2 -0
- package/corpus/core/src/client/extensions/portable-extension.ts +2 -0
- package/corpus/core/src/client/session-replay.ts +971 -53
- package/corpus/core/src/client/settings/DemoModeSection.tsx +3 -3
- package/corpus/core/src/client/sse-event-processor.ts +43 -1
- 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 +34 -2
- package/corpus/core/src/demo/redact.ts +71 -158
- package/corpus/core/src/extensions/html-shell.ts +3 -0
- package/corpus/core/src/extensions/session-replay-iframe.ts +131 -0
- package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +1 -20
- package/corpus/core/src/session-replay-iframe-protocol.ts +58 -0
- package/corpus/core/src/shared/reasoning-effort.ts +35 -0
- package/corpus/core/src/styles/agent-conversation.css +26 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +67 -16
- package/corpus/templates/analytics/AGENTS.md +12 -0
- package/corpus/templates/analytics/actions/get-error-issue.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-events.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-summary.ts +1 -0
- package/corpus/templates/analytics/actions/list-error-issues.ts +1 -0
- package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -0
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +2 -1
- package/corpus/templates/analytics/app/global.css +6 -64
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +41 -4
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +143 -121
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +34 -12
- package/corpus/templates/analytics/changelog/2026-07-12-analytics-chat-retries-before-showing-a-generic-no-data-mess.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-analytics-sessions-search-no-longer-loses-fast-keystrokes-an.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-chart-selection-respects-chat-state.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-demo-mode-anonymizes-error-reporting-emails.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-session-replays-load-faster-in-demo-mode-while-visitor-email.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-session-replays-show-iframe-content.md +6 -0
- package/corpus/templates/analytics/netlify.toml +0 -3
- package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +14 -0
- package/corpus/templates/analytics/server/lib/error-capture.ts +59 -2
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +24 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +2 -9
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +39 -6
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/brain/app/global.css +2 -2
- package/corpus/templates/brain/changelog/2026-07-12-fix-long-response-progress.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/corpus/templates/forms/app/components/CloudUpgrade.tsx +1 -1
- package/corpus/templates/forms/app/components/ThemeToggle.tsx +22 -6
- package/corpus/templates/forms/app/components/builder/FieldPropertiesPanel.tsx +5 -5
- package/corpus/templates/forms/app/components/builder/FieldRenderer.tsx +3 -3
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +16 -16
- package/corpus/templates/forms/app/global.css +110 -5
- package/corpus/templates/forms/app/pages/AskPage.tsx +3 -3
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +134 -52
- package/corpus/templates/forms/app/pages/FormFillPage.tsx +44 -11
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +42 -24
- package/corpus/templates/forms/app/pages/ResponseInsightsPage.tsx +28 -15
- package/corpus/templates/forms/app/pages/ResponsesPage.tsx +38 -15
- package/corpus/templates/forms/app/routes/_app.settings.tsx +1 -1
- package/corpus/templates/forms/changelog/2026-07-12-form-builder-surfaces-are-calmer-fields-stay-stable-on-hover.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-12-smoother-more-tactile-controls-throughout-animated-icon-and-.md +6 -0
- package/corpus/templates/mail/app/components/email/EmailThread.tsx +21 -13
- package/corpus/templates/mail/app/components/email/email-iframe-document.ts +18 -0
- package/dist/agent/durable-background.d.ts +10 -10
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +16 -16
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +19 -8
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
- package/dist/agent/engine/anthropic-engine.js +11 -3
- package/dist/agent/engine/anthropic-engine.js.map +1 -1
- package/dist/agent/engine/output-tokens.js +6 -6
- package/dist/agent/engine/output-tokens.js.map +1 -1
- package/dist/agent/production-agent.d.ts +52 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +154 -26
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +9 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +71 -1
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +9 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +243 -48
- package/dist/agent/run-store.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +6 -2
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +21 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +298 -67
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +146 -1
- package/dist/client/agent-chat-adapter.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/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +2 -1
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +3 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +13 -37
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts +1 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -1
- package/dist/client/conversation/use-near-bottom-autoscroll.js +6 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -1
- package/dist/client/extensions/AgentNativeExtensionFrame.d.ts.map +1 -1
- package/dist/client/extensions/AgentNativeExtensionFrame.js +2 -1
- package/dist/client/extensions/AgentNativeExtensionFrame.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +2 -1
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionEditor.js +5 -2
- package/dist/client/extensions/ExtensionEditor.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +2 -1
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.js +2 -1
- package/dist/client/extensions/InlineExtensionFrame.js.map +1 -1
- package/dist/client/extensions/portable-extension.d.ts.map +1 -1
- package/dist/client/extensions/portable-extension.js +2 -0
- package/dist/client/extensions/portable-extension.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 +793 -49
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/DemoModeSection.js +1 -1
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +5 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +37 -1
- package/dist/client/sse-event-processor.js.map +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 +28 -2
- package/dist/demo/fetch-interceptor.js.map +1 -1
- package/dist/demo/redact.d.ts +14 -7
- package/dist/demo/redact.d.ts.map +1 -1
- package/dist/demo/redact.js +27 -155
- package/dist/demo/redact.js.map +1 -1
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js +2 -0
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/session-replay-iframe.d.ts +10 -0
- package/dist/extensions/session-replay-iframe.d.ts.map +1 -0
- package/dist/extensions/session-replay-iframe.js +121 -0
- package/dist/extensions/session-replay-iframe.js.map +1 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +1 -19
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/session-replay-iframe-protocol.d.ts +36 -0
- package/dist/session-replay-iframe-protocol.d.ts.map +1 -0
- package/dist/session-replay-iframe-protocol.js +24 -0
- package/dist/session-replay-iframe-protocol.js.map +1 -0
- package/dist/shared/reasoning-effort.d.ts +11 -0
- package/dist/shared/reasoning-effort.d.ts.map +1 -1
- package/dist/shared/reasoning-effort.js +36 -0
- package/dist/shared/reasoning-effort.js.map +1 -1
- package/dist/styles/agent-conversation.css +26 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/docs/content/durable-background-runs.mdx +37 -0
- package/docs/content/locales/ar-SA/tracking.mdx +2 -0
- package/docs/content/locales/de-DE/tracking.mdx +2 -0
- package/docs/content/locales/es-ES/tracking.mdx +2 -0
- package/docs/content/locales/fr-FR/tracking.mdx +4 -2
- package/docs/content/locales/hi-IN/tracking.mdx +2 -0
- package/docs/content/locales/ja-JP/tracking.mdx +2 -0
- package/docs/content/locales/ko-KR/tracking.mdx +2 -0
- package/docs/content/locales/pt-BR/tracking.mdx +2 -0
- package/docs/content/locales/zh-CN/tracking.mdx +2 -0
- package/docs/content/locales/zh-TW/durable-background-runs.mdx +14 -0
- package/docs/content/locales/zh-TW/tracking.mdx +2 -0
- package/docs/content/tracking.mdx +2 -0
- package/package.json +2 -2
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/corpus/core/src/observability/hosted-model-experiment.ts +0 -118
- package/dist/observability/hosted-model-experiment.d.ts +0 -39
- package/dist/observability/hosted-model-experiment.d.ts.map +0 -1
- package/dist/observability/hosted-model-experiment.js +0 -90
- package/dist/observability/hosted-model-experiment.js.map +0 -1
|
@@ -18,6 +18,7 @@ import { fileURLToPath } from "node:url";
|
|
|
18
18
|
* reads go through `accessFilter` so an org-scoped key surfaces its issues to
|
|
19
19
|
* the whole org exactly like session recordings.
|
|
20
20
|
*/
|
|
21
|
+
import { readAppState } from "@agent-native/core/application-state";
|
|
21
22
|
import { notifyWithDelivery } from "@agent-native/core/notifications";
|
|
22
23
|
import { recordChange } from "@agent-native/core/server";
|
|
23
24
|
import { accessFilter } from "@agent-native/core/sharing";
|
|
@@ -1076,6 +1077,52 @@ export interface ListErrorIssuesFilters {
|
|
|
1076
1077
|
limit?: number;
|
|
1077
1078
|
}
|
|
1078
1079
|
|
|
1080
|
+
export const ERROR_REPORTING_ANONYMOUS_EMAIL = "anonymous@builder.io";
|
|
1081
|
+
const ERROR_REPORTING_EMAIL_PATTERN = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi;
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Error reports contain emails in identity fields, messages, stacks, URLs,
|
|
1085
|
+
* tags, extra context, and breadcrumbs. Redact every string at this owning
|
|
1086
|
+
* read seam so demo mode never depends on browser interception timing.
|
|
1087
|
+
*/
|
|
1088
|
+
export function anonymizeErrorReportingEmails<T>(value: T): T {
|
|
1089
|
+
if (typeof value === "string") {
|
|
1090
|
+
return value.replace(
|
|
1091
|
+
ERROR_REPORTING_EMAIL_PATTERN,
|
|
1092
|
+
ERROR_REPORTING_ANONYMOUS_EMAIL,
|
|
1093
|
+
) as T;
|
|
1094
|
+
}
|
|
1095
|
+
if (Array.isArray(value)) {
|
|
1096
|
+
return value.map((item) => anonymizeErrorReportingEmails(item)) as T;
|
|
1097
|
+
}
|
|
1098
|
+
if (value && typeof value === "object") {
|
|
1099
|
+
if (value instanceof Date) return value;
|
|
1100
|
+
const output: Record<string, unknown> = {};
|
|
1101
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
1102
|
+
output[key] = anonymizeErrorReportingEmails(entry);
|
|
1103
|
+
}
|
|
1104
|
+
return output as T;
|
|
1105
|
+
}
|
|
1106
|
+
return value;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
async function isErrorDemoModeEnabled(): Promise<boolean> {
|
|
1110
|
+
if (process.env.DEMO_MODE === "true") return true;
|
|
1111
|
+
try {
|
|
1112
|
+
const state = await readAppState("demo-mode");
|
|
1113
|
+
return state?.enabled === true;
|
|
1114
|
+
} catch {
|
|
1115
|
+
return false;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
function anonymizeErrorReportingEmailsInDemoMode<T>(
|
|
1120
|
+
value: T,
|
|
1121
|
+
enabled: boolean,
|
|
1122
|
+
): T {
|
|
1123
|
+
return enabled ? anonymizeErrorReportingEmails(value) : value;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1079
1126
|
export interface ErrorIssueSummary {
|
|
1080
1127
|
id: string;
|
|
1081
1128
|
fingerprint: string;
|
|
@@ -1148,6 +1195,7 @@ export async function listErrorIssues(
|
|
|
1148
1195
|
scope: ErrorReadScope,
|
|
1149
1196
|
filters: ListErrorIssuesFilters = {},
|
|
1150
1197
|
): Promise<ErrorIssueSummary[]> {
|
|
1198
|
+
const demoModeEnabled = isErrorDemoModeEnabled();
|
|
1151
1199
|
const db = getDb() as any;
|
|
1152
1200
|
const limit = Math.min(
|
|
1153
1201
|
MAX_ISSUE_LIMIT,
|
|
@@ -1184,7 +1232,7 @@ export async function listErrorIssues(
|
|
|
1184
1232
|
.limit(limit);
|
|
1185
1233
|
|
|
1186
1234
|
const sparklines = await sparklinesForIssues(rows.map((row: any) => row.id));
|
|
1187
|
-
|
|
1235
|
+
const issues = rows.map((row: any) => ({
|
|
1188
1236
|
id: row.id,
|
|
1189
1237
|
fingerprint: row.fingerprint,
|
|
1190
1238
|
type: row.type,
|
|
@@ -1203,6 +1251,7 @@ export async function listErrorIssues(
|
|
|
1203
1251
|
template: row.template ?? null,
|
|
1204
1252
|
sparkline: sparklines.get(row.id) ?? new Array(SPARKLINE_DAYS).fill(0),
|
|
1205
1253
|
}));
|
|
1254
|
+
return anonymizeErrorReportingEmailsInDemoMode(issues, await demoModeEnabled);
|
|
1206
1255
|
}
|
|
1207
1256
|
|
|
1208
1257
|
export interface ErrorEventDetail {
|
|
@@ -1294,6 +1343,7 @@ export async function getErrorIssue(
|
|
|
1294
1343
|
issueId: string,
|
|
1295
1344
|
options: { eventsLimit?: number } = {},
|
|
1296
1345
|
): Promise<ErrorIssueDetail> {
|
|
1346
|
+
const demoModeEnabled = isErrorDemoModeEnabled();
|
|
1297
1347
|
const db = getDb() as any;
|
|
1298
1348
|
const [issueRow] = await db
|
|
1299
1349
|
.select()
|
|
@@ -1419,7 +1469,14 @@ export async function getErrorIssue(
|
|
|
1419
1469
|
sparkline: sparklines.get(issueId) ?? new Array(SPARKLINE_DAYS).fill(0),
|
|
1420
1470
|
};
|
|
1421
1471
|
|
|
1422
|
-
return
|
|
1472
|
+
return anonymizeErrorReportingEmailsInDemoMode(
|
|
1473
|
+
{
|
|
1474
|
+
issue,
|
|
1475
|
+
events,
|
|
1476
|
+
sessions: Array.from(sessions.values()),
|
|
1477
|
+
},
|
|
1478
|
+
await demoModeEnabled,
|
|
1479
|
+
);
|
|
1423
1480
|
}
|
|
1424
1481
|
|
|
1425
1482
|
export interface UpdateErrorIssueInput {
|
|
@@ -8,6 +8,7 @@ const INJECTED_CONTEXT_BLOCKS = [
|
|
|
8
8
|
"available-agents",
|
|
9
9
|
"available-jobs",
|
|
10
10
|
"plan-mode-note",
|
|
11
|
+
"non-analytics-retry",
|
|
11
12
|
];
|
|
12
13
|
|
|
13
14
|
export const DATA_QUERY_ACTIONS = new Set([
|
|
@@ -231,12 +232,35 @@ export function looksLikeAnalyticsDataRequest(text: string): boolean {
|
|
|
231
232
|
const UNSUPPORTED_RESULT_CLAIM =
|
|
232
233
|
/(?:\b\d[\d,.]*(?:\.\d+)?\s*(?:%|percent|users?|customers?|accounts?|sessions?|events?|deals?|tickets?|issues?|calls?|messages?|signups?|pageviews?)\b|\$\s*\d|\b(?:data|query|results?)\s+(?:shows?|showed|indicates?|returned|found)\b|\b(?:i found|the top|the bottom|highest|lowest|increased|decreased|grew|declined|converted|churned|retained|averaged|total(?:ed)?|count(?:ed)?)\b)/i;
|
|
233
234
|
|
|
235
|
+
export const GENERIC_NO_DATA_FALLBACK_MESSAGE =
|
|
236
|
+
"I can't provide a grounded analytics result yet because no real data-source query ran successfully. Tell me which source to use or connect the missing source, and I'll run it before giving numbers or source-record conclusions.";
|
|
237
|
+
|
|
238
|
+
// The first sentence of the canned fallback, lowercased, with the trailing
|
|
239
|
+
// period dropped. Matching this prefix (rather than the whole message) still
|
|
240
|
+
// catches a model paraphrase that continues differently after "successfully".
|
|
241
|
+
const GENERIC_NO_DATA_FALLBACK_FIRST_SENTENCE =
|
|
242
|
+
GENERIC_NO_DATA_FALLBACK_MESSAGE.slice(
|
|
243
|
+
0,
|
|
244
|
+
GENERIC_NO_DATA_FALLBACK_MESSAGE.indexOf(". ") + 1,
|
|
245
|
+
).toLowerCase();
|
|
246
|
+
|
|
247
|
+
export function isGenericNoDataFallback(text: string): boolean {
|
|
248
|
+
return text
|
|
249
|
+
.trim()
|
|
250
|
+
.toLowerCase()
|
|
251
|
+
.startsWith(GENERIC_NO_DATA_FALLBACK_FIRST_SENTENCE.slice(0, -1));
|
|
252
|
+
}
|
|
253
|
+
|
|
234
254
|
const SAFE_NO_DATA_RESPONSE =
|
|
235
255
|
/\b(?:i can't|i cannot|can't retrieve|cannot retrieve|couldn't retrieve|unable to retrieve|don't have access|do not have access|not configured|missing credentials?|need (?:a|the)? ?data source|need to know which source|which source|which data source|clarify|can you|once (?:that'?s|it is) (?:connected|configured|available)|no data source|without a successful|query failed|source query failed|sql failed|error running|before (?:i|we) can (?:calculate|report|answer|analyze)|i need to query)\b/i;
|
|
236
256
|
|
|
237
257
|
export function isSafeNoDataAnalyticsResponse(text: string): boolean {
|
|
238
258
|
const trimmed = text.trim();
|
|
239
259
|
if (!trimmed) return false;
|
|
260
|
+
// This is the guard's own last-resort fallback. If a model emits it before
|
|
261
|
+
// attempting a query, it must go through the retry path instead of being
|
|
262
|
+
// accepted as an explicit unavailable-source or clarification response.
|
|
263
|
+
if (isGenericNoDataFallback(trimmed)) return false;
|
|
240
264
|
if (UNSUPPORTED_RESULT_CLAIM.test(trimmed)) return false;
|
|
241
265
|
if (SAFE_NO_DATA_RESPONSE.test(trimmed)) return true;
|
|
242
266
|
return /\?\s*$/.test(trimmed) && !UNSUPPORTED_RESULT_CLAIM.test(trimmed);
|
|
@@ -255,6 +255,7 @@ const RETENTION_DELETE_BATCH_SIZE = 500;
|
|
|
255
255
|
const REPLAY_PRIVATE_BLOB_REF_KIND = "agent-native.session-replay.private-blob";
|
|
256
256
|
const REPLAY_PRIVATE_BLOB_REF_VERSION = 1;
|
|
257
257
|
const SESSION_DEMO_EMAIL_PATTERN = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi;
|
|
258
|
+
const SESSION_DEMO_ANONYMOUS_EMAIL = "anonymous@builder.io";
|
|
258
259
|
let inlineReplayFallbackWarned = false;
|
|
259
260
|
|
|
260
261
|
function replayError(message: string, statusCode: number): Error {
|
|
@@ -318,20 +319,12 @@ function demoBuilderSessionCondition() {
|
|
|
318
319
|
}
|
|
319
320
|
|
|
320
321
|
class SessionDemoAnonymizer {
|
|
321
|
-
private readonly aliases = new Map<string, string>();
|
|
322
|
-
|
|
323
322
|
aliasFor(value: unknown): string | null {
|
|
324
323
|
const raw = replayString(value);
|
|
325
324
|
if (!raw || raw.match(SESSION_DEMO_EMAIL_PATTERN)?.[0] !== raw) {
|
|
326
325
|
return null;
|
|
327
326
|
}
|
|
328
|
-
|
|
329
|
-
let alias = this.aliases.get(email);
|
|
330
|
-
if (!alias) {
|
|
331
|
-
alias = `anonymized-${this.aliases.size + 1}@builder.io`;
|
|
332
|
-
this.aliases.set(email, alias);
|
|
333
|
-
}
|
|
334
|
-
return alias;
|
|
327
|
+
return SESSION_DEMO_ANONYMOUS_EMAIL;
|
|
335
328
|
}
|
|
336
329
|
|
|
337
330
|
summarize(row: any, role?: SessionReplayAccessRole): SessionRecordingSummary {
|
|
@@ -10,12 +10,15 @@ import {
|
|
|
10
10
|
applyAnalyticsPlanModePolicy,
|
|
11
11
|
INITIAL_TOOL_NAMES,
|
|
12
12
|
} from "../lib/agent-chat-plan-mode";
|
|
13
|
+
import { ANALYTICS_CONNECTOR_CATALOG } from "../lib/analytics-connector-catalog";
|
|
13
14
|
import {
|
|
14
15
|
failedDataQueryAttemptMessage,
|
|
16
|
+
GENERIC_NO_DATA_FALLBACK_MESSAGE,
|
|
15
17
|
hasExplicitPartialDisclosure,
|
|
16
18
|
hasFailedCorpusWorkflowEvidence,
|
|
17
19
|
hasDataQueryAttempt,
|
|
18
20
|
hasIncompleteDataEvidence,
|
|
21
|
+
isGenericNoDataFallback,
|
|
19
22
|
isSafeNoDataAnalyticsResponse,
|
|
20
23
|
hasOverstatedCoverageConfidenceClaim,
|
|
21
24
|
looksLikeCoverageSensitiveAnalyticsRequest,
|
|
@@ -24,16 +27,34 @@ import {
|
|
|
24
27
|
needsCorpusWorkflowForCoverageSensitiveRequest,
|
|
25
28
|
needsSourceRecordBodyWorkflowForCoverageSensitiveRequest,
|
|
26
29
|
} from "../lib/real-data-actions";
|
|
27
|
-
const ANALYTICS_BACKGROUND_RUN_SOFT_TIMEOUT_MS = 13 * 60_000;
|
|
28
|
-
|
|
29
30
|
export const SIMPLE_TIME_BOUNDED_METRIC_FAST_PATH_GUIDANCE =
|
|
30
31
|
"SIMPLE TIME-BOUNDED METRIC FAST PATH — When the data dictionary or a known canonical source identifies the metric, run one bounded aggregate. Once it returns a valid result, answer the explicit question immediately with the source, time window, row count, and only necessary caveats. Do not schema-discover, retry, enrich, cross-check, or add breakdowns after that successful result unless the query failed or the result conflicts with the known metric definition. This does not waive the real-data requirement: never answer from a guess, stale value, or unverified result. ";
|
|
31
32
|
|
|
33
|
+
export const ANALYTICS_OBSERVABILITY_INCIDENT_GUIDANCE =
|
|
34
|
+
"OBSERVABILITY INCIDENT WORKFLOW — For a named user's session or error question, resolve the user's email from context, then use list-session-recordings with userId and hasErrors=true over a bounded recent window. Use list-error-issues with userId or sessionRecordingId to identify the grouped issue, then get-error-issue for stack, breadcrumbs, occurrences, and linked recordings. When the timeline, page navigation, console diagnostics, failed network requests, or clicks are needed, use create-session-replay-agent-link and follow its bounded diagnostics/context APIs. Prefer these first-party actions over generic SQL; use query-agent-native-analytics only to correlate first-party events. Report the matching evidence and do not claim a root cause without a corroborating error or replay signal. ";
|
|
35
|
+
|
|
36
|
+
export const NON_ANALYTICS_REQUEST_GUIDANCE =
|
|
37
|
+
"NON-ANALYTICS REQUESTS — If the user is not asking for a live metric, source record, or derived analytics claim, answer normally in chat. Greetings, general-knowledge questions, math, writing, coding, and conceptual questions do not need a data-source call. Do not use the no-grounded-data fallback for those requests. ";
|
|
38
|
+
|
|
39
|
+
// Deterministic backstop for the soft NON_ANALYTICS_REQUEST_GUIDANCE prompt
|
|
40
|
+
// above: if a model still parrots the canned no-grounded-data fallback on a
|
|
41
|
+
// non-analytics turn, retry once with this synthetic user message instead of
|
|
42
|
+
// letting the canned sentence reach the user. Wrapped in an injected-context
|
|
43
|
+
// tag (registered in INJECTED_CONTEXT_BLOCKS) so `looksLikeAnalyticsDataRequest`
|
|
44
|
+
// never classifies the guard's own retry turn as a data request and loops.
|
|
45
|
+
export const NON_ANALYTICS_FALLBACK_RETRY_MESSAGE =
|
|
46
|
+
"<non-analytics-retry>\nThe user's latest message is ordinary conversation. Reply to it directly and naturally. Never answer it with the no-grounded-data disclaimer.\n</non-analytics-retry>";
|
|
47
|
+
|
|
48
|
+
export const NON_ANALYTICS_FALLBACK_FINAL_MESSAGE =
|
|
49
|
+
"I got stuck generating a reply to that message. Please try again or rephrase it.";
|
|
50
|
+
|
|
32
51
|
export function analyticsSourceGuidanceOpening(): string {
|
|
33
52
|
return (
|
|
34
53
|
"<data-source-guidance>\n" +
|
|
35
54
|
"Apply real-data requirements only when presenting analytics results, source records, or derived metrics. Do not call data-source tools for workflow migration, recurring-job setup, UI/code fixes, settings help, conceptual planning, or other non-data tasks unless the user explicitly asks for data. " +
|
|
55
|
+
NON_ANALYTICS_REQUEST_GUIDANCE +
|
|
36
56
|
SIMPLE_TIME_BOUNDED_METRIC_FAST_PATH_GUIDANCE +
|
|
57
|
+
ANALYTICS_OBSERVABILITY_INCIDENT_GUIDANCE +
|
|
37
58
|
"SURFACE DIFFERENTIATION — You are the analytics assistant for definitions, deep-dive analysis, and action. For questions about what a metric, model, or table means, use the Data Dictionary and configured schema tools first. For trends, comparisons, anomalies, current data, or anything that requires querying live data, answer directly in chat with the relevant provider query, dashboard analysis, and inline charts when useful. "
|
|
38
59
|
);
|
|
39
60
|
}
|
|
@@ -124,7 +145,20 @@ export function realDataFinalGuard(
|
|
|
124
145
|
return null;
|
|
125
146
|
}
|
|
126
147
|
const userText = latestUserText(context.messages ?? []);
|
|
127
|
-
if (!looksLikeAnalyticsDataRequest(userText))
|
|
148
|
+
if (!looksLikeAnalyticsDataRequest(userText)) {
|
|
149
|
+
// Deterministic backstop: the soft NON_ANALYTICS_REQUEST_GUIDANCE prompt
|
|
150
|
+
// sentence is not always enough, and a model occasionally parrots the
|
|
151
|
+
// canned no-grounded-data fallback even for ordinary conversation. Catch
|
|
152
|
+
// that case here instead of letting it reach the user.
|
|
153
|
+
if (isGenericNoDataFallback(context.text)) {
|
|
154
|
+
return {
|
|
155
|
+
retryMessage: NON_ANALYTICS_FALLBACK_RETRY_MESSAGE,
|
|
156
|
+
fallbackMessage: NON_ANALYTICS_FALLBACK_FINAL_MESSAGE,
|
|
157
|
+
maxRetries: 2,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
128
162
|
const incompleteEvidence = hasIncompleteDataEvidence(context.toolResults);
|
|
129
163
|
if (
|
|
130
164
|
hasFailedCorpusWorkflowEvidence(context.toolResults) &&
|
|
@@ -200,7 +234,7 @@ export function realDataFinalGuard(
|
|
|
200
234
|
" If the right response is a clarification, plan, or explicit unavailable/credentials-missing message with no metrics or source-record claims, finalize that directly instead.",
|
|
201
235
|
fallbackMessage: configuredSources.length
|
|
202
236
|
? `I found connected data sources (${configuredSources.join(", ")}), but the model still did not run a real source query. Please retry the request; you do not need to reconnect those sources.`
|
|
203
|
-
:
|
|
237
|
+
: GENERIC_NO_DATA_FALLBACK_MESSAGE,
|
|
204
238
|
// Some models use separate turns for status, schema discovery, and the
|
|
205
239
|
// actual query. One corrective turn was enough for Sonnet but caused Luna
|
|
206
240
|
// to hit the fallback before it reached the query.
|
|
@@ -223,8 +257,7 @@ export default createAgentChatPlugin({
|
|
|
223
257
|
// Operators deploying to trusted internal environments can set
|
|
224
258
|
// AGENT_PROD_CODE_EXECUTION=trusted to also enable bash/read/edit/write.
|
|
225
259
|
codeExecution: { production: "sandboxed" },
|
|
226
|
-
|
|
227
|
-
runSoftTimeoutMs: ANALYTICS_BACKGROUND_RUN_SOFT_TIMEOUT_MS,
|
|
260
|
+
connectorCatalog: [...ANALYTICS_CONNECTOR_CATALOG],
|
|
228
261
|
resolveOrgId: async (event) => {
|
|
229
262
|
const ctx = await getOrgContext(event);
|
|
230
263
|
return ctx.orgId;
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
.brain-chat-panel [data-agent-empty-state="centered"] .brain-chat-intro {
|
|
136
136
|
display: grid;
|
|
137
137
|
width: 100%;
|
|
138
|
-
max-width: min(
|
|
138
|
+
max-width: min(684px, 90%);
|
|
139
139
|
gap: 0.5rem;
|
|
140
140
|
margin: 0 auto 1rem;
|
|
141
141
|
text-align: center;
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
|
|
166
166
|
.brain-chat-panel [data-agent-empty-state="centered"] .agent-composer-area {
|
|
167
167
|
width: 100%;
|
|
168
|
-
max-width: min(
|
|
168
|
+
max-width: min(684px, 90%);
|
|
169
169
|
padding: 0;
|
|
170
170
|
}
|
|
171
171
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client";
|
|
2
2
|
import type { CalendarEvent, DeleteEventScope } from "@shared/api";
|
|
3
|
-
import { useEffect, useMemo, useState } from "react";
|
|
3
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
|
|
5
5
|
import { getGuestAttendeeCount } from "@/components/calendar/GuestNotificationDialog";
|
|
6
6
|
import {
|
|
@@ -36,6 +36,7 @@ export function DeleteEventDialog({
|
|
|
36
36
|
onConfirm,
|
|
37
37
|
}: DeleteEventDialogProps) {
|
|
38
38
|
const t = useT();
|
|
39
|
+
const confirmButtonRef = useRef<HTMLButtonElement>(null);
|
|
39
40
|
const [scope, setScope] = useState<DeleteEventScope>("single");
|
|
40
41
|
const [message, setMessage] = useState("");
|
|
41
42
|
|
|
@@ -108,7 +109,14 @@ export function DeleteEventDialog({
|
|
|
108
109
|
|
|
109
110
|
return (
|
|
110
111
|
<AlertDialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
|
|
111
|
-
<AlertDialogContent
|
|
112
|
+
<AlertDialogContent
|
|
113
|
+
className="max-w-[420px]"
|
|
114
|
+
onKeyDown={handleKeyDown}
|
|
115
|
+
onOpenAutoFocus={(event) => {
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
confirmButtonRef.current?.focus();
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
112
120
|
<AlertDialogHeader>
|
|
113
121
|
<AlertDialogTitle className="text-sm">{copy.title}</AlertDialogTitle>
|
|
114
122
|
<AlertDialogDescription>{copy.description}</AlertDialogDescription>
|
|
@@ -174,6 +182,7 @@ export function DeleteEventDialog({
|
|
|
174
182
|
</Button>
|
|
175
183
|
)}
|
|
176
184
|
<Button
|
|
185
|
+
ref={confirmButtonRef}
|
|
177
186
|
variant="destructive"
|
|
178
187
|
onClick={() => handleConfirm(canNotifyGuests ? "all" : "none")}
|
|
179
188
|
>
|
|
@@ -194,6 +194,12 @@ function RsvpControls({
|
|
|
194
194
|
doRsvp(status, undefined, "");
|
|
195
195
|
};
|
|
196
196
|
|
|
197
|
+
const savePendingResponse = () => {
|
|
198
|
+
if (!pendingStatus || mutation.isPending) return;
|
|
199
|
+
doRsvp(pendingStatus, isRecurring ? pendingScope : undefined);
|
|
200
|
+
closePopover();
|
|
201
|
+
};
|
|
202
|
+
|
|
197
203
|
return (
|
|
198
204
|
<Popover
|
|
199
205
|
open={!!pendingStatus}
|
|
@@ -255,6 +261,13 @@ function RsvpControls({
|
|
|
255
261
|
className="w-[22rem] max-w-[calc(100vw-2rem)] overflow-hidden p-0"
|
|
256
262
|
onClick={(e) => e.stopPropagation()}
|
|
257
263
|
onPointerDownCapture={(e) => e.stopPropagation()}
|
|
264
|
+
onKeyDown={(e) => {
|
|
265
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
266
|
+
e.preventDefault();
|
|
267
|
+
e.stopPropagation();
|
|
268
|
+
savePendingResponse();
|
|
269
|
+
}
|
|
270
|
+
}}
|
|
258
271
|
>
|
|
259
272
|
{pendingStatus && (
|
|
260
273
|
<div>
|
|
@@ -336,8 +349,7 @@ function RsvpControls({
|
|
|
336
349
|
disabled={mutation.isPending}
|
|
337
350
|
onClick={(e) => {
|
|
338
351
|
e.stopPropagation();
|
|
339
|
-
|
|
340
|
-
closePopover();
|
|
352
|
+
savePendingResponse();
|
|
341
353
|
}}
|
|
342
354
|
>
|
|
343
355
|
{t("eventForm.saveResponse")}
|
|
@@ -168,7 +168,7 @@ export function CloudUpgrade({
|
|
|
168
168
|
key={p.id}
|
|
169
169
|
onClick={() => setSelectedProvider(p.id)}
|
|
170
170
|
className={cn(
|
|
171
|
-
"flex flex-col items-start rounded-lg border px-3 py-2.5 text-left min-h-[44px]",
|
|
171
|
+
"flex flex-col items-start rounded-lg border px-3 py-2.5 text-left min-h-[44px] transition-[border-color,background-color,scale] duration-150 ease-out active:scale-[0.96] motion-reduce:active:scale-100",
|
|
172
172
|
selectedProvider === p.id
|
|
173
173
|
? "border-primary bg-primary/5"
|
|
174
174
|
: "border-border hover:border-primary/30",
|
|
@@ -22,13 +22,29 @@ export function ThemeToggle({ className }: { className?: string }) {
|
|
|
22
22
|
variant="ghost"
|
|
23
23
|
size="icon"
|
|
24
24
|
onClick={() => setTheme(isDark ? "light" : "dark")}
|
|
25
|
-
className={cn(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<IconSun className="h-4 w-4" />
|
|
29
|
-
) : (
|
|
30
|
-
<IconMoon className="h-4 w-4" />
|
|
25
|
+
className={cn(
|
|
26
|
+
"relative text-muted-foreground before:absolute before:-inset-1.5",
|
|
27
|
+
className,
|
|
31
28
|
)}
|
|
29
|
+
>
|
|
30
|
+
<span className="relative inline-flex h-4 w-4 items-center justify-center">
|
|
31
|
+
<IconSun
|
|
32
|
+
className={cn(
|
|
33
|
+
"absolute inset-0 h-4 w-4 transition-[opacity,filter,scale] duration-200 ease-[cubic-bezier(0.2,0,0,1)]",
|
|
34
|
+
isDark
|
|
35
|
+
? "scale-100 opacity-100 blur-none"
|
|
36
|
+
: "scale-[0.25] opacity-0 blur-[4px]",
|
|
37
|
+
)}
|
|
38
|
+
/>
|
|
39
|
+
<IconMoon
|
|
40
|
+
className={cn(
|
|
41
|
+
"absolute inset-0 h-4 w-4 transition-[opacity,filter,scale] duration-200 ease-[cubic-bezier(0.2,0,0,1)]",
|
|
42
|
+
isDark
|
|
43
|
+
? "scale-[0.25] opacity-0 blur-[4px]"
|
|
44
|
+
: "scale-100 opacity-100 blur-none",
|
|
45
|
+
)}
|
|
46
|
+
/>
|
|
47
|
+
</span>
|
|
32
48
|
</Button>
|
|
33
49
|
</TooltipTrigger>
|
|
34
50
|
<TooltipContent>{t("root.toggleTheme")}</TooltipContent>
|
|
@@ -70,7 +70,7 @@ export function FieldPropertiesPanel({
|
|
|
70
70
|
<Button
|
|
71
71
|
variant="ghost"
|
|
72
72
|
size="sm"
|
|
73
|
-
className="
|
|
73
|
+
className="h-10 px-3 text-xs text-destructive active:scale-[0.96]"
|
|
74
74
|
onClick={onDelete}
|
|
75
75
|
>
|
|
76
76
|
{t("common.delete")}
|
|
@@ -181,13 +181,13 @@ export function FieldPropertiesPanel({
|
|
|
181
181
|
<Button
|
|
182
182
|
variant="ghost"
|
|
183
183
|
size="sm"
|
|
184
|
-
className="h-
|
|
184
|
+
className="relative h-10 w-10 shrink-0 p-0 transition-transform duration-150 ease-out before:absolute before:-inset-1 active:scale-[0.96] motion-reduce:active:scale-100 sm:h-7 sm:w-7"
|
|
185
185
|
onClick={() => removeOption(i)}
|
|
186
186
|
aria-label={t("fieldProperties.removeOption", {
|
|
187
187
|
option: opt,
|
|
188
188
|
})}
|
|
189
189
|
>
|
|
190
|
-
<IconX className="h-3 w-3" />
|
|
190
|
+
<IconX className="h-3.5 w-3.5 translate-y-px" />
|
|
191
191
|
</Button>
|
|
192
192
|
</div>
|
|
193
193
|
))}
|
|
@@ -202,11 +202,11 @@ export function FieldPropertiesPanel({
|
|
|
202
202
|
<Button
|
|
203
203
|
variant="ghost"
|
|
204
204
|
size="sm"
|
|
205
|
-
className="h-
|
|
205
|
+
className="relative h-10 w-10 shrink-0 p-0 transition-transform duration-150 ease-out before:absolute before:-inset-1 active:scale-[0.96] motion-reduce:active:scale-100 sm:h-7 sm:w-7"
|
|
206
206
|
onClick={addOption}
|
|
207
207
|
aria-label={t("fieldProperties.addOption")}
|
|
208
208
|
>
|
|
209
|
-
<IconPlus className="h-3 w-3" />
|
|
209
|
+
<IconPlus className="h-3.5 w-3.5 translate-y-px" />
|
|
210
210
|
</Button>
|
|
211
211
|
</div>
|
|
212
212
|
</div>
|
|
@@ -204,14 +204,14 @@ export function FieldRenderer({
|
|
|
204
204
|
key={star}
|
|
205
205
|
type="button"
|
|
206
206
|
onClick={() => !disabled && handleChange(star)}
|
|
207
|
-
className="cursor-pointer p-2
|
|
207
|
+
className="flex size-11 cursor-pointer items-center justify-center rounded-md p-2 transition-[color,transform] duration-150 ease-out active:scale-[0.96] motion-reduce:active:scale-100 disabled:cursor-not-allowed sm:size-10 sm:p-1.5"
|
|
208
208
|
disabled={disabled}
|
|
209
209
|
aria-label={`${star} star${star !== 1 ? "s" : ""}`}
|
|
210
210
|
>
|
|
211
211
|
{(value as number) >= star ? (
|
|
212
|
-
<IconStarFilled className="h-7 w-7 sm:h-6 sm:w-6
|
|
212
|
+
<IconStarFilled className="h-7 w-7 text-amber-400 sm:h-6 sm:w-6" />
|
|
213
213
|
) : (
|
|
214
|
-
<IconStar className="h-7 w-7 sm:h-6 sm:w-6
|
|
214
|
+
<IconStar className="h-7 w-7 text-muted-foreground/30 sm:h-6 sm:w-6" />
|
|
215
215
|
)}
|
|
216
216
|
</button>
|
|
217
217
|
))}
|
|
@@ -131,7 +131,7 @@ export function Sidebar() {
|
|
|
131
131
|
|
|
132
132
|
const newFormButton = (
|
|
133
133
|
<PopoverTrigger asChild>
|
|
134
|
-
<button className="flex min-h-[44px] w-full cursor-pointer items-center gap-2.5 rounded-
|
|
134
|
+
<button className="forms-sidebar-nav-item flex min-h-[44px] w-full cursor-pointer items-center gap-2.5 rounded-lg px-3 py-2 text-sm text-muted-foreground active:scale-[0.96] transition-[background-color,box-shadow,color,transform] hover:bg-accent/50 hover:text-foreground">
|
|
135
135
|
<IconPlus className="h-4 w-4 shrink-0" />
|
|
136
136
|
<span>{t("sidebar.newForm")}</span>
|
|
137
137
|
</button>
|
|
@@ -143,7 +143,7 @@ export function Sidebar() {
|
|
|
143
143
|
side="right"
|
|
144
144
|
align="start"
|
|
145
145
|
sideOffset={8}
|
|
146
|
-
className="w-80 p-0
|
|
146
|
+
className="forms-new-form-popover w-80 rounded-2xl p-0"
|
|
147
147
|
>
|
|
148
148
|
<div className="p-4 pb-3">
|
|
149
149
|
<p className="text-sm font-semibold">{t("sidebar.newForm")}</p>
|
|
@@ -168,7 +168,7 @@ export function Sidebar() {
|
|
|
168
168
|
<Button
|
|
169
169
|
variant="link"
|
|
170
170
|
size="sm"
|
|
171
|
-
className="h-
|
|
171
|
+
className="min-h-10 px-2 text-xs text-muted-foreground active:scale-[0.96] transition-[background-color,color,transform]"
|
|
172
172
|
onClick={handleSkip}
|
|
173
173
|
>
|
|
174
174
|
{t("sidebar.skipPrompt")}
|
|
@@ -180,7 +180,7 @@ export function Sidebar() {
|
|
|
180
180
|
<Button
|
|
181
181
|
variant="secondary"
|
|
182
182
|
size="icon"
|
|
183
|
-
className="
|
|
183
|
+
className="size-10 rounded-lg transition-[background-color,box-shadow,transform] active:scale-[0.96] motion-reduce:active:scale-100"
|
|
184
184
|
onClick={handleSubmitPrompt}
|
|
185
185
|
disabled={!prompt.trim() || promptRun.isActivePrompt(prompt)}
|
|
186
186
|
aria-label={t("sidebar.sendPrompt")}
|
|
@@ -200,7 +200,7 @@ export function Sidebar() {
|
|
|
200
200
|
<button
|
|
201
201
|
type="button"
|
|
202
202
|
onClick={() => setCollapsed(false)}
|
|
203
|
-
className="flex
|
|
203
|
+
className="forms-sidebar-nav-item flex size-10 items-center justify-center rounded-lg text-muted-foreground/55 transition-[background-color,box-shadow,color,transform] duration-150 ease-out hover:bg-accent/50 hover:text-muted-foreground active:scale-[0.96] motion-reduce:active:scale-100"
|
|
204
204
|
aria-label={t("sidebar.expandSidebar")}
|
|
205
205
|
>
|
|
206
206
|
<IconLayoutSidebarLeftExpand className="h-4 w-4 rtl:-scale-x-100" />
|
|
@@ -219,7 +219,7 @@ export function Sidebar() {
|
|
|
219
219
|
onClick={navigateHomeChat}
|
|
220
220
|
aria-label={t("navigation.askForms")}
|
|
221
221
|
className={cn(
|
|
222
|
-
"flex
|
|
222
|
+
"forms-sidebar-nav-item flex size-10 items-center justify-center rounded-lg active:scale-[0.96] transition-[background-color,box-shadow,color,transform]",
|
|
223
223
|
location.pathname === "/ask" || location.pathname === "/"
|
|
224
224
|
? "bg-accent text-accent-foreground"
|
|
225
225
|
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
|
|
@@ -239,7 +239,7 @@ export function Sidebar() {
|
|
|
239
239
|
to="/forms"
|
|
240
240
|
aria-label={t("navigation.allForms")}
|
|
241
241
|
className={cn(
|
|
242
|
-
"flex
|
|
242
|
+
"forms-sidebar-nav-item flex size-10 items-center justify-center rounded-lg active:scale-[0.96] transition-[background-color,box-shadow,color,transform]",
|
|
243
243
|
location.pathname.startsWith("/forms")
|
|
244
244
|
? "bg-accent text-accent-foreground"
|
|
245
245
|
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
|
|
@@ -260,7 +260,7 @@ export function Sidebar() {
|
|
|
260
260
|
<button
|
|
261
261
|
type="button"
|
|
262
262
|
aria-label={t("sidebar.newForm")}
|
|
263
|
-
className="flex
|
|
263
|
+
className="forms-sidebar-nav-item flex size-10 items-center justify-center rounded-lg text-muted-foreground transition-[background-color,box-shadow,color,transform] duration-150 ease-out hover:bg-accent/50 hover:text-foreground active:scale-[0.96] motion-reduce:active:scale-100"
|
|
264
264
|
>
|
|
265
265
|
<IconPlus className="h-4 w-4" />
|
|
266
266
|
</button>
|
|
@@ -279,7 +279,7 @@ export function Sidebar() {
|
|
|
279
279
|
to="/settings"
|
|
280
280
|
aria-label={t("navigation.settings")}
|
|
281
281
|
className={cn(
|
|
282
|
-
"flex
|
|
282
|
+
"forms-sidebar-nav-item flex size-10 items-center justify-center rounded-lg active:scale-[0.96] transition-[background-color,box-shadow,color,transform]",
|
|
283
283
|
location.pathname === "/settings"
|
|
284
284
|
? "bg-accent text-accent-foreground"
|
|
285
285
|
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
|
|
@@ -310,7 +310,7 @@ export function Sidebar() {
|
|
|
310
310
|
<button
|
|
311
311
|
type="button"
|
|
312
312
|
aria-label={t("sidebar.openAskFullScreen")}
|
|
313
|
-
className="flex min-w-0 items-center gap-2 rounded-
|
|
313
|
+
className="flex min-h-10 min-w-0 items-center gap-2 rounded-lg px-2 text-base font-semibold tracking-tight text-muted-foreground/80 active:scale-[0.96] transition-[color,transform] hover:text-foreground/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
314
314
|
onClick={toggleLogoView}
|
|
315
315
|
>
|
|
316
316
|
<img
|
|
@@ -337,7 +337,7 @@ export function Sidebar() {
|
|
|
337
337
|
<Button
|
|
338
338
|
variant="ghost"
|
|
339
339
|
size="icon"
|
|
340
|
-
className="
|
|
340
|
+
className="size-10 transition-[background-color,box-shadow,transform] active:scale-[0.96] motion-reduce:active:scale-100"
|
|
341
341
|
onClick={() => setMobileOpen(false)}
|
|
342
342
|
>
|
|
343
343
|
<IconX size={18} />
|
|
@@ -349,7 +349,7 @@ export function Sidebar() {
|
|
|
349
349
|
<Button
|
|
350
350
|
variant="ghost"
|
|
351
351
|
size="icon"
|
|
352
|
-
className="
|
|
352
|
+
className="size-10 text-muted-foreground/55 transition-[background-color,box-shadow,color,transform] hover:bg-accent/50 hover:text-muted-foreground active:scale-[0.96] motion-reduce:active:scale-100"
|
|
353
353
|
onClick={() => setCollapsed(true)}
|
|
354
354
|
aria-label={t("sidebar.collapseSidebar")}
|
|
355
355
|
>
|
|
@@ -374,7 +374,7 @@ export function Sidebar() {
|
|
|
374
374
|
to="/ask"
|
|
375
375
|
onClick={navigateHomeChat}
|
|
376
376
|
className={cn(
|
|
377
|
-
"flex min-h-[44px] w-full min-w-0 max-w-full items-center gap-2.5 overflow-hidden rounded-
|
|
377
|
+
"forms-sidebar-nav-item flex min-h-[44px] w-full min-w-0 max-w-full items-center gap-2.5 overflow-hidden rounded-lg px-3 py-2 text-sm active:scale-[0.96] transition-[background-color,box-shadow,color,transform] hover:text-primary",
|
|
378
378
|
location.pathname === "/ask" || location.pathname === "/"
|
|
379
379
|
? "bg-accent text-accent-foreground"
|
|
380
380
|
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
|
|
@@ -390,7 +390,7 @@ export function Sidebar() {
|
|
|
390
390
|
to="/forms"
|
|
391
391
|
onClick={() => isMobile && setMobileOpen(false)}
|
|
392
392
|
className={cn(
|
|
393
|
-
"flex min-h-[44px] w-full min-w-0 max-w-full items-center gap-2.5 overflow-hidden rounded-
|
|
393
|
+
"forms-sidebar-nav-item flex min-h-[44px] w-full min-w-0 max-w-full items-center gap-2.5 overflow-hidden rounded-lg px-3 py-2 text-sm active:scale-[0.96] transition-[background-color,box-shadow,color,transform] hover:text-primary",
|
|
394
394
|
location.pathname.startsWith("/forms")
|
|
395
395
|
? "bg-accent text-accent-foreground"
|
|
396
396
|
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
|
|
@@ -415,7 +415,7 @@ export function Sidebar() {
|
|
|
415
415
|
to="/settings"
|
|
416
416
|
onClick={() => isMobile && setMobileOpen(false)}
|
|
417
417
|
className={cn(
|
|
418
|
-
"flex w-full items-center gap-2.5 rounded-
|
|
418
|
+
"forms-sidebar-nav-item flex min-h-[44px] w-full items-center gap-2.5 rounded-lg px-3 py-2 text-sm active:scale-[0.96] transition-[background-color,box-shadow,color,transform]",
|
|
419
419
|
location.pathname === "/settings"
|
|
420
420
|
? "bg-accent text-accent-foreground"
|
|
421
421
|
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
|
|
@@ -449,7 +449,7 @@ export function Sidebar() {
|
|
|
449
449
|
<Button
|
|
450
450
|
variant="ghost"
|
|
451
451
|
size="icon"
|
|
452
|
-
className="fixed top-2 start-2 z-40
|
|
452
|
+
className="fixed top-2 start-2 z-40 size-10 active:scale-[0.96] transition-[background-color,box-shadow,transform] md:hidden"
|
|
453
453
|
onClick={() => setMobileOpen(true)}
|
|
454
454
|
aria-label={t("sidebar.openSidebar")}
|
|
455
455
|
>
|