@agent-native/core 0.114.13 → 0.114.15
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 +15 -0
- package/corpus/core/docs/content/deployment.mdx +1 -1
- package/corpus/core/docs/content/frames.mdx +1 -1
- package/corpus/core/docs/content/integrations.mdx +27 -27
- package/corpus/core/docs/content/pr-visual-recap.mdx +17 -13
- package/corpus/core/docs/content/workspace-management.mdx +1 -1
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/agent/engine/builder-engine.ts +4 -0
- package/corpus/core/src/client/AgentPanel.tsx +10 -4
- package/corpus/core/src/client/ConnectBuilderCard.tsx +5 -1
- package/corpus/core/src/client/chat/markdown-renderer.tsx +3 -5
- package/corpus/core/src/client/error-format.ts +2 -1
- package/corpus/core/src/client/index.ts +1 -0
- package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +2 -18
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +43 -32
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +4 -2
- package/corpus/core/src/client/settings/BackgroundAgentSection.tsx +5 -1
- package/corpus/core/src/client/settings/SettingsPanel.tsx +4 -4
- package/corpus/core/src/client/settings/useBuilderStatus.ts +3 -0
- package/corpus/core/src/localization/default-messages.ts +1 -7
- package/corpus/core/src/server/builder-browser.ts +4 -0
- package/corpus/core/src/server/builder-design-systems.ts +6 -1
- package/corpus/core/src/server/fusion-app.ts +5 -1
- package/corpus/core/src/shared/builder-link-tracking.ts +41 -0
- package/corpus/core/src/shared/index.ts +1 -0
- package/corpus/templates/analytics/AGENTS.md +10 -1
- package/corpus/templates/analytics/actions/save-dashboard-report-subscription.ts +10 -2
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +5 -4
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +20 -32
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +62 -0
- package/corpus/templates/analytics/changelog/2026-07-21-chart-series-controls-stay-open-while-moving-from-the-legend.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-21-dashboard-email-captures-complete-large-dashboards-in-chunks.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +4 -4
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +1 -8
- package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +39 -7
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +341 -251
- package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +114 -0
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +84 -6
- package/corpus/templates/analytics/server/plugins/db.ts +13 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +10 -4
- package/corpus/templates/clips/changelog/2026-07-21-choose-which-whisper-model-to-use-in-settings.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-21-fixed-organization-recording-visibility-default.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-21-meeting-notes-stop-when-calls-end.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +66 -75
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +2 -0
- package/corpus/templates/clips/desktop/src/hooks/useWhisperSettings.ts +172 -0
- package/corpus/templates/clips/desktop/src/lib/meeting-call-app.ts +41 -0
- package/corpus/templates/clips/desktop/src/lib/silence-events.ts +1 -0
- package/corpus/templates/clips/desktop/src/shared/config.ts +1 -0
- package/corpus/templates/clips/desktop/src/styles.css +80 -7
- package/corpus/templates/clips/desktop/src-tauri/src/config.rs +32 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +3 -0
- package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +268 -20
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_model.rs +285 -164
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +18 -7
- package/corpus/templates/clips/learnings.defaults.md +1 -1
- package/corpus/templates/clips/server/plugins/db.ts +11 -0
- package/corpus/templates/clips/shared/builder-credits.ts +1 -1
- package/corpus/templates/design/app/components/design/FusionAppBanner.tsx +9 -1
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +5 -1
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +9 -1
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +9 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +4 -0
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +10 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
- package/dist/client/ConnectBuilderCard.js +5 -1
- package/dist/client/ConnectBuilderCard.js.map +1 -1
- package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
- package/dist/client/chat/markdown-renderer.js +3 -2
- package/dist/client/chat/markdown-renderer.js.map +1 -1
- package/dist/client/error-format.d.ts +1 -1
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +1 -1
- package/dist/client/error-format.js.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +3 -4
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +21 -7
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +2 -2
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/settings/BackgroundAgentSection.d.ts.map +1 -1
- package/dist/client/settings/BackgroundAgentSection.js +5 -1
- package/dist/client/settings/BackgroundAgentSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.js +1 -1
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +2 -0
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +0 -6
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +1 -7
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +4 -0
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +6 -1
- package/dist/server/builder-design-systems.js.map +1 -1
- package/dist/server/fusion-app.d.ts.map +1 -1
- package/dist/server/fusion-app.js +2 -1
- package/dist/server/fusion-app.js.map +1 -1
- package/dist/shared/builder-link-tracking.d.ts +14 -0
- package/dist/shared/builder-link-tracking.d.ts.map +1 -0
- package/dist/shared/builder-link-tracking.js +26 -0
- package/dist/shared/builder-link-tracking.js.map +1 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +1 -0
- package/dist/shared/index.js.map +1 -1
- package/docs/content/deployment.mdx +1 -1
- package/docs/content/frames.mdx +1 -1
- package/docs/content/integrations.mdx +27 -27
- package/docs/content/pr-visual-recap.mdx +17 -13
- package/docs/content/workspace-management.mdx +1 -1
- package/package.json +3 -2
- package/src/agent/engine/builder-engine.ts +4 -0
- package/src/client/AgentPanel.tsx +10 -4
- package/src/client/ConnectBuilderCard.tsx +5 -1
- package/src/client/chat/markdown-renderer.tsx +3 -5
- package/src/client/error-format.ts +2 -1
- package/src/client/index.ts +1 -0
- package/src/client/integrations/IntegrationsPanel.tsx +2 -18
- package/src/client/resources/McpIntegrationDialog.tsx +43 -32
- package/src/client/resources/mcp-integration-catalog.ts +4 -2
- package/src/client/settings/BackgroundAgentSection.tsx +5 -1
- package/src/client/settings/SettingsPanel.tsx +4 -4
- package/src/client/settings/useBuilderStatus.ts +3 -0
- package/src/localization/default-messages.ts +1 -7
- package/src/server/builder-browser.ts +4 -0
- package/src/server/builder-design-systems.ts +6 -1
- package/src/server/fusion-app.ts +5 -1
- package/src/shared/builder-link-tracking.ts +41 -0
- package/src/shared/index.ts +1 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { invoke } from "@tauri-apps/api/core";
|
|
2
|
+
import { listen } from "@tauri-apps/api/event";
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
|
+
|
|
5
|
+
import type { VoiceProvider } from "../lib/voice-dictation";
|
|
6
|
+
import type { FeatureConfig } from "../shared/config";
|
|
7
|
+
|
|
8
|
+
export interface WhisperModelOption {
|
|
9
|
+
id: string;
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
url: string;
|
|
13
|
+
filename: string;
|
|
14
|
+
sha256: string;
|
|
15
|
+
sizeBytes: number;
|
|
16
|
+
sizeMb: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type WhisperModelState =
|
|
20
|
+
| "disabled"
|
|
21
|
+
| "missing"
|
|
22
|
+
| "downloading"
|
|
23
|
+
| "ready";
|
|
24
|
+
|
|
25
|
+
export interface WhisperModelStatus {
|
|
26
|
+
state: WhisperModelState;
|
|
27
|
+
path: string;
|
|
28
|
+
downloadedMb: number;
|
|
29
|
+
totalMb: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const WHISPER_STATUS_EVENTS = [
|
|
33
|
+
"whisper:model-progress",
|
|
34
|
+
"whisper:model-error",
|
|
35
|
+
"whisper:model-enabled-changed",
|
|
36
|
+
"whisper:model-selection-changed",
|
|
37
|
+
] as const;
|
|
38
|
+
|
|
39
|
+
export function useWhisperSettings(
|
|
40
|
+
featureConfig: FeatureConfig | null,
|
|
41
|
+
voiceProvider: VoiceProvider,
|
|
42
|
+
onVoiceProviderChange: (provider: VoiceProvider) => void,
|
|
43
|
+
nativeVoiceProvider: () => VoiceProvider,
|
|
44
|
+
) {
|
|
45
|
+
const [catalog, setCatalog] = useState<WhisperModelOption[]>([]);
|
|
46
|
+
const [downloadedModelIds, setDownloadedModelIds] = useState<string[]>([]);
|
|
47
|
+
const [status, setStatus] = useState<WhisperModelStatus | null>(null);
|
|
48
|
+
|
|
49
|
+
const enabled = featureConfig?.whisperModelEnabled !== false;
|
|
50
|
+
const modelId = featureConfig?.whisperModelId ?? "base";
|
|
51
|
+
const selectedModel = catalog.find((m) => m.id === modelId) ?? null;
|
|
52
|
+
const deletableModels = catalog.filter(
|
|
53
|
+
(m) => m.id !== modelId && downloadedModelIds.includes(m.id),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
invoke<WhisperModelOption[]>("whisper_models")
|
|
58
|
+
.then(setCatalog)
|
|
59
|
+
.catch(() => {});
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
const refreshDownloaded = useCallback(() => {
|
|
63
|
+
invoke<string[]>("whisper_downloaded_models")
|
|
64
|
+
.then(setDownloadedModelIds)
|
|
65
|
+
.catch(() => {});
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
let cancelled = false;
|
|
70
|
+
const refreshStatus = () => {
|
|
71
|
+
invoke<WhisperModelStatus>("whisper_model_status")
|
|
72
|
+
.then((s) => {
|
|
73
|
+
if (!cancelled) setStatus(s);
|
|
74
|
+
})
|
|
75
|
+
.catch(() => {});
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
refreshStatus();
|
|
79
|
+
refreshDownloaded();
|
|
80
|
+
|
|
81
|
+
const unlistens: Array<() => void> = [];
|
|
82
|
+
const track = (p: Promise<() => void>) => {
|
|
83
|
+
p.then((u) => {
|
|
84
|
+
if (cancelled) {
|
|
85
|
+
try {
|
|
86
|
+
u();
|
|
87
|
+
} catch {
|
|
88
|
+
/* ignore */
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
unlistens.push(u);
|
|
93
|
+
}).catch(() => {});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
for (const event of WHISPER_STATUS_EVENTS) {
|
|
97
|
+
track(listen(event, () => refreshStatus()));
|
|
98
|
+
}
|
|
99
|
+
track(
|
|
100
|
+
listen("whisper:model-ready", () => {
|
|
101
|
+
refreshStatus();
|
|
102
|
+
refreshDownloaded();
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
track(listen("whisper:model-deleted", () => refreshDownloaded()));
|
|
106
|
+
|
|
107
|
+
return () => {
|
|
108
|
+
cancelled = true;
|
|
109
|
+
unlistens.forEach((u) => {
|
|
110
|
+
try {
|
|
111
|
+
u();
|
|
112
|
+
} catch {
|
|
113
|
+
/* ignore */
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
}, [refreshDownloaded]);
|
|
118
|
+
|
|
119
|
+
function triggerDownload() {
|
|
120
|
+
invoke("whisper_model_download").catch(() => {});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function setEnabled(next: boolean) {
|
|
124
|
+
if (!featureConfig) return;
|
|
125
|
+
invoke("set_feature_config", {
|
|
126
|
+
config: { ...featureConfig, whisperModelEnabled: next },
|
|
127
|
+
})
|
|
128
|
+
.then(() => {
|
|
129
|
+
if (next) {
|
|
130
|
+
triggerDownload();
|
|
131
|
+
} else if (voiceProvider === "whisper") {
|
|
132
|
+
onVoiceProviderChange(nativeVoiceProvider());
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
.catch((err) =>
|
|
136
|
+
console.error("[whisper] set_feature_config failed", err),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function setModelId(next: string) {
|
|
141
|
+
if (!featureConfig) return;
|
|
142
|
+
invoke("set_feature_config", {
|
|
143
|
+
config: { ...featureConfig, whisperModelId: next },
|
|
144
|
+
})
|
|
145
|
+
.then(() => {
|
|
146
|
+
if (enabled) triggerDownload();
|
|
147
|
+
})
|
|
148
|
+
.catch((err) =>
|
|
149
|
+
console.error("[whisper] set_feature_config failed", err),
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function deleteModel(modelIdToDelete: string) {
|
|
154
|
+
invoke("whisper_model_delete", { modelId: modelIdToDelete })
|
|
155
|
+
.then(() => refreshDownloaded())
|
|
156
|
+
.catch(() => {});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
catalog,
|
|
161
|
+
downloadedModelIds,
|
|
162
|
+
status,
|
|
163
|
+
enabled,
|
|
164
|
+
modelId,
|
|
165
|
+
selectedModel,
|
|
166
|
+
deletableModels,
|
|
167
|
+
triggerDownload,
|
|
168
|
+
setEnabled,
|
|
169
|
+
setModelId,
|
|
170
|
+
deleteModel,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const NATIVE_CALL_APP_BUNDLE_IDS = [
|
|
2
|
+
"us.zoom.xos",
|
|
3
|
+
"us.zoom.ZoomClips",
|
|
4
|
+
"com.microsoft.teams2",
|
|
5
|
+
"com.microsoft.teams",
|
|
6
|
+
] as const;
|
|
7
|
+
|
|
8
|
+
const BROWSER_CALL_APP_BUNDLE_IDS = [
|
|
9
|
+
"com.google.Chrome",
|
|
10
|
+
"company.thebrowser.Browser",
|
|
11
|
+
"com.apple.Safari",
|
|
12
|
+
"org.mozilla.firefox",
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
function isHost(hostname: string, host: string): boolean {
|
|
16
|
+
return hostname === host || hostname.endsWith(`.${host}`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Limit microphone-use monitoring to the app that can own this meeting.
|
|
21
|
+
* Browser bundles are included only when the calendar join URL identifies a
|
|
22
|
+
* browser-hosted provider, so another tab using the microphone cannot end a
|
|
23
|
+
* native Zoom or Teams recording.
|
|
24
|
+
*/
|
|
25
|
+
export function callAppBundleIdsForJoinUrl(joinUrl?: string | null): string[] {
|
|
26
|
+
if (!joinUrl) return [...NATIVE_CALL_APP_BUNDLE_IDS];
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const hostname = new URL(joinUrl).hostname.toLowerCase();
|
|
30
|
+
if (isHost(hostname, "meet.google.com")) {
|
|
31
|
+
return [...BROWSER_CALL_APP_BUNDLE_IDS];
|
|
32
|
+
}
|
|
33
|
+
if (isHost(hostname, "teams.microsoft.com")) {
|
|
34
|
+
return [...NATIVE_CALL_APP_BUNDLE_IDS, ...BROWSER_CALL_APP_BUNDLE_IDS];
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
// Native Zoom and Teams remain the safe fallback for malformed URLs.
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return [...NATIVE_CALL_APP_BUNDLE_IDS];
|
|
41
|
+
}
|
|
@@ -5600,23 +5600,39 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5600
5600
|
}
|
|
5601
5601
|
|
|
5602
5602
|
.whisper-progress-bar {
|
|
5603
|
-
height: 4px;
|
|
5604
5603
|
width: 100%;
|
|
5604
|
+
height: 4px;
|
|
5605
|
+
margin-top: 4px;
|
|
5606
|
+
border: none;
|
|
5605
5607
|
border-radius: 999px;
|
|
5606
|
-
|
|
5608
|
+
appearance: none;
|
|
5607
5609
|
overflow: hidden;
|
|
5608
|
-
|
|
5610
|
+
background: var(--surface-strong);
|
|
5611
|
+
color: #16a34a;
|
|
5609
5612
|
}
|
|
5610
5613
|
|
|
5611
|
-
.whisper-progress-
|
|
5612
|
-
|
|
5614
|
+
.whisper-progress-bar::-webkit-progress-bar {
|
|
5615
|
+
border-radius: inherit;
|
|
5616
|
+
background: var(--surface-strong);
|
|
5617
|
+
}
|
|
5618
|
+
|
|
5619
|
+
.whisper-progress-bar::-webkit-progress-value {
|
|
5620
|
+
border-radius: inherit;
|
|
5621
|
+
background: #16a34a;
|
|
5622
|
+
}
|
|
5623
|
+
|
|
5624
|
+
.whisper-progress-bar::-moz-progress-bar {
|
|
5613
5625
|
border-radius: inherit;
|
|
5614
5626
|
background: #16a34a;
|
|
5615
|
-
transition: width 300ms ease;
|
|
5616
5627
|
}
|
|
5617
5628
|
|
|
5618
5629
|
@media (prefers-color-scheme: dark) {
|
|
5619
|
-
.whisper-progress-
|
|
5630
|
+
.whisper-progress-bar {
|
|
5631
|
+
color: #4ade80;
|
|
5632
|
+
}
|
|
5633
|
+
|
|
5634
|
+
.whisper-progress-bar::-webkit-progress-value,
|
|
5635
|
+
.whisper-progress-bar::-moz-progress-bar {
|
|
5620
5636
|
background: #4ade80;
|
|
5621
5637
|
}
|
|
5622
5638
|
}
|
|
@@ -5644,6 +5660,63 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5644
5660
|
background: var(--surface-hover);
|
|
5645
5661
|
}
|
|
5646
5662
|
|
|
5663
|
+
.whisper-other-models {
|
|
5664
|
+
display: flex;
|
|
5665
|
+
flex-direction: column;
|
|
5666
|
+
gap: 4px;
|
|
5667
|
+
margin-top: 6px;
|
|
5668
|
+
}
|
|
5669
|
+
|
|
5670
|
+
.whisper-other-model-row {
|
|
5671
|
+
display: flex;
|
|
5672
|
+
align-items: center;
|
|
5673
|
+
justify-content: space-between;
|
|
5674
|
+
gap: 8px;
|
|
5675
|
+
padding: 5px 8px;
|
|
5676
|
+
border: 1px solid var(--border);
|
|
5677
|
+
border-radius: var(--radius-sm);
|
|
5678
|
+
background: var(--surface);
|
|
5679
|
+
}
|
|
5680
|
+
|
|
5681
|
+
.whisper-other-model-name {
|
|
5682
|
+
font-size: 11px;
|
|
5683
|
+
color: var(--fg-muted);
|
|
5684
|
+
}
|
|
5685
|
+
|
|
5686
|
+
.whisper-delete-btn {
|
|
5687
|
+
display: inline-flex;
|
|
5688
|
+
align-items: center;
|
|
5689
|
+
gap: 4px;
|
|
5690
|
+
flex-shrink: 0;
|
|
5691
|
+
height: 22px;
|
|
5692
|
+
padding: 0 8px;
|
|
5693
|
+
border: 1px solid var(--border-strong);
|
|
5694
|
+
border-radius: var(--radius-sm);
|
|
5695
|
+
background: var(--surface);
|
|
5696
|
+
color: var(--fg-muted);
|
|
5697
|
+
cursor: pointer;
|
|
5698
|
+
font-size: 11px;
|
|
5699
|
+
font-weight: 600;
|
|
5700
|
+
transition:
|
|
5701
|
+
background 120ms,
|
|
5702
|
+
color 120ms,
|
|
5703
|
+
border-color 120ms;
|
|
5704
|
+
}
|
|
5705
|
+
|
|
5706
|
+
.whisper-delete-btn:hover {
|
|
5707
|
+
background: rgba(239, 68, 68, 0.1);
|
|
5708
|
+
border-color: rgba(239, 68, 68, 0.4);
|
|
5709
|
+
color: #ef4444;
|
|
5710
|
+
}
|
|
5711
|
+
|
|
5712
|
+
@media (prefers-color-scheme: dark) {
|
|
5713
|
+
.whisper-delete-btn:hover {
|
|
5714
|
+
background: rgba(239, 68, 68, 0.15);
|
|
5715
|
+
border-color: rgba(239, 68, 68, 0.5);
|
|
5716
|
+
color: #f87171;
|
|
5717
|
+
}
|
|
5718
|
+
}
|
|
5719
|
+
|
|
5647
5720
|
/* ---- */
|
|
5648
5721
|
|
|
5649
5722
|
.pill-error {
|
|
@@ -135,6 +135,8 @@ pub struct FeatureConfig {
|
|
|
135
135
|
pub onboarding_complete: bool,
|
|
136
136
|
#[serde(default = "default_whisper_model_enabled")]
|
|
137
137
|
pub whisper_model_enabled: bool,
|
|
138
|
+
#[serde(default = "default_whisper_model_id")]
|
|
139
|
+
pub whisper_model_id: String,
|
|
138
140
|
}
|
|
139
141
|
|
|
140
142
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
@@ -170,6 +172,10 @@ fn default_whisper_model_enabled() -> bool {
|
|
|
170
172
|
true
|
|
171
173
|
}
|
|
172
174
|
|
|
175
|
+
fn default_whisper_model_id() -> String {
|
|
176
|
+
"base".to_string()
|
|
177
|
+
}
|
|
178
|
+
|
|
173
179
|
fn default_screen_memory_retention_hours() -> u32 {
|
|
174
180
|
8
|
|
175
181
|
}
|
|
@@ -227,6 +233,7 @@ impl Default for FeatureConfig {
|
|
|
227
233
|
screen_memory: ScreenMemoryConfig::default(),
|
|
228
234
|
onboarding_complete: false,
|
|
229
235
|
whisper_model_enabled: default_whisper_model_enabled(),
|
|
236
|
+
whisper_model_id: default_whisper_model_id(),
|
|
230
237
|
}
|
|
231
238
|
}
|
|
232
239
|
}
|
|
@@ -333,6 +340,12 @@ pub async fn get_feature_config(app: AppHandle) -> Result<FeatureConfig, String>
|
|
|
333
340
|
/// Save feature config to disk and emit a change event.
|
|
334
341
|
#[tauri::command]
|
|
335
342
|
pub async fn set_feature_config(app: AppHandle, config: FeatureConfig) -> Result<(), String> {
|
|
343
|
+
if !crate::whisper_model::is_supported_model_id(&config.whisper_model_id) {
|
|
344
|
+
return Err(format!(
|
|
345
|
+
"unsupported Whisper model: {}",
|
|
346
|
+
config.whisper_model_id
|
|
347
|
+
));
|
|
348
|
+
}
|
|
336
349
|
let previous = load_config(&app);
|
|
337
350
|
if (crate::rewind_clip::is_active(&app) || crate::util::is_recording_active(&app))
|
|
338
351
|
&& rewind_capture_contract_changed(&previous.screen_memory, &config.screen_memory)
|
|
@@ -366,6 +379,12 @@ pub async fn set_feature_config(app: AppHandle, config: FeatureConfig) -> Result
|
|
|
366
379
|
serde_json::json!({ "enabled": config.whisper_model_enabled }),
|
|
367
380
|
);
|
|
368
381
|
}
|
|
382
|
+
if previous.whisper_model_id != config.whisper_model_id {
|
|
383
|
+
let _ = app.emit(
|
|
384
|
+
"whisper:model-selection-changed",
|
|
385
|
+
serde_json::json!({ "modelId": config.whisper_model_id }),
|
|
386
|
+
);
|
|
387
|
+
}
|
|
369
388
|
crate::screen_memory::sync_from_config(&app, &config);
|
|
370
389
|
let _ = app.emit("app:feature-config-changed", config);
|
|
371
390
|
Ok(())
|
|
@@ -406,6 +425,19 @@ mod tests {
|
|
|
406
425
|
.contains(&"com.1password.1password".to_string()));
|
|
407
426
|
}
|
|
408
427
|
|
|
428
|
+
#[test]
|
|
429
|
+
fn feature_config_defaults_to_base_whisper_model_for_legacy_json() {
|
|
430
|
+
let config: FeatureConfig = serde_json::from_value(serde_json::json!({
|
|
431
|
+
"clipsEnabled": true,
|
|
432
|
+
"meetingsEnabled": true,
|
|
433
|
+
"voiceEnabled": true,
|
|
434
|
+
"onboardingComplete": true
|
|
435
|
+
}))
|
|
436
|
+
.unwrap();
|
|
437
|
+
|
|
438
|
+
assert_eq!(config.whisper_model_id, "base");
|
|
439
|
+
}
|
|
440
|
+
|
|
409
441
|
#[test]
|
|
410
442
|
fn rewind_enums_use_stable_kebab_case_values() {
|
|
411
443
|
assert_eq!(
|
|
@@ -231,8 +231,11 @@ pub fn run() {
|
|
|
231
231
|
shortcuts::set_fn_shortcut_enabled,
|
|
232
232
|
shortcuts::set_dictation_escape_active,
|
|
233
233
|
// whisper model management
|
|
234
|
+
whisper_model::whisper_models,
|
|
234
235
|
whisper_model::whisper_model_status,
|
|
235
236
|
whisper_model::whisper_model_download,
|
|
237
|
+
whisper_model::whisper_downloaded_models,
|
|
238
|
+
whisper_model::whisper_model_delete,
|
|
236
239
|
// permission status (silent checks for all TCC permissions)
|
|
237
240
|
permission_status::check_permission_statuses,
|
|
238
241
|
// persistent log file (production debugging)
|