@xopcai/xopc 0.0.277 → 0.0.282
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/dist/browser-ext/_locales/en/messages.json +34 -4
- package/dist/browser-ext/_locales/zh_CN/messages.json +34 -4
- package/dist/browser-ext/dist/assets/{auth-ClQTK565.js → auth-DB30ywek.js} +18 -53
- package/dist/browser-ext/dist/assets/pcm-capture-worklet-CGN9Mlhg.js +39 -0
- package/dist/browser-ext/dist/assets/{sidepanel-CeGqObOa.css → sidepanel-BbSQr-6P.css} +40 -6
- package/dist/browser-ext/dist/background.js +1 -1
- package/dist/browser-ext/dist/sidepanel.html +2 -2
- package/dist/browser-ext/dist/sidepanel.js +1219 -191
- package/dist/browser-ext/manifest.json +2 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-SJZ5fS17.js → activity-store-iPtG94qr.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Cavbls0E.js → agent-avatar-dicebear-Cny5rATT.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-OyQ8OVZv.js +1 -0
- package/dist/gateway/static/root/assets/{agents-DlDTItrB.js → agents-DJeh_Ewo.js} +1 -1
- package/dist/gateway/static/root/assets/{api-CnJAVHBu.js → api-KMJzMqvZ.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-5gS0_LWl.js → app-management-settings-panel-ZqQKaZEI.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DHzZCJon.js → appearance-settings-CfXsQkKO.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-k-QnVhKW.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-Ia98yZe3.js → archive-plugin-BrW53Hap.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DiWW88c8.js → attachment-load-DkfFWHiS.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-BuhTeGRJ.js → automations-page-e-5we6kD.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-DPnlkws1.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DDD48cJv.js → binary-plugins-CWIswfXA.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-0AWVCD3F.js → block-editor-CfeF1OmA.js} +3 -3
- package/dist/gateway/static/root/assets/{browser-automation-inputs-DcVLoIzc.js → browser-automation-inputs-BTIufVbM.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-BKOYX5xV.js → browser-automations-page-DnsuWKRu.js} +2 -2
- package/dist/gateway/static/root/assets/browser-settings-page-C8xyhnxx.js +8 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-CBllOLTT.js +8 -0
- package/dist/gateway/static/root/assets/channels-settings-C-A-VUE2.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-BTT2sIGg.js → channels-status-swr-DMYQNs-J.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-CW9Byi8V.js → chat-terminal-dock-C_Fw1R3A.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-CtsMo3H4.js +2 -0
- package/dist/gateway/static/root/assets/{date-picker-gdYmKC8W.js → date-picker-CPFxjTrN.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-40BYmiMc.js → dependency-picker-C_5KqzjI.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-By1z6tKE.js → desktop-pet-DLJsC5D6.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-ByjJqx9H.js → desktop-pet-settings-BdI1iSgz.js} +1 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-BnvPLhc9.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-DQO65KbM.js → extension-debug-page-BNS_TkZQ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Db32jip6.js → extension-page-DMSDZ7Mb.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CL8Wx8lf.js → extension-settings-page-CeGCWMt0.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-config-swr-Cpmyrr6j.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-DKOTYUma.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-CVTa5HSS.js → gateway-startup-retry-DoiPeb65.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-CRXWu2q6.js → heartbeat-settings-gsdL_Yij.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-CbeAdS1T.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-DtMRG1oF.js → image-generation-api-CqjHWl2T.js} +1 -1
- package/dist/gateway/static/root/assets/index-B_Sg5BKz.css +2 -0
- package/dist/gateway/static/root/assets/index-enFXJJCU.js +74 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CjehhHPz.js → keyboard-shortcuts-settings-CCLtJ8s8.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-DzC6SrXj.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-CrIdaTrK.js → local-apps-page-3LdgP3NO.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-BkJ7g35d.js → locale-store-1urrBBCQ.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-FfSwV_VH.js → logs-page-DHClKtm6.js} +2 -2
- package/dist/gateway/static/root/assets/{management-settings-BakV5aOw.js → management-settings-BaCo9Nuo.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-DF3aJP_5.js → markdown-view-BZmcFIWa.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Blv9U6Jp.js → media-plugins-BMjJppvG.js} +1 -1
- package/dist/gateway/static/root/assets/messages-DYFcjtmG.js +3 -0
- package/dist/gateway/static/root/assets/note-detail-panel-hYO2jNhL.js +5 -0
- package/dist/gateway/static/root/assets/notes-page-BT66x22W.js +8 -0
- package/dist/gateway/static/root/assets/{page-tabs-BQfVtLLC.js → page-tabs-BCszXX_F.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-kjHFiO81.js → preview-open-alternatives-CyM0sanh.js} +1 -1
- package/dist/gateway/static/root/assets/proactive-page-CVDGA5sB.js +1 -0
- package/dist/gateway/static/root/assets/{product-open-page-BazdmFYo.js → product-open-page-lXAbj85Z.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-Bp6TAMPM.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-UhOIiDcg.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-CTq8EECj.js → registry-api-CxQstD00.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DJIkMFT4.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BhJlopSW.js → runtime-tools-settings-panel-BUFCgRdZ.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-cxoO_5I1.js → schema-form-B01ksA8M.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CQOAwPDt.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-CFuqbGI-.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-BiRTWiBi.js → settings-form-section-DvnjZBa3.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-D-Cb71pq.js → settings-page-DZRkpbCh.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DVaEiAVY.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-DciHfTay.js → share-preview-page-vz0UK56q.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-XiCqMDAe.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-C3D8WanU.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-CxMWwR6A.js +2 -0
- package/dist/gateway/static/root/assets/{skills-page.utils-CU7PALQB.js → skills-page.utils-BryVNYll.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-GpjNbqvM.js → system-settings-panel-mKFDe6aZ.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-Cb0RZNcJ.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-mV6Cm2vj.js → theme-store-Dc5s20V3.js} +1 -1
- package/dist/gateway/static/root/assets/tunnel-api-FcI3wKy3.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-LvCiBidm.js → use-autosave-CDgdtjTC.js} +1 -1
- package/dist/gateway/static/root/assets/user-model-page-Cnshc-Un.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-BlGysZxj.js → voice-api-key-field-Ce8cb5mN.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-D3DdcH4H.js → voice-config-api-Mk78BrpP.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-DvIQOR5x.js → work-discovery-overlay-CacFTtXe.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-JIp60bXT.js → workflow-run-setup-panel-V-5HuEUq.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-1OJimIfo.js +6 -0
- package/dist/gateway/static/root/index.html +10 -11
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/discussions.js +17 -0
- package/dist/packages/gateway-contract/src/proactive.js +4 -2
- package/dist/src/agent/agent-manager.js +4 -4
- package/dist/src/agent/background-review/run-background-review.js +1 -1
- package/dist/src/agent/commands/command-isolation.d.ts +1 -0
- package/dist/src/agent/commands/command-isolation.js +17 -1
- package/dist/src/agent/commands/commandMounts.d.ts +2 -0
- package/dist/src/agent/commands/commandMounts.js +32 -0
- package/dist/src/agent/context/project-context.d.ts +1 -0
- package/dist/src/agent/context/project-context.js +12 -4
- package/dist/src/agent/embedded/model-runtime.js +1 -1
- package/dist/src/agent/embedded/run-for-session.js +1 -1
- package/dist/src/agent/image/tool-model-config.js +1 -1
- package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
- package/dist/src/agent/sandbox/command-validator.js +0 -20
- package/dist/src/agent/sandbox/exec-policy.d.ts +1 -0
- package/dist/src/agent/sandbox/exec-policy.js +4 -4
- package/dist/src/agent/sandbox/fileAccess.d.ts +7 -0
- package/dist/src/agent/sandbox/fileAccess.js +100 -0
- package/dist/src/agent/sandbox/path-policy.d.ts +2 -0
- package/dist/src/agent/sandbox/path-policy.js +54 -17
- package/dist/src/agent/sandbox/sanitize-env-vars.js +10 -9
- package/dist/src/agent/service.js +2 -2
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/source-context/task-context.d.ts +3 -0
- package/dist/src/agent/source-context/task-context.js +24 -0
- package/dist/src/agent/source-context/types.d.ts +2 -2
- package/dist/src/agent/source-context/types.js +1 -1
- package/dist/src/agent/tasks/task-judge-service.js +3 -3
- package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -1
- package/dist/src/agent/tool-manuals/xopc-use.js +1 -0
- package/dist/src/agent/tools/apply-patch.js +25 -38
- package/dist/src/agent/tools/create-share-tool.js +11 -3
- package/dist/src/agent/tools/exec-command.js +2 -1
- package/dist/src/agent/tools/find.js +5 -3
- package/dist/src/agent/tools/grep.js +21 -4
- package/dist/src/agent/tools/image-generate-tool.js +3 -4
- package/dist/src/agent/tools/list-dir.js +2 -1
- package/dist/src/agent/tools/managed-job-tool.js +1 -0
- package/dist/src/agent/tools/publish-artifacts.js +4 -3
- package/dist/src/agent/tools/read.js +8 -5
- package/dist/src/agent/tools/repository-search.d.ts +2 -0
- package/dist/src/agent/tools/repository-search.js +51 -7
- package/dist/src/agent/tools/review-workspace.js +76 -10
- package/dist/src/agent/tools/send-media.js +4 -3
- package/dist/src/agent/tools/tool-paths.js +3 -1
- package/dist/src/agent/tools/write.js +4 -17
- package/dist/src/agent/tools/xopc-use-tool.js +2 -2
- package/dist/src/agent-config/schema.d.ts +24 -0
- package/dist/src/agent-config/schema.js +2 -1
- package/dist/src/ai-assist/text-assist.js +1 -1
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/oauth/xopc-cloud.js +1 -1
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +21 -20
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/config/index.js +4 -4
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/config/schema.d.ts +16 -0
- package/dist/src/discussions/action-tasks.d.ts +21 -0
- package/dist/src/discussions/action-tasks.js +93 -0
- package/dist/src/discussions/analyzer.d.ts +21 -1
- package/dist/src/discussions/analyzer.js +229 -62
- package/dist/src/discussions/audio-repair.d.ts +8 -0
- package/dist/src/discussions/audio-repair.js +41 -0
- package/dist/src/discussions/edits.d.ts +22 -0
- package/dist/src/discussions/edits.js +81 -0
- package/dist/src/discussions/errors.d.ts +4 -0
- package/dist/src/discussions/errors.js +10 -0
- package/dist/src/discussions/export.d.ts +2 -0
- package/dist/src/discussions/export.js +23 -0
- package/dist/src/discussions/index.js +3 -2
- package/dist/src/discussions/live-worker.js +1 -1
- package/dist/src/discussions/organizer-worker.js +14 -5
- package/dist/src/discussions/organizer.d.ts +1 -1
- package/dist/src/discussions/organizer.js +60 -24
- package/dist/src/discussions/reconcile.d.ts +22 -0
- package/dist/src/discussions/reconcile.js +55 -0
- package/dist/src/discussions/recording.d.ts +9 -0
- package/dist/src/discussions/recording.js +219 -0
- package/dist/src/discussions/recordingJobs.d.ts +14 -0
- package/dist/src/discussions/recordingJobs.js +69 -0
- package/dist/src/discussions/repository.d.ts +4 -2
- package/dist/src/discussions/repository.js +15 -10
- package/dist/src/discussions/revisions.d.ts +12 -0
- package/dist/src/discussions/revisions.js +36 -0
- package/dist/src/discussions/sealer.d.ts +1 -0
- package/dist/src/discussions/sealer.js +61 -11
- package/dist/src/discussions/service.d.ts +16 -15
- package/dist/src/discussions/service.js +177 -91
- package/dist/src/discussions/types.d.ts +4 -139
- package/dist/src/discussions/types.js +1 -11
- package/dist/src/extensions/lockfile.js +1 -1
- package/dist/src/files/file-service.d.ts +1 -0
- package/dist/src/files/file-service.js +77 -0
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/chat-stream/mapper.js +2 -2
- package/dist/src/gateway/file-path-classifier.js +1 -1
- package/dist/src/gateway/hono/app.js +3 -2
- package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -0
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/static-ui.js +1 -0
- package/dist/src/gateway/hono/routes/context-sources.js +1 -2
- package/dist/src/gateway/hono/routes/discussions.js +126 -19
- package/dist/src/gateway/hono/routes/files.js +1 -22
- package/dist/src/gateway/hono/routes/index.js +0 -2
- package/dist/src/gateway/hono/routes/lazy-bundles.js +16 -0
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/proactive-control.js +2 -36
- package/dist/src/gateway/hono/routes/project-understanding.d.ts +3 -0
- package/dist/src/gateway/hono/routes/project-understanding.js +65 -0
- package/dist/src/gateway/hono/routes/projects.js +20 -4
- package/dist/src/gateway/hono/routes/session-input-handler.d.ts +2 -2
- package/dist/src/gateway/hono/routes/session-input-handler.js +2 -2
- package/dist/src/gateway/hono/routes/shares.js +22 -1
- package/dist/src/gateway/hono/routes/tasks.js +2 -1
- package/dist/src/gateway/hono/routes/work-discovery.d.ts +0 -2
- package/dist/src/gateway/hono/routes/work-discovery.js +2 -16
- package/dist/src/gateway/hono/routes/workflows.js +2 -2
- package/dist/src/gateway/security/gateway-scopes.js +1 -2
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service.d.ts +3 -0
- package/dist/src/gateway/service.js +28 -13
- package/dist/src/knowledge-memory/repository.d.ts +2 -0
- package/dist/src/knowledge-memory/repository.js +3 -1
- package/dist/src/media-understanding/audio-transcription-runner.d.ts +1 -0
- package/dist/src/media-understanding/audio-transcription-runner.js +1 -0
- package/dist/src/media-understanding/runner.js +1 -0
- package/dist/src/media-understanding/types.d.ts +8 -0
- package/dist/src/notes/service.d.ts +3 -1
- package/dist/src/notes/store.d.ts +3 -1
- package/dist/src/notes/store.js +5 -3
- package/dist/src/proactive/experience.d.ts +38 -21
- package/dist/src/proactive/experience.js +113 -12
- package/dist/src/proactive/inbox/cards.js +7 -1
- package/dist/src/proactive/maintenance.js +0 -1
- package/dist/src/proactive/scenarios/control.d.ts +0 -35
- package/dist/src/proactive/scenarios/control.js +7 -53
- package/dist/src/projects/project-store.js +6 -4
- package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/providers/register-runtime-providers.js +1 -1
- package/dist/src/session/client-history.d.ts +1 -1
- package/dist/src/session/client-history.js +1 -1
- package/dist/src/share/share-store.js +5 -1
- package/dist/src/storage/sqlite/migrations/166_remove_proactive_previews.sql +1 -0
- package/dist/src/storage/sqlite/migrations/167_discussion_recording_chunks.sql +7 -0
- package/dist/src/storage/sqlite/migrations/168_discussion_evidence.sql +16 -0
- package/dist/src/storage/sqlite/migrations/169_discussion_action_tasks.sql +8 -0
- package/dist/src/storage/sqlite/migrations/170_discussion_edits.sql +8 -0
- package/dist/src/storage/sqlite/migrations/171_discussion_recording_jobs.sql +14 -0
- package/dist/src/storage/sqlite/migrations/172_project_understanding.sql +3 -0
- package/dist/src/storage/sqlite/migrations/173_mobile_discussion_source.sql +5 -0
- package/dist/src/storage/sqlite/migrations/__tests__/mobile-discussion-source.test.ts +20 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tasks/home-query-service.js +2 -2
- package/dist/src/tasks/task-application-service.js +77 -3
- package/dist/src/tasks/task-context-assembler.js +1 -0
- package/dist/src/tasks/task-repository.d.ts +1 -0
- package/dist/src/tasks/task-repository.js +4 -0
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/dist/src/tui/tui.js +1 -1
- package/dist/src/voice/audio/normalize.js +28 -5
- package/dist/src/voice/stt/transcribe-core.js +1 -0
- package/dist/src/voice/stt/types.d.ts +1 -0
- package/dist/src/work-discovery/analyzer.d.ts +1 -0
- package/dist/src/work-discovery/analyzer.js +28 -22
- package/dist/src/work-discovery/index.js +3 -3
- package/dist/src/work-discovery/investigator.js +1 -1
- package/dist/src/work-discovery/project-understanding.d.ts +7 -0
- package/dist/src/work-discovery/project-understanding.js +38 -0
- package/dist/src/work-discovery/repository.d.ts +3 -1
- package/dist/src/work-discovery/repository.js +18 -5
- package/dist/src/work-discovery/service.d.ts +8 -0
- package/dist/src/work-discovery/service.js +163 -15
- package/dist/src/work-discovery/types.d.ts +2 -0
- package/dist/src/workflows/service/workflow-run-service.js +2 -2
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DyCyuJpi.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-__yzruGu.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-DaisbmEh.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-C7zjxscU.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-7kZMT1r6.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-BKUh6hzO.js +0 -1
- package/dist/gateway/static/root/assets/config-reload-event-Bjh2zoKp.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-m8J-F3u8.js +0 -2
- package/dist/gateway/static/root/assets/device-pairing-wizard-CfWQfz7a.js +0 -1
- package/dist/gateway/static/root/assets/gateway-config-swr-cd8owslz.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-wLly-Kc1.js +0 -1
- package/dist/gateway/static/root/assets/home-page-FqgSwpmy.js +0 -1
- package/dist/gateway/static/root/assets/index-5UchbidQ.js +0 -74
- package/dist/gateway/static/root/assets/index-CXF9-BpI.css +0 -2
- package/dist/gateway/static/root/assets/local-app-workbench-page-DtYZa4GK.js +0 -2
- package/dist/gateway/static/root/assets/messages-BGc-OJWg.js +0 -3
- package/dist/gateway/static/root/assets/note-detail-panel-JbvyGdEX.js +0 -5
- package/dist/gateway/static/root/assets/notes-page-Dm7mE2FK.js +0 -8
- package/dist/gateway/static/root/assets/proactive-card-Ap_wfos3.js +0 -1
- package/dist/gateway/static/root/assets/proactive-page-D1lEuanT.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-h00lfcVI.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-C2Bo1FAL.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-_bZYAl49.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-F7CHsvPa.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DtZSUX4H.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-VPfBsNVv.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-BS2pnWO0.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DX344nVV.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-BhfKUsv7.js +0 -2
- package/dist/gateway/static/root/assets/task-detail-page-CElcQ9Sh.js +0 -1
- package/dist/gateway/static/root/assets/tunnel-api-Bhi_x_h4.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-BydARq2C.js +0 -2
- package/dist/gateway/static/root/assets/workflows-page-B972t6zx.js +0 -6
- package/dist/src/proactive/scenarios/preview.d.ts +0 -13
- package/dist/src/proactive/scenarios/preview.js +0 -81
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { w as t, M as MAX_BROWSER_CONTEXTS_PER_TURN, b as browserPageContextsInputSchema, k as gatewayFetch, o as openDatabase, R as RealtimeClient, a as activeTabId, g as currentTabDescriptor, T as TAB_BINDING_PREFIX, l as getAccessProfile, t as runWithTabSiteAccess, P as PENDING_CONTEXT_KEY, j as extensionLocale, e as captureTabWithPermission, p as pairGateway, v as setAutoConnectEnabled, r as readPendingBrowserPairing, n as readProfile, h as discoverLocalGateway, u as saveExtensionLocalePreference, s as revokeAndForgetProfile, c as cancelPendingBrowserPairing, m as loadExtensionLocalePreference } from './assets/auth-DB30ywek.js';
|
|
2
2
|
|
|
3
3
|
true &&(function polyfill() {
|
|
4
4
|
const relList = document.createElement("link").relList;
|
|
@@ -17345,6 +17345,720 @@ function requireClient () {
|
|
|
17345
17345
|
|
|
17346
17346
|
var clientExports = requireClient();
|
|
17347
17347
|
|
|
17348
|
+
function MicrophonePermission() {
|
|
17349
|
+
const requesting = reactExports.useRef(false);
|
|
17350
|
+
const [state, setState] = reactExports.useState("idle");
|
|
17351
|
+
async function authorize() {
|
|
17352
|
+
if (requesting.current) return;
|
|
17353
|
+
requesting.current = true;
|
|
17354
|
+
setState("pending");
|
|
17355
|
+
try {
|
|
17356
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
17357
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
17358
|
+
setState("granted");
|
|
17359
|
+
} catch {
|
|
17360
|
+
setState("denied");
|
|
17361
|
+
} finally {
|
|
17362
|
+
requesting.current = false;
|
|
17363
|
+
}
|
|
17364
|
+
}
|
|
17365
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("main", { className: "microphone-permission", children: [
|
|
17366
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { children: t("voicePermissionOpen") }),
|
|
17367
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { role: "status", children: t(state === "granted" ? "voicePermissionGranted" : state === "denied" ? "voicePermissionFailed" : "voicePermissionHelp") }),
|
|
17368
|
+
state !== "granted" ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", disabled: state === "pending", onClick: () => void authorize(), children: t(state === "pending" ? "voiceStarting" : "voicePermissionOpen") }) : null
|
|
17369
|
+
] });
|
|
17370
|
+
}
|
|
17371
|
+
|
|
17372
|
+
function appendPageContext(pages, page) {
|
|
17373
|
+
const others = pages.filter((item) => item.tabId !== page.tabId || Boolean(item.context.selection) !== Boolean(page.context.selection));
|
|
17374
|
+
if (others.length >= MAX_BROWSER_CONTEXTS_PER_TURN) throw new Error(t("errorPageLimit", String(MAX_BROWSER_CONTEXTS_PER_TURN)));
|
|
17375
|
+
const next = [...others, page];
|
|
17376
|
+
if (!browserPageContextsInputSchema.safeParse(next.map((item) => item.context)).success) throw new Error(t("errorPageContextSize"));
|
|
17377
|
+
return next;
|
|
17378
|
+
}
|
|
17379
|
+
|
|
17380
|
+
const LARGE_PASTE_BYTES = 8 * 1024;
|
|
17381
|
+
const LARGE_PASTE_LINES = 80;
|
|
17382
|
+
const CODE_PASTE_BYTES = 2 * 1024;
|
|
17383
|
+
const CODE_PASTE_LINES = 20;
|
|
17384
|
+
function detectPasteFormat(text) {
|
|
17385
|
+
const sample = text.trimStart().slice(0, 8 * 1024);
|
|
17386
|
+
if (/^(?:<!doctype\s+html\b|<(?:html|head|body)\b)/i.test(sample)) return "html";
|
|
17387
|
+
if (/^<(?:div|span|section|main|article|script|style)\b/i.test(sample)) return "html";
|
|
17388
|
+
const trimmed = text.trim();
|
|
17389
|
+
if ((trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) && /[\":,]/.test(sample)) {
|
|
17390
|
+
return "json";
|
|
17391
|
+
}
|
|
17392
|
+
if (/(?:^|\n)\s*(?:(?:import|export|const|let|var|function|class|interface|type|def|SELECT|CREATE)\b|#!\/)/m.test(
|
|
17393
|
+
sample
|
|
17394
|
+
) || /(?:=>|\{\s*$|;\s*$)/m.test(sample)) {
|
|
17395
|
+
return "code";
|
|
17396
|
+
}
|
|
17397
|
+
return "text";
|
|
17398
|
+
}
|
|
17399
|
+
function classifyPastedText(text) {
|
|
17400
|
+
const byteLength = new TextEncoder().encode(text).byteLength;
|
|
17401
|
+
const lineCount = text.split(/\r\n|\n|\r/).length;
|
|
17402
|
+
const format = detectPasteFormat(text);
|
|
17403
|
+
const isCode = format !== "text";
|
|
17404
|
+
const shouldAttach = byteLength >= LARGE_PASTE_BYTES || lineCount >= LARGE_PASTE_LINES || isCode && (byteLength >= CODE_PASTE_BYTES || lineCount >= CODE_PASTE_LINES);
|
|
17405
|
+
if (!shouldAttach) return null;
|
|
17406
|
+
const file = format === "html" ? { name: "pasted-text.html", mimeType: "text/html" } : format === "json" ? { name: "pasted-text.json", mimeType: "application/json" } : format === "code" ? { name: "pasted-code.txt", mimeType: "text/plain" } : { name: "pasted-text.txt", mimeType: "text/plain" };
|
|
17407
|
+
return { text, ...file, byteLength, lineCount };
|
|
17408
|
+
}
|
|
17409
|
+
|
|
17410
|
+
function thinkingLabel(level) {
|
|
17411
|
+
return t(`thinking${level[0].toUpperCase()}${level.slice(1)}`);
|
|
17412
|
+
}
|
|
17413
|
+
function ModelControls({ models, config, disabled, onModel, onThinking }) {
|
|
17414
|
+
const details = reactExports.useRef(null);
|
|
17415
|
+
const [query, setQuery] = reactExports.useState("");
|
|
17416
|
+
const [saving, setSaving] = reactExports.useState(false);
|
|
17417
|
+
const [error, setError] = reactExports.useState("");
|
|
17418
|
+
const selected = models.find((model) => model.id === config?.model);
|
|
17419
|
+
const filtered = models.filter((model) => `${model.name} ${model.id}`.toLowerCase().includes(query.toLowerCase()));
|
|
17420
|
+
reactExports.useEffect(() => {
|
|
17421
|
+
const close = (event) => {
|
|
17422
|
+
if (details.current && (event instanceof KeyboardEvent && event.key === "Escape" || event instanceof MouseEvent && !details.current.contains(event.target))) details.current.open = false;
|
|
17423
|
+
};
|
|
17424
|
+
document.addEventListener("mousedown", close);
|
|
17425
|
+
document.addEventListener("keydown", close);
|
|
17426
|
+
return () => {
|
|
17427
|
+
document.removeEventListener("mousedown", close);
|
|
17428
|
+
document.removeEventListener("keydown", close);
|
|
17429
|
+
};
|
|
17430
|
+
}, []);
|
|
17431
|
+
async function update(action) {
|
|
17432
|
+
if (saving || disabled) return;
|
|
17433
|
+
setSaving(true);
|
|
17434
|
+
setError("");
|
|
17435
|
+
try {
|
|
17436
|
+
await action();
|
|
17437
|
+
} catch (cause) {
|
|
17438
|
+
setError(String(cause));
|
|
17439
|
+
} finally {
|
|
17440
|
+
setSaving(false);
|
|
17441
|
+
}
|
|
17442
|
+
}
|
|
17443
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("details", { className: "model-picker", ref: details, children: [
|
|
17444
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("summary", { "aria-label": t("sessionModel"), children: [
|
|
17445
|
+
selected?.name ?? config?.model ?? t("model"),
|
|
17446
|
+
config?.thinkingLevel ? ` · ${thinkingLabel(config.thinkingLevel)}` : ""
|
|
17447
|
+
] }),
|
|
17448
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "model-picker-panel", children: [
|
|
17449
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("input", { "aria-label": t("searchModels"), placeholder: t("searchModels"), value: query, onChange: (event) => setQuery(event.target.value) }),
|
|
17450
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "model-picker-list", children: [
|
|
17451
|
+
filtered.map((model) => /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", disabled: disabled || saving, "aria-pressed": model.id === config?.model, onClick: () => void update(() => onModel(model.id)), children: [
|
|
17452
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: model.name }),
|
|
17453
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("small", { children: model.id })
|
|
17454
|
+
] }, model.id)),
|
|
17455
|
+
!filtered.length ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: t("noMatchingModels") }) : null
|
|
17456
|
+
] }),
|
|
17457
|
+
selected?.thinking?.options?.length ? /* @__PURE__ */ jsxRuntimeExports.jsxs("fieldset", { disabled: disabled || saving, children: [
|
|
17458
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("legend", { children: t("thinkingLevel") }),
|
|
17459
|
+
selected.thinking.options.map((level) => /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", "aria-pressed": config?.thinkingLevel === level, onClick: () => void update(() => onThinking(level)), children: thinkingLabel(level) }, level))
|
|
17460
|
+
] }) : null,
|
|
17461
|
+
error ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { role: "alert", children: error }) : null
|
|
17462
|
+
] })
|
|
17463
|
+
] });
|
|
17464
|
+
}
|
|
17465
|
+
|
|
17466
|
+
const pcmCaptureWorkletUrl = ""+new URL('assets/pcm-capture-worklet-CGN9Mlhg.js', import.meta.url).href+"";
|
|
17467
|
+
|
|
17468
|
+
const TARGET_SAMPLE_RATE = 16e3;
|
|
17469
|
+
function calculateRmsLevel(samples) {
|
|
17470
|
+
if (samples.length === 0) return 0;
|
|
17471
|
+
let sumSquares = 0;
|
|
17472
|
+
for (let i = 0; i < samples.length; i += 1) {
|
|
17473
|
+
sumSquares += samples[i] * samples[i];
|
|
17474
|
+
}
|
|
17475
|
+
return Math.min(1, Math.sqrt(sumSquares / samples.length));
|
|
17476
|
+
}
|
|
17477
|
+
function mergeChunks(chunks) {
|
|
17478
|
+
const length = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
17479
|
+
const merged = new Float32Array(length);
|
|
17480
|
+
let offset = 0;
|
|
17481
|
+
for (const chunk of chunks) {
|
|
17482
|
+
merged.set(chunk, offset);
|
|
17483
|
+
offset += chunk.length;
|
|
17484
|
+
}
|
|
17485
|
+
return merged;
|
|
17486
|
+
}
|
|
17487
|
+
function resamplePcm(input, sourceRate, targetRate = TARGET_SAMPLE_RATE) {
|
|
17488
|
+
if (sourceRate === targetRate) return input;
|
|
17489
|
+
const outputLength = Math.max(1, Math.round(input.length * targetRate / sourceRate));
|
|
17490
|
+
const output = new Float32Array(outputLength);
|
|
17491
|
+
const ratio = sourceRate / targetRate;
|
|
17492
|
+
for (let i = 0; i < outputLength; i += 1) {
|
|
17493
|
+
const position = i * ratio;
|
|
17494
|
+
const left = Math.min(input.length - 1, Math.floor(position));
|
|
17495
|
+
const right = Math.min(input.length - 1, left + 1);
|
|
17496
|
+
const fraction = position - left;
|
|
17497
|
+
output[i] = input[left] * (1 - fraction) + input[right] * fraction;
|
|
17498
|
+
}
|
|
17499
|
+
return output;
|
|
17500
|
+
}
|
|
17501
|
+
function encodePcm16Wav(samples, sampleRate = TARGET_SAMPLE_RATE) {
|
|
17502
|
+
const buffer = new ArrayBuffer(44 + samples.length * 2);
|
|
17503
|
+
const view = new DataView(buffer);
|
|
17504
|
+
const writeText = (offset, value) => {
|
|
17505
|
+
for (let i = 0; i < value.length; i += 1) view.setUint8(offset + i, value.charCodeAt(i));
|
|
17506
|
+
};
|
|
17507
|
+
writeText(0, "RIFF");
|
|
17508
|
+
view.setUint32(4, 36 + samples.length * 2, true);
|
|
17509
|
+
writeText(8, "WAVE");
|
|
17510
|
+
writeText(12, "fmt ");
|
|
17511
|
+
view.setUint32(16, 16, true);
|
|
17512
|
+
view.setUint16(20, 1, true);
|
|
17513
|
+
view.setUint16(22, 1, true);
|
|
17514
|
+
view.setUint32(24, sampleRate, true);
|
|
17515
|
+
view.setUint32(28, sampleRate * 2, true);
|
|
17516
|
+
view.setUint16(32, 2, true);
|
|
17517
|
+
view.setUint16(34, 16, true);
|
|
17518
|
+
writeText(36, "data");
|
|
17519
|
+
view.setUint32(40, samples.length * 2, true);
|
|
17520
|
+
for (let i = 0; i < samples.length; i += 1) {
|
|
17521
|
+
const sample = Math.max(-1, Math.min(1, samples[i]));
|
|
17522
|
+
view.setInt16(44 + i * 2, sample < 0 ? sample * 32768 : sample * 32767, true);
|
|
17523
|
+
}
|
|
17524
|
+
return buffer;
|
|
17525
|
+
}
|
|
17526
|
+
const WORKLET_NAME = "xopc-pcm-capture";
|
|
17527
|
+
const WORKLET_FLUSH_TIMEOUT_MS = 1e3;
|
|
17528
|
+
class PcmFrameCapture {
|
|
17529
|
+
constructor(context, source, node, mutedOutput, options) {
|
|
17530
|
+
this.context = context;
|
|
17531
|
+
this.source = source;
|
|
17532
|
+
this.node = node;
|
|
17533
|
+
this.mutedOutput = mutedOutput;
|
|
17534
|
+
this.options = options;
|
|
17535
|
+
this.sampleRate = context.sampleRate;
|
|
17536
|
+
this.node.port.onmessage = (event) => {
|
|
17537
|
+
if (event.data.type === "flushed") {
|
|
17538
|
+
this.flushResolve?.();
|
|
17539
|
+
return;
|
|
17540
|
+
}
|
|
17541
|
+
if (!this.accepting || this.paused) return;
|
|
17542
|
+
const samples = new Float32Array(event.data.buffer);
|
|
17543
|
+
this.options.onSamples(samples);
|
|
17544
|
+
if (this.options.onAudioLevel) {
|
|
17545
|
+
const level = calculateRmsLevel(samples);
|
|
17546
|
+
this.options.onAudioLevel({
|
|
17547
|
+
level,
|
|
17548
|
+
speaking: level >= (this.options.speechThreshold ?? 0.015)
|
|
17549
|
+
});
|
|
17550
|
+
}
|
|
17551
|
+
};
|
|
17552
|
+
this.node.onprocessorerror = () => {
|
|
17553
|
+
this.processorFailed = true;
|
|
17554
|
+
this.flushResolve?.();
|
|
17555
|
+
};
|
|
17556
|
+
}
|
|
17557
|
+
context;
|
|
17558
|
+
source;
|
|
17559
|
+
node;
|
|
17560
|
+
mutedOutput;
|
|
17561
|
+
options;
|
|
17562
|
+
sampleRate;
|
|
17563
|
+
paused = false;
|
|
17564
|
+
accepting = true;
|
|
17565
|
+
processorFailed = false;
|
|
17566
|
+
stopPromise;
|
|
17567
|
+
flushResolve;
|
|
17568
|
+
static async start(stream, options) {
|
|
17569
|
+
if (typeof AudioWorkletNode === "undefined") {
|
|
17570
|
+
throw new Error("PCM audio recording is not supported in this browser");
|
|
17571
|
+
}
|
|
17572
|
+
const context = new AudioContext();
|
|
17573
|
+
try {
|
|
17574
|
+
await context.audioWorklet.addModule(pcmCaptureWorkletUrl);
|
|
17575
|
+
const source = context.createMediaStreamSource(stream);
|
|
17576
|
+
const node = new AudioWorkletNode(context, WORKLET_NAME);
|
|
17577
|
+
const mutedOutput = context.createGain();
|
|
17578
|
+
mutedOutput.gain.value = 0;
|
|
17579
|
+
const capture = new PcmFrameCapture(context, source, node, mutedOutput, options);
|
|
17580
|
+
source.connect(node);
|
|
17581
|
+
node.connect(mutedOutput);
|
|
17582
|
+
mutedOutput.connect(context.destination);
|
|
17583
|
+
await context.resume();
|
|
17584
|
+
return capture;
|
|
17585
|
+
} catch (error) {
|
|
17586
|
+
await context.close().catch(() => void 0);
|
|
17587
|
+
throw error;
|
|
17588
|
+
}
|
|
17589
|
+
}
|
|
17590
|
+
pause() {
|
|
17591
|
+
this.paused = true;
|
|
17592
|
+
}
|
|
17593
|
+
resume() {
|
|
17594
|
+
this.paused = false;
|
|
17595
|
+
}
|
|
17596
|
+
stop() {
|
|
17597
|
+
this.stopPromise ??= this.finish();
|
|
17598
|
+
return this.stopPromise;
|
|
17599
|
+
}
|
|
17600
|
+
cancel() {
|
|
17601
|
+
if (!this.accepting) return;
|
|
17602
|
+
this.accepting = false;
|
|
17603
|
+
this.flushResolve?.();
|
|
17604
|
+
this.flushResolve = void 0;
|
|
17605
|
+
this.disconnect();
|
|
17606
|
+
void this.context.close().catch(() => void 0);
|
|
17607
|
+
}
|
|
17608
|
+
async finish() {
|
|
17609
|
+
if (!this.accepting) return;
|
|
17610
|
+
if (!this.processorFailed) await this.flushWorklet();
|
|
17611
|
+
this.flushResolve = void 0;
|
|
17612
|
+
if (!this.accepting) return;
|
|
17613
|
+
this.accepting = false;
|
|
17614
|
+
this.disconnect();
|
|
17615
|
+
await this.context.close().catch(() => void 0);
|
|
17616
|
+
}
|
|
17617
|
+
flushWorklet() {
|
|
17618
|
+
return new Promise((resolve) => {
|
|
17619
|
+
let settled = false;
|
|
17620
|
+
const complete = () => {
|
|
17621
|
+
if (settled) return;
|
|
17622
|
+
settled = true;
|
|
17623
|
+
globalThis.clearTimeout(timeout);
|
|
17624
|
+
resolve();
|
|
17625
|
+
};
|
|
17626
|
+
const timeout = globalThis.setTimeout(complete, WORKLET_FLUSH_TIMEOUT_MS);
|
|
17627
|
+
this.flushResolve = complete;
|
|
17628
|
+
try {
|
|
17629
|
+
this.node.port.postMessage("flush");
|
|
17630
|
+
} catch {
|
|
17631
|
+
complete();
|
|
17632
|
+
}
|
|
17633
|
+
});
|
|
17634
|
+
}
|
|
17635
|
+
disconnect() {
|
|
17636
|
+
this.node.port.onmessage = null;
|
|
17637
|
+
this.node.onprocessorerror = null;
|
|
17638
|
+
this.source.disconnect();
|
|
17639
|
+
this.node.disconnect();
|
|
17640
|
+
this.mutedOutput.disconnect();
|
|
17641
|
+
}
|
|
17642
|
+
}
|
|
17643
|
+
class PcmWavRecorder {
|
|
17644
|
+
constructor(capture, chunks) {
|
|
17645
|
+
this.capture = capture;
|
|
17646
|
+
this.chunks = chunks;
|
|
17647
|
+
}
|
|
17648
|
+
capture;
|
|
17649
|
+
chunks;
|
|
17650
|
+
stopped = false;
|
|
17651
|
+
static async start(stream, options = {}) {
|
|
17652
|
+
const chunks = [];
|
|
17653
|
+
const capture = await PcmFrameCapture.start(stream, {
|
|
17654
|
+
...options,
|
|
17655
|
+
onSamples: (samples) => chunks.push(samples)
|
|
17656
|
+
});
|
|
17657
|
+
return new PcmWavRecorder(capture, chunks);
|
|
17658
|
+
}
|
|
17659
|
+
async stop() {
|
|
17660
|
+
if (this.stopped) return new Blob([], { type: "audio/wav" });
|
|
17661
|
+
this.stopped = true;
|
|
17662
|
+
await this.capture.stop();
|
|
17663
|
+
const merged = mergeChunks(this.chunks);
|
|
17664
|
+
const samples = resamplePcm(merged, this.capture.sampleRate);
|
|
17665
|
+
return new Blob([encodePcm16Wav(samples)], { type: "audio/wav" });
|
|
17666
|
+
}
|
|
17667
|
+
cancel() {
|
|
17668
|
+
if (this.stopped) return;
|
|
17669
|
+
this.stopped = true;
|
|
17670
|
+
this.capture.cancel();
|
|
17671
|
+
this.chunks.length = 0;
|
|
17672
|
+
}
|
|
17673
|
+
}
|
|
17674
|
+
|
|
17675
|
+
function IconBase({ children, ...props }) {
|
|
17676
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", ...props, children });
|
|
17677
|
+
}
|
|
17678
|
+
function ChevronDownIcon(props) {
|
|
17679
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m7 10 5 5 5-5" }) });
|
|
17680
|
+
}
|
|
17681
|
+
function ArrowDownIcon(props) {
|
|
17682
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 5v14M6 13l6 6 6-6" }) });
|
|
17683
|
+
}
|
|
17684
|
+
function PlusIcon(props) {
|
|
17685
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 5v14M5 12h14" }) });
|
|
17686
|
+
}
|
|
17687
|
+
function SearchIcon(props) {
|
|
17688
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17689
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "11", cy: "11", r: "7" }),
|
|
17690
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m20 20-4-4" })
|
|
17691
|
+
] });
|
|
17692
|
+
}
|
|
17693
|
+
function PaperclipIcon(props) {
|
|
17694
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m20.5 11.5-8.9 8.9a6 6 0 0 1-8.5-8.5l9.5-9.5a4 4 0 0 1 5.7 5.7l-9.5 9.5A2 2 0 0 1 6 14.8l8.8-8.8" }) });
|
|
17695
|
+
}
|
|
17696
|
+
function PageIcon(props) {
|
|
17697
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17698
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
|
|
17699
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 2v6h6M8 13h8M8 17h5" })
|
|
17700
|
+
] });
|
|
17701
|
+
}
|
|
17702
|
+
function SelectionIcon(props) {
|
|
17703
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 4H5a1 1 0 0 0-1 1v3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3M8 9h8M8 13h6" }) });
|
|
17704
|
+
}
|
|
17705
|
+
function CameraIcon(props) {
|
|
17706
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17707
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14.5 4 16 7h3a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h3l1.5-3Z" }),
|
|
17708
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "13", r: "3" })
|
|
17709
|
+
] });
|
|
17710
|
+
}
|
|
17711
|
+
function FileIcon(props) {
|
|
17712
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17713
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
|
|
17714
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 2v6h6" })
|
|
17715
|
+
] });
|
|
17716
|
+
}
|
|
17717
|
+
function EyeIcon(props) {
|
|
17718
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17719
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12Z" }),
|
|
17720
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "2.5" })
|
|
17721
|
+
] });
|
|
17722
|
+
}
|
|
17723
|
+
function CursorIcon(props) {
|
|
17724
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m5 3 14 9-6 2-3 6Z" }) });
|
|
17725
|
+
}
|
|
17726
|
+
function SendIcon(props) {
|
|
17727
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m5 12 7-7 7 7M12 19V5" }) });
|
|
17728
|
+
}
|
|
17729
|
+
function StopIcon(props) {
|
|
17730
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "7", y: "7", width: "10", height: "10", rx: "1.5", fill: "currentColor", stroke: "none" }) });
|
|
17731
|
+
}
|
|
17732
|
+
function CopyIcon(props) {
|
|
17733
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17734
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "9", y: "9", width: "11", height: "11", rx: "2" }),
|
|
17735
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3" })
|
|
17736
|
+
] });
|
|
17737
|
+
}
|
|
17738
|
+
function CheckIcon(props) {
|
|
17739
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m5 12 4 4L19 6" }) });
|
|
17740
|
+
}
|
|
17741
|
+
function CloseIcon(props) {
|
|
17742
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m6 6 12 12M18 6 6 18" }) });
|
|
17743
|
+
}
|
|
17744
|
+
function SparkleIcon(props) {
|
|
17745
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 3c.7 4.4 3.6 7.3 8 8-4.4.7-7.3 3.6-8 8-.7-4.4-3.6-7.3-8-8 4.4-.7 7.3-3.6 8-8Z" }) });
|
|
17746
|
+
}
|
|
17747
|
+
function AlertIcon(props) {
|
|
17748
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17749
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
17750
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 8v5M12 16.5h.01" })
|
|
17751
|
+
] });
|
|
17752
|
+
}
|
|
17753
|
+
function SettingsIcon(props) {
|
|
17754
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17755
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "3" }),
|
|
17756
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19.4 15a1.7 1.7 0 0 0 .34 1.88l.06.06-2.86 2.86-.06-.06A1.7 1.7 0 0 0 15 19.4a1.7 1.7 0 0 0-1 .6 1.7 1.7 0 0 0-.4 1.1V21H9.55v-.1A1.7 1.7 0 0 0 8.5 19.4a1.7 1.7 0 0 0-1.88.34l-.06.06-2.86-2.86.06-.06A1.7 1.7 0 0 0 4.1 15a1.7 1.7 0 0 0-.6-1 1.7 1.7 0 0 0-1.1-.4H2V9.55h.4A1.7 1.7 0 0 0 4.1 8.5a1.7 1.7 0 0 0-.34-1.88l-.06-.06L6.56 3.7l.06.06A1.7 1.7 0 0 0 8.5 4.1a1.7 1.7 0 0 0 1-.6 1.7 1.7 0 0 0 .4-1.1V2h4.05v.4A1.7 1.7 0 0 0 15 4.1a1.7 1.7 0 0 0 1.88-.34l.06-.06 2.86 2.86-.06.06A1.7 1.7 0 0 0 19.4 8.5a1.7 1.7 0 0 0 .6 1 1.7 1.7 0 0 0 1.1.4h.4v4.05h-.4A1.7 1.7 0 0 0 19.4 15Z" })
|
|
17757
|
+
] });
|
|
17758
|
+
}
|
|
17759
|
+
function SunIcon(props) {
|
|
17760
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17761
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "4" }),
|
|
17762
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 2v2M12 20v2M4.93 4.93l1.42 1.42M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.42-1.42M17.66 6.34l1.41-1.41" })
|
|
17763
|
+
] });
|
|
17764
|
+
}
|
|
17765
|
+
function GlobeIcon(props) {
|
|
17766
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17767
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
17768
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M3 12h18M12 3a15 15 0 0 1 0 18M12 3a15 15 0 0 0 0 18" })
|
|
17769
|
+
] });
|
|
17770
|
+
}
|
|
17771
|
+
function MicrophoneIcon(props) {
|
|
17772
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
17773
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "9", y: "2", width: "6", height: "12", rx: "3" }),
|
|
17774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 10v2a7 7 0 0 0 14 0v-2M12 19v3M8 22h8" })
|
|
17775
|
+
] });
|
|
17776
|
+
}
|
|
17777
|
+
|
|
17778
|
+
function VoiceInput({ disabled, onTranscript, onBusy }) {
|
|
17779
|
+
const [state, setState] = reactExports.useState("idle");
|
|
17780
|
+
const [error, setError] = reactExports.useState("");
|
|
17781
|
+
const [needsPermission, setNeedsPermission] = reactExports.useState(false);
|
|
17782
|
+
const [seconds, setSeconds] = reactExports.useState(0);
|
|
17783
|
+
const recorder = reactExports.useRef(void 0);
|
|
17784
|
+
const stream = reactExports.useRef(void 0);
|
|
17785
|
+
const generation = reactExports.useRef(0);
|
|
17786
|
+
const timer = reactExports.useRef(void 0);
|
|
17787
|
+
const controller = reactExports.useRef(void 0);
|
|
17788
|
+
const audio = reactExports.useRef(void 0);
|
|
17789
|
+
const busy = reactExports.useRef(false);
|
|
17790
|
+
const stopTracks = (media = stream.current) => {
|
|
17791
|
+
media?.getTracks().forEach((track) => track.stop());
|
|
17792
|
+
if (stream.current === media) {
|
|
17793
|
+
stream.current = void 0;
|
|
17794
|
+
clearInterval(timer.current);
|
|
17795
|
+
}
|
|
17796
|
+
};
|
|
17797
|
+
function cancel() {
|
|
17798
|
+
generation.current++;
|
|
17799
|
+
controller.current?.abort();
|
|
17800
|
+
recorder.current?.cancel();
|
|
17801
|
+
recorder.current = void 0;
|
|
17802
|
+
stopTracks();
|
|
17803
|
+
busy.current = false;
|
|
17804
|
+
audio.current = void 0;
|
|
17805
|
+
setState("idle");
|
|
17806
|
+
onBusy(false);
|
|
17807
|
+
}
|
|
17808
|
+
reactExports.useEffect(() => () => {
|
|
17809
|
+
generation.current++;
|
|
17810
|
+
controller.current?.abort();
|
|
17811
|
+
recorder.current?.cancel();
|
|
17812
|
+
stopTracks();
|
|
17813
|
+
onBusy(false);
|
|
17814
|
+
}, []);
|
|
17815
|
+
async function transcribe(blob, id) {
|
|
17816
|
+
setState("transcribing");
|
|
17817
|
+
setError("");
|
|
17818
|
+
busy.current = true;
|
|
17819
|
+
onBusy(true);
|
|
17820
|
+
controller.current = new AbortController();
|
|
17821
|
+
try {
|
|
17822
|
+
const form = new FormData();
|
|
17823
|
+
form.append("audio", blob, "recording.wav");
|
|
17824
|
+
const response = await gatewayFetch("/api/voice/transcriptions", {
|
|
17825
|
+
method: "POST",
|
|
17826
|
+
body: form,
|
|
17827
|
+
signal: AbortSignal.any([controller.current.signal, AbortSignal.timeout(12e4)])
|
|
17828
|
+
});
|
|
17829
|
+
const body = await response.json();
|
|
17830
|
+
if (!response.ok) throw new Error(body.error?.message ?? t("errorGatewayStatus", String(response.status)));
|
|
17831
|
+
if (typeof body.payload?.text !== "string" || !body.payload.text.trim()) throw new Error(t("voiceNoSpeech"));
|
|
17832
|
+
if (generation.current === id) {
|
|
17833
|
+
onTranscript(body.payload.text.trim());
|
|
17834
|
+
audio.current = void 0;
|
|
17835
|
+
}
|
|
17836
|
+
} catch (cause) {
|
|
17837
|
+
if (generation.current === id) setError(cause instanceof Error ? cause.message : String(cause));
|
|
17838
|
+
} finally {
|
|
17839
|
+
if (generation.current === id) {
|
|
17840
|
+
busy.current = false;
|
|
17841
|
+
setState("idle");
|
|
17842
|
+
onBusy(false);
|
|
17843
|
+
}
|
|
17844
|
+
}
|
|
17845
|
+
}
|
|
17846
|
+
async function finish(id = generation.current) {
|
|
17847
|
+
if (!recorder.current || generation.current !== id) return;
|
|
17848
|
+
const current = recorder.current;
|
|
17849
|
+
const media = stream.current;
|
|
17850
|
+
recorder.current = void 0;
|
|
17851
|
+
clearInterval(timer.current);
|
|
17852
|
+
setState("transcribing");
|
|
17853
|
+
try {
|
|
17854
|
+
const blob = await current.stop();
|
|
17855
|
+
stopTracks(media);
|
|
17856
|
+
if (generation.current !== id) return;
|
|
17857
|
+
audio.current = blob;
|
|
17858
|
+
await transcribe(blob, id);
|
|
17859
|
+
} catch (cause) {
|
|
17860
|
+
if (generation.current === id) stopTracks();
|
|
17861
|
+
if (generation.current === id) {
|
|
17862
|
+
busy.current = false;
|
|
17863
|
+
setState("idle");
|
|
17864
|
+
onBusy(false);
|
|
17865
|
+
setError(String(cause));
|
|
17866
|
+
}
|
|
17867
|
+
}
|
|
17868
|
+
}
|
|
17869
|
+
async function start() {
|
|
17870
|
+
if (disabled || busy.current) return;
|
|
17871
|
+
busy.current = true;
|
|
17872
|
+
onBusy(true);
|
|
17873
|
+
setState("starting");
|
|
17874
|
+
setError("");
|
|
17875
|
+
setNeedsPermission(false);
|
|
17876
|
+
audio.current = void 0;
|
|
17877
|
+
const id = ++generation.current;
|
|
17878
|
+
try {
|
|
17879
|
+
const statusResponse = await gatewayFetch("/api/status");
|
|
17880
|
+
if (!statusResponse.ok) throw new Error(t("errorGatewayStatus", String(statusResponse.status)));
|
|
17881
|
+
const status = await statusResponse.json();
|
|
17882
|
+
if (!status.voice?.sttAvailable) throw new Error(t("voiceUnavailable"));
|
|
17883
|
+
if (generation.current !== id) return;
|
|
17884
|
+
const media = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
17885
|
+
if (generation.current !== id) {
|
|
17886
|
+
media.getTracks().forEach((track) => track.stop());
|
|
17887
|
+
return;
|
|
17888
|
+
}
|
|
17889
|
+
stream.current = media;
|
|
17890
|
+
const next = await PcmWavRecorder.start(media);
|
|
17891
|
+
if (generation.current !== id) {
|
|
17892
|
+
next.cancel();
|
|
17893
|
+
media.getTracks().forEach((track) => track.stop());
|
|
17894
|
+
return;
|
|
17895
|
+
}
|
|
17896
|
+
recorder.current = next;
|
|
17897
|
+
setSeconds(0);
|
|
17898
|
+
setState("recording");
|
|
17899
|
+
const started = Date.now();
|
|
17900
|
+
timer.current = setInterval(() => {
|
|
17901
|
+
const elapsed = Math.floor((Date.now() - started) / 1e3);
|
|
17902
|
+
setSeconds(elapsed);
|
|
17903
|
+
if (elapsed >= 120) void finish(id);
|
|
17904
|
+
}, 1e3);
|
|
17905
|
+
} catch (cause) {
|
|
17906
|
+
if (generation.current === id) stopTracks();
|
|
17907
|
+
if (generation.current === id) {
|
|
17908
|
+
const denied = (cause instanceof DOMException || cause instanceof Error) && cause.name === "NotAllowedError";
|
|
17909
|
+
busy.current = false;
|
|
17910
|
+
setState("idle");
|
|
17911
|
+
onBusy(false);
|
|
17912
|
+
setNeedsPermission(denied);
|
|
17913
|
+
setError(denied ? t("voicePermissionHelp") : cause instanceof Error ? cause.message : String(cause));
|
|
17914
|
+
}
|
|
17915
|
+
}
|
|
17916
|
+
}
|
|
17917
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "voice-input", children: [
|
|
17918
|
+
state === "idle" ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "composer-icon-button", disabled, title: t("voiceInput"), "aria-label": t("voiceInput"), onClick: () => void start(), children: /* @__PURE__ */ jsxRuntimeExports.jsx(MicrophoneIcon, {}) }) : null,
|
|
17919
|
+
state !== "idle" || error ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "voice-input-panel", role: "status", children: [
|
|
17920
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: error || (state === "recording" ? `${t("voiceRecording")} ${seconds}s` : state === "starting" ? t("voiceStarting") : t("voiceTranscribing")) }),
|
|
17921
|
+
needsPermission ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", onClick: () => {
|
|
17922
|
+
void chrome.tabs.create({ url: chrome.runtime.getURL("dist/sidepanel.html?microphone-permission") }).catch((cause) => setError(String(cause)));
|
|
17923
|
+
}, children: t("voicePermissionOpen") }) : null,
|
|
17924
|
+
state === "recording" ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", onClick: () => void finish(), children: t("voiceFinish") }) : null,
|
|
17925
|
+
state === "idle" && audio.current ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", disabled, onClick: () => void transcribe(audio.current, ++generation.current), children: t("voiceRetry") }) : null,
|
|
17926
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", onClick: () => {
|
|
17927
|
+
cancel();
|
|
17928
|
+
setError("");
|
|
17929
|
+
}, children: t("cancelQueuedMessage") })
|
|
17930
|
+
] }) : null
|
|
17931
|
+
] });
|
|
17932
|
+
}
|
|
17933
|
+
|
|
17934
|
+
function QueuedInput({ input, onSave, onCancel }) {
|
|
17935
|
+
const [edit, setEdit] = reactExports.useState();
|
|
17936
|
+
const [busy, setBusy] = reactExports.useState(false);
|
|
17937
|
+
const [error, setError] = reactExports.useState("");
|
|
17938
|
+
async function run(action) {
|
|
17939
|
+
if (busy) return;
|
|
17940
|
+
setBusy(true);
|
|
17941
|
+
setError("");
|
|
17942
|
+
try {
|
|
17943
|
+
await action();
|
|
17944
|
+
setEdit(void 0);
|
|
17945
|
+
} catch (cause) {
|
|
17946
|
+
setError(String(cause));
|
|
17947
|
+
} finally {
|
|
17948
|
+
setBusy(false);
|
|
17949
|
+
}
|
|
17950
|
+
}
|
|
17951
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "queued-input", children: [
|
|
17952
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "composer-notice", children: [
|
|
17953
|
+
edit ? /* @__PURE__ */ jsxRuntimeExports.jsx("input", { "aria-label": t("editQueuedMessage"), value: edit.content, disabled: busy, onChange: (event) => setEdit({ ...edit, content: event.target.value }), onKeyDown: (event) => {
|
|
17954
|
+
if (event.key === "Enter") {
|
|
17955
|
+
event.preventDefault();
|
|
17956
|
+
if (!event.nativeEvent.isComposing && edit.content.trim()) void run(() => onSave(edit.content, edit.version));
|
|
17957
|
+
}
|
|
17958
|
+
} }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
17959
|
+
t("queued"),
|
|
17960
|
+
" · ",
|
|
17961
|
+
input.content || t("attachment")
|
|
17962
|
+
] }),
|
|
17963
|
+
edit ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
17964
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", disabled: busy || !edit.content.trim(), onClick: () => void run(() => onSave(edit.content, edit.version)), children: t("saveQueuedMessage") }),
|
|
17965
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", disabled: busy, onClick: () => setEdit(void 0), children: t("cancelQueuedMessage") })
|
|
17966
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
17967
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", disabled: busy, onClick: () => setEdit({ content: input.content, version: input.version }), children: t("editQueuedMessage") }),
|
|
17968
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", disabled: busy, onClick: () => void run(onCancel), children: t("cancelQueuedMessage") })
|
|
17969
|
+
] })
|
|
17970
|
+
] }),
|
|
17971
|
+
error ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "composer-error", role: "alert", children: error }) : null
|
|
17972
|
+
] });
|
|
17973
|
+
}
|
|
17974
|
+
|
|
17975
|
+
function findCommand(value, cursor) {
|
|
17976
|
+
const match = /(?:^|\s)\/([\w.-]*)$/.exec(value.slice(0, cursor));
|
|
17977
|
+
return match ? { start: cursor - match[1].length - 1, end: cursor, query: match[1] } : void 0;
|
|
17978
|
+
}
|
|
17979
|
+
async function loadComposerCommands(sessionKey) {
|
|
17980
|
+
const params = new URLSearchParams(sessionKey ? { sessionKey } : {});
|
|
17981
|
+
const responses = await Promise.all([
|
|
17982
|
+
gatewayFetch("/api/commands"),
|
|
17983
|
+
gatewayFetch(`/api/chat/skills?${params}`)
|
|
17984
|
+
]);
|
|
17985
|
+
for (const response of responses) if (!response.ok) throw new Error(t("errorGatewayStatus", String(response.status)));
|
|
17986
|
+
const [commands, skills] = await Promise.all(responses.map((response) => response.json()));
|
|
17987
|
+
return [
|
|
17988
|
+
...(commands.payload?.commands ?? []).map((command) => ({
|
|
17989
|
+
id: `command:${command.name}`,
|
|
17990
|
+
name: `/${command.name}`,
|
|
17991
|
+
description: command.description,
|
|
17992
|
+
wire: `/${command.name} `
|
|
17993
|
+
})),
|
|
17994
|
+
...(skills.payload?.skills ?? []).map((skill) => ({
|
|
17995
|
+
id: `skill:${skill.name}`,
|
|
17996
|
+
name: skill.name,
|
|
17997
|
+
description: skill.description,
|
|
17998
|
+
wire: `/skill:${skill.name} `,
|
|
17999
|
+
disabled: !skill.availableForCurrentAgent
|
|
18000
|
+
}))
|
|
18001
|
+
];
|
|
18002
|
+
}
|
|
18003
|
+
|
|
18004
|
+
function ComposerPreviewDialog({ preview, onClose }) {
|
|
18005
|
+
const dialog = reactExports.useRef(null);
|
|
18006
|
+
reactExports.useEffect(() => {
|
|
18007
|
+
dialog.current?.showModal();
|
|
18008
|
+
}, []);
|
|
18009
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("dialog", { ref: dialog, className: "composer-preview", "aria-label": preview.title, onClose, children: [
|
|
18010
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("header", { children: [
|
|
18011
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: preview.title }),
|
|
18012
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", onClick: () => dialog.current?.close(), children: t("closePreview") })
|
|
18013
|
+
] }),
|
|
18014
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "composer-preview-body", children: preview.image ? /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: preview.image, alt: preview.title }) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { children: preview.text }) })
|
|
18015
|
+
] });
|
|
18016
|
+
}
|
|
18017
|
+
|
|
18018
|
+
const OUTBOX_STORE = "outbox";
|
|
18019
|
+
function transactionResult(database, mode, createRequest) {
|
|
18020
|
+
return new Promise((resolve, reject) => {
|
|
18021
|
+
const transaction = database.transaction(OUTBOX_STORE, mode);
|
|
18022
|
+
const request = createRequest(transaction.objectStore(OUTBOX_STORE));
|
|
18023
|
+
let result;
|
|
18024
|
+
request.onsuccess = () => {
|
|
18025
|
+
result = request.result;
|
|
18026
|
+
};
|
|
18027
|
+
request.onerror = () => reject(request.error ?? new Error(t("errorOutboxRequest")));
|
|
18028
|
+
transaction.oncomplete = () => resolve(result);
|
|
18029
|
+
transaction.onerror = () => reject(transaction.error ?? new Error(t("errorOutboxTransaction")));
|
|
18030
|
+
transaction.onabort = () => reject(transaction.error ?? new Error(t("errorOutboxAborted")));
|
|
18031
|
+
});
|
|
18032
|
+
}
|
|
18033
|
+
async function readBrowserOutbox(sessionKey) {
|
|
18034
|
+
const database = await openDatabase();
|
|
18035
|
+
try {
|
|
18036
|
+
return await transactionResult(
|
|
18037
|
+
database,
|
|
18038
|
+
"readonly",
|
|
18039
|
+
(store) => store.get(sessionKey)
|
|
18040
|
+
);
|
|
18041
|
+
} finally {
|
|
18042
|
+
database.close();
|
|
18043
|
+
}
|
|
18044
|
+
}
|
|
18045
|
+
async function writeBrowserOutbox(sessionKey, value) {
|
|
18046
|
+
const database = await openDatabase();
|
|
18047
|
+
try {
|
|
18048
|
+
await transactionResult(database, "readwrite", (store) => store.put(value, sessionKey));
|
|
18049
|
+
} finally {
|
|
18050
|
+
database.close();
|
|
18051
|
+
}
|
|
18052
|
+
}
|
|
18053
|
+
async function deleteBrowserOutbox(sessionKey) {
|
|
18054
|
+
const database = await openDatabase();
|
|
18055
|
+
try {
|
|
18056
|
+
await transactionResult(database, "readwrite", (store) => store.delete(sessionKey));
|
|
18057
|
+
} finally {
|
|
18058
|
+
database.close();
|
|
18059
|
+
}
|
|
18060
|
+
}
|
|
18061
|
+
|
|
17348
18062
|
const CLIENT_ID_KEY = "xopc.browser.client-id";
|
|
17349
18063
|
const ACTIVE_CHAT_KEY = "xopc.browser.active-chat";
|
|
17350
18064
|
const CURSOR_PREFIX = "xopc.browser.cursor.";
|
|
@@ -17457,8 +18171,10 @@ class BrowserChatClient {
|
|
|
17457
18171
|
turnClaim;
|
|
17458
18172
|
runTopic;
|
|
17459
18173
|
recoveringOutbox = false;
|
|
18174
|
+
sendingInput = false;
|
|
17460
18175
|
lastOutboxRecoveryAt = 0;
|
|
17461
18176
|
sessionsRequest = 0;
|
|
18177
|
+
inputsRequest = 0;
|
|
17462
18178
|
endpointBinding;
|
|
17463
18179
|
endpointBindingTask;
|
|
17464
18180
|
endpointPoll;
|
|
@@ -17659,6 +18375,7 @@ ${endpointId}`;
|
|
|
17659
18375
|
stopping: false,
|
|
17660
18376
|
sessionLoading: true,
|
|
17661
18377
|
pendingDelivery: false,
|
|
18378
|
+
queuedInputs: [],
|
|
17662
18379
|
clarification: void 0,
|
|
17663
18380
|
tabBinding: void 0,
|
|
17664
18381
|
browserApproval: void 0,
|
|
@@ -17699,7 +18416,19 @@ ${endpointId}`;
|
|
|
17699
18416
|
}
|
|
17700
18417
|
}
|
|
17701
18418
|
}
|
|
18419
|
+
get currentSessionKey() {
|
|
18420
|
+
return this.snapshot.sessionKey;
|
|
18421
|
+
}
|
|
17702
18422
|
async send(content, browserContexts = [], attachments = []) {
|
|
18423
|
+
if (this.sendingInput) throw new Error(t("errorWaitQueuedMessage"));
|
|
18424
|
+
this.sendingInput = true;
|
|
18425
|
+
try {
|
|
18426
|
+
return await this.sendInput(content, browserContexts, attachments);
|
|
18427
|
+
} finally {
|
|
18428
|
+
this.sendingInput = false;
|
|
18429
|
+
}
|
|
18430
|
+
}
|
|
18431
|
+
async sendInput(content, browserContexts = [], attachments = []) {
|
|
17703
18432
|
const text = content.trim();
|
|
17704
18433
|
if (!text && attachments.length === 0) return "sent";
|
|
17705
18434
|
if (!this.snapshot.sessionKey) throw new Error(t("errorOpenChatBeforeSending"));
|
|
@@ -17707,14 +18436,16 @@ ${endpointId}`;
|
|
|
17707
18436
|
throw new Error(t("errorWaitQueuedMessage"));
|
|
17708
18437
|
}
|
|
17709
18438
|
if (!this.turnClaim) throw new Error(t("errorEndpointNotReady"));
|
|
17710
|
-
await this.bindSessionEndpoint();
|
|
17711
18439
|
const sessionKey = this.snapshot.sessionKey;
|
|
18440
|
+
await this.bindSessionEndpoint();
|
|
18441
|
+
if (this.snapshot.sessionKey !== sessionKey) throw new Error(t("errorChatChanged"));
|
|
17712
18442
|
const clientMessageId = crypto.randomUUID();
|
|
17713
18443
|
const request = {
|
|
17714
18444
|
content: text,
|
|
17715
18445
|
clientMessageId,
|
|
17716
18446
|
delivery: "next",
|
|
17717
18447
|
expectedSessionId: this.snapshot.sessionId,
|
|
18448
|
+
...this.snapshot.modelConfig?.fixedModel ? { configVersion: this.snapshot.modelConfig.configVersion } : {},
|
|
17718
18449
|
origin: { type: "endpoint", endpointId: this.turnClaim.endpointId, token: this.turnClaim.token },
|
|
17719
18450
|
...browserContexts.length ? { browserContexts } : {},
|
|
17720
18451
|
...attachments.length ? { attachments } : {}
|
|
@@ -17727,7 +18458,7 @@ ${endpointId}`;
|
|
|
17727
18458
|
await writeBrowserOutbox(sessionKey, request);
|
|
17728
18459
|
outboxStored = true;
|
|
17729
18460
|
this.update({
|
|
17730
|
-
messages: [...this.snapshot.messages, {
|
|
18461
|
+
messages: this.snapshot.runId ? this.snapshot.messages : [...this.snapshot.messages, {
|
|
17731
18462
|
id: clientMessageId,
|
|
17732
18463
|
role: "user",
|
|
17733
18464
|
text,
|
|
@@ -17740,7 +18471,7 @@ ${endpointId}`;
|
|
|
17740
18471
|
}))
|
|
17741
18472
|
} : {}
|
|
17742
18473
|
}],
|
|
17743
|
-
streamingText: "",
|
|
18474
|
+
...this.snapshot.runId ? {} : { streamingText: "" },
|
|
17744
18475
|
error: void 0
|
|
17745
18476
|
});
|
|
17746
18477
|
const response = await json(
|
|
@@ -17832,6 +18563,49 @@ ${endpointId}`;
|
|
|
17832
18563
|
this.recoveringOutbox = false;
|
|
17833
18564
|
}
|
|
17834
18565
|
}
|
|
18566
|
+
async refreshInputs() {
|
|
18567
|
+
const requestId = ++this.inputsRequest;
|
|
18568
|
+
const sessionKey = this.snapshot.sessionKey;
|
|
18569
|
+
if (!sessionKey) return;
|
|
18570
|
+
const result = await json(
|
|
18571
|
+
await gatewayFetch(`/api/sessions/${encodeURIComponent(sessionKey)}/input-state`)
|
|
18572
|
+
);
|
|
18573
|
+
if (this.snapshot.sessionKey !== sessionKey || requestId !== this.inputsRequest) return;
|
|
18574
|
+
this.update({ queuedInputs: (result.payload.inputs ?? []).filter((input) => input.status === "queued") });
|
|
18575
|
+
if (result.payload.activeRunId !== this.snapshot.runId) {
|
|
18576
|
+
await this.reloadMessages();
|
|
18577
|
+
if (this.snapshot.sessionKey !== sessionKey || requestId !== this.inputsRequest) return;
|
|
18578
|
+
if (result.payload.activeRunId) await this.followRun(result.payload.activeRunId);
|
|
18579
|
+
else {
|
|
18580
|
+
if (this.runTopic) this.realtime?.unsubscribe(this.runTopic);
|
|
18581
|
+
this.runTopic = void 0;
|
|
18582
|
+
this.update({ runId: void 0, streamingText: "", stopping: false });
|
|
18583
|
+
}
|
|
18584
|
+
}
|
|
18585
|
+
}
|
|
18586
|
+
async editInput(id, version, content) {
|
|
18587
|
+
const key = this.snapshot.sessionKey;
|
|
18588
|
+
if (!key) return;
|
|
18589
|
+
try {
|
|
18590
|
+
await json(await gatewayFetch(`/api/sessions/${encodeURIComponent(key)}/inputs/${encodeURIComponent(id)}`, {
|
|
18591
|
+
method: "PATCH",
|
|
18592
|
+
headers: { "Content-Type": "application/json" },
|
|
18593
|
+
body: JSON.stringify({ version, content })
|
|
18594
|
+
}));
|
|
18595
|
+
} finally {
|
|
18596
|
+
if (this.snapshot.sessionKey === key) await this.refreshInputs();
|
|
18597
|
+
}
|
|
18598
|
+
}
|
|
18599
|
+
async cancelInput(id, version) {
|
|
18600
|
+
const key = this.snapshot.sessionKey;
|
|
18601
|
+
if (!key) return;
|
|
18602
|
+
try {
|
|
18603
|
+
await json(await gatewayFetch(`/api/sessions/${encodeURIComponent(key)}/inputs/${encodeURIComponent(id)}?version=${version}`, { method: "DELETE" }));
|
|
18604
|
+
if (this.snapshot.sessionKey === key) await this.reloadMessages();
|
|
18605
|
+
} finally {
|
|
18606
|
+
if (this.snapshot.sessionKey === key) await this.refreshInputs();
|
|
18607
|
+
}
|
|
18608
|
+
}
|
|
17835
18609
|
async abort() {
|
|
17836
18610
|
const runId = this.snapshot.runId;
|
|
17837
18611
|
if (!runId || this.snapshot.stopping) return;
|
|
@@ -17931,12 +18705,16 @@ ${endpointId}`;
|
|
|
17931
18705
|
return void 0;
|
|
17932
18706
|
}
|
|
17933
18707
|
async followRun(runId) {
|
|
18708
|
+
const topic = `run:${runId}`;
|
|
18709
|
+
if (this.runTopic === topic) return;
|
|
18710
|
+
const sessionKey = this.snapshot.sessionKey;
|
|
17934
18711
|
if (this.runTopic) this.realtime?.unsubscribe(this.runTopic);
|
|
17935
|
-
this.runTopic =
|
|
18712
|
+
this.runTopic = topic;
|
|
17936
18713
|
const stored = await chrome.storage.session.get(`${CURSOR_PREFIX}${runId}`);
|
|
18714
|
+
if (this.snapshot.sessionKey !== sessionKey || this.runTopic !== topic) return;
|
|
17937
18715
|
const cursor = typeof stored[`${CURSOR_PREFIX}${runId}`] === "number" ? stored[`${CURSOR_PREFIX}${runId}`] : void 0;
|
|
17938
|
-
this.
|
|
17939
|
-
this.
|
|
18716
|
+
this.update({ runId, streamingText: "" });
|
|
18717
|
+
this.realtime?.subscribe(topic, cursor);
|
|
17940
18718
|
}
|
|
17941
18719
|
async onRealtimeEvent(topic, seq, event, data) {
|
|
17942
18720
|
if (topic === "gateway") {
|
|
@@ -18124,8 +18902,8 @@ ${endpointId}`;
|
|
|
18124
18902
|
}
|
|
18125
18903
|
}
|
|
18126
18904
|
|
|
18127
|
-
const MAX_BROWSER_ATTACHMENT_BYTES =
|
|
18128
|
-
const MAX_BROWSER_ATTACHMENTS =
|
|
18905
|
+
const MAX_BROWSER_ATTACHMENT_BYTES = 32 * 1024 * 1024;
|
|
18906
|
+
const MAX_BROWSER_ATTACHMENTS = 10;
|
|
18129
18907
|
const SUPPORTED_DOCUMENT_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
18130
18908
|
"application/json",
|
|
18131
18909
|
"application/pdf",
|
|
@@ -18134,7 +18912,30 @@ const SUPPORTED_DOCUMENT_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
|
18134
18912
|
"text/markdown",
|
|
18135
18913
|
"text/plain"
|
|
18136
18914
|
]);
|
|
18137
|
-
const
|
|
18915
|
+
const DOCUMENT_MIMES = {
|
|
18916
|
+
pdf: "application/pdf",
|
|
18917
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
18918
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
18919
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
18920
|
+
csv: "text/csv",
|
|
18921
|
+
tsv: "text/tab-separated-values",
|
|
18922
|
+
json: "application/json",
|
|
18923
|
+
md: "text/markdown",
|
|
18924
|
+
txt: "text/plain",
|
|
18925
|
+
html: "text/html",
|
|
18926
|
+
xml: "text/xml",
|
|
18927
|
+
css: "text/css",
|
|
18928
|
+
js: "text/javascript",
|
|
18929
|
+
ts: "text/plain",
|
|
18930
|
+
jsx: "text/plain",
|
|
18931
|
+
tsx: "text/plain",
|
|
18932
|
+
yaml: "text/plain",
|
|
18933
|
+
yml: "text/plain",
|
|
18934
|
+
py: "text/plain",
|
|
18935
|
+
sh: "text/plain",
|
|
18936
|
+
sql: "text/plain"
|
|
18937
|
+
};
|
|
18938
|
+
const BROWSER_ATTACHMENT_ACCEPT = `image/*,${Object.keys(DOCUMENT_MIMES).map((extension) => `.${extension}`).join(",")}`;
|
|
18138
18939
|
function encodeBase64(bytes) {
|
|
18139
18940
|
const chunkSize = 32 * 1024;
|
|
18140
18941
|
let binary = "";
|
|
@@ -18151,13 +18952,13 @@ function assertSize(size) {
|
|
|
18151
18952
|
function assertSupportedFile(file) {
|
|
18152
18953
|
const mimeType = file.type.toLowerCase();
|
|
18153
18954
|
const name = file.name.toLowerCase();
|
|
18154
|
-
if (mimeType.startsWith("image/") || SUPPORTED_DOCUMENT_MIME_TYPES.has(mimeType) ||
|
|
18955
|
+
if (mimeType.startsWith("image/") || SUPPORTED_DOCUMENT_MIME_TYPES.has(mimeType) || Object.keys(DOCUMENT_MIMES).some((extension) => name.endsWith(`.${extension}`))) return;
|
|
18155
18956
|
throw new Error(t("errorUnsupportedAttachment"));
|
|
18156
18957
|
}
|
|
18157
18958
|
async function fileToBrowserAttachment(file) {
|
|
18158
18959
|
assertSupportedFile(file);
|
|
18159
18960
|
assertSize(file.size);
|
|
18160
|
-
const mimeType = file.type || "application/octet-stream";
|
|
18961
|
+
const mimeType = file.type || DOCUMENT_MIMES[file.name.split(".").pop()?.toLowerCase() ?? ""] || "application/octet-stream";
|
|
18161
18962
|
return {
|
|
18162
18963
|
type: mimeType.startsWith("image/") ? "image" : "file",
|
|
18163
18964
|
mimeType,
|
|
@@ -18167,11 +18968,16 @@ async function fileToBrowserAttachment(file) {
|
|
|
18167
18968
|
};
|
|
18168
18969
|
}
|
|
18169
18970
|
async function captureVisibleScreenshot() {
|
|
18170
|
-
const
|
|
18171
|
-
|
|
18971
|
+
const tabPromise = chrome.tabs.query({ active: true, currentWindow: true });
|
|
18972
|
+
const [granted, [activeTab]] = await Promise.all([
|
|
18973
|
+
chrome.permissions.request({ origins: ["<all_urls>"] }),
|
|
18974
|
+
tabPromise
|
|
18975
|
+
]);
|
|
18976
|
+
if (!granted) throw new Error(t("errorScreenshotPermissionRequired"));
|
|
18977
|
+
if (activeTab?.id === void 0) throw new Error(t("errorNoActivePage"));
|
|
18172
18978
|
const dataUrl = await runWithTabSiteAccess(activeTab.id, async (accessibleTab) => {
|
|
18173
18979
|
const [currentTab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
18174
|
-
if (currentTab
|
|
18980
|
+
if (currentTab?.id !== accessibleTab.id) throw new Error(t("errorActiveTabChanged"));
|
|
18175
18981
|
return chrome.tabs.captureVisibleTab(accessibleTab.windowId, { format: "png" });
|
|
18176
18982
|
});
|
|
18177
18983
|
const separator = dataUrl.indexOf(",");
|
|
@@ -18221,101 +19027,107 @@ async function listMentionableTabs(query) {
|
|
|
18221
19027
|
return filterMentionableTabs(mentionable, query);
|
|
18222
19028
|
}
|
|
18223
19029
|
|
|
18224
|
-
|
|
18225
|
-
|
|
18226
|
-
|
|
18227
|
-
|
|
18228
|
-
|
|
18229
|
-
|
|
18230
|
-
|
|
18231
|
-
|
|
18232
|
-
}
|
|
18233
|
-
|
|
18234
|
-
|
|
18235
|
-
}
|
|
18236
|
-
function SearchIcon(props) {
|
|
18237
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
18238
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "11", cy: "11", r: "7" }),
|
|
18239
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m20 20-4-4" })
|
|
18240
|
-
] });
|
|
18241
|
-
}
|
|
18242
|
-
function PaperclipIcon(props) {
|
|
18243
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m20.5 11.5-8.9 8.9a6 6 0 0 1-8.5-8.5l9.5-9.5a4 4 0 0 1 5.7 5.7l-9.5 9.5A2 2 0 0 1 6 14.8l8.8-8.8" }) });
|
|
18244
|
-
}
|
|
18245
|
-
function PageIcon(props) {
|
|
18246
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
18247
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
|
|
18248
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 2v6h6M8 13h8M8 17h5" })
|
|
18249
|
-
] });
|
|
18250
|
-
}
|
|
18251
|
-
function SelectionIcon(props) {
|
|
18252
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 4H5a1 1 0 0 0-1 1v3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3M8 9h8M8 13h6" }) });
|
|
18253
|
-
}
|
|
18254
|
-
function CameraIcon(props) {
|
|
18255
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
18256
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14.5 4 16 7h3a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h3l1.5-3Z" }),
|
|
18257
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "13", r: "3" })
|
|
18258
|
-
] });
|
|
18259
|
-
}
|
|
18260
|
-
function FileIcon(props) {
|
|
18261
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
18262
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
|
|
18263
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 2v6h6" })
|
|
18264
|
-
] });
|
|
18265
|
-
}
|
|
18266
|
-
function EyeIcon(props) {
|
|
18267
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
18268
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12Z" }),
|
|
18269
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "2.5" })
|
|
18270
|
-
] });
|
|
18271
|
-
}
|
|
18272
|
-
function CursorIcon(props) {
|
|
18273
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m5 3 14 9-6 2-3 6Z" }) });
|
|
18274
|
-
}
|
|
18275
|
-
function SendIcon(props) {
|
|
18276
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m5 12 7-7 7 7M12 19V5" }) });
|
|
18277
|
-
}
|
|
18278
|
-
function StopIcon(props) {
|
|
18279
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "7", y: "7", width: "10", height: "10", rx: "1.5", fill: "currentColor", stroke: "none" }) });
|
|
18280
|
-
}
|
|
18281
|
-
function CopyIcon(props) {
|
|
18282
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
18283
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "9", y: "9", width: "11", height: "11", rx: "2" }),
|
|
18284
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3" })
|
|
18285
|
-
] });
|
|
18286
|
-
}
|
|
18287
|
-
function CheckIcon(props) {
|
|
18288
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m5 12 4 4L19 6" }) });
|
|
18289
|
-
}
|
|
18290
|
-
function CloseIcon(props) {
|
|
18291
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m6 6 12 12M18 6 6 18" }) });
|
|
18292
|
-
}
|
|
18293
|
-
function SparkleIcon(props) {
|
|
18294
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 3c.7 4.4 3.6 7.3 8 8-4.4.7-7.3 3.6-8 8-.7-4.4-3.6-7.3-8-8 4.4-.7 7.3-3.6 8-8Z" }) });
|
|
18295
|
-
}
|
|
18296
|
-
function AlertIcon(props) {
|
|
18297
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(IconBase, { ...props, children: [
|
|
18298
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
18299
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 8v5M12 16.5h.01" })
|
|
18300
|
-
] });
|
|
19030
|
+
const EMPTY_DRAFT = { text: "", attachments: [], pages: [] };
|
|
19031
|
+
async function readDraft(key) {
|
|
19032
|
+
const db = await openDatabase();
|
|
19033
|
+
try {
|
|
19034
|
+
return await new Promise((resolve, reject) => {
|
|
19035
|
+
const request = db.transaction("drafts").objectStore("drafts").get(key);
|
|
19036
|
+
request.onsuccess = () => resolve(request.result);
|
|
19037
|
+
request.onerror = () => reject(request.error);
|
|
19038
|
+
});
|
|
19039
|
+
} finally {
|
|
19040
|
+
db.close();
|
|
19041
|
+
}
|
|
18301
19042
|
}
|
|
18302
|
-
function
|
|
18303
|
-
|
|
18304
|
-
|
|
18305
|
-
|
|
18306
|
-
|
|
19043
|
+
async function writeDraft(key, draft) {
|
|
19044
|
+
const db = await openDatabase();
|
|
19045
|
+
try {
|
|
19046
|
+
await new Promise((resolve, reject) => {
|
|
19047
|
+
const tx = db.transaction("drafts", "readwrite");
|
|
19048
|
+
const store = tx.objectStore("drafts");
|
|
19049
|
+
if (!draft.text && !draft.attachments.length && !draft.pages.length) store.delete(key);
|
|
19050
|
+
else store.put(draft, key);
|
|
19051
|
+
tx.oncomplete = () => resolve();
|
|
19052
|
+
tx.onerror = () => reject(tx.error);
|
|
19053
|
+
tx.onabort = () => reject(tx.error);
|
|
19054
|
+
});
|
|
19055
|
+
} finally {
|
|
19056
|
+
db.close();
|
|
19057
|
+
}
|
|
18307
19058
|
}
|
|
18308
|
-
|
|
18309
|
-
|
|
18310
|
-
|
|
18311
|
-
|
|
18312
|
-
|
|
19059
|
+
class ComposerDrafts {
|
|
19060
|
+
constructor(onError, save = writeDraft, read = readDraft) {
|
|
19061
|
+
this.onError = onError;
|
|
19062
|
+
this.save = save;
|
|
19063
|
+
this.read = read;
|
|
19064
|
+
}
|
|
19065
|
+
onError;
|
|
19066
|
+
save;
|
|
19067
|
+
read;
|
|
19068
|
+
records = /* @__PURE__ */ new Map();
|
|
19069
|
+
listeners = /* @__PURE__ */ new Set();
|
|
19070
|
+
pendingWrites = /* @__PURE__ */ new Map();
|
|
19071
|
+
writing = false;
|
|
19072
|
+
subscribe = (listener) => {
|
|
19073
|
+
this.listeners.add(listener);
|
|
19074
|
+
return () => {
|
|
19075
|
+
this.listeners.delete(listener);
|
|
19076
|
+
};
|
|
19077
|
+
};
|
|
19078
|
+
peek = (key) => this.records.get(key);
|
|
19079
|
+
get = (key) => this.records.get(key) ?? EMPTY_DRAFT;
|
|
19080
|
+
async load(key) {
|
|
19081
|
+
if (this.records.has(key)) return;
|
|
19082
|
+
let draft;
|
|
19083
|
+
try {
|
|
19084
|
+
draft = await this.read(key);
|
|
19085
|
+
} catch (cause) {
|
|
19086
|
+
this.onError(cause);
|
|
19087
|
+
}
|
|
19088
|
+
if (this.records.has(key)) return;
|
|
19089
|
+
this.records.set(key, draft ? { ...draft, pages: draft.pages.map((page) => ({ ...page, stale: true })) } : EMPTY_DRAFT);
|
|
19090
|
+
this.listeners.forEach((listener) => listener());
|
|
19091
|
+
}
|
|
19092
|
+
update(key, update) {
|
|
19093
|
+
const draft = update(this.get(key));
|
|
19094
|
+
this.records.set(key, draft);
|
|
19095
|
+
this.listeners.forEach((listener) => listener());
|
|
19096
|
+
this.pendingWrites.set(key, draft);
|
|
19097
|
+
void this.flush();
|
|
19098
|
+
}
|
|
19099
|
+
async flush() {
|
|
19100
|
+
if (this.writing) return;
|
|
19101
|
+
this.writing = true;
|
|
19102
|
+
try {
|
|
19103
|
+
while (this.pendingWrites.size) {
|
|
19104
|
+
const [key, draft] = this.pendingWrites.entries().next().value;
|
|
19105
|
+
this.pendingWrites.delete(key);
|
|
19106
|
+
try {
|
|
19107
|
+
await this.save(key, draft);
|
|
19108
|
+
} catch (cause) {
|
|
19109
|
+
this.onError(cause);
|
|
19110
|
+
}
|
|
19111
|
+
}
|
|
19112
|
+
} finally {
|
|
19113
|
+
this.writing = false;
|
|
19114
|
+
}
|
|
19115
|
+
}
|
|
19116
|
+
invalidate(tabId) {
|
|
19117
|
+
for (const [key, draft] of this.records) {
|
|
19118
|
+
if (draft.pages.some((page) => page.tabId === tabId && !page.stale)) {
|
|
19119
|
+
this.update(key, (current) => ({ ...current, pages: current.pages.map((page) => page.tabId === tabId ? { ...page, stale: true } : page) }));
|
|
19120
|
+
}
|
|
19121
|
+
}
|
|
19122
|
+
}
|
|
18313
19123
|
}
|
|
18314
|
-
function
|
|
18315
|
-
|
|
18316
|
-
|
|
18317
|
-
|
|
18318
|
-
|
|
19124
|
+
function useComposerDrafts(key, onError) {
|
|
19125
|
+
const store = reactExports.useMemo(() => new ComposerDrafts(onError), []);
|
|
19126
|
+
const draft = reactExports.useSyncExternalStore(store.subscribe, () => store.peek(key));
|
|
19127
|
+
reactExports.useEffect(() => {
|
|
19128
|
+
void store.load(key).catch(onError);
|
|
19129
|
+
}, [store, key]);
|
|
19130
|
+
return { store, draft: draft ?? EMPTY_DRAFT, ready: draft !== void 0, update: (update) => store.update(key, update) };
|
|
18319
19131
|
}
|
|
18320
19132
|
|
|
18321
19133
|
/* eslint-disable no-bitwise */
|
|
@@ -26842,30 +27654,41 @@ const RISK_MESSAGE_KEYS = {
|
|
|
26842
27654
|
draft: "riskDraft",
|
|
26843
27655
|
read: "riskRead"
|
|
26844
27656
|
};
|
|
26845
|
-
const THINKING_MESSAGE_KEYS = {
|
|
26846
|
-
off: "thinkingOff",
|
|
26847
|
-
minimal: "thinkingMinimal",
|
|
26848
|
-
low: "thinkingLow",
|
|
26849
|
-
medium: "thinkingMedium",
|
|
26850
|
-
high: "thinkingHigh",
|
|
26851
|
-
xhigh: "thinkingXhigh",
|
|
26852
|
-
max: "thinkingMax",
|
|
26853
|
-
ultra: "thinkingUltra"
|
|
26854
|
-
};
|
|
26855
|
-
function thinkingLabel(level) {
|
|
26856
|
-
const key = THINKING_MESSAGE_KEYS[level];
|
|
26857
|
-
return key ? t(key) : level;
|
|
26858
|
-
}
|
|
26859
27657
|
function formatFileSize(size) {
|
|
26860
27658
|
if (typeof size !== "number" || !Number.isFinite(size) || size < 0) return "";
|
|
26861
27659
|
if (size < 1024) return `${size} B`;
|
|
26862
27660
|
if (size < 1024 * 1024) return `${Math.round(size / 1024)} KB`;
|
|
26863
27661
|
return `${(size / (1024 * 1024)).toFixed(1)} MB`;
|
|
26864
27662
|
}
|
|
26865
|
-
function ChatPanel() {
|
|
27663
|
+
function ChatPanel({ gatewayId }) {
|
|
26866
27664
|
const client = reactExports.useMemo(() => new BrowserChatClient(), []);
|
|
26867
27665
|
const [snapshot, setSnapshot] = reactExports.useState(EMPTY);
|
|
26868
|
-
const [
|
|
27666
|
+
const keyForSession = (sessionKey) => JSON.stringify([gatewayId, sessionKey ?? "new"]);
|
|
27667
|
+
const draftKey = keyForSession(snapshot.sessionKey);
|
|
27668
|
+
const { store: drafts, draft: composerDraft, ready: draftReady, update: updateDraft } = useComposerDrafts(draftKey, (cause) => setError(String(cause)));
|
|
27669
|
+
const draft = composerDraft.text;
|
|
27670
|
+
const attachments = composerDraft.attachments;
|
|
27671
|
+
const pageContexts = composerDraft.pages;
|
|
27672
|
+
const [preview, setPreview] = reactExports.useState();
|
|
27673
|
+
const setDraft = (text) => updateDraft((current) => ({ ...current, text }));
|
|
27674
|
+
const setAttachments = (value) => updateDraft((current) => ({ ...current, attachments: typeof value === "function" ? value(current.attachments) : value }));
|
|
27675
|
+
function addPageContext(page) {
|
|
27676
|
+
updateDraft((current) => ({ ...current, pages: appendPageContext(current.pages, page) }));
|
|
27677
|
+
}
|
|
27678
|
+
const submittingRef = reactExports.useRef(false);
|
|
27679
|
+
const composing = reactExports.useRef(false);
|
|
27680
|
+
const historyWalk = reactExports.useRef(void 0);
|
|
27681
|
+
const [sending, setSending] = reactExports.useState(false);
|
|
27682
|
+
const [processing, setProcessing] = reactExports.useState(false);
|
|
27683
|
+
const [voiceBusy, setVoiceBusy] = reactExports.useState(false);
|
|
27684
|
+
const [cursor, setCursor] = reactExports.useState(0);
|
|
27685
|
+
const [commandsOpen, setCommandsOpen] = reactExports.useState(false);
|
|
27686
|
+
const [commands, setCommands] = reactExports.useState([]);
|
|
27687
|
+
const [commandsLoading, setCommandsLoading] = reactExports.useState(false);
|
|
27688
|
+
const [commandIndex, setCommandIndex] = reactExports.useState(0);
|
|
27689
|
+
const commandRange = commandsOpen ? findCommand(draft, cursor) : void 0;
|
|
27690
|
+
const commandItems = commandRange ? commands.filter((item) => `${item.name} ${item.description}`.toLowerCase().includes(commandRange.query.toLowerCase())).slice(0, 12) : [];
|
|
27691
|
+
const canSend = draftReady && !sending && !processing && !voiceBusy && !snapshot.submitting && !snapshot.pendingDelivery && !snapshot.sessionLoading && !snapshot.stopping && snapshot.endpointReady;
|
|
26869
27692
|
const [search, setSearch] = reactExports.useState("");
|
|
26870
27693
|
const [menuOpen, setMenuOpen] = reactExports.useState(false);
|
|
26871
27694
|
const [toolsOpen, setToolsOpen] = reactExports.useState(false);
|
|
@@ -26873,8 +27696,6 @@ function ChatPanel() {
|
|
|
26873
27696
|
const [copiedMessageId, setCopiedMessageId] = reactExports.useState("");
|
|
26874
27697
|
const [clarificationAnswer, setClarificationAnswer] = reactExports.useState("");
|
|
26875
27698
|
const [clarificationSubmitting, setClarificationSubmitting] = reactExports.useState(false);
|
|
26876
|
-
const [pageContext, setPageContext] = reactExports.useState();
|
|
26877
|
-
const [attachments, setAttachments] = reactExports.useState([]);
|
|
26878
27699
|
const [tabMention, setTabMention] = reactExports.useState();
|
|
26879
27700
|
const [mentionTabs, setMentionTabs] = reactExports.useState([]);
|
|
26880
27701
|
const [mentionIndex, setMentionIndex] = reactExports.useState(0);
|
|
@@ -26908,26 +27729,35 @@ function ChatPanel() {
|
|
|
26908
27729
|
setAtBottom(isAtBottom);
|
|
26909
27730
|
}, []);
|
|
26910
27731
|
reactExports.useEffect(() => {
|
|
27732
|
+
let active = true;
|
|
26911
27733
|
const unsubscribe = client.subscribe(setSnapshot);
|
|
26912
|
-
void client.start().
|
|
27734
|
+
void client.start().then(async () => {
|
|
27735
|
+
if (!active) return;
|
|
27736
|
+
const stored = await chrome.storage.session.get(PENDING_CONTEXT_KEY);
|
|
27737
|
+
const pending = stored[PENDING_CONTEXT_KEY];
|
|
27738
|
+
if (!pending || !active) return;
|
|
27739
|
+
const key = keyForSession(client.currentSessionKey);
|
|
27740
|
+
await drafts.load(key);
|
|
27741
|
+
if (!active) return;
|
|
27742
|
+
drafts.update(key, (current) => ({ ...current, pages: appendPageContext(current.pages, pending) }));
|
|
27743
|
+
await chrome.storage.session.remove(PENDING_CONTEXT_KEY);
|
|
27744
|
+
}).catch((cause) => {
|
|
27745
|
+
if (active) setError(cause instanceof Error ? cause.message : String(cause));
|
|
27746
|
+
});
|
|
26913
27747
|
return () => {
|
|
27748
|
+
active = false;
|
|
26914
27749
|
unsubscribe();
|
|
26915
27750
|
client.stop();
|
|
26916
27751
|
};
|
|
26917
27752
|
}, [client]);
|
|
26918
27753
|
reactExports.useEffect(() => {
|
|
26919
|
-
void chrome.storage.session.get(PENDING_CONTEXT_KEY).then(async (stored) => {
|
|
26920
|
-
const pending = stored[PENDING_CONTEXT_KEY];
|
|
26921
|
-
if (pending?.context.kind === "browser_page") setPageContext(pending);
|
|
26922
|
-
await chrome.storage.session.remove(PENDING_CONTEXT_KEY);
|
|
26923
|
-
});
|
|
26924
27754
|
const onUpdated = (tabId, change) => {
|
|
26925
27755
|
if (change.url || change.status === "loading") {
|
|
26926
|
-
|
|
27756
|
+
drafts.invalidate(tabId);
|
|
26927
27757
|
}
|
|
26928
27758
|
};
|
|
26929
27759
|
const onRemoved = (tabId) => {
|
|
26930
|
-
|
|
27760
|
+
drafts.invalidate(tabId);
|
|
26931
27761
|
};
|
|
26932
27762
|
chrome.tabs.onUpdated.addListener(onUpdated);
|
|
26933
27763
|
chrome.tabs.onRemoved.addListener(onRemoved);
|
|
@@ -26992,53 +27822,148 @@ function ChatPanel() {
|
|
|
26992
27822
|
document.removeEventListener("keydown", closeOnEscape);
|
|
26993
27823
|
};
|
|
26994
27824
|
}, []);
|
|
26995
|
-
|
|
27825
|
+
reactExports.useEffect(() => {
|
|
27826
|
+
historyWalk.current = void 0;
|
|
27827
|
+
mentionRequest.current += 1;
|
|
27828
|
+
setTabMention(void 0);
|
|
27829
|
+
setMentionTabs([]);
|
|
27830
|
+
setCommandsOpen(false);
|
|
27831
|
+
setPreview(void 0);
|
|
27832
|
+
setError("");
|
|
27833
|
+
if (!snapshot.sessionKey) return;
|
|
27834
|
+
let active = true;
|
|
27835
|
+
const refresh = () => {
|
|
27836
|
+
if (active) void client.refreshInputs().catch((cause) => {
|
|
27837
|
+
if (active) setError(String(cause));
|
|
27838
|
+
});
|
|
27839
|
+
};
|
|
27840
|
+
refresh();
|
|
27841
|
+
const timer = setInterval(refresh, 2e3);
|
|
27842
|
+
return () => {
|
|
27843
|
+
active = false;
|
|
27844
|
+
clearInterval(timer);
|
|
27845
|
+
};
|
|
27846
|
+
}, [client, snapshot.sessionKey]);
|
|
27847
|
+
reactExports.useEffect(() => {
|
|
27848
|
+
if (!commandsOpen) return;
|
|
27849
|
+
let active = true;
|
|
27850
|
+
setCommandsLoading(true);
|
|
27851
|
+
void loadComposerCommands(snapshot.sessionKey).then((items) => {
|
|
27852
|
+
if (active) setCommands(items);
|
|
27853
|
+
}).catch((cause) => {
|
|
27854
|
+
if (active) {
|
|
27855
|
+
setCommands([]);
|
|
27856
|
+
setError(String(cause));
|
|
27857
|
+
}
|
|
27858
|
+
}).finally(() => {
|
|
27859
|
+
if (active) setCommandsLoading(false);
|
|
27860
|
+
});
|
|
27861
|
+
return () => {
|
|
27862
|
+
active = false;
|
|
27863
|
+
};
|
|
27864
|
+
}, [commandsOpen, snapshot.sessionKey]);
|
|
27865
|
+
function chooseCommand(item) {
|
|
27866
|
+
if (!commandRange || item.disabled) return;
|
|
27867
|
+
const text = `${draft.slice(0, commandRange.start)}${item.wire}${draft.slice(commandRange.end)}`;
|
|
27868
|
+
setDraft(text);
|
|
27869
|
+
setCommandsOpen(false);
|
|
27870
|
+
const nextCursor = commandRange.start + item.wire.length;
|
|
27871
|
+
requestAnimationFrame(() => {
|
|
27872
|
+
textarea.current?.focus();
|
|
27873
|
+
textarea.current?.setSelectionRange(nextCursor, nextCursor);
|
|
27874
|
+
});
|
|
27875
|
+
}
|
|
27876
|
+
async function submit(event, interrupt = false) {
|
|
26996
27877
|
event.preventDefault();
|
|
26997
|
-
if (!
|
|
26998
|
-
const
|
|
26999
|
-
|
|
27000
|
-
|
|
27001
|
-
|
|
27878
|
+
if (!canSend || submittingRef.current || composing.current || tabMention || commandRange || attachmentTask.current) return;
|
|
27879
|
+
const payload = drafts.get(draftKey);
|
|
27880
|
+
if (!payload.text.trim() && !payload.attachments.length) return;
|
|
27881
|
+
if (payload.pages.some((page) => page.stale)) {
|
|
27882
|
+
setError(t("errorAttachedPageChanged"));
|
|
27883
|
+
return;
|
|
27884
|
+
}
|
|
27885
|
+
submittingRef.current = true;
|
|
27886
|
+
setSending(true);
|
|
27002
27887
|
setError("");
|
|
27003
27888
|
followingTail.current = true;
|
|
27004
27889
|
setAtBottom(true);
|
|
27890
|
+
let targetKey = draftKey;
|
|
27005
27891
|
try {
|
|
27006
|
-
if (!snapshot.sessionKey)
|
|
27007
|
-
|
|
27008
|
-
|
|
27009
|
-
|
|
27892
|
+
if (!snapshot.sessionKey) {
|
|
27893
|
+
await client.createSession();
|
|
27894
|
+
targetKey = keyForSession(client.currentSessionKey);
|
|
27895
|
+
drafts.update(targetKey, () => payload);
|
|
27896
|
+
drafts.update(draftKey, () => EMPTY_DRAFT);
|
|
27897
|
+
}
|
|
27898
|
+
if (interrupt && snapshot.runId) await client.abort();
|
|
27899
|
+
await client.send(payload.text, payload.pages.map((page) => page.context), payload.attachments);
|
|
27900
|
+
historyWalk.current = void 0;
|
|
27901
|
+
drafts.update(targetKey, (current) => ({
|
|
27902
|
+
text: current.text === payload.text ? "" : current.text,
|
|
27903
|
+
attachments: current.attachments.filter((item) => !payload.attachments.includes(item)),
|
|
27904
|
+
pages: current.pages.filter((page) => !payload.pages.some((sent) => sent.context.sourceId === page.context.sourceId))
|
|
27905
|
+
}));
|
|
27010
27906
|
} catch (cause) {
|
|
27011
|
-
setDraft(sending);
|
|
27012
|
-
setAttachments(sendingAttachments);
|
|
27013
27907
|
setError(cause instanceof Error ? cause.message : String(cause));
|
|
27908
|
+
} finally {
|
|
27909
|
+
submittingRef.current = false;
|
|
27910
|
+
setSending(false);
|
|
27014
27911
|
}
|
|
27015
27912
|
}
|
|
27016
|
-
async function
|
|
27017
|
-
|
|
27018
|
-
|
|
27913
|
+
async function updateModelConfig(action) {
|
|
27914
|
+
if (submittingRef.current) return;
|
|
27915
|
+
submittingRef.current = true;
|
|
27916
|
+
setSending(true);
|
|
27917
|
+
try {
|
|
27918
|
+
await action();
|
|
27919
|
+
} catch (cause) {
|
|
27920
|
+
setError(String(cause));
|
|
27921
|
+
throw cause;
|
|
27922
|
+
} finally {
|
|
27923
|
+
submittingRef.current = false;
|
|
27924
|
+
setSending(false);
|
|
27925
|
+
}
|
|
27926
|
+
}
|
|
27927
|
+
async function processAttachmentTask(operation) {
|
|
27928
|
+
if (attachmentTask.current || submittingRef.current || !draftReady || snapshot.sessionLoading) return;
|
|
27019
27929
|
attachmentTask.current = true;
|
|
27930
|
+
setProcessing(true);
|
|
27020
27931
|
setError("");
|
|
27021
27932
|
try {
|
|
27022
|
-
|
|
27023
|
-
if (incoming.length > remaining) throw new Error(t("errorAttachmentLimit", String(MAX_BROWSER_ATTACHMENTS)));
|
|
27024
|
-
const added = await Promise.all(incoming.map(fileToBrowserAttachment));
|
|
27025
|
-
setAttachments((current) => [...current, ...added]);
|
|
27933
|
+
await operation();
|
|
27026
27934
|
} catch (cause) {
|
|
27027
27935
|
setError(cause instanceof Error ? cause.message : String(cause));
|
|
27028
27936
|
} finally {
|
|
27029
27937
|
attachmentTask.current = false;
|
|
27030
|
-
|
|
27938
|
+
setProcessing(false);
|
|
27031
27939
|
}
|
|
27032
27940
|
}
|
|
27941
|
+
async function addFiles(files) {
|
|
27942
|
+
const incoming = Array.from(files ?? []);
|
|
27943
|
+
if (!incoming.length) return;
|
|
27944
|
+
await processAttachmentTask(async () => {
|
|
27945
|
+
const remaining = MAX_BROWSER_ATTACHMENTS - drafts.get(draftKey).attachments.length;
|
|
27946
|
+
const failures = [];
|
|
27947
|
+
if (incoming.length > remaining) failures.push(t("errorAttachmentLimit", String(MAX_BROWSER_ATTACHMENTS)));
|
|
27948
|
+
const added = [];
|
|
27949
|
+
for (const file of incoming.slice(0, remaining)) {
|
|
27950
|
+
try {
|
|
27951
|
+
added.push(await fileToBrowserAttachment(file));
|
|
27952
|
+
} catch (cause) {
|
|
27953
|
+
failures.push(`${file.name}: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
27954
|
+
}
|
|
27955
|
+
}
|
|
27956
|
+
setAttachments((current) => [...current, ...added]);
|
|
27957
|
+
if (fileInput.current) fileInput.current.value = "";
|
|
27958
|
+
if (failures.length) setError(failures.join("\n"));
|
|
27959
|
+
});
|
|
27960
|
+
}
|
|
27033
27961
|
async function addScreenshot() {
|
|
27034
|
-
|
|
27035
|
-
|
|
27036
|
-
if (attachments.length >= MAX_BROWSER_ATTACHMENTS) throw new Error(t("errorAttachmentLimit", String(MAX_BROWSER_ATTACHMENTS)));
|
|
27962
|
+
await processAttachmentTask(async () => {
|
|
27963
|
+
if (drafts.get(draftKey).attachments.length >= MAX_BROWSER_ATTACHMENTS) throw new Error(t("errorAttachmentLimit", String(MAX_BROWSER_ATTACHMENTS)));
|
|
27037
27964
|
const screenshot = await captureVisibleScreenshot();
|
|
27038
27965
|
setAttachments((current) => [...current, screenshot]);
|
|
27039
|
-
}
|
|
27040
|
-
setError(cause instanceof Error ? cause.message : String(cause));
|
|
27041
|
-
}
|
|
27966
|
+
});
|
|
27042
27967
|
}
|
|
27043
27968
|
async function runControlAction(action) {
|
|
27044
27969
|
setError("");
|
|
@@ -27048,14 +27973,15 @@ function ChatPanel() {
|
|
|
27048
27973
|
setError(cause instanceof Error ? cause.message : String(cause));
|
|
27049
27974
|
}
|
|
27050
27975
|
}
|
|
27051
|
-
const selectedModel = snapshot.models.find((model) => model.id === snapshot.modelConfig?.model);
|
|
27052
|
-
const thinkingOptions = selectedModel?.thinking?.options ?? [];
|
|
27053
27976
|
async function attachPage(mode) {
|
|
27977
|
+
if (attachmentTask.current || submittingRef.current || !draftReady) return false;
|
|
27978
|
+
attachmentTask.current = true;
|
|
27979
|
+
setProcessing(true);
|
|
27054
27980
|
setError("");
|
|
27055
27981
|
try {
|
|
27056
27982
|
const tabId = await activeTabId();
|
|
27057
27983
|
if (tabId === void 0) throw new Error(t("errorNoActivePage"));
|
|
27058
|
-
|
|
27984
|
+
addPageContext({
|
|
27059
27985
|
context: await captureTabWithPermission(tabId, mode),
|
|
27060
27986
|
tabId,
|
|
27061
27987
|
source: mode === "selection" ? "current_selection" : "current_page"
|
|
@@ -27064,6 +27990,9 @@ function ChatPanel() {
|
|
|
27064
27990
|
} catch (cause) {
|
|
27065
27991
|
setError(cause instanceof Error ? cause.message : String(cause));
|
|
27066
27992
|
return false;
|
|
27993
|
+
} finally {
|
|
27994
|
+
attachmentTask.current = false;
|
|
27995
|
+
setProcessing(false);
|
|
27067
27996
|
}
|
|
27068
27997
|
}
|
|
27069
27998
|
async function startQuickPrompt(prompt, mode) {
|
|
@@ -27081,8 +28010,10 @@ function ChatPanel() {
|
|
|
27081
28010
|
setError(cause instanceof Error ? cause.message : String(cause));
|
|
27082
28011
|
}
|
|
27083
28012
|
}
|
|
27084
|
-
async function refreshPageContext() {
|
|
27085
|
-
if (
|
|
28013
|
+
async function refreshPageContext(pageContext) {
|
|
28014
|
+
if (attachmentTask.current || submittingRef.current) return;
|
|
28015
|
+
attachmentTask.current = true;
|
|
28016
|
+
setProcessing(true);
|
|
27086
28017
|
setError("");
|
|
27087
28018
|
try {
|
|
27088
28019
|
const mode = pageContext.context.selection ? "selection" : "page";
|
|
@@ -27090,14 +28021,20 @@ function ChatPanel() {
|
|
|
27090
28021
|
pageContext.tabId,
|
|
27091
28022
|
mode
|
|
27092
28023
|
);
|
|
27093
|
-
|
|
28024
|
+
addPageContext({ ...pageContext, context, stale: false });
|
|
27094
28025
|
} catch (cause) {
|
|
27095
28026
|
setError(cause instanceof Error ? cause.message : String(cause));
|
|
28027
|
+
} finally {
|
|
28028
|
+
attachmentTask.current = false;
|
|
28029
|
+
setProcessing(false);
|
|
27096
28030
|
}
|
|
27097
28031
|
}
|
|
27098
|
-
async function updateTabMention(value,
|
|
28032
|
+
async function updateTabMention(value, cursor2) {
|
|
28033
|
+
setCursor(cursor2);
|
|
28034
|
+
setCommandsOpen(Boolean(findCommand(value, cursor2)));
|
|
28035
|
+
setCommandIndex(0);
|
|
27099
28036
|
const requestId = ++mentionRequest.current;
|
|
27100
|
-
const mention = findTabMention(value,
|
|
28037
|
+
const mention = findTabMention(value, cursor2);
|
|
27101
28038
|
setTabMention(mention);
|
|
27102
28039
|
setMentionIndex(0);
|
|
27103
28040
|
if (!mention) {
|
|
@@ -27117,7 +28054,9 @@ function ChatPanel() {
|
|
|
27117
28054
|
}
|
|
27118
28055
|
async function chooseMentionedTab(tab) {
|
|
27119
28056
|
const mention = tabMention;
|
|
27120
|
-
if (!mention) return;
|
|
28057
|
+
if (!mention || attachmentTask.current || submittingRef.current) return;
|
|
28058
|
+
attachmentTask.current = true;
|
|
28059
|
+
setProcessing(true);
|
|
27121
28060
|
mentionRequest.current += 1;
|
|
27122
28061
|
setTabMention(void 0);
|
|
27123
28062
|
setMentionTabs([]);
|
|
@@ -27125,7 +28064,7 @@ function ChatPanel() {
|
|
|
27125
28064
|
try {
|
|
27126
28065
|
const context = await captureTabWithPermission(tab.id, "page");
|
|
27127
28066
|
const nextDraft = removeTabMention(draft, mention);
|
|
27128
|
-
|
|
28067
|
+
addPageContext({ context, tabId: tab.id, source: "tab_mention" });
|
|
27129
28068
|
setDraft(nextDraft);
|
|
27130
28069
|
requestAnimationFrame(() => {
|
|
27131
28070
|
textarea.current?.focus();
|
|
@@ -27133,6 +28072,9 @@ function ChatPanel() {
|
|
|
27133
28072
|
});
|
|
27134
28073
|
} catch (cause) {
|
|
27135
28074
|
setError(cause instanceof Error ? cause.message : String(cause));
|
|
28075
|
+
} finally {
|
|
28076
|
+
attachmentTask.current = false;
|
|
28077
|
+
setProcessing(false);
|
|
27136
28078
|
}
|
|
27137
28079
|
}
|
|
27138
28080
|
async function runSearch(value) {
|
|
@@ -27155,6 +28097,7 @@ function ChatPanel() {
|
|
|
27155
28097
|
const connectionText = snapshot.endpointReady ? t("ready") : snapshot.connection === "connected" ? t("wakingUp") : snapshot.connection === "connecting" || snapshot.connection === "reconnecting" ? t("connecting") : t("offline");
|
|
27156
28098
|
const connectionProblem = !snapshot.endpointReady && (snapshot.connection === "error" || snapshot.connection === "disconnected");
|
|
27157
28099
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "chat", children: [
|
|
28100
|
+
preview ? /* @__PURE__ */ jsxRuntimeExports.jsx(ComposerPreviewDialog, { preview, onClose: () => setPreview(void 0) }) : null,
|
|
27158
28101
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "chat-toolbar", children: [
|
|
27159
28102
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { ref: sessionTrigger, className: "session-trigger", "aria-expanded": menuOpen, onClick: () => setMenuOpen((open) => !open), children: [
|
|
27160
28103
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "session-trigger-copy", children: [
|
|
@@ -27166,7 +28109,7 @@ function ChatPanel() {
|
|
|
27166
28109
|
] }),
|
|
27167
28110
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDownIcon, { className: "icon-sm" })
|
|
27168
28111
|
] }),
|
|
27169
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "icon-button", type: "button", "aria-label": t("startNewChat"), title: t("newChat"), disabled: snapshot.submitting, onClick: () => void runControlAction(() => client.createSession()), children: /* @__PURE__ */ jsxRuntimeExports.jsx(PlusIcon, {}) })
|
|
28112
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "icon-button", type: "button", "aria-label": t("startNewChat"), title: t("newChat"), disabled: sending || snapshot.submitting || snapshot.sessionLoading, onClick: () => void runControlAction(() => client.createSession()), children: /* @__PURE__ */ jsxRuntimeExports.jsx(PlusIcon, {}) })
|
|
27170
28113
|
] }),
|
|
27171
28114
|
menuOpen ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "session-menu", ref: sessionMenu, children: [
|
|
27172
28115
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "session-menu-header", children: [
|
|
@@ -27178,7 +28121,7 @@ function ChatPanel() {
|
|
|
27178
28121
|
/* @__PURE__ */ jsxRuntimeExports.jsx("input", { value: search, onChange: (event) => void runSearch(event.target.value), placeholder: t("searchChats"), autoFocus: true })
|
|
27179
28122
|
] }),
|
|
27180
28123
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "session-list", children: [
|
|
27181
|
-
snapshot.sessions.map((session) => /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { disabled: snapshot.submitting, className: session.key === snapshot.sessionKey ? "active" : "", onClick: () => {
|
|
28124
|
+
snapshot.sessions.map((session) => /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { disabled: sending || snapshot.submitting || snapshot.sessionLoading, className: session.key === snapshot.sessionKey ? "active" : "", onClick: () => {
|
|
27182
28125
|
setMenuOpen(false);
|
|
27183
28126
|
void runControlAction(() => client.openSession(session.key));
|
|
27184
28127
|
}, children: [
|
|
@@ -27264,6 +28207,9 @@ function ChatPanel() {
|
|
|
27264
28207
|
{
|
|
27265
28208
|
className: `composer${draggingFiles ? " dragging" : ""}`,
|
|
27266
28209
|
onSubmit: submit,
|
|
28210
|
+
onKeyDown: (event) => {
|
|
28211
|
+
if (event.key === "Enter" && event.target instanceof HTMLInputElement) event.preventDefault();
|
|
28212
|
+
},
|
|
27267
28213
|
onDragEnter: (event) => {
|
|
27268
28214
|
if (event.dataTransfer.types.includes("Files")) setDraggingFiles(true);
|
|
27269
28215
|
},
|
|
@@ -27334,13 +28280,15 @@ function ChatPanel() {
|
|
|
27334
28280
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", disabled: clarificationSubmitting, onClick: () => void respondToClarification("cancel"), children: t("cancelTask") })
|
|
27335
28281
|
] })
|
|
27336
28282
|
] }) : null,
|
|
28283
|
+
processing ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "composer-notice", role: "status", children: t("processingAttachments") }) : null,
|
|
28284
|
+
snapshot.queuedInputs?.map((input) => /* @__PURE__ */ jsxRuntimeExports.jsx(QueuedInput, { input, onSave: (content, version) => client.editInput(input.id, version, content), onCancel: () => client.cancelInput(input.id, input.version) }, `${snapshot.sessionKey}:${input.id}`)),
|
|
27337
28285
|
snapshot.pendingDelivery ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "composer-notice", role: "status", children: t("queuedMessageNotice") }) : null,
|
|
27338
28286
|
error || !connectionProblem && snapshot.error ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "composer-error", role: "alert", children: [
|
|
27339
28287
|
/* @__PURE__ */ jsxRuntimeExports.jsx(AlertIcon, {}),
|
|
27340
28288
|
error || snapshot.error
|
|
27341
28289
|
] }) : null,
|
|
27342
|
-
|
|
27343
|
-
pageContext
|
|
28290
|
+
pageContexts.length || attachments.length ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "composer-contexts", children: [
|
|
28291
|
+
pageContexts.map((pageContext) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `context-chip${pageContext.stale ? " stale" : ""}`, children: [
|
|
27344
28292
|
pageContext.context.selection ? /* @__PURE__ */ jsxRuntimeExports.jsx(SelectionIcon, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(PageIcon, {}),
|
|
27345
28293
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
27346
28294
|
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: pageContext.source === "tab_mention" ? t("tab") : pageContext.context.selection ? t("selection") : t("page") }),
|
|
@@ -27349,15 +28297,21 @@ function ChatPanel() {
|
|
|
27349
28297
|
" · ",
|
|
27350
28298
|
pageContext.context.title
|
|
27351
28299
|
] }),
|
|
27352
|
-
|
|
27353
|
-
|
|
27354
|
-
|
|
28300
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", onClick: () => setPreview({ title: pageContext.context.title, text: `${pageContext.context.url}
|
|
28301
|
+
|
|
28302
|
+
${pageContext.context.selection ?? pageContext.context.text ?? ""}` }), children: t("preview") }),
|
|
28303
|
+
pageContext.context.truncated ? /* @__PURE__ */ jsxRuntimeExports.jsx("small", { children: t("truncated") }) : null,
|
|
28304
|
+
pageContext.stale ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", disabled: processing, onClick: () => void refreshPageContext(pageContext), children: t("refresh") }) : null,
|
|
28305
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "chip-remove", "aria-label": t("removePageContext"), onClick: () => updateDraft((current) => ({ ...current, pages: current.pages.filter((page) => page.context.sourceId !== pageContext.context.sourceId) })), children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, {}) })
|
|
28306
|
+
] }, pageContext.context.sourceId)),
|
|
27355
28307
|
attachments.map((attachment, index) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "attachment-chip", children: [
|
|
27356
|
-
attachment.type === "image" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28308
|
+
attachment.type === "image" ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "attachment-thumbnail", "aria-label": t("preview"), onClick: () => setPreview({ title: attachment.name, image: `data:${attachment.mimeType};base64,${attachment.data}` }), children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: `data:${attachment.mimeType};base64,${attachment.data}`, alt: attachment.name }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(FileIcon, {}),
|
|
27357
28309
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
27358
28310
|
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: attachment.type === "image" ? t("image") : t("file") }),
|
|
27359
28311
|
" · ",
|
|
27360
|
-
attachment.name
|
|
28312
|
+
attachment.name,
|
|
28313
|
+
" · ",
|
|
28314
|
+
formatFileSize(attachment.size)
|
|
27361
28315
|
] }),
|
|
27362
28316
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "chip-remove", "aria-label": t("removeAttachment", attachment.name), onClick: () => setAttachments((current) => current.filter((_, candidate) => candidate !== index)), children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, {}) })
|
|
27363
28317
|
] }, `${attachment.name}-${index}`))
|
|
@@ -27369,7 +28323,7 @@ function ChatPanel() {
|
|
|
27369
28323
|
className: "file-input",
|
|
27370
28324
|
type: "file",
|
|
27371
28325
|
multiple: true,
|
|
27372
|
-
accept:
|
|
28326
|
+
accept: BROWSER_ATTACHMENT_ACCEPT,
|
|
27373
28327
|
onChange: (event) => void addFiles(event.target.files)
|
|
27374
28328
|
}
|
|
27375
28329
|
),
|
|
@@ -27394,22 +28348,71 @@ function ChatPanel() {
|
|
|
27394
28348
|
},
|
|
27395
28349
|
tab.id
|
|
27396
28350
|
)) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "tab-mention-empty", children: t("noMatchingTabs") }) }) : null,
|
|
28351
|
+
commandRange ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "tab-mention-menu", role: "listbox", "aria-label": t("commandsAndSkills"), children: [
|
|
28352
|
+
commandsLoading ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "message-skeleton", "aria-label": t("loadingCommands"), children: [
|
|
28353
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", {}),
|
|
28354
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", {}),
|
|
28355
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", {})
|
|
28356
|
+
] }) : commandItems.map((item, index) => /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", role: "option", "aria-selected": index === commandIndex, disabled: item.disabled, title: item.disabled ? t("skillUnavailable") : item.description, className: index === commandIndex ? "selected" : "", onMouseDown: (event) => {
|
|
28357
|
+
event.preventDefault();
|
|
28358
|
+
chooseCommand(item);
|
|
28359
|
+
}, children: [
|
|
28360
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: item.name }),
|
|
28361
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("small", { children: [
|
|
28362
|
+
item.description,
|
|
28363
|
+
item.disabled ? ` · ${t("skillUnavailable")}` : ""
|
|
28364
|
+
] })
|
|
28365
|
+
] }, item.id)),
|
|
28366
|
+
!commandsLoading && !commandItems.length ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "tab-mention-empty", children: t("noMatchingCommands") }) : null
|
|
28367
|
+
] }) : null,
|
|
27397
28368
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "composer-input-row", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
27398
28369
|
"textarea",
|
|
27399
28370
|
{
|
|
27400
28371
|
ref: textarea,
|
|
27401
28372
|
value: draft,
|
|
27402
28373
|
onChange: (event) => {
|
|
28374
|
+
historyWalk.current = void 0;
|
|
27403
28375
|
setDraft(event.target.value);
|
|
27404
28376
|
void updateTabMention(event.target.value, event.target.selectionStart);
|
|
27405
28377
|
},
|
|
27406
28378
|
onSelect: (event) => void updateTabMention(event.currentTarget.value, event.currentTarget.selectionStart),
|
|
27407
28379
|
onPaste: (event) => {
|
|
27408
|
-
if (
|
|
27409
|
-
|
|
27410
|
-
|
|
28380
|
+
if (event.clipboardData.files.length) {
|
|
28381
|
+
event.preventDefault();
|
|
28382
|
+
void addFiles(event.clipboardData.files);
|
|
28383
|
+
return;
|
|
28384
|
+
}
|
|
28385
|
+
const pasted = classifyPastedText(event.clipboardData.getData("text/plain"));
|
|
28386
|
+
if (pasted) {
|
|
28387
|
+
event.preventDefault();
|
|
28388
|
+
void addFiles([new File([pasted.text], pasted.name, { type: pasted.mimeType })]);
|
|
28389
|
+
}
|
|
28390
|
+
},
|
|
28391
|
+
onCompositionStart: () => {
|
|
28392
|
+
composing.current = true;
|
|
28393
|
+
},
|
|
28394
|
+
onCompositionEnd: () => {
|
|
28395
|
+
composing.current = false;
|
|
27411
28396
|
},
|
|
27412
28397
|
onKeyDown: (event) => {
|
|
28398
|
+
if (composing.current || event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) return;
|
|
28399
|
+
if (commandRange) {
|
|
28400
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
28401
|
+
event.preventDefault();
|
|
28402
|
+
if (commandItems.length) setCommandIndex((current) => (current + (event.key === "ArrowDown" ? 1 : -1) + commandItems.length) % commandItems.length);
|
|
28403
|
+
return;
|
|
28404
|
+
}
|
|
28405
|
+
if (event.key === "Escape") {
|
|
28406
|
+
event.preventDefault();
|
|
28407
|
+
setCommandsOpen(false);
|
|
28408
|
+
return;
|
|
28409
|
+
}
|
|
28410
|
+
if (event.key === "Enter" || event.key === "Tab") {
|
|
28411
|
+
event.preventDefault();
|
|
28412
|
+
if (commandItems[commandIndex]) chooseCommand(commandItems[commandIndex]);
|
|
28413
|
+
return;
|
|
28414
|
+
}
|
|
28415
|
+
}
|
|
27413
28416
|
if (tabMention) {
|
|
27414
28417
|
if (event.key === "ArrowDown" && mentionTabs.length) {
|
|
27415
28418
|
event.preventDefault();
|
|
@@ -27435,18 +28438,35 @@ function ChatPanel() {
|
|
|
27435
28438
|
return;
|
|
27436
28439
|
}
|
|
27437
28440
|
}
|
|
28441
|
+
if ((event.key === "ArrowUp" || event.key === "ArrowDown") && !event.shiftKey && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
28442
|
+
const input = event.currentTarget;
|
|
28443
|
+
const walk = historyWalk.current;
|
|
28444
|
+
if (walk || event.key === "ArrowUp" && input.selectionStart === 0 && input.selectionEnd === 0) {
|
|
28445
|
+
const history = walk ?? { items: snapshot.messages.filter((message) => message.role === "user" && message.text.trim()).map((message) => message.text).reverse(), index: -1, draft };
|
|
28446
|
+
const index = event.key === "ArrowUp" ? Math.min(history.index + 1, history.items.length - 1) : history.index - 1;
|
|
28447
|
+
if (index >= 0 || walk) {
|
|
28448
|
+
event.preventDefault();
|
|
28449
|
+
historyWalk.current = index >= 0 ? { ...history, index } : void 0;
|
|
28450
|
+
setDraft(index >= 0 ? history.items[index] : history.draft);
|
|
28451
|
+
requestAnimationFrame(() => textarea.current?.setSelectionRange(0, 0));
|
|
28452
|
+
return;
|
|
28453
|
+
}
|
|
28454
|
+
}
|
|
28455
|
+
}
|
|
27438
28456
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
27439
28457
|
event.preventDefault();
|
|
27440
|
-
event.
|
|
28458
|
+
if ((event.ctrlKey || event.metaKey) && snapshot.runId) void submit(event, true);
|
|
28459
|
+
else event.currentTarget.form?.requestSubmit();
|
|
27441
28460
|
}
|
|
27442
28461
|
},
|
|
27443
28462
|
onBlur: () => {
|
|
28463
|
+
setCommandsOpen(false);
|
|
27444
28464
|
mentionRequest.current += 1;
|
|
27445
28465
|
setTabMention(void 0);
|
|
27446
28466
|
setMentionTabs([]);
|
|
27447
28467
|
},
|
|
27448
28468
|
placeholder: t("composerPlaceholder"),
|
|
27449
|
-
disabled: snapshot.submitting,
|
|
28469
|
+
disabled: !draftReady || sending || snapshot.submitting || snapshot.sessionLoading || processing,
|
|
27450
28470
|
rows: 1
|
|
27451
28471
|
}
|
|
27452
28472
|
) }),
|
|
@@ -27545,11 +28565,19 @@ function ChatPanel() {
|
|
|
27545
28565
|
] })
|
|
27546
28566
|
] }),
|
|
27547
28567
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "composer-toolbar-end", children: [
|
|
27548
|
-
|
|
27549
|
-
|
|
27550
|
-
|
|
27551
|
-
|
|
27552
|
-
|
|
28568
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ModelControls, { models: snapshot.models, config: snapshot.modelConfig, disabled: sending || processing || voiceBusy || snapshot.submitting || snapshot.sessionLoading || Boolean(snapshot.runId), onModel: (model) => updateModelConfig(async () => {
|
|
28569
|
+
if (!client.currentSessionKey) {
|
|
28570
|
+
const payload = drafts.get(draftKey);
|
|
28571
|
+
await client.createSession();
|
|
28572
|
+
drafts.update(keyForSession(client.currentSessionKey), () => payload);
|
|
28573
|
+
drafts.update(draftKey, () => EMPTY_DRAFT);
|
|
28574
|
+
}
|
|
28575
|
+
await client.updateModel(model);
|
|
28576
|
+
}), onThinking: (level) => updateModelConfig(() => client.updateThinking(level)) }, draftKey),
|
|
28577
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(VoiceInput, { disabled: sending || processing || snapshot.submitting || snapshot.sessionLoading || !draftReady || !snapshot.endpointReady, onBusy: setVoiceBusy, onTranscript: (text) => updateDraft((current) => ({ ...current, text: current.text.trim() ? `${current.text} ${text}` : text })) }, `voice:${draftKey}`),
|
|
28578
|
+
snapshot.runId && (draft.trim() || attachments.length) ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "composer-icon-button", disabled: !canSend, title: t("interruptSend"), "aria-label": t("interruptSend"), onClick: (event) => void submit(event, true), children: /* @__PURE__ */ jsxRuntimeExports.jsx(SendIcon, {}) }) : null,
|
|
28579
|
+
snapshot.runId ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "send-button stop-button", "aria-label": t("stopResponse"), title: snapshot.stopping ? t("stoppingResponse") : t("stopResponse"), disabled: snapshot.stopping, onClick: () => void runControlAction(() => client.abort()), children: /* @__PURE__ */ jsxRuntimeExports.jsx(StopIcon, {}) }) : null,
|
|
28580
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "send-button", type: "submit", "aria-label": snapshot.runId ? t("queueMessage") : t("sendMessage"), title: snapshot.runId ? t("queueMessage") : t("sendMessage"), disabled: !canSend || !draft.trim() && attachments.length === 0 || Boolean(tabMention) || Boolean(commandRange), children: /* @__PURE__ */ jsxRuntimeExports.jsx(SendIcon, {}) })
|
|
27553
28581
|
] })
|
|
27554
28582
|
] })
|
|
27555
28583
|
]
|
|
@@ -27809,7 +28837,7 @@ function SidePanelApp({ initialLocale, initialTheme }) {
|
|
|
27809
28837
|
invitation ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => void cancelPairing(), disabled: state === "pairing", children: t("cancelPairing") }) : null
|
|
27810
28838
|
] })
|
|
27811
28839
|
] }) : null
|
|
27812
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChatPanel, {})
|
|
28840
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChatPanel, { gatewayId: profile.gatewayId }, profile.gatewayId)
|
|
27813
28841
|
] });
|
|
27814
28842
|
}
|
|
27815
28843
|
|
|
@@ -27820,5 +28848,5 @@ const [locale, theme] = await Promise.all([
|
|
|
27820
28848
|
loadSidePanelThemePreference()
|
|
27821
28849
|
]);
|
|
27822
28850
|
clientExports.createRoot(root).render(
|
|
27823
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.StrictMode, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(SidePanelApp, { initialLocale: locale, initialTheme: theme }) })
|
|
28851
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.StrictMode, { children: new URLSearchParams(location.search).has("microphone-permission") ? /* @__PURE__ */ jsxRuntimeExports.jsx(MicrophonePermission, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(SidePanelApp, { initialLocale: locale, initialTheme: theme }) })
|
|
27824
28852
|
);
|