cowork-os 0.3.21
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/LICENSE +21 -0
- package/README.md +1638 -0
- package/bin/cowork.js +42 -0
- package/build/entitlements.mac.plist +16 -0
- package/build/icon.icns +0 -0
- package/build/icon.png +0 -0
- package/dist/electron/electron/activity/ActivityRepository.js +190 -0
- package/dist/electron/electron/agent/browser/browser-service.js +639 -0
- package/dist/electron/electron/agent/context-manager.js +225 -0
- package/dist/electron/electron/agent/custom-skill-loader.js +566 -0
- package/dist/electron/electron/agent/daemon.js +975 -0
- package/dist/electron/electron/agent/executor.js +3561 -0
- package/dist/electron/electron/agent/llm/anthropic-provider.js +155 -0
- package/dist/electron/electron/agent/llm/bedrock-provider.js +202 -0
- package/dist/electron/electron/agent/llm/gemini-provider.js +375 -0
- package/dist/electron/electron/agent/llm/index.js +34 -0
- package/dist/electron/electron/agent/llm/ollama-provider.js +263 -0
- package/dist/electron/electron/agent/llm/openai-oauth.js +101 -0
- package/dist/electron/electron/agent/llm/openai-provider.js +657 -0
- package/dist/electron/electron/agent/llm/openrouter-provider.js +232 -0
- package/dist/electron/electron/agent/llm/pricing.js +160 -0
- package/dist/electron/electron/agent/llm/provider-factory.js +880 -0
- package/dist/electron/electron/agent/llm/types.js +178 -0
- package/dist/electron/electron/agent/queue-manager.js +378 -0
- package/dist/electron/electron/agent/sandbox/docker-sandbox.js +402 -0
- package/dist/electron/electron/agent/sandbox/macos-sandbox.js +407 -0
- package/dist/electron/electron/agent/sandbox/runner.js +410 -0
- package/dist/electron/electron/agent/sandbox/sandbox-factory.js +228 -0
- package/dist/electron/electron/agent/sandbox/security-utils.js +258 -0
- package/dist/electron/electron/agent/search/brave-provider.js +119 -0
- package/dist/electron/electron/agent/search/google-provider.js +100 -0
- package/dist/electron/electron/agent/search/index.js +28 -0
- package/dist/electron/electron/agent/search/provider-factory.js +395 -0
- package/dist/electron/electron/agent/search/serpapi-provider.js +112 -0
- package/dist/electron/electron/agent/search/tavily-provider.js +90 -0
- package/dist/electron/electron/agent/search/types.js +40 -0
- package/dist/electron/electron/agent/security/index.js +12 -0
- package/dist/electron/electron/agent/security/input-sanitizer.js +303 -0
- package/dist/electron/electron/agent/security/output-filter.js +217 -0
- package/dist/electron/electron/agent/skill-eligibility.js +281 -0
- package/dist/electron/electron/agent/skill-registry.js +396 -0
- package/dist/electron/electron/agent/skills/document.js +878 -0
- package/dist/electron/electron/agent/skills/image-generator.js +225 -0
- package/dist/electron/electron/agent/skills/organizer.js +141 -0
- package/dist/electron/electron/agent/skills/presentation.js +367 -0
- package/dist/electron/electron/agent/skills/spreadsheet.js +165 -0
- package/dist/electron/electron/agent/tools/browser-tools.js +523 -0
- package/dist/electron/electron/agent/tools/builtin-settings.js +384 -0
- package/dist/electron/electron/agent/tools/canvas-tools.js +530 -0
- package/dist/electron/electron/agent/tools/cron-tools.js +577 -0
- package/dist/electron/electron/agent/tools/edit-tools.js +194 -0
- package/dist/electron/electron/agent/tools/file-tools.js +719 -0
- package/dist/electron/electron/agent/tools/glob-tools.js +283 -0
- package/dist/electron/electron/agent/tools/grep-tools.js +387 -0
- package/dist/electron/electron/agent/tools/image-tools.js +111 -0
- package/dist/electron/electron/agent/tools/mention-tools.js +282 -0
- package/dist/electron/electron/agent/tools/node-tools.js +476 -0
- package/dist/electron/electron/agent/tools/registry.js +2719 -0
- package/dist/electron/electron/agent/tools/search-tools.js +91 -0
- package/dist/electron/electron/agent/tools/shell-tools.js +574 -0
- package/dist/electron/electron/agent/tools/skill-tools.js +274 -0
- package/dist/electron/electron/agent/tools/system-tools.js +578 -0
- package/dist/electron/electron/agent/tools/web-fetch-tools.js +444 -0
- package/dist/electron/electron/agent/tools/x-tools.js +264 -0
- package/dist/electron/electron/agents/AgentRoleRepository.js +420 -0
- package/dist/electron/electron/agents/HeartbeatService.js +356 -0
- package/dist/electron/electron/agents/MentionRepository.js +197 -0
- package/dist/electron/electron/agents/TaskSubscriptionRepository.js +168 -0
- package/dist/electron/electron/agents/WorkingStateRepository.js +229 -0
- package/dist/electron/electron/canvas/canvas-manager.js +714 -0
- package/dist/electron/electron/canvas/canvas-preload.js +53 -0
- package/dist/electron/electron/canvas/canvas-protocol.js +195 -0
- package/dist/electron/electron/canvas/canvas-store.js +174 -0
- package/dist/electron/electron/canvas/index.js +13 -0
- package/dist/electron/electron/control-plane/client.js +364 -0
- package/dist/electron/electron/control-plane/handlers.js +572 -0
- package/dist/electron/electron/control-plane/index.js +41 -0
- package/dist/electron/electron/control-plane/node-manager.js +264 -0
- package/dist/electron/electron/control-plane/protocol.js +194 -0
- package/dist/electron/electron/control-plane/remote-client.js +437 -0
- package/dist/electron/electron/control-plane/server.js +640 -0
- package/dist/electron/electron/control-plane/settings.js +369 -0
- package/dist/electron/electron/control-plane/ssh-tunnel.js +549 -0
- package/dist/electron/electron/cron/index.js +30 -0
- package/dist/electron/electron/cron/schedule.js +190 -0
- package/dist/electron/electron/cron/service.js +614 -0
- package/dist/electron/electron/cron/store.js +155 -0
- package/dist/electron/electron/cron/types.js +82 -0
- package/dist/electron/electron/cron/webhook.js +258 -0
- package/dist/electron/electron/database/SecureSettingsRepository.js +444 -0
- package/dist/electron/electron/database/TaskLabelRepository.js +120 -0
- package/dist/electron/electron/database/repositories.js +1781 -0
- package/dist/electron/electron/database/schema.js +978 -0
- package/dist/electron/electron/extensions/index.js +33 -0
- package/dist/electron/electron/extensions/loader.js +313 -0
- package/dist/electron/electron/extensions/registry.js +485 -0
- package/dist/electron/electron/extensions/types.js +11 -0
- package/dist/electron/electron/gateway/channel-registry.js +1102 -0
- package/dist/electron/electron/gateway/channels/bluebubbles-client.js +479 -0
- package/dist/electron/electron/gateway/channels/bluebubbles.js +432 -0
- package/dist/electron/electron/gateway/channels/discord.js +975 -0
- package/dist/electron/electron/gateway/channels/email-client.js +593 -0
- package/dist/electron/electron/gateway/channels/email.js +443 -0
- package/dist/electron/electron/gateway/channels/google-chat.js +631 -0
- package/dist/electron/electron/gateway/channels/imessage-client.js +363 -0
- package/dist/electron/electron/gateway/channels/imessage.js +465 -0
- package/dist/electron/electron/gateway/channels/index.js +36 -0
- package/dist/electron/electron/gateway/channels/line-client.js +470 -0
- package/dist/electron/electron/gateway/channels/line.js +479 -0
- package/dist/electron/electron/gateway/channels/matrix-client.js +432 -0
- package/dist/electron/electron/gateway/channels/matrix.js +592 -0
- package/dist/electron/electron/gateway/channels/mattermost-client.js +394 -0
- package/dist/electron/electron/gateway/channels/mattermost.js +496 -0
- package/dist/electron/electron/gateway/channels/signal-client.js +500 -0
- package/dist/electron/electron/gateway/channels/signal.js +582 -0
- package/dist/electron/electron/gateway/channels/slack.js +415 -0
- package/dist/electron/electron/gateway/channels/teams.js +596 -0
- package/dist/electron/electron/gateway/channels/telegram.js +1390 -0
- package/dist/electron/electron/gateway/channels/twitch-client.js +502 -0
- package/dist/electron/electron/gateway/channels/twitch.js +396 -0
- package/dist/electron/electron/gateway/channels/types.js +8 -0
- package/dist/electron/electron/gateway/channels/whatsapp.js +953 -0
- package/dist/electron/electron/gateway/context-policy.js +268 -0
- package/dist/electron/electron/gateway/index.js +1063 -0
- package/dist/electron/electron/gateway/infrastructure.js +496 -0
- package/dist/electron/electron/gateway/router.js +2700 -0
- package/dist/electron/electron/gateway/security.js +375 -0
- package/dist/electron/electron/gateway/session.js +115 -0
- package/dist/electron/electron/gateway/tunnel.js +503 -0
- package/dist/electron/electron/guardrails/guardrail-manager.js +348 -0
- package/dist/electron/electron/hooks/gmail-watcher.js +300 -0
- package/dist/electron/electron/hooks/index.js +46 -0
- package/dist/electron/electron/hooks/mappings.js +381 -0
- package/dist/electron/electron/hooks/server.js +480 -0
- package/dist/electron/electron/hooks/settings.js +447 -0
- package/dist/electron/electron/hooks/types.js +41 -0
- package/dist/electron/electron/ipc/canvas-handlers.js +158 -0
- package/dist/electron/electron/ipc/handlers.js +3138 -0
- package/dist/electron/electron/ipc/mission-control-handlers.js +141 -0
- package/dist/electron/electron/main.js +448 -0
- package/dist/electron/electron/mcp/client/MCPClientManager.js +330 -0
- package/dist/electron/electron/mcp/client/MCPServerConnection.js +437 -0
- package/dist/electron/electron/mcp/client/transports/SSETransport.js +304 -0
- package/dist/electron/electron/mcp/client/transports/StdioTransport.js +307 -0
- package/dist/electron/electron/mcp/client/transports/WebSocketTransport.js +329 -0
- package/dist/electron/electron/mcp/host/MCPHostServer.js +354 -0
- package/dist/electron/electron/mcp/host/ToolAdapter.js +100 -0
- package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +497 -0
- package/dist/electron/electron/mcp/settings.js +446 -0
- package/dist/electron/electron/mcp/types.js +59 -0
- package/dist/electron/electron/memory/MemoryService.js +435 -0
- package/dist/electron/electron/notifications/index.js +17 -0
- package/dist/electron/electron/notifications/service.js +118 -0
- package/dist/electron/electron/notifications/store.js +144 -0
- package/dist/electron/electron/preload.js +842 -0
- package/dist/electron/electron/reports/StandupReportService.js +272 -0
- package/dist/electron/electron/security/concurrency.js +293 -0
- package/dist/electron/electron/security/index.js +15 -0
- package/dist/electron/electron/security/policy-manager.js +435 -0
- package/dist/electron/electron/settings/appearance-manager.js +193 -0
- package/dist/electron/electron/settings/personality-manager.js +724 -0
- package/dist/electron/electron/settings/x-manager.js +58 -0
- package/dist/electron/electron/tailscale/exposure.js +188 -0
- package/dist/electron/electron/tailscale/index.js +28 -0
- package/dist/electron/electron/tailscale/settings.js +205 -0
- package/dist/electron/electron/tailscale/tailscale.js +355 -0
- package/dist/electron/electron/tray/QuickInputWindow.js +568 -0
- package/dist/electron/electron/tray/TrayManager.js +895 -0
- package/dist/electron/electron/tray/index.js +9 -0
- package/dist/electron/electron/updater/index.js +6 -0
- package/dist/electron/electron/updater/update-manager.js +418 -0
- package/dist/electron/electron/utils/env-migration.js +209 -0
- package/dist/electron/electron/utils/process.js +102 -0
- package/dist/electron/electron/utils/rate-limiter.js +104 -0
- package/dist/electron/electron/utils/validation.js +419 -0
- package/dist/electron/electron/utils/x-cli.js +177 -0
- package/dist/electron/electron/voice/VoiceService.js +507 -0
- package/dist/electron/electron/voice/index.js +14 -0
- package/dist/electron/electron/voice/voice-settings-manager.js +359 -0
- package/dist/electron/shared/channelMessages.js +170 -0
- package/dist/electron/shared/types.js +1185 -0
- package/package.json +159 -0
- package/resources/skills/1password.json +10 -0
- package/resources/skills/add-documentation.json +31 -0
- package/resources/skills/analyze-csv.json +17 -0
- package/resources/skills/apple-notes.json +10 -0
- package/resources/skills/apple-reminders.json +10 -0
- package/resources/skills/auto-commenter.json +10 -0
- package/resources/skills/bear-notes.json +10 -0
- package/resources/skills/bird.json +35 -0
- package/resources/skills/blogwatcher.json +10 -0
- package/resources/skills/blucli.json +10 -0
- package/resources/skills/bluebubbles.json +10 -0
- package/resources/skills/camsnap.json +10 -0
- package/resources/skills/clean-imports.json +18 -0
- package/resources/skills/code-review.json +18 -0
- package/resources/skills/coding-agent.json +10 -0
- package/resources/skills/compare-files.json +23 -0
- package/resources/skills/convert-code.json +34 -0
- package/resources/skills/create-changelog.json +24 -0
- package/resources/skills/debug-error.json +17 -0
- package/resources/skills/dependency-check.json +10 -0
- package/resources/skills/discord.json +10 -0
- package/resources/skills/eightctl.json +10 -0
- package/resources/skills/explain-code.json +29 -0
- package/resources/skills/extract-todos.json +18 -0
- package/resources/skills/food-order.json +10 -0
- package/resources/skills/gemini.json +10 -0
- package/resources/skills/generate-readme.json +10 -0
- package/resources/skills/gifgrep.json +10 -0
- package/resources/skills/git-commit.json +10 -0
- package/resources/skills/github.json +10 -0
- package/resources/skills/gog.json +10 -0
- package/resources/skills/goplaces.json +10 -0
- package/resources/skills/himalaya.json +10 -0
- package/resources/skills/imsg.json +10 -0
- package/resources/skills/karpathy-guidelines.json +12 -0
- package/resources/skills/last30days.json +26 -0
- package/resources/skills/local-places.json +10 -0
- package/resources/skills/mcporter.json +10 -0
- package/resources/skills/model-usage.json +10 -0
- package/resources/skills/nano-banana-pro.json +10 -0
- package/resources/skills/nano-pdf.json +10 -0
- package/resources/skills/notion.json +10 -0
- package/resources/skills/obsidian.json +10 -0
- package/resources/skills/openai-image-gen.json +10 -0
- package/resources/skills/openai-whisper-api.json +10 -0
- package/resources/skills/openai-whisper.json +10 -0
- package/resources/skills/openhue.json +10 -0
- package/resources/skills/oracle.json +10 -0
- package/resources/skills/ordercli.json +10 -0
- package/resources/skills/peekaboo.json +10 -0
- package/resources/skills/project-structure.json +10 -0
- package/resources/skills/proofread.json +17 -0
- package/resources/skills/refactor-code.json +31 -0
- package/resources/skills/rename-symbol.json +23 -0
- package/resources/skills/sag.json +10 -0
- package/resources/skills/security-audit.json +18 -0
- package/resources/skills/session-logs.json +10 -0
- package/resources/skills/sherpa-onnx-tts.json +10 -0
- package/resources/skills/skill-creator.json +15 -0
- package/resources/skills/skill-hub.json +29 -0
- package/resources/skills/slack.json +10 -0
- package/resources/skills/songsee.json +10 -0
- package/resources/skills/sonoscli.json +10 -0
- package/resources/skills/spotify-player.json +10 -0
- package/resources/skills/startup-cfo.json +55 -0
- package/resources/skills/summarize-folder.json +18 -0
- package/resources/skills/summarize.json +10 -0
- package/resources/skills/things-mac.json +10 -0
- package/resources/skills/tmux.json +10 -0
- package/resources/skills/translate.json +36 -0
- package/resources/skills/trello.json +10 -0
- package/resources/skills/video-frames.json +10 -0
- package/resources/skills/voice-call.json +10 -0
- package/resources/skills/wacli.json +10 -0
- package/resources/skills/weather.json +10 -0
- package/resources/skills/write-tests.json +31 -0
- package/src/electron/activity/ActivityRepository.ts +238 -0
- package/src/electron/agent/browser/browser-service.ts +721 -0
- package/src/electron/agent/context-manager.ts +257 -0
- package/src/electron/agent/custom-skill-loader.ts +634 -0
- package/src/electron/agent/daemon.ts +1097 -0
- package/src/electron/agent/executor.ts +4017 -0
- package/src/electron/agent/llm/anthropic-provider.ts +175 -0
- package/src/electron/agent/llm/bedrock-provider.ts +236 -0
- package/src/electron/agent/llm/gemini-provider.ts +422 -0
- package/src/electron/agent/llm/index.ts +9 -0
- package/src/electron/agent/llm/ollama-provider.ts +347 -0
- package/src/electron/agent/llm/openai-oauth.ts +127 -0
- package/src/electron/agent/llm/openai-provider.ts +686 -0
- package/src/electron/agent/llm/openrouter-provider.ts +273 -0
- package/src/electron/agent/llm/pricing.ts +180 -0
- package/src/electron/agent/llm/provider-factory.ts +971 -0
- package/src/electron/agent/llm/types.ts +291 -0
- package/src/electron/agent/queue-manager.ts +408 -0
- package/src/electron/agent/sandbox/docker-sandbox.ts +453 -0
- package/src/electron/agent/sandbox/macos-sandbox.ts +426 -0
- package/src/electron/agent/sandbox/runner.ts +453 -0
- package/src/electron/agent/sandbox/sandbox-factory.ts +337 -0
- package/src/electron/agent/sandbox/security-utils.ts +251 -0
- package/src/electron/agent/search/brave-provider.ts +141 -0
- package/src/electron/agent/search/google-provider.ts +131 -0
- package/src/electron/agent/search/index.ts +6 -0
- package/src/electron/agent/search/provider-factory.ts +450 -0
- package/src/electron/agent/search/serpapi-provider.ts +138 -0
- package/src/electron/agent/search/tavily-provider.ts +108 -0
- package/src/electron/agent/search/types.ts +118 -0
- package/src/electron/agent/security/index.ts +20 -0
- package/src/electron/agent/security/input-sanitizer.ts +380 -0
- package/src/electron/agent/security/output-filter.ts +259 -0
- package/src/electron/agent/skill-eligibility.ts +334 -0
- package/src/electron/agent/skill-registry.ts +457 -0
- package/src/electron/agent/skills/document.ts +1070 -0
- package/src/electron/agent/skills/image-generator.ts +272 -0
- package/src/electron/agent/skills/organizer.ts +131 -0
- package/src/electron/agent/skills/presentation.ts +418 -0
- package/src/electron/agent/skills/spreadsheet.ts +166 -0
- package/src/electron/agent/tools/browser-tools.ts +546 -0
- package/src/electron/agent/tools/builtin-settings.ts +422 -0
- package/src/electron/agent/tools/canvas-tools.ts +572 -0
- package/src/electron/agent/tools/cron-tools.ts +723 -0
- package/src/electron/agent/tools/edit-tools.ts +196 -0
- package/src/electron/agent/tools/file-tools.ts +811 -0
- package/src/electron/agent/tools/glob-tools.ts +303 -0
- package/src/electron/agent/tools/grep-tools.ts +432 -0
- package/src/electron/agent/tools/image-tools.ts +126 -0
- package/src/electron/agent/tools/mention-tools.ts +371 -0
- package/src/electron/agent/tools/node-tools.ts +550 -0
- package/src/electron/agent/tools/registry.ts +3052 -0
- package/src/electron/agent/tools/search-tools.ts +111 -0
- package/src/electron/agent/tools/shell-tools.ts +651 -0
- package/src/electron/agent/tools/skill-tools.ts +340 -0
- package/src/electron/agent/tools/system-tools.ts +665 -0
- package/src/electron/agent/tools/web-fetch-tools.ts +528 -0
- package/src/electron/agent/tools/x-tools.ts +267 -0
- package/src/electron/agents/AgentRoleRepository.ts +557 -0
- package/src/electron/agents/HeartbeatService.ts +469 -0
- package/src/electron/agents/MentionRepository.ts +242 -0
- package/src/electron/agents/TaskSubscriptionRepository.ts +231 -0
- package/src/electron/agents/WorkingStateRepository.ts +278 -0
- package/src/electron/canvas/canvas-manager.ts +818 -0
- package/src/electron/canvas/canvas-preload.ts +102 -0
- package/src/electron/canvas/canvas-protocol.ts +174 -0
- package/src/electron/canvas/canvas-store.ts +200 -0
- package/src/electron/canvas/index.ts +8 -0
- package/src/electron/control-plane/client.ts +527 -0
- package/src/electron/control-plane/handlers.ts +723 -0
- package/src/electron/control-plane/index.ts +51 -0
- package/src/electron/control-plane/node-manager.ts +322 -0
- package/src/electron/control-plane/protocol.ts +269 -0
- package/src/electron/control-plane/remote-client.ts +517 -0
- package/src/electron/control-plane/server.ts +853 -0
- package/src/electron/control-plane/settings.ts +401 -0
- package/src/electron/control-plane/ssh-tunnel.ts +624 -0
- package/src/electron/cron/index.ts +9 -0
- package/src/electron/cron/schedule.ts +217 -0
- package/src/electron/cron/service.ts +743 -0
- package/src/electron/cron/store.ts +165 -0
- package/src/electron/cron/types.ts +291 -0
- package/src/electron/cron/webhook.ts +303 -0
- package/src/electron/database/SecureSettingsRepository.ts +514 -0
- package/src/electron/database/TaskLabelRepository.ts +148 -0
- package/src/electron/database/repositories.ts +2397 -0
- package/src/electron/database/schema.ts +1017 -0
- package/src/electron/extensions/index.ts +18 -0
- package/src/electron/extensions/loader.ts +336 -0
- package/src/electron/extensions/registry.ts +546 -0
- package/src/electron/extensions/types.ts +372 -0
- package/src/electron/gateway/channel-registry.ts +1267 -0
- package/src/electron/gateway/channels/bluebubbles-client.ts +641 -0
- package/src/electron/gateway/channels/bluebubbles.ts +509 -0
- package/src/electron/gateway/channels/discord.ts +1150 -0
- package/src/electron/gateway/channels/email-client.ts +708 -0
- package/src/electron/gateway/channels/email.ts +516 -0
- package/src/electron/gateway/channels/google-chat.ts +760 -0
- package/src/electron/gateway/channels/imessage-client.ts +473 -0
- package/src/electron/gateway/channels/imessage.ts +520 -0
- package/src/electron/gateway/channels/index.ts +21 -0
- package/src/electron/gateway/channels/line-client.ts +598 -0
- package/src/electron/gateway/channels/line.ts +559 -0
- package/src/electron/gateway/channels/matrix-client.ts +632 -0
- package/src/electron/gateway/channels/matrix.ts +655 -0
- package/src/electron/gateway/channels/mattermost-client.ts +526 -0
- package/src/electron/gateway/channels/mattermost.ts +550 -0
- package/src/electron/gateway/channels/signal-client.ts +722 -0
- package/src/electron/gateway/channels/signal.ts +666 -0
- package/src/electron/gateway/channels/slack.ts +458 -0
- package/src/electron/gateway/channels/teams.ts +681 -0
- package/src/electron/gateway/channels/telegram.ts +1727 -0
- package/src/electron/gateway/channels/twitch-client.ts +665 -0
- package/src/electron/gateway/channels/twitch.ts +468 -0
- package/src/electron/gateway/channels/types.ts +1002 -0
- package/src/electron/gateway/channels/whatsapp.ts +1101 -0
- package/src/electron/gateway/context-policy.ts +382 -0
- package/src/electron/gateway/index.ts +1274 -0
- package/src/electron/gateway/infrastructure.ts +645 -0
- package/src/electron/gateway/router.ts +3206 -0
- package/src/electron/gateway/security.ts +422 -0
- package/src/electron/gateway/session.ts +144 -0
- package/src/electron/gateway/tunnel.ts +626 -0
- package/src/electron/guardrails/guardrail-manager.ts +380 -0
- package/src/electron/hooks/gmail-watcher.ts +355 -0
- package/src/electron/hooks/index.ts +30 -0
- package/src/electron/hooks/mappings.ts +404 -0
- package/src/electron/hooks/server.ts +574 -0
- package/src/electron/hooks/settings.ts +466 -0
- package/src/electron/hooks/types.ts +245 -0
- package/src/electron/ipc/canvas-handlers.ts +223 -0
- package/src/electron/ipc/handlers.ts +3661 -0
- package/src/electron/ipc/mission-control-handlers.ts +182 -0
- package/src/electron/main.ts +496 -0
- package/src/electron/mcp/client/MCPClientManager.ts +406 -0
- package/src/electron/mcp/client/MCPServerConnection.ts +514 -0
- package/src/electron/mcp/client/transports/SSETransport.ts +360 -0
- package/src/electron/mcp/client/transports/StdioTransport.ts +355 -0
- package/src/electron/mcp/client/transports/WebSocketTransport.ts +384 -0
- package/src/electron/mcp/host/MCPHostServer.ts +388 -0
- package/src/electron/mcp/host/ToolAdapter.ts +140 -0
- package/src/electron/mcp/registry/MCPRegistryManager.ts +565 -0
- package/src/electron/mcp/settings.ts +468 -0
- package/src/electron/mcp/types.ts +371 -0
- package/src/electron/memory/MemoryService.ts +523 -0
- package/src/electron/notifications/index.ts +16 -0
- package/src/electron/notifications/service.ts +161 -0
- package/src/electron/notifications/store.ts +163 -0
- package/src/electron/preload.ts +2845 -0
- package/src/electron/reports/StandupReportService.ts +356 -0
- package/src/electron/security/concurrency.ts +333 -0
- package/src/electron/security/index.ts +17 -0
- package/src/electron/security/policy-manager.ts +539 -0
- package/src/electron/settings/appearance-manager.ts +182 -0
- package/src/electron/settings/personality-manager.ts +800 -0
- package/src/electron/settings/x-manager.ts +62 -0
- package/src/electron/tailscale/exposure.ts +262 -0
- package/src/electron/tailscale/index.ts +34 -0
- package/src/electron/tailscale/settings.ts +218 -0
- package/src/electron/tailscale/tailscale.ts +379 -0
- package/src/electron/tray/QuickInputWindow.ts +609 -0
- package/src/electron/tray/TrayManager.ts +1005 -0
- package/src/electron/tray/index.ts +6 -0
- package/src/electron/updater/index.ts +1 -0
- package/src/electron/updater/update-manager.ts +447 -0
- package/src/electron/utils/env-migration.ts +203 -0
- package/src/electron/utils/process.ts +124 -0
- package/src/electron/utils/rate-limiter.ts +130 -0
- package/src/electron/utils/validation.ts +493 -0
- package/src/electron/utils/x-cli.ts +198 -0
- package/src/electron/voice/VoiceService.ts +583 -0
- package/src/electron/voice/index.ts +9 -0
- package/src/electron/voice/voice-settings-manager.ts +403 -0
- package/src/renderer/App.tsx +775 -0
- package/src/renderer/components/ActivityFeed.tsx +407 -0
- package/src/renderer/components/ActivityFeedItem.tsx +285 -0
- package/src/renderer/components/AgentRoleCard.tsx +343 -0
- package/src/renderer/components/AgentRoleEditor.tsx +805 -0
- package/src/renderer/components/AgentSquadSettings.tsx +295 -0
- package/src/renderer/components/AgentWorkingStatePanel.tsx +411 -0
- package/src/renderer/components/AppearanceSettings.tsx +122 -0
- package/src/renderer/components/ApprovalDialog.tsx +100 -0
- package/src/renderer/components/BlueBubblesSettings.tsx +505 -0
- package/src/renderer/components/BuiltinToolsSettings.tsx +307 -0
- package/src/renderer/components/CanvasPreview.tsx +1189 -0
- package/src/renderer/components/CommandOutput.tsx +202 -0
- package/src/renderer/components/ContextPolicySettings.tsx +523 -0
- package/src/renderer/components/ControlPlaneSettings.tsx +1134 -0
- package/src/renderer/components/DisclaimerModal.tsx +124 -0
- package/src/renderer/components/DiscordSettings.tsx +436 -0
- package/src/renderer/components/EmailSettings.tsx +606 -0
- package/src/renderer/components/ExtensionsSettings.tsx +542 -0
- package/src/renderer/components/FileViewer.tsx +224 -0
- package/src/renderer/components/GoogleChatSettings.tsx +535 -0
- package/src/renderer/components/GuardrailSettings.tsx +487 -0
- package/src/renderer/components/HooksSettings.tsx +581 -0
- package/src/renderer/components/ImessageSettings.tsx +484 -0
- package/src/renderer/components/LineSettings.tsx +483 -0
- package/src/renderer/components/MCPRegistryBrowser.tsx +386 -0
- package/src/renderer/components/MCPSettings.tsx +943 -0
- package/src/renderer/components/MainContent.tsx +2433 -0
- package/src/renderer/components/MatrixSettings.tsx +510 -0
- package/src/renderer/components/MattermostSettings.tsx +473 -0
- package/src/renderer/components/MemorySettings.tsx +247 -0
- package/src/renderer/components/MentionBadge.tsx +87 -0
- package/src/renderer/components/MentionInput.tsx +409 -0
- package/src/renderer/components/MentionList.tsx +476 -0
- package/src/renderer/components/MissionControlPanel.tsx +1995 -0
- package/src/renderer/components/NodesSettings.tsx +316 -0
- package/src/renderer/components/NotificationPanel.tsx +481 -0
- package/src/renderer/components/Onboarding/AwakeningOrb.tsx +44 -0
- package/src/renderer/components/Onboarding/Onboarding.tsx +443 -0
- package/src/renderer/components/Onboarding/TypewriterText.tsx +102 -0
- package/src/renderer/components/Onboarding/index.ts +3 -0
- package/src/renderer/components/OnboardingModal.tsx +698 -0
- package/src/renderer/components/PairingCodeDisplay.tsx +324 -0
- package/src/renderer/components/PersonalitySettings.tsx +597 -0
- package/src/renderer/components/QueueSettings.tsx +119 -0
- package/src/renderer/components/QuickTaskFAB.tsx +71 -0
- package/src/renderer/components/RightPanel.tsx +413 -0
- package/src/renderer/components/ScheduledTasksSettings.tsx +1328 -0
- package/src/renderer/components/SearchSettings.tsx +328 -0
- package/src/renderer/components/Settings.tsx +1504 -0
- package/src/renderer/components/Sidebar.tsx +344 -0
- package/src/renderer/components/SignalSettings.tsx +673 -0
- package/src/renderer/components/SkillHubBrowser.tsx +458 -0
- package/src/renderer/components/SkillParameterModal.tsx +185 -0
- package/src/renderer/components/SkillsSettings.tsx +451 -0
- package/src/renderer/components/SlackSettings.tsx +442 -0
- package/src/renderer/components/StandupReportViewer.tsx +614 -0
- package/src/renderer/components/TaskBoard.tsx +498 -0
- package/src/renderer/components/TaskBoardCard.tsx +357 -0
- package/src/renderer/components/TaskBoardColumn.tsx +211 -0
- package/src/renderer/components/TaskLabelManager.tsx +472 -0
- package/src/renderer/components/TaskQueuePanel.tsx +144 -0
- package/src/renderer/components/TaskQuickActions.tsx +492 -0
- package/src/renderer/components/TaskTimeline.tsx +216 -0
- package/src/renderer/components/TaskView.tsx +162 -0
- package/src/renderer/components/TeamsSettings.tsx +518 -0
- package/src/renderer/components/TelegramSettings.tsx +421 -0
- package/src/renderer/components/Toast.tsx +76 -0
- package/src/renderer/components/TraySettings.tsx +189 -0
- package/src/renderer/components/TwitchSettings.tsx +511 -0
- package/src/renderer/components/UpdateSettings.tsx +295 -0
- package/src/renderer/components/VoiceIndicator.tsx +270 -0
- package/src/renderer/components/VoiceSettings.tsx +867 -0
- package/src/renderer/components/WhatsAppSettings.tsx +721 -0
- package/src/renderer/components/WorkingStateEditor.tsx +309 -0
- package/src/renderer/components/WorkingStateHistory.tsx +481 -0
- package/src/renderer/components/WorkspaceSelector.tsx +150 -0
- package/src/renderer/components/XSettings.tsx +311 -0
- package/src/renderer/global.d.ts +9 -0
- package/src/renderer/hooks/useAgentContext.ts +153 -0
- package/src/renderer/hooks/useOnboardingFlow.ts +548 -0
- package/src/renderer/hooks/useVoiceInput.ts +268 -0
- package/src/renderer/index.html +12 -0
- package/src/renderer/main.tsx +10 -0
- package/src/renderer/public/cowork-os-logo.png +0 -0
- package/src/renderer/quick-input.html +164 -0
- package/src/renderer/styles/index.css +14504 -0
- package/src/renderer/utils/agentMessages.ts +749 -0
- package/src/renderer/utils/voice-directives.ts +169 -0
- package/src/shared/channelMessages.ts +213 -0
- package/src/shared/types.ts +3608 -0
- package/tsconfig.electron.json +26 -0
- package/tsconfig.json +26 -0
- package/tsconfig.node.json +10 -0
- package/vite.config.ts +23 -0
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Voice Service - Text-to-Speech and Speech-to-Text
|
|
3
|
+
*
|
|
4
|
+
* Provides voice interaction capabilities using ElevenLabs for TTS
|
|
5
|
+
* and OpenAI Whisper for STT.
|
|
6
|
+
*
|
|
7
|
+
* NOTE: This service runs in the Electron main process.
|
|
8
|
+
* Audio playback must be handled by the renderer process.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { EventEmitter } from 'events';
|
|
12
|
+
import {
|
|
13
|
+
VoiceSettings,
|
|
14
|
+
VoiceState,
|
|
15
|
+
ElevenLabsVoice,
|
|
16
|
+
DEFAULT_VOICE_SETTINGS,
|
|
17
|
+
} from '../../shared/types';
|
|
18
|
+
|
|
19
|
+
// ElevenLabs API configuration
|
|
20
|
+
const ELEVENLABS_API_BASE = 'https://api.elevenlabs.io/v1';
|
|
21
|
+
const OPENAI_API_BASE = 'https://api.openai.com/v1';
|
|
22
|
+
|
|
23
|
+
// Default ElevenLabs voice (Rachel - conversational)
|
|
24
|
+
const DEFAULT_ELEVENLABS_VOICE_ID = '21m00Tcm4TlvDq8ikWAM';
|
|
25
|
+
|
|
26
|
+
export interface VoiceServiceOptions {
|
|
27
|
+
settings?: Partial<VoiceSettings>;
|
|
28
|
+
onStateChange?: (state: VoiceState) => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class VoiceService extends EventEmitter {
|
|
32
|
+
private settings: VoiceSettings;
|
|
33
|
+
private state: VoiceState;
|
|
34
|
+
|
|
35
|
+
constructor(options: VoiceServiceOptions = {}) {
|
|
36
|
+
super();
|
|
37
|
+
this.settings = { ...DEFAULT_VOICE_SETTINGS, ...options.settings };
|
|
38
|
+
this.state = {
|
|
39
|
+
isActive: false,
|
|
40
|
+
isListening: false,
|
|
41
|
+
isSpeaking: false,
|
|
42
|
+
isProcessing: false,
|
|
43
|
+
audioLevel: 0,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
if (options.onStateChange) {
|
|
47
|
+
this.on('stateChange', options.onStateChange);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Initialize the voice service
|
|
53
|
+
*/
|
|
54
|
+
async initialize(): Promise<void> {
|
|
55
|
+
console.log('[VoiceService] Initializing...');
|
|
56
|
+
this.updateState({ isActive: this.settings.enabled });
|
|
57
|
+
console.log('[VoiceService] Initialized with settings:', {
|
|
58
|
+
enabled: this.settings.enabled,
|
|
59
|
+
ttsProvider: this.settings.ttsProvider,
|
|
60
|
+
sttProvider: this.settings.sttProvider,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Update settings
|
|
66
|
+
*/
|
|
67
|
+
updateSettings(settings: Partial<VoiceSettings>): void {
|
|
68
|
+
this.settings = { ...this.settings, ...settings };
|
|
69
|
+
this.updateState({ isActive: this.settings.enabled });
|
|
70
|
+
this.emit('settingsChange', this.settings);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get current settings
|
|
75
|
+
*/
|
|
76
|
+
getSettings(): VoiceSettings {
|
|
77
|
+
return { ...this.settings };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get current state
|
|
82
|
+
*/
|
|
83
|
+
getState(): VoiceState {
|
|
84
|
+
return { ...this.state };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Check if speech-to-text transcription is available
|
|
89
|
+
* Returns true if an STT provider with valid API keys is configured
|
|
90
|
+
*/
|
|
91
|
+
isTranscriptionAvailable(): boolean {
|
|
92
|
+
const { sttProvider, openaiApiKey, azureApiKey, azureEndpoint } = this.settings;
|
|
93
|
+
|
|
94
|
+
switch (sttProvider) {
|
|
95
|
+
case 'openai':
|
|
96
|
+
return !!openaiApiKey;
|
|
97
|
+
case 'azure':
|
|
98
|
+
return !!(azureApiKey && azureEndpoint);
|
|
99
|
+
case 'elevenlabs':
|
|
100
|
+
// ElevenLabs uses OpenAI or Azure for STT
|
|
101
|
+
return !!openaiApiKey || !!(azureApiKey && azureEndpoint);
|
|
102
|
+
case 'local':
|
|
103
|
+
return false; // Not available in main process
|
|
104
|
+
default:
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Text-to-Speech: Convert text to audio data
|
|
111
|
+
* Returns audio data as Buffer for the renderer to play
|
|
112
|
+
*/
|
|
113
|
+
async speak(text: string): Promise<Buffer | null> {
|
|
114
|
+
if (!this.settings.enabled) {
|
|
115
|
+
console.log('[VoiceService] Voice mode disabled, skipping TTS');
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!text || text.trim().length === 0) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log('[VoiceService] Generating TTS:', text.substring(0, 100) + (text.length > 100 ? '...' : ''));
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
// Clear any previous error
|
|
127
|
+
this.updateState({ isSpeaking: true, isProcessing: true, error: undefined });
|
|
128
|
+
this.emit('speakingStart', text);
|
|
129
|
+
|
|
130
|
+
let audioBuffer: ArrayBuffer;
|
|
131
|
+
|
|
132
|
+
switch (this.settings.ttsProvider) {
|
|
133
|
+
case 'elevenlabs':
|
|
134
|
+
audioBuffer = await this.elevenLabsTTS(text);
|
|
135
|
+
break;
|
|
136
|
+
case 'openai':
|
|
137
|
+
audioBuffer = await this.openaiTTS(text);
|
|
138
|
+
break;
|
|
139
|
+
case 'azure':
|
|
140
|
+
audioBuffer = await this.azureTTS(text);
|
|
141
|
+
break;
|
|
142
|
+
case 'local':
|
|
143
|
+
// Local TTS requires browser APIs - not available in main process
|
|
144
|
+
throw new Error('Local TTS is not available in the main process. Please use ElevenLabs, OpenAI, or Azure.');
|
|
145
|
+
default:
|
|
146
|
+
throw new Error(`Unknown TTS provider: ${this.settings.ttsProvider}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
this.updateState({ isProcessing: false });
|
|
150
|
+
|
|
151
|
+
// Return audio data as Buffer for renderer to play
|
|
152
|
+
return Buffer.from(audioBuffer);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error('[VoiceService] TTS error:', error);
|
|
155
|
+
this.updateState({ error: (error as Error).message, isSpeaking: false, isProcessing: false });
|
|
156
|
+
this.emit('error', error);
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Mark speaking as finished (called by renderer after audio playback)
|
|
163
|
+
*/
|
|
164
|
+
finishSpeaking(): void {
|
|
165
|
+
this.updateState({ isSpeaking: false });
|
|
166
|
+
this.emit('speakingEnd');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Stop current speech
|
|
171
|
+
*/
|
|
172
|
+
stopSpeaking(): void {
|
|
173
|
+
this.updateState({ isSpeaking: false });
|
|
174
|
+
this.emit('speakingEnd');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Speech-to-Text: Transcribe audio to text
|
|
179
|
+
* Accepts audio data as Buffer from the renderer
|
|
180
|
+
* @param audioData - Audio data as Buffer
|
|
181
|
+
* @param options - Optional settings
|
|
182
|
+
* @param options.force - If true, bypass the enabled check (useful for channel audio messages)
|
|
183
|
+
*/
|
|
184
|
+
async transcribe(audioData: Buffer, options?: { force?: boolean }): Promise<string> {
|
|
185
|
+
if (!this.settings.enabled && !options?.force) {
|
|
186
|
+
throw new Error('Voice mode is disabled');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
console.log('[VoiceService] Transcribing audio...');
|
|
190
|
+
// Clear any previous error
|
|
191
|
+
this.updateState({ isProcessing: true, error: undefined });
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
let transcript: string;
|
|
195
|
+
|
|
196
|
+
switch (this.settings.sttProvider) {
|
|
197
|
+
case 'openai':
|
|
198
|
+
transcript = await this.openaiSTT(audioData);
|
|
199
|
+
break;
|
|
200
|
+
case 'azure':
|
|
201
|
+
transcript = await this.azureSTT(audioData);
|
|
202
|
+
break;
|
|
203
|
+
case 'local':
|
|
204
|
+
// Local STT requires browser APIs - not available in main process
|
|
205
|
+
throw new Error('Local STT is not available in the main process. Please use OpenAI Whisper or Azure.');
|
|
206
|
+
case 'elevenlabs':
|
|
207
|
+
// ElevenLabs doesn't have an STT API - redirect to OpenAI if key available
|
|
208
|
+
if (this.settings.openaiApiKey) {
|
|
209
|
+
transcript = await this.openaiSTT(audioData);
|
|
210
|
+
} else if (this.settings.azureEndpoint && this.settings.azureApiKey) {
|
|
211
|
+
transcript = await this.azureSTT(audioData);
|
|
212
|
+
} else {
|
|
213
|
+
throw new Error('ElevenLabs does not provide speech-to-text. Please use OpenAI Whisper, Azure, or configure an API key.');
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
default:
|
|
217
|
+
throw new Error(`Unknown STT provider: ${this.settings.sttProvider}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this.emit('transcript', transcript);
|
|
221
|
+
return transcript;
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error('[VoiceService] STT error:', error);
|
|
224
|
+
this.updateState({ error: (error as Error).message });
|
|
225
|
+
this.emit('error', error);
|
|
226
|
+
throw error;
|
|
227
|
+
} finally {
|
|
228
|
+
this.updateState({ isProcessing: false });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get available ElevenLabs voices
|
|
234
|
+
*/
|
|
235
|
+
async getElevenLabsVoices(): Promise<ElevenLabsVoice[]> {
|
|
236
|
+
const apiKey = this.settings.elevenLabsApiKey;
|
|
237
|
+
if (!apiKey) {
|
|
238
|
+
throw new Error('ElevenLabs API key not configured');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const response = await fetch(`${ELEVENLABS_API_BASE}/voices`, {
|
|
242
|
+
headers: {
|
|
243
|
+
'xi-api-key': apiKey,
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (!response.ok) {
|
|
248
|
+
const error = await response.text();
|
|
249
|
+
throw new Error(`Failed to fetch voices: ${error}`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const data = await response.json() as { voices?: ElevenLabsVoice[] };
|
|
253
|
+
return data.voices || [];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Test ElevenLabs connection
|
|
258
|
+
*/
|
|
259
|
+
async testElevenLabsConnection(): Promise<{ success: boolean; voiceCount?: number; error?: string }> {
|
|
260
|
+
try {
|
|
261
|
+
const voices = await this.getElevenLabsVoices();
|
|
262
|
+
return { success: true, voiceCount: voices.length };
|
|
263
|
+
} catch (error) {
|
|
264
|
+
return { success: false, error: (error as Error).message };
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Test OpenAI voice connection
|
|
270
|
+
*/
|
|
271
|
+
async testOpenAIConnection(): Promise<{ success: boolean; error?: string }> {
|
|
272
|
+
const apiKey = this.settings.openaiApiKey;
|
|
273
|
+
if (!apiKey) {
|
|
274
|
+
return { success: false, error: 'OpenAI API key not configured' };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
// Test with a minimal TTS request
|
|
279
|
+
const response = await fetch(`${OPENAI_API_BASE}/audio/speech`, {
|
|
280
|
+
method: 'POST',
|
|
281
|
+
headers: {
|
|
282
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
283
|
+
'Content-Type': 'application/json',
|
|
284
|
+
},
|
|
285
|
+
body: JSON.stringify({
|
|
286
|
+
model: 'tts-1',
|
|
287
|
+
input: 'Test',
|
|
288
|
+
voice: 'alloy',
|
|
289
|
+
}),
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
if (!response.ok) {
|
|
293
|
+
const error = await response.text();
|
|
294
|
+
return { success: false, error };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return { success: true };
|
|
298
|
+
} catch (error) {
|
|
299
|
+
return { success: false, error: (error as Error).message };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Test Azure OpenAI voice connection
|
|
305
|
+
*/
|
|
306
|
+
async testAzureConnection(): Promise<{ success: boolean; error?: string }> {
|
|
307
|
+
const endpoint = this.settings.azureEndpoint;
|
|
308
|
+
const apiKey = this.settings.azureApiKey;
|
|
309
|
+
const deploymentName = this.settings.azureTtsDeploymentName;
|
|
310
|
+
|
|
311
|
+
if (!endpoint) {
|
|
312
|
+
return { success: false, error: 'Azure OpenAI endpoint not configured' };
|
|
313
|
+
}
|
|
314
|
+
if (!apiKey) {
|
|
315
|
+
return { success: false, error: 'Azure OpenAI API key not configured' };
|
|
316
|
+
}
|
|
317
|
+
if (!deploymentName) {
|
|
318
|
+
return { success: false, error: 'Azure OpenAI TTS deployment name not configured' };
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
const apiVersion = this.settings.azureApiVersion || '2024-02-15-preview';
|
|
323
|
+
const url = `${endpoint}/openai/deployments/${deploymentName}/audio/speech?api-version=${apiVersion}`;
|
|
324
|
+
|
|
325
|
+
const response = await fetch(url, {
|
|
326
|
+
method: 'POST',
|
|
327
|
+
headers: {
|
|
328
|
+
'api-key': apiKey,
|
|
329
|
+
'Content-Type': 'application/json',
|
|
330
|
+
},
|
|
331
|
+
body: JSON.stringify({
|
|
332
|
+
model: deploymentName,
|
|
333
|
+
input: 'Test',
|
|
334
|
+
voice: 'alloy',
|
|
335
|
+
}),
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
if (!response.ok) {
|
|
339
|
+
const error = await response.text();
|
|
340
|
+
return { success: false, error };
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return { success: true };
|
|
344
|
+
} catch (error) {
|
|
345
|
+
return { success: false, error: (error as Error).message };
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Cleanup resources
|
|
351
|
+
*/
|
|
352
|
+
dispose(): void {
|
|
353
|
+
this.stopSpeaking();
|
|
354
|
+
this.removeAllListeners();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ============ Private Methods ============
|
|
358
|
+
|
|
359
|
+
private updateState(partial: Partial<VoiceState>): void {
|
|
360
|
+
this.state = { ...this.state, ...partial };
|
|
361
|
+
this.emit('stateChange', this.state);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* ElevenLabs Text-to-Speech
|
|
366
|
+
*/
|
|
367
|
+
private async elevenLabsTTS(text: string): Promise<ArrayBuffer> {
|
|
368
|
+
const apiKey = this.settings.elevenLabsApiKey;
|
|
369
|
+
if (!apiKey) {
|
|
370
|
+
throw new Error('ElevenLabs API key not configured');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const voiceId = this.settings.elevenLabsVoiceId || DEFAULT_ELEVENLABS_VOICE_ID;
|
|
374
|
+
|
|
375
|
+
const response = await fetch(`${ELEVENLABS_API_BASE}/text-to-speech/${voiceId}`, {
|
|
376
|
+
method: 'POST',
|
|
377
|
+
headers: {
|
|
378
|
+
'Accept': 'audio/mpeg',
|
|
379
|
+
'xi-api-key': apiKey,
|
|
380
|
+
'Content-Type': 'application/json',
|
|
381
|
+
},
|
|
382
|
+
body: JSON.stringify({
|
|
383
|
+
text,
|
|
384
|
+
model_id: 'eleven_monolingual_v1',
|
|
385
|
+
voice_settings: {
|
|
386
|
+
stability: 0.5,
|
|
387
|
+
similarity_boost: 0.75,
|
|
388
|
+
style: 0.0,
|
|
389
|
+
use_speaker_boost: true,
|
|
390
|
+
},
|
|
391
|
+
}),
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
if (!response.ok) {
|
|
395
|
+
const errorText = await response.text();
|
|
396
|
+
throw new Error(`ElevenLabs TTS failed: ${errorText}`);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return response.arrayBuffer();
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* OpenAI Text-to-Speech
|
|
404
|
+
*/
|
|
405
|
+
private async openaiTTS(text: string): Promise<ArrayBuffer> {
|
|
406
|
+
const apiKey = this.settings.openaiApiKey;
|
|
407
|
+
if (!apiKey) {
|
|
408
|
+
throw new Error('OpenAI API key not configured');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const voice = this.settings.openaiVoice || 'nova';
|
|
412
|
+
|
|
413
|
+
const response = await fetch(`${OPENAI_API_BASE}/audio/speech`, {
|
|
414
|
+
method: 'POST',
|
|
415
|
+
headers: {
|
|
416
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
417
|
+
'Content-Type': 'application/json',
|
|
418
|
+
},
|
|
419
|
+
body: JSON.stringify({
|
|
420
|
+
model: 'tts-1',
|
|
421
|
+
input: text,
|
|
422
|
+
voice,
|
|
423
|
+
speed: this.settings.speechRate,
|
|
424
|
+
}),
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
if (!response.ok) {
|
|
428
|
+
const errorText = await response.text();
|
|
429
|
+
throw new Error(`OpenAI TTS failed: ${errorText}`);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return response.arrayBuffer();
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* OpenAI Whisper Speech-to-Text
|
|
437
|
+
*/
|
|
438
|
+
private async openaiSTT(audioData: Buffer): Promise<string> {
|
|
439
|
+
const apiKey = this.settings.openaiApiKey;
|
|
440
|
+
if (!apiKey) {
|
|
441
|
+
throw new Error('OpenAI API key not configured');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Create a Blob-like object for Node.js fetch
|
|
445
|
+
// Convert Buffer to Uint8Array for BlobPart compatibility
|
|
446
|
+
const uint8Array = new Uint8Array(audioData.buffer as ArrayBuffer, audioData.byteOffset, audioData.byteLength);
|
|
447
|
+
const blob = new Blob([uint8Array], { type: 'audio/webm' });
|
|
448
|
+
|
|
449
|
+
const formData = new FormData();
|
|
450
|
+
formData.append('file', blob, 'audio.webm');
|
|
451
|
+
formData.append('model', 'whisper-1');
|
|
452
|
+
formData.append('language', this.settings.language.split('-')[0]); // e.g., 'en' from 'en-US'
|
|
453
|
+
|
|
454
|
+
const response = await fetch(`${OPENAI_API_BASE}/audio/transcriptions`, {
|
|
455
|
+
method: 'POST',
|
|
456
|
+
headers: {
|
|
457
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
458
|
+
},
|
|
459
|
+
body: formData,
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
if (!response.ok) {
|
|
463
|
+
const errorText = await response.text();
|
|
464
|
+
throw new Error(`OpenAI STT failed: ${errorText}`);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const data = await response.json() as { text: string };
|
|
468
|
+
return data.text;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Azure OpenAI Text-to-Speech
|
|
473
|
+
*/
|
|
474
|
+
private async azureTTS(text: string): Promise<ArrayBuffer> {
|
|
475
|
+
const endpoint = this.settings.azureEndpoint;
|
|
476
|
+
const apiKey = this.settings.azureApiKey;
|
|
477
|
+
const deploymentName = this.settings.azureTtsDeploymentName;
|
|
478
|
+
|
|
479
|
+
if (!endpoint) {
|
|
480
|
+
throw new Error('Azure OpenAI endpoint not configured');
|
|
481
|
+
}
|
|
482
|
+
if (!apiKey) {
|
|
483
|
+
throw new Error('Azure OpenAI API key not configured');
|
|
484
|
+
}
|
|
485
|
+
if (!deploymentName) {
|
|
486
|
+
throw new Error('Azure OpenAI TTS deployment name not configured');
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const voice = this.settings.azureVoice || 'nova';
|
|
490
|
+
const apiVersion = this.settings.azureApiVersion || '2024-02-15-preview';
|
|
491
|
+
const url = `${endpoint}/openai/deployments/${deploymentName}/audio/speech?api-version=${apiVersion}`;
|
|
492
|
+
|
|
493
|
+
const response = await fetch(url, {
|
|
494
|
+
method: 'POST',
|
|
495
|
+
headers: {
|
|
496
|
+
'api-key': apiKey,
|
|
497
|
+
'Content-Type': 'application/json',
|
|
498
|
+
},
|
|
499
|
+
body: JSON.stringify({
|
|
500
|
+
model: deploymentName,
|
|
501
|
+
input: text,
|
|
502
|
+
voice,
|
|
503
|
+
speed: this.settings.speechRate,
|
|
504
|
+
}),
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
if (!response.ok) {
|
|
508
|
+
const errorText = await response.text();
|
|
509
|
+
throw new Error(`Azure OpenAI TTS failed: ${errorText}`);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return response.arrayBuffer();
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Azure OpenAI Whisper Speech-to-Text
|
|
517
|
+
*/
|
|
518
|
+
private async azureSTT(audioData: Buffer): Promise<string> {
|
|
519
|
+
const endpoint = this.settings.azureEndpoint;
|
|
520
|
+
const apiKey = this.settings.azureApiKey;
|
|
521
|
+
const deploymentName = this.settings.azureSttDeploymentName;
|
|
522
|
+
|
|
523
|
+
if (!endpoint) {
|
|
524
|
+
throw new Error('Azure OpenAI endpoint not configured');
|
|
525
|
+
}
|
|
526
|
+
if (!apiKey) {
|
|
527
|
+
throw new Error('Azure OpenAI API key not configured');
|
|
528
|
+
}
|
|
529
|
+
if (!deploymentName) {
|
|
530
|
+
throw new Error('Azure OpenAI STT deployment name not configured');
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const apiVersion = this.settings.azureApiVersion || '2024-02-15-preview';
|
|
534
|
+
const url = `${endpoint}/openai/deployments/${deploymentName}/audio/transcriptions?api-version=${apiVersion}`;
|
|
535
|
+
|
|
536
|
+
// Create a Blob-like object for Node.js fetch
|
|
537
|
+
const uint8Array = new Uint8Array(audioData.buffer as ArrayBuffer, audioData.byteOffset, audioData.byteLength);
|
|
538
|
+
const blob = new Blob([uint8Array], { type: 'audio/webm' });
|
|
539
|
+
|
|
540
|
+
const formData = new FormData();
|
|
541
|
+
formData.append('file', blob, 'audio.webm');
|
|
542
|
+
formData.append('language', this.settings.language.split('-')[0]);
|
|
543
|
+
|
|
544
|
+
const response = await fetch(url, {
|
|
545
|
+
method: 'POST',
|
|
546
|
+
headers: {
|
|
547
|
+
'api-key': apiKey,
|
|
548
|
+
},
|
|
549
|
+
body: formData,
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
if (!response.ok) {
|
|
553
|
+
const errorText = await response.text();
|
|
554
|
+
throw new Error(`Azure OpenAI STT failed: ${errorText}`);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const data = await response.json() as { text: string };
|
|
558
|
+
return data.text;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Singleton instance
|
|
563
|
+
let voiceServiceInstance: VoiceService | null = null;
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Get or create the VoiceService singleton
|
|
567
|
+
*/
|
|
568
|
+
export function getVoiceService(options?: VoiceServiceOptions): VoiceService {
|
|
569
|
+
if (!voiceServiceInstance) {
|
|
570
|
+
voiceServiceInstance = new VoiceService(options);
|
|
571
|
+
}
|
|
572
|
+
return voiceServiceInstance;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Reset the VoiceService singleton (for testing)
|
|
577
|
+
*/
|
|
578
|
+
export function resetVoiceService(): void {
|
|
579
|
+
if (voiceServiceInstance) {
|
|
580
|
+
voiceServiceInstance.dispose();
|
|
581
|
+
voiceServiceInstance = null;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Voice Module Exports
|
|
3
|
+
*
|
|
4
|
+
* Provides voice interaction capabilities with TTS/STT support.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { VoiceService, getVoiceService, resetVoiceService } from './VoiceService';
|
|
8
|
+
export type { VoiceServiceOptions } from './VoiceService';
|
|
9
|
+
export { VoiceSettingsManager } from './voice-settings-manager';
|