@fraziym/axoniz 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/agents/definition.d.ts +15 -0
- package/dist/agents/definition.d.ts.map +1 -0
- package/dist/agents/definition.js +41 -0
- package/dist/agents/definition.js.map +1 -0
- package/dist/agents/index.d.ts +12 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +11 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/registry.d.ts +17 -0
- package/dist/agents/registry.d.ts.map +1 -0
- package/dist/agents/registry.js +23 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/specialized.d.ts +31 -0
- package/dist/agents/specialized.d.ts.map +1 -0
- package/dist/agents/specialized.js +75 -0
- package/dist/agents/specialized.js.map +1 -0
- package/dist/awareness/index.d.ts +14 -0
- package/dist/awareness/index.d.ts.map +1 -0
- package/dist/awareness/index.js +22 -0
- package/dist/awareness/index.js.map +1 -0
- package/dist/awareness/service.d.ts +180 -0
- package/dist/awareness/service.d.ts.map +1 -0
- package/dist/awareness/service.js +789 -0
- package/dist/awareness/service.js.map +1 -0
- package/dist/cli/entry.d.ts +13 -0
- package/dist/cli/entry.d.ts.map +1 -0
- package/dist/cli/entry.js +35 -0
- package/dist/cli/entry.js.map +1 -0
- package/dist/comms/telegram.d.ts +41 -0
- package/dist/comms/telegram.d.ts.map +1 -0
- package/dist/comms/telegram.js +332 -0
- package/dist/comms/telegram.js.map +1 -0
- package/dist/core/agent.d.ts +252 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +1399 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/auth.d.ts +23 -0
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/core/auth.js +113 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/authority.d.ts +118 -0
- package/dist/core/authority.d.ts.map +1 -0
- package/dist/core/authority.js +402 -0
- package/dist/core/authority.js.map +1 -0
- package/dist/core/backend/async_queue.d.ts +17 -0
- package/dist/core/backend/async_queue.d.ts.map +1 -0
- package/dist/core/backend/async_queue.js +66 -0
- package/dist/core/backend/async_queue.js.map +1 -0
- package/dist/core/backend/index.d.ts +24 -0
- package/dist/core/backend/index.d.ts.map +1 -0
- package/dist/core/backend/index.js +128 -0
- package/dist/core/backend/index.js.map +1 -0
- package/dist/core/backend/llama_server.d.ts +39 -0
- package/dist/core/backend/llama_server.d.ts.map +1 -0
- package/dist/core/backend/llama_server.js +182 -0
- package/dist/core/backend/llama_server.js.map +1 -0
- package/dist/core/backend/llamacpp.d.ts +40 -0
- package/dist/core/backend/llamacpp.d.ts.map +1 -0
- package/dist/core/backend/llamacpp.js +200 -0
- package/dist/core/backend/llamacpp.js.map +1 -0
- package/dist/core/backend/lmstudio.d.ts +53 -0
- package/dist/core/backend/lmstudio.d.ts.map +1 -0
- package/dist/core/backend/lmstudio.js +274 -0
- package/dist/core/backend/lmstudio.js.map +1 -0
- package/dist/core/backend/ollama.d.ts +25 -0
- package/dist/core/backend/ollama.d.ts.map +1 -0
- package/dist/core/backend/ollama.js +86 -0
- package/dist/core/backend/ollama.js.map +1 -0
- package/dist/core/backend/openai.d.ts +27 -0
- package/dist/core/backend/openai.d.ts.map +1 -0
- package/dist/core/backend/openai.js +84 -0
- package/dist/core/backend/openai.js.map +1 -0
- package/dist/core/backend/types.d.ts +73 -0
- package/dist/core/backend/types.d.ts.map +1 -0
- package/dist/core/backend/types.js +137 -0
- package/dist/core/backend/types.js.map +1 -0
- package/dist/core/chat_store.d.ts +77 -0
- package/dist/core/chat_store.d.ts.map +1 -0
- package/dist/core/chat_store.js +332 -0
- package/dist/core/chat_store.js.map +1 -0
- package/dist/core/cli.d.ts +82 -0
- package/dist/core/cli.d.ts.map +1 -0
- package/dist/core/cli.js +602 -0
- package/dist/core/cli.js.map +1 -0
- package/dist/core/config.d.ts +127 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +295 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/debug.d.ts +8 -0
- package/dist/core/debug.d.ts.map +1 -0
- package/dist/core/debug.js +8 -0
- package/dist/core/debug.js.map +1 -0
- package/dist/core/downloader.d.ts +31 -0
- package/dist/core/downloader.d.ts.map +1 -0
- package/dist/core/downloader.js +180 -0
- package/dist/core/downloader.js.map +1 -0
- package/dist/core/errors.d.ts +80 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +134 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/extras.d.ts +160 -0
- package/dist/core/extras.d.ts.map +1 -0
- package/dist/core/extras.js +553 -0
- package/dist/core/extras.js.map +1 -0
- package/dist/core/health.d.ts +27 -0
- package/dist/core/health.d.ts.map +1 -0
- package/dist/core/health.js +96 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/history.d.ts +50 -0
- package/dist/core/history.d.ts.map +1 -0
- package/dist/core/history.js +276 -0
- package/dist/core/history.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/intelligence/ast_index.d.ts +255 -0
- package/dist/core/intelligence/ast_index.d.ts.map +1 -0
- package/dist/core/intelligence/ast_index.js +1369 -0
- package/dist/core/intelligence/ast_index.js.map +1 -0
- package/dist/core/intelligence/confidence.d.ts +113 -0
- package/dist/core/intelligence/confidence.d.ts.map +1 -0
- package/dist/core/intelligence/confidence.js +298 -0
- package/dist/core/intelligence/confidence.js.map +1 -0
- package/dist/core/intelligence/context_compressor.d.ts +80 -0
- package/dist/core/intelligence/context_compressor.d.ts.map +1 -0
- package/dist/core/intelligence/context_compressor.js +245 -0
- package/dist/core/intelligence/context_compressor.js.map +1 -0
- package/dist/core/intelligence/daemon.d.ts +247 -0
- package/dist/core/intelligence/daemon.d.ts.map +1 -0
- package/dist/core/intelligence/daemon.js +842 -0
- package/dist/core/intelligence/daemon.js.map +1 -0
- package/dist/core/intelligence/index.d.ts +60 -0
- package/dist/core/intelligence/index.d.ts.map +1 -0
- package/dist/core/intelligence/index.js +101 -0
- package/dist/core/intelligence/index.js.map +1 -0
- package/dist/core/intelligence/predictor.d.ts +246 -0
- package/dist/core/intelligence/predictor.d.ts.map +1 -0
- package/dist/core/intelligence/predictor.js +590 -0
- package/dist/core/intelligence/predictor.js.map +1 -0
- package/dist/core/intelligence/reflex.d.ts +84 -0
- package/dist/core/intelligence/reflex.d.ts.map +1 -0
- package/dist/core/intelligence/reflex.js +344 -0
- package/dist/core/intelligence/reflex.js.map +1 -0
- package/dist/core/intelligence/self_correction.d.ts +121 -0
- package/dist/core/intelligence/self_correction.d.ts.map +1 -0
- package/dist/core/intelligence/self_correction.js +327 -0
- package/dist/core/intelligence/self_correction.js.map +1 -0
- package/dist/core/intelligence/skill_distiller.d.ts +100 -0
- package/dist/core/intelligence/skill_distiller.d.ts.map +1 -0
- package/dist/core/intelligence/skill_distiller.js +246 -0
- package/dist/core/intelligence/skill_distiller.js.map +1 -0
- package/dist/core/intelligence/swarm.d.ts +330 -0
- package/dist/core/intelligence/swarm.d.ts.map +1 -0
- package/dist/core/intelligence/swarm.js +1064 -0
- package/dist/core/intelligence/swarm.js.map +1 -0
- package/dist/core/intelligence/trajectory.d.ts +107 -0
- package/dist/core/intelligence/trajectory.d.ts.map +1 -0
- package/dist/core/intelligence/trajectory.js +330 -0
- package/dist/core/intelligence/trajectory.js.map +1 -0
- package/dist/core/logger.d.ts +111 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +640 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/loop.d.ts +123 -0
- package/dist/core/loop.d.ts.map +1 -0
- package/dist/core/loop.js +423 -0
- package/dist/core/loop.js.map +1 -0
- package/dist/core/memory.d.ts +81 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +328 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/metrics.d.ts +29 -0
- package/dist/core/metrics.d.ts.map +1 -0
- package/dist/core/metrics.js +109 -0
- package/dist/core/metrics.js.map +1 -0
- package/dist/core/models.d.ts +51 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +146 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/optimizer.d.ts +34 -0
- package/dist/core/optimizer.d.ts.map +1 -0
- package/dist/core/optimizer.js +131 -0
- package/dist/core/optimizer.js.map +1 -0
- package/dist/core/persona.d.ts +35 -0
- package/dist/core/persona.d.ts.map +1 -0
- package/dist/core/persona.js +126 -0
- package/dist/core/persona.js.map +1 -0
- package/dist/core/rate_limit.d.ts +23 -0
- package/dist/core/rate_limit.d.ts.map +1 -0
- package/dist/core/rate_limit.js +62 -0
- package/dist/core/rate_limit.js.map +1 -0
- package/dist/core/runner.d.ts +63 -0
- package/dist/core/runner.d.ts.map +1 -0
- package/dist/core/runner.js +671 -0
- package/dist/core/runner.js.map +1 -0
- package/dist/core/stream_parser.d.ts +43 -0
- package/dist/core/stream_parser.d.ts.map +1 -0
- package/dist/core/stream_parser.js +140 -0
- package/dist/core/stream_parser.js.map +1 -0
- package/dist/core/tool_schemas.d.ts +26 -0
- package/dist/core/tool_schemas.d.ts.map +1 -0
- package/dist/core/tool_schemas.js +124 -0
- package/dist/core/tool_schemas.js.map +1 -0
- package/dist/core/which.d.ts +2 -0
- package/dist/core/which.d.ts.map +1 -0
- package/dist/core/which.js +35 -0
- package/dist/core/which.js.map +1 -0
- package/dist/goals/index.d.ts +9 -0
- package/dist/goals/index.d.ts.map +1 -0
- package/dist/goals/index.js +17 -0
- package/dist/goals/index.js.map +1 -0
- package/dist/goals/service.d.ts +115 -0
- package/dist/goals/service.d.ts.map +1 -0
- package/dist/goals/service.js +415 -0
- package/dist/goals/service.js.map +1 -0
- package/dist/goals/types.d.ts +47 -0
- package/dist/goals/types.d.ts.map +1 -0
- package/dist/goals/types.js +66 -0
- package/dist/goals/types.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/autonomous_startup.d.ts +51 -0
- package/dist/integrations/autonomous_startup.d.ts.map +1 -0
- package/dist/integrations/autonomous_startup.js +419 -0
- package/dist/integrations/autonomous_startup.js.map +1 -0
- package/dist/integrations/goose.d.ts +105 -0
- package/dist/integrations/goose.d.ts.map +1 -0
- package/dist/integrations/goose.js +408 -0
- package/dist/integrations/goose.js.map +1 -0
- package/dist/integrations/index.d.ts +21 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +17 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/mcp.d.ts +73 -0
- package/dist/integrations/mcp.d.ts.map +1 -0
- package/dist/integrations/mcp.js +307 -0
- package/dist/integrations/mcp.js.map +1 -0
- package/dist/integrations/mempalace.d.ts +18 -0
- package/dist/integrations/mempalace.d.ts.map +1 -0
- package/dist/integrations/mempalace.js +25 -0
- package/dist/integrations/mempalace.js.map +1 -0
- package/dist/integrations/multi_agent.d.ts +82 -0
- package/dist/integrations/multi_agent.d.ts.map +1 -0
- package/dist/integrations/multi_agent.js +280 -0
- package/dist/integrations/multi_agent.js.map +1 -0
- package/dist/integrations/unified_memory.d.ts +415 -0
- package/dist/integrations/unified_memory.d.ts.map +1 -0
- package/dist/integrations/unified_memory.js +1489 -0
- package/dist/integrations/unified_memory.js.map +1 -0
- package/dist/roles/beru.yaml +48 -0
- package/dist/sidecar/client.d.ts +63 -0
- package/dist/sidecar/client.d.ts.map +1 -0
- package/dist/sidecar/client.js +222 -0
- package/dist/sidecar/client.js.map +1 -0
- package/dist/sidecar/index.d.ts +7 -0
- package/dist/sidecar/index.d.ts.map +1 -0
- package/dist/sidecar/index.js +6 -0
- package/dist/sidecar/index.js.map +1 -0
- package/dist/startup.d.ts +22 -0
- package/dist/startup.d.ts.map +1 -0
- package/dist/startup.js +194 -0
- package/dist/startup.js.map +1 -0
- package/dist/tools/_internal.d.ts +90 -0
- package/dist/tools/_internal.d.ts.map +1 -0
- package/dist/tools/_internal.js +375 -0
- package/dist/tools/_internal.js.map +1 -0
- package/dist/tools/_smoke.d.ts +2 -0
- package/dist/tools/_smoke.d.ts.map +1 -0
- package/dist/tools/_smoke.js +203 -0
- package/dist/tools/_smoke.js.map +1 -0
- package/dist/tools/axodex_tools.d.ts +51 -0
- package/dist/tools/axodex_tools.d.ts.map +1 -0
- package/dist/tools/axodex_tools.js +181 -0
- package/dist/tools/axodex_tools.js.map +1 -0
- package/dist/tools/code_tools.d.ts +33 -0
- package/dist/tools/code_tools.d.ts.map +1 -0
- package/dist/tools/code_tools.js +191 -0
- package/dist/tools/code_tools.js.map +1 -0
- package/dist/tools/computer_tools.d.ts +59 -0
- package/dist/tools/computer_tools.d.ts.map +1 -0
- package/dist/tools/computer_tools.js +348 -0
- package/dist/tools/computer_tools.js.map +1 -0
- package/dist/tools/file_tools.d.ts +51 -0
- package/dist/tools/file_tools.d.ts.map +1 -0
- package/dist/tools/file_tools.js +424 -0
- package/dist/tools/file_tools.js.map +1 -0
- package/dist/tools/index.d.ts +13 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +13 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/shell_tools.d.ts +39 -0
- package/dist/tools/shell_tools.d.ts.map +1 -0
- package/dist/tools/shell_tools.js +163 -0
- package/dist/tools/shell_tools.js.map +1 -0
- package/dist/tools/web_tools.d.ts +31 -0
- package/dist/tools/web_tools.d.ts.map +1 -0
- package/dist/tools/web_tools.js +117 -0
- package/dist/tools/web_tools.js.map +1 -0
- package/dist/voice/index.d.ts +41 -0
- package/dist/voice/index.d.ts.map +1 -0
- package/dist/voice/index.js +58 -0
- package/dist/voice/index.js.map +1 -0
- package/dist/voice/light_daemon.d.ts +197 -0
- package/dist/voice/light_daemon.d.ts.map +1 -0
- package/dist/voice/light_daemon.js +746 -0
- package/dist/voice/light_daemon.js.map +1 -0
- package/dist/voice/setup.d.ts +63 -0
- package/dist/voice/setup.d.ts.map +1 -0
- package/dist/voice/setup.js +443 -0
- package/dist/voice/setup.js.map +1 -0
- package/dist/voice/stt.d.ts +148 -0
- package/dist/voice/stt.d.ts.map +1 -0
- package/dist/voice/stt.js +361 -0
- package/dist/voice/stt.js.map +1 -0
- package/dist/voice/tts.d.ts +168 -0
- package/dist/voice/tts.d.ts.map +1 -0
- package/dist/voice/tts.js +698 -0
- package/dist/voice/tts.js.map +1 -0
- package/dist/voice/voice_loop.d.ts +101 -0
- package/dist/voice/voice_loop.d.ts.map +1 -0
- package/dist/voice/voice_loop.js +463 -0
- package/dist/voice/voice_loop.js.map +1 -0
- package/dist/voice/wake_word.d.ts +153 -0
- package/dist/voice/wake_word.d.ts.map +1 -0
- package/dist/voice/wake_word.js +458 -0
- package/dist/voice/wake_word.js.map +1 -0
- package/dist/voice/wav.d.ts +99 -0
- package/dist/voice/wav.d.ts.map +1 -0
- package/dist/voice/wav.js +306 -0
- package/dist/voice/wav.js.map +1 -0
- package/dist/web/broker.d.ts +33 -0
- package/dist/web/broker.d.ts.map +1 -0
- package/dist/web/broker.js +58 -0
- package/dist/web/broker.js.map +1 -0
- package/dist/web/open_browser.d.ts +2 -0
- package/dist/web/open_browser.d.ts.map +1 -0
- package/dist/web/open_browser.js +42 -0
- package/dist/web/open_browser.js.map +1 -0
- package/dist/web/server.d.ts +54 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +831 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/static/app.js +4121 -0
- package/dist/web/static/index.html +2281 -0
- package/dist/web/static/js/MODULE_SUMMARY.md +124 -0
- package/dist/web/static/js/a11y.js +165 -0
- package/dist/web/static/js/admin.js +2145 -0
- package/dist/web/static/js/assistant.js +475 -0
- package/dist/web/static/js/calendar/reminders.js +114 -0
- package/dist/web/static/js/calendar/utils.js +166 -0
- package/dist/web/static/js/calendar.js +3348 -0
- package/dist/web/static/js/censor.js +356 -0
- package/dist/web/static/js/chat.js +4546 -0
- package/dist/web/static/js/chatRenderer.js +2294 -0
- package/dist/web/static/js/chatStream.js +276 -0
- package/dist/web/static/js/codeRunner.js +398 -0
- package/dist/web/static/js/color/hex.js +14 -0
- package/dist/web/static/js/colorPicker.js +453 -0
- package/dist/web/static/js/compare/icons.js +77 -0
- package/dist/web/static/js/compare/index.js +1482 -0
- package/dist/web/static/js/compare/models.js +104 -0
- package/dist/web/static/js/compare/panes.js +817 -0
- package/dist/web/static/js/compare/probe.js +78 -0
- package/dist/web/static/js/compare/scoreboard.js +223 -0
- package/dist/web/static/js/compare/selector.js +1335 -0
- package/dist/web/static/js/compare/state.js +58 -0
- package/dist/web/static/js/compare/stream.js +695 -0
- package/dist/web/static/js/compare/vote.js +254 -0
- package/dist/web/static/js/cookbook-diagnosis.js +694 -0
- package/dist/web/static/js/cookbook-hwfit.js +1888 -0
- package/dist/web/static/js/cookbook.js +2093 -0
- package/dist/web/static/js/cookbookDownload.js +633 -0
- package/dist/web/static/js/cookbookProgressSignal.js +29 -0
- package/dist/web/static/js/cookbookRunning.js +3506 -0
- package/dist/web/static/js/cookbookServe.js +2128 -0
- package/dist/web/static/js/document.js +9731 -0
- package/dist/web/static/js/documentLibrary.js +3376 -0
- package/dist/web/static/js/dragSort.js +265 -0
- package/dist/web/static/js/editor/ai-inpaint.js +374 -0
- package/dist/web/static/js/editor/ai-models.js +273 -0
- package/dist/web/static/js/editor/ai-rembg.js +230 -0
- package/dist/web/static/js/editor/ai-tool-runner.js +147 -0
- package/dist/web/static/js/editor/ai-tools-misc.js +216 -0
- package/dist/web/static/js/editor/build/controls.js +366 -0
- package/dist/web/static/js/editor/build/popups.js +112 -0
- package/dist/web/static/js/editor/build/right-panel.js +200 -0
- package/dist/web/static/js/editor/build/toolbar.js +73 -0
- package/dist/web/static/js/editor/build/topbar.js +131 -0
- package/dist/web/static/js/editor/build/transform-popup.js +109 -0
- package/dist/web/static/js/editor/canvas-coords.js +21 -0
- package/dist/web/static/js/editor/canvas-events.js +197 -0
- package/dist/web/static/js/editor/canvas-transforms.js +132 -0
- package/dist/web/static/js/editor/checkerboard.js +24 -0
- package/dist/web/static/js/editor/clipboard-and-drop.js +133 -0
- package/dist/web/static/js/editor/composite-helpers.js +83 -0
- package/dist/web/static/js/editor/filters/blur.js +118 -0
- package/dist/web/static/js/editor/filters/edge-feather.js +70 -0
- package/dist/web/static/js/editor/fx/adj-popup.js +677 -0
- package/dist/web/static/js/editor/fx/filter-string.js +38 -0
- package/dist/web/static/js/editor/fx/histogram.js +67 -0
- package/dist/web/static/js/editor/fx/pixel-pass.js +249 -0
- package/dist/web/static/js/editor/harmonize-masks.js +116 -0
- package/dist/web/static/js/editor/history-panel.js +176 -0
- package/dist/web/static/js/editor/keyboard-shortcuts.js +271 -0
- package/dist/web/static/js/editor/layer-helpers.js +131 -0
- package/dist/web/static/js/editor/layer-panel.js +600 -0
- package/dist/web/static/js/editor/mask-utils.js +91 -0
- package/dist/web/static/js/editor/shortcuts-popover.js +149 -0
- package/dist/web/static/js/editor/slider-ux.js +191 -0
- package/dist/web/static/js/editor/snap.js +107 -0
- package/dist/web/static/js/editor/state.js +257 -0
- package/dist/web/static/js/editor/stroke-pipeline.js +162 -0
- package/dist/web/static/js/editor/stroke-tool-sliders.js +64 -0
- package/dist/web/static/js/editor/tools/clone.js +81 -0
- package/dist/web/static/js/editor/tools/crop.js +137 -0
- package/dist/web/static/js/editor/tools/flood-fill.js +72 -0
- package/dist/web/static/js/editor/tools/lasso-mask.js +171 -0
- package/dist/web/static/js/editor/tools/lasso.js +65 -0
- package/dist/web/static/js/editor/tools/move.js +79 -0
- package/dist/web/static/js/editor/tools/stroke.js +123 -0
- package/dist/web/static/js/editor/tools/transform-drag.js +174 -0
- package/dist/web/static/js/editor/tools/transform-handles.js +271 -0
- package/dist/web/static/js/editor/tools/transform-session.js +381 -0
- package/dist/web/static/js/editor/tools/wand.js +46 -0
- package/dist/web/static/js/editor/wire-import.js +148 -0
- package/dist/web/static/js/editor/wire-inpaint-controls.js +164 -0
- package/dist/web/static/js/editor/wire-merge-buttons.js +103 -0
- package/dist/web/static/js/editor/wire-selection-controls.js +170 -0
- package/dist/web/static/js/editor/wire-topbar-menus.js +174 -0
- package/dist/web/static/js/editor/wire-topbar-overflow.js +49 -0
- package/dist/web/static/js/editor/wire-topbar.js +188 -0
- package/dist/web/static/js/emailInbox.js +1245 -0
- package/dist/web/static/js/emailLibrary/replyRecipients.js +27 -0
- package/dist/web/static/js/emailLibrary/signatureFold.js +339 -0
- package/dist/web/static/js/emailLibrary/state.js +34 -0
- package/dist/web/static/js/emailLibrary/utils.js +202 -0
- package/dist/web/static/js/emailLibrary.js +5217 -0
- package/dist/web/static/js/emojiPicker.js +311 -0
- package/dist/web/static/js/escMenuStack.js +102 -0
- package/dist/web/static/js/fileHandler.js +295 -0
- package/dist/web/static/js/gallery.js +2835 -0
- package/dist/web/static/js/galleryEditor.js +3798 -0
- package/dist/web/static/js/group.js +955 -0
- package/dist/web/static/js/init.js +405 -0
- package/dist/web/static/js/keyboard-shortcuts.js +292 -0
- package/dist/web/static/js/langIcons.js +187 -0
- package/dist/web/static/js/markdown/tableRow.js +19 -0
- package/dist/web/static/js/markdown.js +806 -0
- package/dist/web/static/js/memory.js +1418 -0
- package/dist/web/static/js/modalManager.js +1552 -0
- package/dist/web/static/js/modalSnap.js +782 -0
- package/dist/web/static/js/model/matchKey.js +19 -0
- package/dist/web/static/js/modelPicker.js +695 -0
- package/dist/web/static/js/modelSort.js +33 -0
- package/dist/web/static/js/models.js +642 -0
- package/dist/web/static/js/notes.js +5054 -0
- package/dist/web/static/js/package.json +1 -0
- package/dist/web/static/js/platform.js +47 -0
- package/dist/web/static/js/presets.js +1110 -0
- package/dist/web/static/js/providers.js +93 -0
- package/dist/web/static/js/rag.js +177 -0
- package/dist/web/static/js/research/jobs.js +335 -0
- package/dist/web/static/js/research/panel.js +1233 -0
- package/dist/web/static/js/researchSynapse.js +225 -0
- package/dist/web/static/js/search-chat.js +201 -0
- package/dist/web/static/js/search.js +52 -0
- package/dist/web/static/js/section-management.js +260 -0
- package/dist/web/static/js/sessions.js +3108 -0
- package/dist/web/static/js/settings.js +4991 -0
- package/dist/web/static/js/sidebar-layout.js +573 -0
- package/dist/web/static/js/signature.js +504 -0
- package/dist/web/static/js/skills.js +1908 -0
- package/dist/web/static/js/slashAutocomplete.js +267 -0
- package/dist/web/static/js/slashCommands.js +6099 -0
- package/dist/web/static/js/spinner.js +406 -0
- package/dist/web/static/js/storage.js +123 -0
- package/dist/web/static/js/tasks.js +2699 -0
- package/dist/web/static/js/theme.js +2086 -0
- package/dist/web/static/js/tileManager.js +386 -0
- package/dist/web/static/js/tourAutoplay.js +133 -0
- package/dist/web/static/js/tourHints.js +179 -0
- package/dist/web/static/js/tts-ai.js +521 -0
- package/dist/web/static/js/ui.js +1288 -0
- package/dist/web/static/js/util/ordinal.js +13 -0
- package/dist/web/static/js/voiceRecorder.js +283 -0
- package/dist/web/static/js/windowDrag.js +326 -0
- package/dist/web/static/js/windowResize.js +233 -0
- package/dist/web/static/landing.html +824 -0
- package/dist/web/static/lib/docx.umd.min.js +20116 -0
- package/dist/web/static/lib/highlight.min.js +1213 -0
- package/dist/web/static/lib/html2pdf.bundle.min.js +3 -0
- package/dist/web/static/lib/mammoth.browser.min.js +21 -0
- package/dist/web/static/lib/qrcode.min.js +8 -0
- package/dist/web/static/lib/xlsx.full.min.js +24 -0
- package/dist/web/static/login.html +582 -0
- package/dist/web/static/manifest.json +15 -0
- package/dist/web/static/style.css +35733 -0
- package/dist/web/static/sw.js +144 -0
- package/dist/workflows/engine.d.ts +162 -0
- package/dist/workflows/engine.d.ts.map +1 -0
- package/dist/workflows/engine.js +625 -0
- package/dist/workflows/engine.js.map +1 -0
- package/dist/workflows/index.d.ts +8 -0
- package/dist/workflows/index.d.ts.map +1 -0
- package/dist/workflows/index.js +14 -0
- package/dist/workflows/index.js.map +1 -0
- package/package.json +112 -0
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
// compare/panes.js — pane lifecycle, actions, layout
|
|
2
|
+
import state from './state.js';
|
|
3
|
+
import { _persistSelections } from './models.js';
|
|
4
|
+
import { buildVoteBar } from './vote.js';
|
|
5
|
+
import {
|
|
6
|
+
ICON_REROLL, ICON_COPY, ICON_EXPAND, ICON_COLLAPSE, ICON_CLOSE,
|
|
7
|
+
ICON_PLAY, ICON_CODE, SEND_SVG,
|
|
8
|
+
} from './icons.js';
|
|
9
|
+
import { _clearProbeWaves } from './probe.js';
|
|
10
|
+
import Storage from '../storage.js';
|
|
11
|
+
import uiModule from '../ui.js';
|
|
12
|
+
import spinnerModule from '../spinner.js';
|
|
13
|
+
import { bindMenuDismiss } from '../escMenuStack.js';
|
|
14
|
+
|
|
15
|
+
var escapeHtml = uiModule.esc;
|
|
16
|
+
|
|
17
|
+
// ── Lazy-registered functions from compare.js (avoids circular imports) ──
|
|
18
|
+
let _setSendBtn = null;
|
|
19
|
+
let _deactivate = null;
|
|
20
|
+
let _streamToPane = null;
|
|
21
|
+
let _renderSearchResults = null;
|
|
22
|
+
let _fetchModels = null;
|
|
23
|
+
|
|
24
|
+
/** Register external functions that live in compare.js or sibling modules. */
|
|
25
|
+
function registerPaneActions({ setSendBtn, deactivate, streamToPane, renderSearchResults, fetchModels }) {
|
|
26
|
+
if (setSendBtn) _setSendBtn = setSendBtn;
|
|
27
|
+
if (deactivate) _deactivate = deactivate;
|
|
28
|
+
if (streamToPane) _streamToPane = streamToPane;
|
|
29
|
+
if (renderSearchResults) _renderSearchResults = renderSearchResults;
|
|
30
|
+
if (fetchModels) _fetchModels = fetchModels;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Slot label: A/B/C in parallel mode, 1/2/3 in sequential. */
|
|
34
|
+
function _slotChar(i) { return state._parallel ? String.fromCharCode(65 + i) : String(i + 1); }
|
|
35
|
+
|
|
36
|
+
// ── Stop / reroll ──
|
|
37
|
+
|
|
38
|
+
function stopAll() {
|
|
39
|
+
state._abortControllers.forEach(ac => { if (ac) ac.abort(); });
|
|
40
|
+
state._abortControllers = [];
|
|
41
|
+
state._streaming = false;
|
|
42
|
+
if (_setSendBtn) _setSendBtn('send');
|
|
43
|
+
// Re-enable header buttons
|
|
44
|
+
document.querySelectorAll('#compare-shuffle-btn, #compare-check-btn, #compare-add-btn').forEach(b => {
|
|
45
|
+
b.disabled = false; b.style.opacity = '0.7'; b.style.pointerEvents = '';
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function stopPane(paneIdx) {
|
|
50
|
+
const ac = state._abortControllers[paneIdx];
|
|
51
|
+
if (ac) {
|
|
52
|
+
ac.abort();
|
|
53
|
+
state._abortControllers[paneIdx] = null;
|
|
54
|
+
}
|
|
55
|
+
// Hide stop button, show reroll
|
|
56
|
+
const pane = document.querySelector(`.compare-pane[data-pane="${paneIdx}"]`);
|
|
57
|
+
if (pane) {
|
|
58
|
+
const stopBtn = pane.querySelector('.pane-stop-btn');
|
|
59
|
+
if (stopBtn) stopBtn.style.display = 'none';
|
|
60
|
+
pane.querySelectorAll('.pane-needs-response').forEach(b => b.style.display = '');
|
|
61
|
+
}
|
|
62
|
+
// Remove spinner if present
|
|
63
|
+
const hist = document.getElementById('cmp-history-' + paneIdx);
|
|
64
|
+
if (hist) {
|
|
65
|
+
const lastAi = hist.querySelector('.msg-ai:last-child');
|
|
66
|
+
if (lastAi && lastAi._spinner) { lastAi._spinner.destroy(); lastAi._spinner = null; }
|
|
67
|
+
const body = lastAi && lastAi.querySelector('.body');
|
|
68
|
+
if (body && !body.textContent.trim()) {
|
|
69
|
+
body.innerHTML = '<span style="opacity:0.4;font-style:italic;">Stopped</span>';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function rerollPane(paneIdx, overrideTimeout) {
|
|
75
|
+
// Allow reroll even while other panes stream — just stop this pane first
|
|
76
|
+
if (state._abortControllers[paneIdx]) stopPane(paneIdx);
|
|
77
|
+
const hist = document.getElementById('cmp-history-' + paneIdx);
|
|
78
|
+
// Reset preview state
|
|
79
|
+
const _ri = document.getElementById('cmp-iframe-' + paneIdx);
|
|
80
|
+
if (_ri) { _ri.srcdoc = ''; _ri.style.display = 'none'; _ri._htmlCode = null; }
|
|
81
|
+
const _rp = document.getElementById('cmp-preview-' + paneIdx);
|
|
82
|
+
if (_rp) { _rp.style.display = 'none'; _rp.classList.remove('active'); }
|
|
83
|
+
if (hist) hist.style.display = '';
|
|
84
|
+
if (!hist) return;
|
|
85
|
+
const userBodies = hist.querySelectorAll('.msg-user .body');
|
|
86
|
+
const firstUserText = userBodies.length > 0 ? userBodies[0].textContent : '';
|
|
87
|
+
if (!firstUserText) return;
|
|
88
|
+
|
|
89
|
+
// Clear all messages and start fresh
|
|
90
|
+
hist.innerHTML = '';
|
|
91
|
+
const userMsg = document.createElement('div');
|
|
92
|
+
userMsg.className = 'msg msg-user';
|
|
93
|
+
userMsg.innerHTML = '<div class="role">You</div><div class="body">' + escapeHtml(firstUserText) + '</div>';
|
|
94
|
+
hist.appendChild(userMsg);
|
|
95
|
+
|
|
96
|
+
// Reset badge and timer
|
|
97
|
+
const badge = document.getElementById('cmp-badge-' + paneIdx);
|
|
98
|
+
if (badge) { badge.textContent = ''; badge.style.color = ''; }
|
|
99
|
+
const timer = document.getElementById('cmp-timer-' + paneIdx);
|
|
100
|
+
if (timer) timer.textContent = '';
|
|
101
|
+
|
|
102
|
+
// Search mode: re-query the search provider
|
|
103
|
+
if (state._compareMode === 'search') {
|
|
104
|
+
const aiMsg = document.createElement('div');
|
|
105
|
+
aiMsg.className = 'msg msg-ai';
|
|
106
|
+
aiMsg.innerHTML = '<div class="role">Search</div><div class="body"></div>';
|
|
107
|
+
const aiBody = aiMsg.querySelector('.body');
|
|
108
|
+
if (spinnerModule) {
|
|
109
|
+
const spinner = spinnerModule.create('Searching...', 'right');
|
|
110
|
+
aiBody.appendChild(spinner.createElement());
|
|
111
|
+
spinner.start();
|
|
112
|
+
}
|
|
113
|
+
hist.appendChild(aiMsg);
|
|
114
|
+
hist.scrollTop = hist.scrollHeight;
|
|
115
|
+
|
|
116
|
+
const m = state._selectedModels[paneIdx];
|
|
117
|
+
const fd = new FormData();
|
|
118
|
+
fd.append('query', firstUserText);
|
|
119
|
+
fd.append('provider', m.model);
|
|
120
|
+
fd.append('count', '10');
|
|
121
|
+
try {
|
|
122
|
+
const ac = new AbortController();
|
|
123
|
+
state._abortControllers[paneIdx] = ac;
|
|
124
|
+
const t0 = performance.now();
|
|
125
|
+
const res = await fetch(`${state.API_BASE}/api/search/query`, { method: 'POST', body: fd, signal: ac.signal });
|
|
126
|
+
const data = await res.json();
|
|
127
|
+
const elapsed = ((performance.now() - t0) / 1000).toFixed(2);
|
|
128
|
+
aiBody.innerHTML = '';
|
|
129
|
+
if (data.error) {
|
|
130
|
+
aiBody.innerHTML = '<div style="color:var(--color-error);font-size:0.85em;">Error: ' + escapeHtml(data.error) + '</div>';
|
|
131
|
+
} else if (!data.results || data.results.length === 0) {
|
|
132
|
+
aiBody.innerHTML = '<div style="color:color-mix(in srgb, var(--fg) 50%, transparent);font-size:0.85em;font-style:italic;">No results found</div>';
|
|
133
|
+
} else {
|
|
134
|
+
aiBody.appendChild(_renderSearchResults(data));
|
|
135
|
+
}
|
|
136
|
+
const footer = document.createElement('div');
|
|
137
|
+
footer.className = 'msg-footer';
|
|
138
|
+
const span = document.createElement('span');
|
|
139
|
+
span.className = 'response-metrics';
|
|
140
|
+
const parts = [];
|
|
141
|
+
if (data.results) parts.push(data.results.length + ' results');
|
|
142
|
+
parts.push(elapsed + 's');
|
|
143
|
+
span.textContent = parts.join(' | ');
|
|
144
|
+
footer.appendChild(span);
|
|
145
|
+
aiMsg.appendChild(footer);
|
|
146
|
+
} catch (err) {
|
|
147
|
+
aiBody.innerHTML = '<div style="color:var(--color-error);font-size:0.85em;">Error: ' + escapeHtml(err.message) + '</div>';
|
|
148
|
+
}
|
|
149
|
+
state._abortControllers[paneIdx] = null;
|
|
150
|
+
hist.scrollTop = hist.scrollHeight;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Chat/agent mode: stream via session
|
|
155
|
+
const aiMsg = document.createElement('div');
|
|
156
|
+
aiMsg.className = 'msg msg-ai';
|
|
157
|
+
aiMsg.innerHTML = '<div class="role">AI</div><div class="body"></div>';
|
|
158
|
+
const aiBody = aiMsg.querySelector('.body');
|
|
159
|
+
if (spinnerModule) {
|
|
160
|
+
const label = overrideTimeout ? 'Retrying (' + overrideTimeout + 's)...' : 'Re-rolling...';
|
|
161
|
+
const spinner = spinnerModule.create(label, 'right');
|
|
162
|
+
aiBody.appendChild(spinner.createElement());
|
|
163
|
+
spinner.start();
|
|
164
|
+
aiMsg._spinner = spinner;
|
|
165
|
+
}
|
|
166
|
+
hist.appendChild(aiMsg);
|
|
167
|
+
hist.scrollTop = hist.scrollHeight;
|
|
168
|
+
|
|
169
|
+
const opts = { skipBadge: true };
|
|
170
|
+
if (overrideTimeout) opts.timeout = overrideTimeout;
|
|
171
|
+
await _streamToPane(paneIdx, state._paneSessionIds[paneIdx], firstUserText, aiMsg, opts);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ── Expand / preview / copy ──
|
|
175
|
+
|
|
176
|
+
function toggleExpandPane(paneIdx, btn) {
|
|
177
|
+
const grid = document.querySelector('.compare-grid');
|
|
178
|
+
if (!grid) return;
|
|
179
|
+
const panes = grid.querySelectorAll('.compare-pane');
|
|
180
|
+
const target = panes[paneIdx];
|
|
181
|
+
if (!target) return;
|
|
182
|
+
|
|
183
|
+
if (target.classList.contains('expanded')) {
|
|
184
|
+
target.classList.remove('expanded');
|
|
185
|
+
panes.forEach(p => { p.style.display = ''; });
|
|
186
|
+
if (btn) btn.innerHTML = ICON_EXPAND;
|
|
187
|
+
} else {
|
|
188
|
+
target.classList.add('expanded');
|
|
189
|
+
panes.forEach((p, i) => { if (i !== paneIdx) p.style.display = 'none'; });
|
|
190
|
+
if (btn) btn.innerHTML = ICON_COLLAPSE;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* After streaming finishes, check for HTML code in the response.
|
|
196
|
+
* If found, show the play button in the header. User clicks to run.
|
|
197
|
+
*/
|
|
198
|
+
function _autoPreviewHtml(paneIdx, accumulated) {
|
|
199
|
+
if (!accumulated) return;
|
|
200
|
+
const htmlCode = _extractHtmlFromText(accumulated);
|
|
201
|
+
if (!htmlCode) return;
|
|
202
|
+
|
|
203
|
+
const iframe = document.getElementById('cmp-iframe-' + paneIdx);
|
|
204
|
+
const previewBtn = document.getElementById('cmp-preview-' + paneIdx);
|
|
205
|
+
if (!iframe || !previewBtn) return;
|
|
206
|
+
|
|
207
|
+
// Store the HTML on the iframe for when user clicks play
|
|
208
|
+
iframe._htmlCode = htmlCode;
|
|
209
|
+
|
|
210
|
+
// Show the play button
|
|
211
|
+
previewBtn.style.display = '';
|
|
212
|
+
previewBtn.innerHTML = ICON_PLAY;
|
|
213
|
+
previewBtn.title = 'Run preview';
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Toggle between iframe preview and code view for a pane. */
|
|
217
|
+
function togglePanePreview(paneIdx) {
|
|
218
|
+
const iframe = document.getElementById('cmp-iframe-' + paneIdx);
|
|
219
|
+
const hist = document.getElementById('cmp-history-' + paneIdx);
|
|
220
|
+
const btn = document.getElementById('cmp-preview-' + paneIdx);
|
|
221
|
+
if (!iframe || !hist || !btn) return;
|
|
222
|
+
|
|
223
|
+
const showingPreview = iframe.style.display !== 'none';
|
|
224
|
+
if (showingPreview) {
|
|
225
|
+
// Switch to code view
|
|
226
|
+
iframe.style.display = 'none';
|
|
227
|
+
hist.style.display = '';
|
|
228
|
+
btn.innerHTML = ICON_PLAY;
|
|
229
|
+
btn.title = 'Run preview';
|
|
230
|
+
btn.classList.remove('active');
|
|
231
|
+
} else {
|
|
232
|
+
// Switch to preview — load on first click
|
|
233
|
+
if (iframe._htmlCode) iframe.srcdoc = iframe._htmlCode;
|
|
234
|
+
iframe.style.display = '';
|
|
235
|
+
hist.style.display = 'none';
|
|
236
|
+
btn.innerHTML = ICON_CODE;
|
|
237
|
+
btn.title = 'Show code';
|
|
238
|
+
btn.classList.add('active');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Extract full HTML document from raw accumulated text. */
|
|
243
|
+
function _extractHtmlFromText(text) {
|
|
244
|
+
// 1. Try markdown code fences
|
|
245
|
+
const fenceRe = /`{3,}(?:html)?\s*\r?\n([\s\S]*?)`{3,}/gi;
|
|
246
|
+
let match;
|
|
247
|
+
while ((match = fenceRe.exec(text)) !== null) {
|
|
248
|
+
const code = match[1].trim();
|
|
249
|
+
if (/<!doctype\s+html|<html[\s>]/i.test(code)) return code;
|
|
250
|
+
}
|
|
251
|
+
// 2. Bare HTML
|
|
252
|
+
const bare = text.match(/(<!doctype\s+html[\s\S]*<\/html>)/i)
|
|
253
|
+
|| text.match(/(<html[\s>][\s\S]*<\/html>)/i);
|
|
254
|
+
if (bare) return bare[1].trim();
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function copyPaneResponse(paneIdx) {
|
|
259
|
+
const hist = document.getElementById('cmp-history-' + paneIdx);
|
|
260
|
+
if (!hist) return;
|
|
261
|
+
const aiMsgs = hist.querySelectorAll('.msg-ai');
|
|
262
|
+
if (aiMsgs.length === 0) return;
|
|
263
|
+
const lastAi = aiMsgs[aiMsgs.length - 1];
|
|
264
|
+
// For image panes, copy the prompt text
|
|
265
|
+
const text = lastAi._imageData ? (lastAi._imageData.prompt || '') : (lastAi.querySelector('.body')?.textContent || '');
|
|
266
|
+
try { await navigator.clipboard.writeText(text); }
|
|
267
|
+
catch (e) {
|
|
268
|
+
const ta = document.createElement('textarea');
|
|
269
|
+
ta.value = text; document.body.appendChild(ta); ta.select();
|
|
270
|
+
document.execCommand('copy'); ta.remove();
|
|
271
|
+
}
|
|
272
|
+
if (uiModule) uiModule.showToast(lastAi._imageData ? 'Prompt copied!' : 'Copied!');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ── Add / create / remove panes ──
|
|
276
|
+
|
|
277
|
+
/** Show a model picker dropdown anchored to the "+" button in the pane header. */
|
|
278
|
+
async function _addPane(anchorBtn) {
|
|
279
|
+
if (state._streaming) return;
|
|
280
|
+
const _effectiveType = (state._compareMode === 'agent' || state._compareMode === 'research') ? 'chat' : state._compareMode;
|
|
281
|
+
const filtered = state._cachedModels.filter(m => m.type === _effectiveType);
|
|
282
|
+
if (!filtered.length) return;
|
|
283
|
+
|
|
284
|
+
// Toggle existing dropdown
|
|
285
|
+
const existing = document.querySelector('.add-pane-dropdown');
|
|
286
|
+
if (existing) { if (typeof existing._dismiss === 'function') existing._dismiss(); else existing.remove(); return; }
|
|
287
|
+
|
|
288
|
+
const dropdown = document.createElement('div');
|
|
289
|
+
dropdown.className = 'add-pane-dropdown';
|
|
290
|
+
let closeMenu = () => dropdown.remove();
|
|
291
|
+
|
|
292
|
+
// Search input for large model lists
|
|
293
|
+
if (filtered.length >= 5) {
|
|
294
|
+
const searchInput = document.createElement('input');
|
|
295
|
+
searchInput.type = 'text';
|
|
296
|
+
searchInput.placeholder = 'Search models\u2026';
|
|
297
|
+
searchInput.className = 'add-pane-search';
|
|
298
|
+
searchInput.addEventListener('input', () => {
|
|
299
|
+
const q = searchInput.value.toLowerCase().trim();
|
|
300
|
+
dropdown.querySelectorAll('.pane-model-item').forEach(item => {
|
|
301
|
+
item.style.display = item.textContent.toLowerCase().includes(q) ? '' : 'none';
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
searchInput.addEventListener('click', (e) => e.stopPropagation());
|
|
305
|
+
searchInput.addEventListener('keydown', (e) => {
|
|
306
|
+
if (e.key === 'Enter') {
|
|
307
|
+
e.preventDefault();
|
|
308
|
+
const first = dropdown.querySelector('.pane-model-item:not([style*="display: none"])');
|
|
309
|
+
if (first) first.click();
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
dropdown.appendChild(searchInput);
|
|
313
|
+
// Desktop: auto-focus the search box so the user can start typing.
|
|
314
|
+
// Mobile: skip — auto-focus pops the on-screen keyboard and covers
|
|
315
|
+
// the model list. The user can tap the search box if they want to
|
|
316
|
+
// filter, otherwise they just tap a model directly.
|
|
317
|
+
if (window.innerWidth > 768) setTimeout(() => searchInput.focus(), 0);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
filtered.forEach(m => {
|
|
321
|
+
const item = document.createElement('button');
|
|
322
|
+
item.type = 'button';
|
|
323
|
+
item.className = 'pane-model-item';
|
|
324
|
+
const label = m.endpointName ? m.name + ' (' + m.endpointName + ')' : m.name;
|
|
325
|
+
item.textContent = label;
|
|
326
|
+
const alreadyUsed = state._selectedModels.some(s => s.model === m.id && s.endpointId === m.endpointId);
|
|
327
|
+
if (alreadyUsed) item.classList.add('current');
|
|
328
|
+
|
|
329
|
+
item.addEventListener('click', async (e) => {
|
|
330
|
+
e.stopPropagation();
|
|
331
|
+
closeMenu();
|
|
332
|
+
await _createAndAppendPane(m);
|
|
333
|
+
});
|
|
334
|
+
dropdown.appendChild(item);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Position dropdown relative to the viewport (position: fixed) so it
|
|
338
|
+
// can't end up off-screen even when the toolbar has scrolled or the
|
|
339
|
+
// chat-container is wider than the viewport.
|
|
340
|
+
const btnRect = anchorBtn.getBoundingClientRect();
|
|
341
|
+
dropdown.style.position = 'fixed';
|
|
342
|
+
const vw = window.innerWidth;
|
|
343
|
+
const vh = window.innerHeight;
|
|
344
|
+
const margin = 8;
|
|
345
|
+
// Render off-screen first so we can measure the dropdown's actual size.
|
|
346
|
+
// Clamp the width to the viewport up front so long model names can't push
|
|
347
|
+
// the dropdown off the screen edge, and lift z-index above the panes.
|
|
348
|
+
dropdown.style.left = '-9999px';
|
|
349
|
+
dropdown.style.top = '0';
|
|
350
|
+
dropdown.style.maxWidth = (vw - margin * 2) + 'px';
|
|
351
|
+
dropdown.style.zIndex = '100000';
|
|
352
|
+
document.body.appendChild(dropdown);
|
|
353
|
+
const ddRect = dropdown.getBoundingClientRect();
|
|
354
|
+
const ddW = ddRect.width;
|
|
355
|
+
const ddH = ddRect.height;
|
|
356
|
+
// Horizontal: align dropdown's right edge with the button's, then
|
|
357
|
+
// clamp so the dropdown stays within [margin, vw - margin].
|
|
358
|
+
let left = btnRect.right - ddW;
|
|
359
|
+
if (left + ddW > vw - margin) left = vw - margin - ddW;
|
|
360
|
+
if (left < margin) left = margin;
|
|
361
|
+
// Vertical: drop below the button if there's room, otherwise above.
|
|
362
|
+
const spaceBelow = vh - btnRect.bottom;
|
|
363
|
+
const spaceAbove = btnRect.top;
|
|
364
|
+
let top;
|
|
365
|
+
if (spaceBelow >= ddH + margin || spaceBelow >= spaceAbove) {
|
|
366
|
+
top = Math.min(btnRect.bottom + 4, vh - margin - Math.min(ddH, vh - margin * 2));
|
|
367
|
+
} else {
|
|
368
|
+
top = Math.max(margin, btnRect.top - 4 - ddH);
|
|
369
|
+
}
|
|
370
|
+
dropdown.style.left = left + 'px';
|
|
371
|
+
dropdown.style.top = top + 'px';
|
|
372
|
+
dropdown.style.right = 'auto';
|
|
373
|
+
dropdown.style.bottom = 'auto';
|
|
374
|
+
dropdown.style.maxHeight = Math.min(ddH, vh - margin * 2) + 'px';
|
|
375
|
+
|
|
376
|
+
// Close on outside click or Escape (the latter via the registry).
|
|
377
|
+
closeMenu = bindMenuDismiss(dropdown, () => dropdown.remove(), (e) => !dropdown.contains(e.target) && e.target !== anchorBtn);}
|
|
378
|
+
|
|
379
|
+
/** Create a new pane for the given model and append it to the compare grid. */
|
|
380
|
+
async function _createAndAppendPane(m) {
|
|
381
|
+
const i = state._selectedModels.length; // New index
|
|
382
|
+
|
|
383
|
+
// Create session
|
|
384
|
+
const fd = new FormData();
|
|
385
|
+
// Blind mode: neutral slot name only — never leak the model (issue #1285).
|
|
386
|
+
fd.append('name', '[CMP] ' + (state._blindMode ? 'Model ' + _slotChar(i) : m.name));
|
|
387
|
+
fd.append('endpoint_url', m.url || '');
|
|
388
|
+
fd.append('model', m.id || '');
|
|
389
|
+
if (m.endpointId) {
|
|
390
|
+
fd.append('endpoint_id', m.endpointId);
|
|
391
|
+
fd.append('skip_validation', 'true');
|
|
392
|
+
}
|
|
393
|
+
const res = await fetch(`${state.API_BASE}/api/session`, { method: 'POST', body: fd });
|
|
394
|
+
if (!res.ok) return;
|
|
395
|
+
const data = await res.json();
|
|
396
|
+
|
|
397
|
+
// Update arrays
|
|
398
|
+
state._selectedModels.push({ model: m.id, endpoint: m.url, endpointId: m.endpointId, name: m.name, endpointName: m.endpointName || '' });
|
|
399
|
+
state._paneSessionIds.push(data.id);
|
|
400
|
+
state._paneMetrics.push(null);
|
|
401
|
+
state._abortControllers.push(null);
|
|
402
|
+
_persistSelections();
|
|
403
|
+
if (window._updateCheckBtnState) window._updateCheckBtnState();
|
|
404
|
+
|
|
405
|
+
// Build pane DOM
|
|
406
|
+
const label = state._blindMode ? 'Model ' + _slotChar(i) : m.name;
|
|
407
|
+
const pane = document.createElement('div');
|
|
408
|
+
pane.className = 'compare-pane';
|
|
409
|
+
pane.dataset.pane = String(i);
|
|
410
|
+
pane.innerHTML =
|
|
411
|
+
'<div class="pane-header">' +
|
|
412
|
+
'<button class="pane-title pane-title-btn" id="cmp-title-' + i + '" data-pane="' + i + '" type="button">' + escapeHtml(label) + ' <span class="pane-title-caret">▾</span></button>' +
|
|
413
|
+
'<span class="pane-timer" id="cmp-timer-' + i + '"></span>' +
|
|
414
|
+
'<span class="pane-finish-badge" id="cmp-badge-' + i + '"></span>' +
|
|
415
|
+
'<div class="pane-actions">' +
|
|
416
|
+
'<button class="pane-action-btn pane-preview-btn" data-action="preview" data-pane="' + i + '" id="cmp-preview-' + i + '" title="Run preview" style="display:none;">' + ICON_PLAY + '</button>' +
|
|
417
|
+
'<button class="pane-action-btn" data-action="reroll" data-pane="' + i + '" title="Re-roll">' + ICON_REROLL + '</button>' +
|
|
418
|
+
'<button class="pane-action-btn" data-action="copy" data-pane="' + i + '" title="Copy">' + ICON_COPY + '</button>' +
|
|
419
|
+
'<button class="pane-action-btn" data-action="expand" data-pane="' + i + '" title="Expand">' + ICON_EXPAND + '</button>' +
|
|
420
|
+
'<button class="pane-action-btn pane-close-btn" data-action="close" data-pane="' + i + '" title="Remove pane">' + ICON_CLOSE + '</button>' +
|
|
421
|
+
'</div>' +
|
|
422
|
+
'</div>' +
|
|
423
|
+
'<div class="chat-history" id="cmp-history-' + i + '"></div>' +
|
|
424
|
+
'<iframe class="compare-pane-iframe" id="cmp-iframe-' + i + '" sandbox="allow-scripts" style="display:none;"></iframe>' +
|
|
425
|
+
'<div class="pane-vote-footer">' +
|
|
426
|
+
'<button class="pane-vote-btn" data-pane="' + i + '" type="button" disabled style="opacity:0.4;">' +
|
|
427
|
+
'<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:4px;vertical-align:-2px;"><polyline points="20 6 9 17 4 12"/></svg>' +
|
|
428
|
+
'<span class="pane-vote-label">Vote ' + escapeHtml(label) + '</span>' +
|
|
429
|
+
'</button>' +
|
|
430
|
+
'</div>';
|
|
431
|
+
|
|
432
|
+
// Append to grid
|
|
433
|
+
const grid = document.querySelector('.compare-grid');
|
|
434
|
+
grid.appendChild(pane);
|
|
435
|
+
|
|
436
|
+
// Update grid columns
|
|
437
|
+
const n = state._selectedModels.length;
|
|
438
|
+
grid.dataset.cols = String(Math.min(n, 4));
|
|
439
|
+
|
|
440
|
+
// Update header label
|
|
441
|
+
const headerSpan = document.querySelector('.compare-active > div:first-child span');
|
|
442
|
+
if (headerSpan) {
|
|
443
|
+
const modeLabel = ({ search: ' search providers', agent: ' agents', research: ' research models' }[state._compareMode] || ' models');
|
|
444
|
+
headerSpan.textContent = 'Comparing' + modeLabel +
|
|
445
|
+
(state._blindMode ? ' (blind)' : '') + ' \u00b7 ' + state._timeout + 's timeout';
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Rebuild vote bar
|
|
449
|
+
buildVoteBar(n);
|
|
450
|
+
|
|
451
|
+
// Prompt to shuffle in blind mode — tooltip bubble next to Shuffle button
|
|
452
|
+
if (state._blindMode && n > 2) {
|
|
453
|
+
const shuffleBtn = document.getElementById('compare-shuffle-btn');
|
|
454
|
+
if (shuffleBtn) {
|
|
455
|
+
const bubble = document.createElement('div');
|
|
456
|
+
bubble.style.cssText = 'position:absolute;top:100%;right:0;margin-top:6px;background:var(--panel);border:1px solid var(--border);border-radius:6px;padding:5px 10px;font-size:11px;white-space:nowrap;z-index:10000;box-shadow:0 4px 12px rgba(0,0,0,0.25);pointer-events:none;opacity:0;transition:opacity 0.2s;';
|
|
457
|
+
bubble.textContent = 'Shuffle models?';
|
|
458
|
+
shuffleBtn.style.position = 'relative';
|
|
459
|
+
shuffleBtn.appendChild(bubble);
|
|
460
|
+
requestAnimationFrame(() => { bubble.style.opacity = '1'; });
|
|
461
|
+
setTimeout(() => { bubble.style.opacity = '0'; setTimeout(() => bubble.remove(), 200); }, 4000);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/** Remove a pane from the compare grid. If only 1 remains, exit compare mode. */
|
|
467
|
+
function _removePane(paneIdx) {
|
|
468
|
+
if (state._streaming) return;
|
|
469
|
+
|
|
470
|
+
// Abort if streaming
|
|
471
|
+
if (state._abortControllers[paneIdx]) state._abortControllers[paneIdx].abort();
|
|
472
|
+
|
|
473
|
+
// Delete the session
|
|
474
|
+
const sid = state._paneSessionIds[paneIdx];
|
|
475
|
+
if (sid) {
|
|
476
|
+
fetch(`${state.API_BASE}/api/session/${sid}`, { method: 'DELETE' }).catch(() => {});
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Remove from arrays
|
|
480
|
+
state._selectedModels.splice(paneIdx, 1);
|
|
481
|
+
state._paneSessionIds.splice(paneIdx, 1);
|
|
482
|
+
state._paneMetrics.splice(paneIdx, 1);
|
|
483
|
+
state._abortControllers.splice(paneIdx, 1);
|
|
484
|
+
_persistSelections();
|
|
485
|
+
if (window._updateCheckBtnState) window._updateCheckBtnState();
|
|
486
|
+
|
|
487
|
+
// If no panes left, exit compare mode
|
|
488
|
+
if (state._selectedModels.length === 0) {
|
|
489
|
+
if (_deactivate) _deactivate(true);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Rebuild pane DOM — re-index all panes so IDs stay consistent
|
|
494
|
+
const grid = document.querySelector('.compare-grid');
|
|
495
|
+
grid.querySelectorAll('.compare-pane').forEach(p => p.remove());
|
|
496
|
+
|
|
497
|
+
const n = state._selectedModels.length;
|
|
498
|
+
for (let i = 0; i < n; i++) {
|
|
499
|
+
const label = state._blindMode ? 'Model ' + _slotChar(i) : state._selectedModels[i].name;
|
|
500
|
+
const pane = document.createElement('div');
|
|
501
|
+
pane.className = 'compare-pane';
|
|
502
|
+
pane.dataset.pane = String(i);
|
|
503
|
+
pane.innerHTML =
|
|
504
|
+
'<div class="pane-header">' +
|
|
505
|
+
'<button class="pane-title pane-title-btn" id="cmp-title-' + i + '" data-pane="' + i + '" type="button">' + escapeHtml(label) + ' <span class="pane-title-caret">▾</span></button>' +
|
|
506
|
+
'<span class="pane-timer" id="cmp-timer-' + i + '"></span>' +
|
|
507
|
+
'<span class="pane-finish-badge" id="cmp-badge-' + i + '"></span>' +
|
|
508
|
+
'<div class="pane-actions">' +
|
|
509
|
+
'<button class="pane-action-btn pane-stop-btn" data-action="stop" data-pane="' + i + '" title="Stop" style="display:none;"><svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2"/></svg></button>' +
|
|
510
|
+
'<button class="pane-action-btn pane-preview-btn" data-action="preview" data-pane="' + i + '" id="cmp-preview-' + i + '" title="Run preview" style="display:none;">' + ICON_PLAY + '</button>' +
|
|
511
|
+
'<button class="pane-action-btn pane-needs-response" data-action="reroll" data-pane="' + i + '" title="Re-roll" style="display:none;">' + ICON_REROLL + '</button>' +
|
|
512
|
+
'<button class="pane-action-btn pane-needs-response" data-action="copy" data-pane="' + i + '" title="Copy" style="display:none;">' + ICON_COPY + '</button>' +
|
|
513
|
+
'<button class="pane-action-btn" data-action="expand" data-pane="' + i + '" title="Expand">' + ICON_EXPAND + '</button>' +
|
|
514
|
+
'<button class="pane-action-btn pane-close-btn" data-action="close" data-pane="' + i + '" title="Remove pane">' + ICON_CLOSE + '</button>' +
|
|
515
|
+
'</div>' +
|
|
516
|
+
'</div>' +
|
|
517
|
+
'<div class="chat-history" id="cmp-history-' + i + '"></div>' +
|
|
518
|
+
'<iframe class="compare-pane-iframe" id="cmp-iframe-' + i + '" sandbox="allow-scripts" style="display:none;"></iframe>' +
|
|
519
|
+
'<div class="pane-vote-footer">' +
|
|
520
|
+
'<button class="pane-vote-btn" data-pane="' + i + '" type="button" disabled style="opacity:0.4;">' +
|
|
521
|
+
'<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:4px;vertical-align:-2px;"><polyline points="20 6 9 17 4 12"/></svg>' +
|
|
522
|
+
'<span class="pane-vote-label">Vote ' + escapeHtml(label) + '</span>' +
|
|
523
|
+
'</button>' +
|
|
524
|
+
'</div>';
|
|
525
|
+
grid.appendChild(pane);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Update grid columns
|
|
529
|
+
grid.dataset.cols = String(Math.min(n, 4));
|
|
530
|
+
|
|
531
|
+
// Update header label
|
|
532
|
+
const headerSpan = document.querySelector('.compare-active > div:first-child span');
|
|
533
|
+
if (headerSpan) {
|
|
534
|
+
const modeLabel = ({ search: ' search providers', agent: ' agents', research: ' research models' }[state._compareMode] || ' models');
|
|
535
|
+
headerSpan.textContent = 'Comparing' + modeLabel +
|
|
536
|
+
(state._blindMode ? ' (blind)' : '') + ' \u00b7 ' + state._timeout + 's timeout';
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Rebuild vote bar
|
|
540
|
+
buildVoteBar(n);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/** Show a dropdown under the pane title to swap the model for that pane. */
|
|
544
|
+
function _showModelSwapDropdown(paneIdx, titleBtn) {
|
|
545
|
+
// Don't allow swaps while streaming
|
|
546
|
+
if (state._streaming) return;
|
|
547
|
+
|
|
548
|
+
// Remove any existing dropdown
|
|
549
|
+
const existing = document.querySelector('.pane-model-dropdown');
|
|
550
|
+
if (existing) { if (typeof existing._dismiss === 'function') existing._dismiss(); else existing.remove(); return; }
|
|
551
|
+
|
|
552
|
+
const _effectiveType = (state._compareMode === 'agent' || state._compareMode === 'research') ? 'chat' : state._compareMode;
|
|
553
|
+
const filtered = state._cachedModels.filter(m => m.type === _effectiveType);
|
|
554
|
+
if (filtered.length === 0) return;
|
|
555
|
+
|
|
556
|
+
const dropdown = document.createElement('div');
|
|
557
|
+
dropdown.className = 'pane-model-dropdown';
|
|
558
|
+
let closeMenu = () => dropdown.remove();
|
|
559
|
+
|
|
560
|
+
filtered.forEach(m => {
|
|
561
|
+
const item = document.createElement('button');
|
|
562
|
+
item.type = 'button';
|
|
563
|
+
item.className = 'pane-model-item';
|
|
564
|
+
const label = m.endpointName ? m.name + ' (' + m.endpointName + ')' : m.name;
|
|
565
|
+
item.textContent = label;
|
|
566
|
+
// Highlight current model
|
|
567
|
+
if (state._selectedModels[paneIdx] && state._selectedModels[paneIdx].model === m.id
|
|
568
|
+
&& state._selectedModels[paneIdx].endpointId === m.endpointId) {
|
|
569
|
+
item.classList.add('current');
|
|
570
|
+
}
|
|
571
|
+
item.addEventListener('click', async (e) => {
|
|
572
|
+
e.stopPropagation();
|
|
573
|
+
closeMenu();
|
|
574
|
+
|
|
575
|
+
// Update the model for this pane and persist
|
|
576
|
+
state._selectedModels[paneIdx] = {
|
|
577
|
+
model: m.id, endpoint: m.url, endpointId: m.endpointId, name: m.name,
|
|
578
|
+
};
|
|
579
|
+
_persistSelections();
|
|
580
|
+
if (window._updateCheckBtnState) window._updateCheckBtnState();
|
|
581
|
+
|
|
582
|
+
// Delete old session, create new one
|
|
583
|
+
const oldSid = state._paneSessionIds[paneIdx];
|
|
584
|
+
if (oldSid) {
|
|
585
|
+
fetch(`${state.API_BASE}/api/session/${oldSid}`, { method: 'DELETE' }).catch(() => {});
|
|
586
|
+
}
|
|
587
|
+
const fd = new FormData();
|
|
588
|
+
// Blind mode: neutral slot name only — never leak the model (issue #1285).
|
|
589
|
+
fd.append('name', '[CMP] ' + (state._blindMode ? 'Model ' + _slotChar(paneIdx) : m.name));
|
|
590
|
+
fd.append('endpoint_url', m.url || '');
|
|
591
|
+
fd.append('model', m.id || '');
|
|
592
|
+
if (m.endpointId) {
|
|
593
|
+
fd.append('endpoint_id', m.endpointId);
|
|
594
|
+
fd.append('skip_validation', 'true');
|
|
595
|
+
}
|
|
596
|
+
try {
|
|
597
|
+
const res = await fetch(`${state.API_BASE}/api/session`, { method: 'POST', body: fd });
|
|
598
|
+
const data = await res.json();
|
|
599
|
+
state._paneSessionIds[paneIdx] = data.id;
|
|
600
|
+
} catch (err) {
|
|
601
|
+
console.error('Failed to create session for swapped model:', err);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Update title display
|
|
605
|
+
const titleEl = document.getElementById('cmp-title-' + paneIdx);
|
|
606
|
+
if (titleEl) {
|
|
607
|
+
const displayName = state._blindMode
|
|
608
|
+
? 'Model ' + _slotChar(paneIdx)
|
|
609
|
+
: m.name;
|
|
610
|
+
titleEl.innerHTML = escapeHtml(displayName) + ' <span class="pane-title-caret">▾</span>';
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Clear pane history for fresh start
|
|
614
|
+
const hist = document.getElementById('cmp-history-' + paneIdx);
|
|
615
|
+
if (hist) { hist.innerHTML = ''; hist.style.display = ''; }
|
|
616
|
+
const iframe = document.getElementById('cmp-iframe-' + paneIdx);
|
|
617
|
+
if (iframe) { iframe.srcdoc = ''; iframe.style.display = 'none'; iframe._htmlCode = null; }
|
|
618
|
+
const previewBtn = document.getElementById('cmp-preview-' + paneIdx);
|
|
619
|
+
if (previewBtn) { previewBtn.style.display = 'none'; previewBtn.classList.remove('active'); }
|
|
620
|
+
const badge = document.getElementById('cmp-badge-' + paneIdx);
|
|
621
|
+
if (badge) { badge.textContent = ''; badge.style.color = ''; }
|
|
622
|
+
});
|
|
623
|
+
dropdown.appendChild(item);
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
// Position relative to the viewport (fixed) and append to document.body so
|
|
627
|
+
// the dropdown can't be clipped by the narrow pane's overflow or run off the
|
|
628
|
+
// screen edge on mobile (matches the "+" add-pane picker behaviour).
|
|
629
|
+
const rect = titleBtn.getBoundingClientRect();
|
|
630
|
+
const vw = window.innerWidth, vh = window.innerHeight, margin = 8;
|
|
631
|
+
dropdown.style.position = 'fixed';
|
|
632
|
+
dropdown.style.zIndex = '100000';
|
|
633
|
+
dropdown.style.maxWidth = (vw - margin * 2) + 'px';
|
|
634
|
+
dropdown.style.overflowY = 'auto';
|
|
635
|
+
dropdown.style.left = '-9999px';
|
|
636
|
+
dropdown.style.top = '0';
|
|
637
|
+
document.body.appendChild(dropdown);
|
|
638
|
+
const ddRect = dropdown.getBoundingClientRect();
|
|
639
|
+
const ddW = ddRect.width, ddH = ddRect.height;
|
|
640
|
+
let left = rect.left;
|
|
641
|
+
if (left + ddW > vw - margin) left = vw - margin - ddW;
|
|
642
|
+
if (left < margin) left = margin;
|
|
643
|
+
const spaceBelow = vh - rect.bottom, spaceAbove = rect.top;
|
|
644
|
+
let top;
|
|
645
|
+
if (spaceBelow >= ddH + margin || spaceBelow >= spaceAbove) {
|
|
646
|
+
top = Math.min(rect.bottom + 4, vh - margin - Math.min(ddH, vh - margin * 2));
|
|
647
|
+
} else {
|
|
648
|
+
top = Math.max(margin, rect.top - 4 - ddH);
|
|
649
|
+
}
|
|
650
|
+
dropdown.style.left = left + 'px';
|
|
651
|
+
dropdown.style.top = top + 'px';
|
|
652
|
+
dropdown.style.maxHeight = Math.min(ddH, vh - margin * 2) + 'px';
|
|
653
|
+
|
|
654
|
+
// Close on outside click or Escape (the latter via the registry).
|
|
655
|
+
closeMenu = bindMenuDismiss(dropdown, () => dropdown.remove(), (e) => !dropdown.contains(e.target) && e.target !== titleBtn);}
|
|
656
|
+
|
|
657
|
+
// ── Shuffle / reset ──
|
|
658
|
+
|
|
659
|
+
function shufflePanePositions() {
|
|
660
|
+
if (state._streaming) return;
|
|
661
|
+
// Remove shuffle prompt bubble if present
|
|
662
|
+
const shuffleBtn = document.getElementById('compare-shuffle-btn');
|
|
663
|
+
if (shuffleBtn) { const b = shuffleBtn.querySelector('div'); if (b) b.remove(); }
|
|
664
|
+
const n = state._selectedModels.length;
|
|
665
|
+
if (n < 2) return;
|
|
666
|
+
|
|
667
|
+
// Fisher-Yates shuffle to get new order
|
|
668
|
+
const indices = Array.from({ length: n }, (_, i) => i);
|
|
669
|
+
for (let i = indices.length - 1; i > 0; i--) {
|
|
670
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
671
|
+
[indices[i], indices[j]] = [indices[j], indices[i]];
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Reorder internal state
|
|
675
|
+
const newModels = indices.map(i => state._selectedModels[i]);
|
|
676
|
+
const newSessionIds = indices.map(i => state._paneSessionIds[i]);
|
|
677
|
+
const newMetrics = indices.map(i => state._paneMetrics[i]);
|
|
678
|
+
|
|
679
|
+
// Collect pane contents (HTML) before swapping
|
|
680
|
+
const paneContents = [];
|
|
681
|
+
const paneClasses = [];
|
|
682
|
+
for (let i = 0; i < n; i++) {
|
|
683
|
+
const hist = document.getElementById('cmp-history-' + i);
|
|
684
|
+
paneContents.push(hist ? hist.innerHTML : '');
|
|
685
|
+
const pane = document.querySelector(`.compare-pane[data-pane="${i}"]`);
|
|
686
|
+
paneClasses.push(pane ? { winner: pane.classList.contains('winner'), loser: pane.classList.contains('loser') } : {});
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// Apply shuffled state
|
|
690
|
+
state._selectedModels = newModels;
|
|
691
|
+
state._paneSessionIds = newSessionIds;
|
|
692
|
+
state._paneMetrics = newMetrics;
|
|
693
|
+
|
|
694
|
+
// Spin the shuffle button dice icon
|
|
695
|
+
const shuffleBtn2 = document.getElementById('compare-shuffle-btn');
|
|
696
|
+
if (shuffleBtn2) {
|
|
697
|
+
const diceSvg = shuffleBtn2.querySelector('svg');
|
|
698
|
+
if (diceSvg) {
|
|
699
|
+
diceSvg.style.transition = 'transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1)';
|
|
700
|
+
diceSvg.style.transform = 'rotate(360deg)';
|
|
701
|
+
setTimeout(() => { diceSvg.style.transition = ''; diceSvg.style.transform = ''; }, 400);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// Shake panes and flash titles
|
|
706
|
+
for (let i = 0; i < n; i++) {
|
|
707
|
+
const pane = document.querySelector(`.compare-pane[data-pane="${i}"]`);
|
|
708
|
+
if (pane) {
|
|
709
|
+
pane.style.animation = 'pane-shake 0.3s ease';
|
|
710
|
+
pane.addEventListener('animationend', () => { pane.style.animation = ''; }, { once: true });
|
|
711
|
+
}
|
|
712
|
+
const titleEl = document.getElementById('cmp-title-' + i);
|
|
713
|
+
if (titleEl) {
|
|
714
|
+
titleEl.style.transition = 'opacity 0.12s ease, transform 0.12s ease';
|
|
715
|
+
titleEl.style.opacity = '0.3';
|
|
716
|
+
titleEl.style.transform = 'scale(0.9)';
|
|
717
|
+
titleEl.innerHTML = '?';
|
|
718
|
+
}
|
|
719
|
+
const hist = document.getElementById('cmp-history-' + i);
|
|
720
|
+
if (hist) {
|
|
721
|
+
hist.style.transition = 'opacity 0.15s ease';
|
|
722
|
+
hist.style.opacity = '0';
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
setTimeout(() => {
|
|
727
|
+
for (let i = 0; i < n; i++) {
|
|
728
|
+
const hist = document.getElementById('cmp-history-' + i);
|
|
729
|
+
const pane = document.querySelector(`.compare-pane[data-pane="${i}"]`);
|
|
730
|
+
const titleEl = document.getElementById('cmp-title-' + i);
|
|
731
|
+
const badge = document.getElementById('cmp-badge-' + i);
|
|
732
|
+
const src = indices[i];
|
|
733
|
+
|
|
734
|
+
if (hist) hist.innerHTML = paneContents[src];
|
|
735
|
+
if (titleEl) {
|
|
736
|
+
const lbl = state._blindMode ? 'Model ' + _slotChar(i) : state._selectedModels[i].name;
|
|
737
|
+
titleEl.innerHTML = escapeHtml(lbl) + ' <span class="pane-title-caret">▾</span>';
|
|
738
|
+
titleEl.style.transition = 'opacity 0.25s ease, transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1)';
|
|
739
|
+
titleEl.style.opacity = '1';
|
|
740
|
+
titleEl.style.transform = 'scale(1)';
|
|
741
|
+
}
|
|
742
|
+
if (badge) { badge.textContent = ''; badge.style.color = ''; }
|
|
743
|
+
if (pane) {
|
|
744
|
+
pane.classList.toggle('winner', !!paneClasses[src].winner);
|
|
745
|
+
pane.classList.toggle('loser', !!paneClasses[src].loser);
|
|
746
|
+
}
|
|
747
|
+
if (hist) {
|
|
748
|
+
hist.style.transition = 'opacity 0.25s ease';
|
|
749
|
+
hist.style.opacity = '1';
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}, 200);
|
|
753
|
+
|
|
754
|
+
// Re-enable blind mode after shuffle
|
|
755
|
+
state._blindMode = true;
|
|
756
|
+
|
|
757
|
+
// Rebuild vote bar with new labels
|
|
758
|
+
setTimeout(() => buildVoteBar(n), 250);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
function resetCompare() {
|
|
762
|
+
if (state._streaming) stopAll();
|
|
763
|
+
const n = state._selectedModels.length;
|
|
764
|
+
|
|
765
|
+
// Clear last prompt so vote buttons are disabled until next prompt
|
|
766
|
+
state._lastPrompt = '';
|
|
767
|
+
|
|
768
|
+
// Reset finish badges, titles, winner/loser state
|
|
769
|
+
state._finishOrder = 0;
|
|
770
|
+
state._paneMetrics = new Array(n).fill(null);
|
|
771
|
+
const panes = document.querySelectorAll('.compare-pane');
|
|
772
|
+
for (let i = 0; i < n; i++) {
|
|
773
|
+
const badge = document.getElementById('cmp-badge-' + i);
|
|
774
|
+
if (badge) { badge.textContent = ''; badge.style.color = ''; }
|
|
775
|
+
const titleEl = document.getElementById('cmp-title-' + i);
|
|
776
|
+
if (titleEl) {
|
|
777
|
+
const lbl = state._blindMode ? 'Model ' + _slotChar(i) : state._selectedModels[i].name;
|
|
778
|
+
titleEl.innerHTML = escapeHtml(lbl) + ' <span class="pane-title-caret">▾</span>';
|
|
779
|
+
}
|
|
780
|
+
if (panes[i]) { panes[i].classList.remove('winner', 'loser'); }
|
|
781
|
+
|
|
782
|
+
// Clear all messages from pane history
|
|
783
|
+
const hist = document.getElementById('cmp-history-' + i);
|
|
784
|
+
if (hist) { hist.innerHTML = ''; hist.style.display = ''; }
|
|
785
|
+
|
|
786
|
+
// Reset iframe preview
|
|
787
|
+
const iframe = document.getElementById('cmp-iframe-' + i);
|
|
788
|
+
if (iframe) { iframe.srcdoc = ''; iframe.style.display = 'none'; iframe._htmlCode = null; }
|
|
789
|
+
const previewBtn = document.getElementById('cmp-preview-' + i);
|
|
790
|
+
if (previewBtn) { previewBtn.style.display = 'none'; previewBtn.classList.remove('active'); }
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Re-enable vote bar
|
|
794
|
+
buildVoteBar(n);
|
|
795
|
+
|
|
796
|
+
// Focus input for next prompt
|
|
797
|
+
const ta = document.getElementById('message');
|
|
798
|
+
if (ta) ta.focus();
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
export {
|
|
802
|
+
registerPaneActions,
|
|
803
|
+
stopAll,
|
|
804
|
+
stopPane,
|
|
805
|
+
rerollPane,
|
|
806
|
+
toggleExpandPane,
|
|
807
|
+
togglePanePreview,
|
|
808
|
+
_autoPreviewHtml,
|
|
809
|
+
_extractHtmlFromText,
|
|
810
|
+
copyPaneResponse,
|
|
811
|
+
_addPane,
|
|
812
|
+
_createAndAppendPane,
|
|
813
|
+
_removePane,
|
|
814
|
+
_showModelSwapDropdown,
|
|
815
|
+
shufflePanePositions,
|
|
816
|
+
resetCompare,
|
|
817
|
+
};
|