@pellux/goodvibes-tui 0.18.4
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/.goodvibes/GOODVIBES.md +35 -0
- package/.goodvibes/agents/reviewer.md +89 -0
- package/.goodvibes/skills/add-provider/SKILL.md +199 -0
- package/CHANGELOG.md +1681 -0
- package/README.md +1607 -0
- package/bin/goodvibes +66 -0
- package/docs/README.md +32 -0
- package/docs/foundation-artifacts/README.md +16 -0
- package/docs/foundation-artifacts/knowledge-graphql.graphql +397 -0
- package/docs/foundation-artifacts/knowledge-store.sql +183 -0
- package/docs/foundation-artifacts/operator-contract.json +55157 -0
- package/docs/foundation-artifacts/peer-contract.json +2384 -0
- package/package.json +114 -0
- package/scripts/postinstall.mjs +203 -0
- package/src/acp/connection.ts +447 -0
- package/src/acp/index.ts +7 -0
- package/src/acp/manager.ts +133 -0
- package/src/adapters/bluebubbles/index.ts +127 -0
- package/src/adapters/discord/index.ts +297 -0
- package/src/adapters/github/index.ts +73 -0
- package/src/adapters/google-chat/index.ts +119 -0
- package/src/adapters/imessage/index.ts +92 -0
- package/src/adapters/index.ts +15 -0
- package/src/adapters/matrix/index.ts +116 -0
- package/src/adapters/mattermost/index.ts +151 -0
- package/src/adapters/msteams/index.ts +180 -0
- package/src/adapters/ntfy/index.ts +118 -0
- package/src/adapters/signal/index.ts +92 -0
- package/src/adapters/slack/index.ts +323 -0
- package/src/adapters/telegram/index.ts +160 -0
- package/src/adapters/types.ts +97 -0
- package/src/adapters/webhook/index.ts +178 -0
- package/src/adapters/whatsapp/index.ts +135 -0
- package/src/agents/message-bus-core.ts +312 -0
- package/src/agents/message-bus.ts +2 -0
- package/src/agents/orchestrator-prompts.ts +351 -0
- package/src/agents/orchestrator-runner.ts +668 -0
- package/src/agents/orchestrator.ts +437 -0
- package/src/agents/session.ts +108 -0
- package/src/agents/worktree.ts +153 -0
- package/src/agents/wrfc-config.ts +47 -0
- package/src/agents/wrfc-controller.ts +747 -0
- package/src/agents/wrfc-gate-runtime.ts +75 -0
- package/src/agents/wrfc-reporting.ts +284 -0
- package/src/agents/wrfc-runtime-events.ts +150 -0
- package/src/agents/wrfc-types.ts +67 -0
- package/src/automation/delivery-manager.ts +368 -0
- package/src/automation/index.ts +72 -0
- package/src/automation/manager-runtime-delivery.ts +139 -0
- package/src/automation/manager-runtime-events.ts +131 -0
- package/src/automation/manager-runtime-execution.ts +511 -0
- package/src/automation/manager-runtime-helpers.ts +433 -0
- package/src/automation/manager-runtime-job-mutations.ts +175 -0
- package/src/automation/manager-runtime-reconcile.ts +148 -0
- package/src/automation/manager-runtime-scheduling.ts +189 -0
- package/src/automation/manager-runtime-sync.ts +54 -0
- package/src/automation/manager-runtime.ts +721 -0
- package/src/automation/manager.ts +10 -0
- package/src/automation/service.ts +242 -0
- package/src/channels/builtin/account-actions.ts +490 -0
- package/src/channels/builtin/accounts.ts +433 -0
- package/src/channels/builtin/contracts.ts +405 -0
- package/src/channels/builtin/plugins.ts +308 -0
- package/src/channels/builtin/rendering.ts +174 -0
- package/src/channels/builtin/setup-schema.ts +504 -0
- package/src/channels/builtin/shared.ts +96 -0
- package/src/channels/builtin/surfaces.ts +57 -0
- package/src/channels/builtin/targets.ts +693 -0
- package/src/channels/builtin-runtime.ts +443 -0
- package/src/channels/delivery/shared.ts +199 -0
- package/src/channels/delivery/strategies-bridge.ts +246 -0
- package/src/channels/delivery/strategies-core.ts +299 -0
- package/src/channels/delivery/strategies-enterprise.ts +178 -0
- package/src/channels/delivery/types.ts +59 -0
- package/src/channels/delivery-router.ts +127 -0
- package/src/channels/index.ts +77 -0
- package/src/channels/plugin-registry.ts +551 -0
- package/src/channels/provider-runtime.ts +330 -0
- package/src/channels/reply-pipeline.ts +522 -0
- package/src/channels/route-manager.ts +340 -0
- package/src/channels/surface-registry.ts +186 -0
- package/src/config/helper-model.ts +233 -0
- package/src/config/index.ts +193 -0
- package/src/config/manager.ts +404 -0
- package/src/config/secrets.ts +547 -0
- package/src/config/service-registry.ts +329 -0
- package/src/config/subscription-auth.ts +31 -0
- package/src/config/subscription-providers.ts +127 -0
- package/src/config/tool-llm.ts +110 -0
- package/src/control-plane/approval-broker.ts +351 -0
- package/src/control-plane/gateway.ts +713 -0
- package/src/control-plane/index.ts +54 -0
- package/src/control-plane/media-contract-schemas.ts +208 -0
- package/src/control-plane/method-catalog-admin.ts +136 -0
- package/src/control-plane/method-catalog-channels.ts +591 -0
- package/src/control-plane/method-catalog-control-automation.ts +475 -0
- package/src/control-plane/method-catalog-control-core.ts +594 -0
- package/src/control-plane/method-catalog-control.ts +8 -0
- package/src/control-plane/method-catalog-events.ts +74 -0
- package/src/control-plane/method-catalog-knowledge.ts +531 -0
- package/src/control-plane/method-catalog-media.ts +279 -0
- package/src/control-plane/method-catalog-runtime.ts +304 -0
- package/src/control-plane/method-catalog-shared.ts +223 -0
- package/src/control-plane/method-catalog.ts +242 -0
- package/src/control-plane/operator-contract-schemas-admin.ts +639 -0
- package/src/control-plane/operator-contract-schemas-channels.ts +375 -0
- package/src/control-plane/operator-contract-schemas-control.ts +226 -0
- package/src/control-plane/operator-contract-schemas-domains.ts +4 -0
- package/src/control-plane/operator-contract-schemas-knowledge.ts +582 -0
- package/src/control-plane/operator-contract-schemas-media.ts +297 -0
- package/src/control-plane/operator-contract-schemas-permissions.ts +100 -0
- package/src/control-plane/operator-contract-schemas-remote.ts +38 -0
- package/src/control-plane/operator-contract-schemas-runtime.ts +563 -0
- package/src/control-plane/operator-contract-schemas-shared.ts +85 -0
- package/src/control-plane/operator-contract-schemas-telemetry.ts +349 -0
- package/src/control-plane/operator-contract-schemas.ts +6 -0
- package/src/control-plane/operator-contract.ts +163 -0
- package/src/control-plane/session-broker.ts +780 -0
- package/src/core/compaction-sections.ts +492 -0
- package/src/core/compaction-types.ts +147 -0
- package/src/core/composer-state.ts +59 -0
- package/src/core/context-compaction.ts +542 -0
- package/src/core/conversation-compaction.ts +68 -0
- package/src/core/conversation-diff.ts +55 -0
- package/src/core/conversation-rendering.ts +343 -0
- package/src/core/conversation-utils.ts +72 -0
- package/src/core/conversation.ts +775 -0
- package/src/core/event-replay.ts +287 -0
- package/src/core/orchestrator-context-runtime.ts +407 -0
- package/src/core/orchestrator-follow-up-runtime.ts +134 -0
- package/src/core/orchestrator-runtime.ts +132 -0
- package/src/core/orchestrator-tool-runtime.ts +468 -0
- package/src/core/orchestrator-turn-helpers.ts +355 -0
- package/src/core/orchestrator-turn-loop.ts +443 -0
- package/src/core/orchestrator.ts +733 -0
- package/src/core/plan-command-handler.ts +169 -0
- package/src/core/system-message-router.ts +210 -0
- package/src/core/transcript-events/classify.ts +95 -0
- package/src/core/transcript-events/index.ts +15 -0
- package/src/daemon/cli.ts +88 -0
- package/src/daemon/control-plane.ts +522 -0
- package/src/daemon/facade-composition.ts +397 -0
- package/src/daemon/facade.ts +638 -0
- package/src/daemon/helpers.ts +74 -0
- package/src/daemon/http/router-route-contexts.ts +370 -0
- package/src/daemon/http/router.ts +531 -0
- package/src/daemon/http-listener.ts +301 -0
- package/src/daemon/index.ts +3 -0
- package/src/daemon/server.ts +1 -0
- package/src/daemon/service-manager.ts +413 -0
- package/src/daemon/surface-actions.ts +183 -0
- package/src/daemon/surface-delivery.ts +530 -0
- package/src/daemon/surface-policy.ts +60 -0
- package/src/daemon/transport-events.ts +110 -0
- package/src/daemon/types.ts +191 -0
- package/src/export/markdown.ts +213 -0
- package/src/export/session-export.ts +633 -0
- package/src/git/index.ts +1 -0
- package/src/git/service.ts +414 -0
- package/src/hooks/chain-engine.ts +414 -0
- package/src/hooks/dispatcher.ts +414 -0
- package/src/hooks/hook-api.ts +170 -0
- package/src/hooks/index.ts +48 -0
- package/src/hooks/runners/agent.ts +93 -0
- package/src/hooks/runners/prompt.ts +69 -0
- package/src/hooks/workbench.ts +360 -0
- package/src/input/autocomplete.ts +96 -0
- package/src/input/bookmark-modal.ts +115 -0
- package/src/input/command-registry.ts +300 -0
- package/src/input/commands/branch-runtime.ts +72 -0
- package/src/input/commands/config.ts +515 -0
- package/src/input/commands/control-room-runtime.ts +255 -0
- package/src/input/commands/conversation-runtime.ts +207 -0
- package/src/input/commands/diff-runtime.ts +161 -0
- package/src/input/commands/discovery-runtime.ts +45 -0
- package/src/input/commands/eval.ts +204 -0
- package/src/input/commands/experience-runtime.ts +278 -0
- package/src/input/commands/git-runtime.ts +81 -0
- package/src/input/commands/guidance-runtime.ts +101 -0
- package/src/input/commands/health-runtime.ts +434 -0
- package/src/input/commands/hooks-runtime.ts +148 -0
- package/src/input/commands/incident-runtime.ts +95 -0
- package/src/input/commands/integration-runtime.ts +394 -0
- package/src/input/commands/intelligence-runtime.ts +223 -0
- package/src/input/commands/knowledge.ts +368 -0
- package/src/input/commands/local-auth-runtime.ts +105 -0
- package/src/input/commands/local-provider-runtime.ts +170 -0
- package/src/input/commands/local-runtime.ts +458 -0
- package/src/input/commands/local-setup-review.ts +192 -0
- package/src/input/commands/local-setup-transfer.ts +134 -0
- package/src/input/commands/local-setup.ts +292 -0
- package/src/input/commands/managed-runtime.ts +208 -0
- package/src/input/commands/marketplace-runtime.ts +290 -0
- package/src/input/commands/mcp-runtime.ts +202 -0
- package/src/input/commands/memory-product-runtime.ts +111 -0
- package/src/input/commands/memory.ts +151 -0
- package/src/input/commands/notify-runtime.ts +83 -0
- package/src/input/commands/operator-panel-runtime.ts +141 -0
- package/src/input/commands/operator-runtime.ts +392 -0
- package/src/input/commands/permissions-runtime.ts +104 -0
- package/src/input/commands/planning-runtime.ts +97 -0
- package/src/input/commands/platform-access-runtime.ts +422 -0
- package/src/input/commands/platform-runtime.ts +6 -0
- package/src/input/commands/platform-sandbox-qemu.ts +137 -0
- package/src/input/commands/platform-sandbox-runtime.ts +406 -0
- package/src/input/commands/platform-sandbox-session.ts +128 -0
- package/src/input/commands/platform-services-runtime.ts +246 -0
- package/src/input/commands/policy-dispatch.ts +339 -0
- package/src/input/commands/policy.ts +17 -0
- package/src/input/commands/product-runtime.ts +351 -0
- package/src/input/commands/profile-sync-runtime.ts +99 -0
- package/src/input/commands/provider-accounts-runtime.ts +113 -0
- package/src/input/commands/provider.ts +363 -0
- package/src/input/commands/quit-shared.ts +162 -0
- package/src/input/commands/recall-bundle.ts +132 -0
- package/src/input/commands/recall-capture.ts +152 -0
- package/src/input/commands/recall-query.ts +229 -0
- package/src/input/commands/recall-review.ts +98 -0
- package/src/input/commands/recall-shared.ts +22 -0
- package/src/input/commands/remote-runtime-pool.ts +106 -0
- package/src/input/commands/remote-runtime-setup.ts +199 -0
- package/src/input/commands/remote-runtime.ts +531 -0
- package/src/input/commands/replay-runtime.ts +18 -0
- package/src/input/commands/runtime-services.ts +279 -0
- package/src/input/commands/schedule-runtime.ts +332 -0
- package/src/input/commands/services-runtime.ts +207 -0
- package/src/input/commands/session-content.ts +408 -0
- package/src/input/commands/session-workflow.ts +464 -0
- package/src/input/commands/session.ts +376 -0
- package/src/input/commands/settings-sync-runtime.ts +173 -0
- package/src/input/commands/share-runtime.ts +114 -0
- package/src/input/commands/shell-core.ts +320 -0
- package/src/input/commands/skills-runtime.ts +221 -0
- package/src/input/commands/subscription-runtime.ts +434 -0
- package/src/input/commands/tasks-runtime.ts +230 -0
- package/src/input/commands/teamwork-runtime.ts +374 -0
- package/src/input/commands/teleport-runtime.ts +57 -0
- package/src/input/commands/worktree-runtime.ts +137 -0
- package/src/input/commands.ts +127 -0
- package/src/input/file-picker.ts +192 -0
- package/src/input/handler-command-route.ts +106 -0
- package/src/input/handler-content-actions.ts +465 -0
- package/src/input/handler-feed-routes.ts +541 -0
- package/src/input/handler-feed.ts +361 -0
- package/src/input/handler-modal-routes.ts +335 -0
- package/src/input/handler-modal-stack.ts +237 -0
- package/src/input/handler-modal-token-routes.ts +272 -0
- package/src/input/handler-picker-routes.ts +416 -0
- package/src/input/handler-prompt-buffer.ts +320 -0
- package/src/input/handler-shortcuts.ts +195 -0
- package/src/input/handler-ui-state.ts +294 -0
- package/src/input/handler.ts +798 -0
- package/src/input/input-history.ts +267 -0
- package/src/input/keybindings.ts +256 -0
- package/src/input/model-picker.ts +730 -0
- package/src/input/panel-integration-actions.ts +77 -0
- package/src/input/profile-picker-modal.ts +222 -0
- package/src/input/search.ts +100 -0
- package/src/input/selection-modal.ts +163 -0
- package/src/input/selection.ts +135 -0
- package/src/input/session-picker-modal.ts +136 -0
- package/src/input/settings-modal.ts +718 -0
- package/src/input/submission-intent.ts +18 -0
- package/src/input/submission-router.ts +64 -0
- package/src/integrations/index.ts +42 -0
- package/src/integrations/notifier.ts +206 -0
- package/src/integrations/webhooks.ts +177 -0
- package/src/knowledge/consolidation.ts +346 -0
- package/src/knowledge/graphql.ts +324 -0
- package/src/knowledge/index.ts +60 -0
- package/src/knowledge/ingest-compile.ts +386 -0
- package/src/knowledge/ingest-context.ts +18 -0
- package/src/knowledge/ingest-inputs.ts +387 -0
- package/src/knowledge/ingest.ts +20 -0
- package/src/knowledge/internal.ts +257 -0
- package/src/knowledge/knowledge-api.ts +432 -0
- package/src/knowledge/lint.ts +121 -0
- package/src/knowledge/memory-sync.ts +62 -0
- package/src/knowledge/packet.ts +370 -0
- package/src/knowledge/scheduling.ts +283 -0
- package/src/knowledge/service.ts +715 -0
- package/src/main.ts +798 -0
- package/src/mcp/client.ts +383 -0
- package/src/mcp/index.ts +12 -0
- package/src/mcp/mcp-api.ts +90 -0
- package/src/mcp/registry.ts +508 -0
- package/src/media/builtin-image-understanding.ts +303 -0
- package/src/media/builtin-providers.ts +26 -0
- package/src/media/index.ts +18 -0
- package/src/multimodal/index.ts +13 -0
- package/src/multimodal/service.ts +492 -0
- package/src/panels/agent-inspector-panel.ts +515 -0
- package/src/panels/agent-inspector-shared.ts +94 -0
- package/src/panels/agent-logs-panel.ts +539 -0
- package/src/panels/agent-logs-shared.ts +129 -0
- package/src/panels/approval-panel.ts +169 -0
- package/src/panels/automation-control-panel.ts +253 -0
- package/src/panels/base-panel.ts +72 -0
- package/src/panels/builtin/agent.ts +88 -0
- package/src/panels/builtin/development.ts +111 -0
- package/src/panels/builtin/knowledge.ts +26 -0
- package/src/panels/builtin/operations.ts +385 -0
- package/src/panels/builtin/session.ts +61 -0
- package/src/panels/builtin/shared.ts +240 -0
- package/src/panels/builtin-panels.ts +23 -0
- package/src/panels/cockpit-panel.ts +183 -0
- package/src/panels/communication-panel.ts +191 -0
- package/src/panels/context-visualizer-panel.ts +199 -0
- package/src/panels/control-plane-panel.ts +266 -0
- package/src/panels/cost-tracker-panel.ts +444 -0
- package/src/panels/debug-panel.ts +432 -0
- package/src/panels/diff-panel.ts +518 -0
- package/src/panels/docs-panel.ts +283 -0
- package/src/panels/eval-panel.ts +399 -0
- package/src/panels/file-explorer-panel.ts +556 -0
- package/src/panels/file-preview-panel.ts +412 -0
- package/src/panels/forensics-panel.ts +364 -0
- package/src/panels/git-panel.ts +630 -0
- package/src/panels/hooks-panel.ts +274 -0
- package/src/panels/incident-review-panel.ts +247 -0
- package/src/panels/index.ts +48 -0
- package/src/panels/intelligence-panel.ts +176 -0
- package/src/panels/knowledge-panel.ts +328 -0
- package/src/panels/local-auth-panel.ts +146 -0
- package/src/panels/marketplace-panel.ts +223 -0
- package/src/panels/mcp-panel.ts +260 -0
- package/src/panels/memory-panel.ts +293 -0
- package/src/panels/ops-control-panel.ts +184 -0
- package/src/panels/ops-strategy-panel.ts +235 -0
- package/src/panels/orchestration-panel.ts +254 -0
- package/src/panels/panel-list-panel.ts +508 -0
- package/src/panels/panel-manager.ts +538 -0
- package/src/panels/panel-picker.ts +106 -0
- package/src/panels/plan-dashboard-panel.ts +272 -0
- package/src/panels/plugins-panel.ts +201 -0
- package/src/panels/policy-panel.ts +308 -0
- package/src/panels/polish.ts +668 -0
- package/src/panels/provider-account-snapshot.ts +259 -0
- package/src/panels/provider-accounts-panel.ts +221 -0
- package/src/panels/provider-health-domains.ts +211 -0
- package/src/panels/provider-health-panel.ts +725 -0
- package/src/panels/provider-health-tracker.ts +115 -0
- package/src/panels/provider-stats-panel.ts +366 -0
- package/src/panels/remote-panel.ts +449 -0
- package/src/panels/routes-panel.ts +228 -0
- package/src/panels/sandbox-panel.ts +289 -0
- package/src/panels/schedule-panel.ts +344 -0
- package/src/panels/search-focus.ts +32 -0
- package/src/panels/security-panel.ts +329 -0
- package/src/panels/services-panel.ts +271 -0
- package/src/panels/session-browser-panel.ts +399 -0
- package/src/panels/session-maintenance.ts +125 -0
- package/src/panels/settings-sync-panel.ts +164 -0
- package/src/panels/skills-panel.ts +475 -0
- package/src/panels/subscription-panel.ts +273 -0
- package/src/panels/symbol-outline-panel.ts +486 -0
- package/src/panels/system-messages-panel.ts +224 -0
- package/src/panels/tasks-panel.ts +448 -0
- package/src/panels/thinking-panel.ts +304 -0
- package/src/panels/token-budget-panel.ts +469 -0
- package/src/panels/tool-inspector-panel.ts +434 -0
- package/src/panels/types.ts +44 -0
- package/src/panels/watchers-panel.ts +241 -0
- package/src/panels/welcome-panel.ts +64 -0
- package/src/panels/worktree-panel.ts +180 -0
- package/src/panels/wrfc-panel.ts +480 -0
- package/src/permissions/briefs/build.ts +88 -0
- package/src/permissions/manager.ts +356 -0
- package/src/permissions/prompt.ts +184 -0
- package/src/plugins/api.ts +383 -0
- package/src/plugins/loader.ts +304 -0
- package/src/plugins/manager.ts +481 -0
- package/src/profiles/shape.ts +58 -0
- package/src/providers/amazon-bedrock-mantle.ts +50 -0
- package/src/providers/amazon-bedrock.ts +61 -0
- package/src/providers/anthropic-compat.ts +373 -0
- package/src/providers/anthropic-sdk-provider.ts +230 -0
- package/src/providers/anthropic-vertex.ts +59 -0
- package/src/providers/anthropic.ts +469 -0
- package/src/providers/auto-register.ts +417 -0
- package/src/providers/builtin-catalog.ts +326 -0
- package/src/providers/builtin-registry.ts +575 -0
- package/src/providers/cache-planner.ts +258 -0
- package/src/providers/capabilities.ts +601 -0
- package/src/providers/custom-loader.ts +425 -0
- package/src/providers/discovered-compat.ts +18 -0
- package/src/providers/discovered-factory.ts +61 -0
- package/src/providers/discovered-traits.ts +138 -0
- package/src/providers/gemini.ts +462 -0
- package/src/providers/github-copilot.ts +254 -0
- package/src/providers/index.ts +47 -0
- package/src/providers/interface.ts +185 -0
- package/src/providers/llama-cpp.ts +402 -0
- package/src/providers/lm-studio-helpers.ts +367 -0
- package/src/providers/lm-studio.ts +484 -0
- package/src/providers/model-catalog-cache.ts +221 -0
- package/src/providers/model-catalog-notifications.ts +97 -0
- package/src/providers/model-catalog-synthetic.ts +202 -0
- package/src/providers/model-catalog.ts +211 -0
- package/src/providers/model-limits.ts +280 -0
- package/src/providers/ollama.ts +469 -0
- package/src/providers/openai-codex.ts +472 -0
- package/src/providers/openai-compat.ts +615 -0
- package/src/providers/openai.ts +231 -0
- package/src/providers/optimizer.ts +381 -0
- package/src/providers/provider-api.ts +553 -0
- package/src/providers/registry-helpers.ts +34 -0
- package/src/providers/registry-models.ts +77 -0
- package/src/providers/registry-types.ts +67 -0
- package/src/providers/registry.ts +729 -0
- package/src/providers/runtime-metadata.ts +149 -0
- package/src/providers/runtime-snapshot.ts +130 -0
- package/src/providers/synthetic.ts +561 -0
- package/src/providers/tier-prompts.ts +84 -0
- package/src/providers/tool-formats.ts +414 -0
- package/src/renderer/agent-detail-modal.ts +285 -0
- package/src/renderer/autocomplete-overlay.ts +154 -0
- package/src/renderer/block-actions.ts +76 -0
- package/src/renderer/bookmark-modal.ts +101 -0
- package/src/renderer/bottom-bar.ts +58 -0
- package/src/renderer/buffer.ts +34 -0
- package/src/renderer/code-block.ts +373 -0
- package/src/renderer/compositor.ts +261 -0
- package/src/renderer/context-inspector.ts +219 -0
- package/src/renderer/conversation-layout.ts +67 -0
- package/src/renderer/conversation-overlays.ts +123 -0
- package/src/renderer/conversation-surface.ts +260 -0
- package/src/renderer/diff-view.ts +132 -0
- package/src/renderer/diff.ts +122 -0
- package/src/renderer/file-picker-overlay.ts +101 -0
- package/src/renderer/file-tree.ts +153 -0
- package/src/renderer/git-status.ts +89 -0
- package/src/renderer/help-overlay.ts +247 -0
- package/src/renderer/history-search-overlay.ts +73 -0
- package/src/renderer/layout-engine.ts +97 -0
- package/src/renderer/layout.ts +32 -0
- package/src/renderer/live-tail-modal.ts +156 -0
- package/src/renderer/markdown.ts +777 -0
- package/src/renderer/modal-factory.ts +467 -0
- package/src/renderer/modal-utils.ts +24 -0
- package/src/renderer/model-picker-overlay.ts +396 -0
- package/src/renderer/overlay-box.ts +165 -0
- package/src/renderer/overlay-viewport.ts +104 -0
- package/src/renderer/panel-composite.ts +80 -0
- package/src/renderer/panel-picker-overlay.ts +202 -0
- package/src/renderer/panel-tab-bar.ts +69 -0
- package/src/renderer/panel-workspace-bar.ts +38 -0
- package/src/renderer/process-indicator.ts +96 -0
- package/src/renderer/process-modal.ts +295 -0
- package/src/renderer/profile-picker-modal.ts +129 -0
- package/src/renderer/progress.ts +98 -0
- package/src/renderer/search-overlay.ts +54 -0
- package/src/renderer/selection-modal-overlay.ts +214 -0
- package/src/renderer/semantic-diff.ts +369 -0
- package/src/renderer/session-picker-modal.ts +127 -0
- package/src/renderer/settings-modal.ts +701 -0
- package/src/renderer/shell-surface.ts +88 -0
- package/src/renderer/surface-layout.ts +101 -0
- package/src/renderer/syntax-highlighter.ts +542 -0
- package/src/renderer/system-message.ts +83 -0
- package/src/renderer/tab-strip.ts +108 -0
- package/src/renderer/text-layout.ts +31 -0
- package/src/renderer/thinking.ts +17 -0
- package/src/renderer/tool-call.ts +233 -0
- package/src/renderer/ui-factory.ts +524 -0
- package/src/renderer/ui-primitives.ts +96 -0
- package/src/runtime/auth/inspection.ts +125 -0
- package/src/runtime/bootstrap-background.ts +147 -0
- package/src/runtime/bootstrap-command-context.ts +265 -0
- package/src/runtime/bootstrap-command-parts.ts +357 -0
- package/src/runtime/bootstrap-core.ts +375 -0
- package/src/runtime/bootstrap-helpers.ts +88 -0
- package/src/runtime/bootstrap-hook-bridge.ts +271 -0
- package/src/runtime/bootstrap-runtime-events.ts +254 -0
- package/src/runtime/bootstrap-services.ts +197 -0
- package/src/runtime/bootstrap-shell.ts +262 -0
- package/src/runtime/bootstrap.ts +488 -0
- package/src/runtime/compaction/index.ts +90 -0
- package/src/runtime/compaction/lifecycle.ts +167 -0
- package/src/runtime/compaction/manager.ts +474 -0
- package/src/runtime/compaction/quality-score.ts +279 -0
- package/src/runtime/compaction/resume-repair.ts +183 -0
- package/src/runtime/compaction/strategies/autocompact.ts +65 -0
- package/src/runtime/compaction/strategies/boundary-commit.ts +106 -0
- package/src/runtime/compaction/strategies/collapse.ts +90 -0
- package/src/runtime/compaction/strategies/index.ts +23 -0
- package/src/runtime/compaction/strategies/microcompact.ts +74 -0
- package/src/runtime/compaction/strategies/reactive.ts +89 -0
- package/src/runtime/compaction/types.ts +221 -0
- package/src/runtime/context.ts +158 -0
- package/src/runtime/diagnostics/actions.ts +776 -0
- package/src/runtime/diagnostics/index.ts +99 -0
- package/src/runtime/diagnostics/panels/agents.ts +252 -0
- package/src/runtime/diagnostics/panels/events.ts +188 -0
- package/src/runtime/diagnostics/panels/health.ts +242 -0
- package/src/runtime/diagnostics/panels/index.ts +24 -0
- package/src/runtime/diagnostics/panels/ops.ts +156 -0
- package/src/runtime/diagnostics/panels/policy.ts +176 -0
- package/src/runtime/diagnostics/panels/tasks.ts +251 -0
- package/src/runtime/diagnostics/panels/tool-calls.ts +267 -0
- package/src/runtime/diagnostics/provider.ts +262 -0
- package/src/runtime/ecosystem/catalog.ts +606 -0
- package/src/runtime/ecosystem/recommendations.ts +117 -0
- package/src/runtime/emitters/agents.ts +96 -0
- package/src/runtime/emitters/automation.ts +112 -0
- package/src/runtime/emitters/communication.ts +53 -0
- package/src/runtime/emitters/compaction.ts +161 -0
- package/src/runtime/emitters/control-plane.ts +65 -0
- package/src/runtime/emitters/deliveries.ts +65 -0
- package/src/runtime/emitters/forensics.ts +17 -0
- package/src/runtime/emitters/index.ts +59 -0
- package/src/runtime/emitters/knowledge.ts +129 -0
- package/src/runtime/emitters/mcp.ts +95 -0
- package/src/runtime/emitters/ops.ts +163 -0
- package/src/runtime/emitters/orchestration.ts +87 -0
- package/src/runtime/emitters/permissions.ts +98 -0
- package/src/runtime/emitters/planner.ts +23 -0
- package/src/runtime/emitters/plugins.ts +78 -0
- package/src/runtime/emitters/providers.ts +30 -0
- package/src/runtime/emitters/routes.ts +57 -0
- package/src/runtime/emitters/security.ts +53 -0
- package/src/runtime/emitters/session.ts +93 -0
- package/src/runtime/emitters/surfaces.ts +57 -0
- package/src/runtime/emitters/tasks.ts +69 -0
- package/src/runtime/emitters/tools.ts +140 -0
- package/src/runtime/emitters/transport.ts +78 -0
- package/src/runtime/emitters/turn.ts +155 -0
- package/src/runtime/emitters/ui.ts +57 -0
- package/src/runtime/emitters/watchers.ts +57 -0
- package/src/runtime/emitters/workflows.ts +79 -0
- package/src/runtime/eval/index.ts +48 -0
- package/src/runtime/eval/runner.ts +163 -0
- package/src/runtime/eval/suites.ts +264 -0
- package/src/runtime/events/domain-map.ts +148 -0
- package/src/runtime/events/index.ts +194 -0
- package/src/runtime/events/turn.ts +60 -0
- package/src/runtime/events/workflows.ts +17 -0
- package/src/runtime/forensics/collector.ts +693 -0
- package/src/runtime/forensics/index.ts +23 -0
- package/src/runtime/foundation-clients.ts +78 -0
- package/src/runtime/foundation-services.ts +96 -0
- package/src/runtime/guidance.ts +183 -0
- package/src/runtime/health/effect-handlers.ts +189 -0
- package/src/runtime/health/index.ts +70 -0
- package/src/runtime/health/wiring.ts +115 -0
- package/src/runtime/index.ts +174 -0
- package/src/runtime/integration/helpers.ts +640 -0
- package/src/runtime/lifecycle.ts +107 -0
- package/src/runtime/mcp/index.ts +68 -0
- package/src/runtime/mcp/manager.ts +513 -0
- package/src/runtime/network/inbound.ts +131 -0
- package/src/runtime/network/index.ts +30 -0
- package/src/runtime/network/outbound.ts +292 -0
- package/src/runtime/network/shared.ts +82 -0
- package/src/runtime/operator-client.ts +235 -0
- package/src/runtime/ops/control-plane.ts +363 -0
- package/src/runtime/ops/index.ts +122 -0
- package/src/runtime/ops/playbooks/index.ts +10 -0
- package/src/runtime/ops/playbooks/session-unrecoverable.ts +196 -0
- package/src/runtime/ops/playbooks/stuck-turn.ts +197 -0
- package/src/runtime/ops/runtime-context.ts +100 -0
- package/src/runtime/ops-api.ts +27 -0
- package/src/runtime/orchestration/spawn-policy.ts +83 -0
- package/src/runtime/peer-client.ts +404 -0
- package/src/runtime/perf/index.ts +57 -0
- package/src/runtime/perf/slo-collector.ts +375 -0
- package/src/runtime/permissions/index.ts +190 -0
- package/src/runtime/permissions/policy-runtime.ts +175 -0
- package/src/runtime/permissions/preflight.ts +101 -0
- package/src/runtime/permissions/rule-suggestions.ts +36 -0
- package/src/runtime/plugins/hot-reload.ts +221 -0
- package/src/runtime/plugins/index.ts +84 -0
- package/src/runtime/plugins/lifecycle.ts +95 -0
- package/src/runtime/plugins/manager.ts +474 -0
- package/src/runtime/plugins/manifest.ts +167 -0
- package/src/runtime/plugins/quarantine.ts +202 -0
- package/src/runtime/plugins/trust.ts +291 -0
- package/src/runtime/plugins/types.ts +205 -0
- package/src/runtime/provider-accounts/registry.ts +326 -0
- package/src/runtime/remote/distributed-runtime-contract-schemas.ts +386 -0
- package/src/runtime/remote/index.ts +488 -0
- package/src/runtime/remote/runner-registry.ts +438 -0
- package/src/runtime/remote/supervisor.ts +70 -0
- package/src/runtime/runtime-hook-api.ts +5 -0
- package/src/runtime/runtime-knowledge-api.ts +14 -0
- package/src/runtime/runtime-mcp-api.ts +5 -0
- package/src/runtime/runtime-ops-api.ts +86 -0
- package/src/runtime/runtime-provider-api.ts +18 -0
- package/src/runtime/sandbox/backend.ts +291 -0
- package/src/runtime/sandbox/manager.ts +364 -0
- package/src/runtime/sandbox/provisioning.ts +422 -0
- package/src/runtime/sandbox/session-registry.ts +289 -0
- package/src/runtime/services.ts +541 -0
- package/src/runtime/session-maintenance.ts +188 -0
- package/src/runtime/session-persistence.ts +288 -0
- package/src/runtime/session-return-context.ts +195 -0
- package/src/runtime/settings/control-plane-store.ts +258 -0
- package/src/runtime/settings/control-plane.ts +599 -0
- package/src/runtime/shell-command-extensions.ts +54 -0
- package/src/runtime/shell-command-ops.ts +207 -0
- package/src/runtime/shell-command-platform.ts +47 -0
- package/src/runtime/shell-command-services.ts +143 -0
- package/src/runtime/shell-command-workspace.ts +31 -0
- package/src/runtime/store/domains/conversation.ts +181 -0
- package/src/runtime/store/domains/domain-read-matrix.ts +17 -0
- package/src/runtime/store/domains/index.ts +222 -0
- package/src/runtime/store/domains/panels.ts +117 -0
- package/src/runtime/store/domains/permissions.ts +143 -0
- package/src/runtime/store/domains/ui-perf.ts +103 -0
- package/src/runtime/store/helpers/reducers/conversation.ts +228 -0
- package/src/runtime/store/helpers/reducers/lifecycle.ts +440 -0
- package/src/runtime/store/helpers/reducers/shared.ts +60 -0
- package/src/runtime/store/helpers/reducers/sync.ts +555 -0
- package/src/runtime/store/helpers/reducers.ts +30 -0
- package/src/runtime/store/index.ts +304 -0
- package/src/runtime/store/selectors/index.ts +354 -0
- package/src/runtime/store/state.ts +137 -0
- package/src/runtime/tasks/adapters/acp-adapter.ts +211 -0
- package/src/runtime/tasks/adapters/agent-adapter.ts +208 -0
- package/src/runtime/tasks/adapters/index.ts +16 -0
- package/src/runtime/tasks/adapters/process-adapter.ts +214 -0
- package/src/runtime/tasks/adapters/scheduler-adapter.ts +193 -0
- package/src/runtime/tasks/index.ts +68 -0
- package/src/runtime/tasks/manager.ts +415 -0
- package/src/runtime/telemetry/api-helpers.ts +517 -0
- package/src/runtime/telemetry/api.ts +768 -0
- package/src/runtime/telemetry/index.ts +178 -0
- package/src/runtime/telemetry/instrumentation/domain-bridge-agent-session.ts +440 -0
- package/src/runtime/telemetry/instrumentation/domain-bridge-plugin-mcp.ts +200 -0
- package/src/runtime/telemetry/instrumentation/domain-bridge-shared.ts +18 -0
- package/src/runtime/telemetry/instrumentation/domain-bridge-transport-task.ts +204 -0
- package/src/runtime/telemetry/instrumentation/domain-bridge.ts +125 -0
- package/src/runtime/telemetry/instrumentation/index.ts +67 -0
- package/src/runtime/tools/context.ts +114 -0
- package/src/runtime/tools/index.ts +46 -0
- package/src/runtime/tools/phased-executor.ts +448 -0
- package/src/runtime/tools/phases/budget.ts +130 -0
- package/src/runtime/tools/phases/execute.ts +69 -0
- package/src/runtime/tools/phases/index.ts +13 -0
- package/src/runtime/tools/phases/map-output.ts +98 -0
- package/src/runtime/tools/phases/permission.ts +133 -0
- package/src/runtime/tools/phases/posthook.ts +57 -0
- package/src/runtime/tools/phases/prehook.ts +68 -0
- package/src/runtime/tools/phases/validate.ts +53 -0
- package/src/runtime/transports/direct.ts +73 -0
- package/src/runtime/transports/http-helpers.ts +218 -0
- package/src/runtime/transports/http-types.ts +364 -0
- package/src/runtime/transports/http.ts +629 -0
- package/src/runtime/transports/realtime.ts +50 -0
- package/src/runtime/transports/remote-events.ts +16 -0
- package/src/runtime/transports/shared.ts +39 -0
- package/src/runtime/transports/ui-runtime-events.ts +35 -0
- package/src/runtime/ui/index.ts +39 -0
- package/src/runtime/ui/model-picker/data-provider.ts +182 -0
- package/src/runtime/ui/model-picker/health-enrichment.ts +228 -0
- package/src/runtime/ui/model-picker/index.ts +59 -0
- package/src/runtime/ui/model-picker/types.ts +149 -0
- package/src/runtime/ui/provider-health/data-provider.ts +244 -0
- package/src/runtime/ui/provider-health/fallback-visualizer.ts +69 -0
- package/src/runtime/ui/provider-health/index.ts +46 -0
- package/src/runtime/ui/provider-health/types.ts +146 -0
- package/src/runtime/ui-events.ts +46 -0
- package/src/runtime/ui-read-model-helpers.ts +32 -0
- package/src/runtime/ui-read-models-core.ts +95 -0
- package/src/runtime/ui-read-models-observability-maintenance.ts +81 -0
- package/src/runtime/ui-read-models-observability-options.ts +5 -0
- package/src/runtime/ui-read-models-observability-remote.ts +73 -0
- package/src/runtime/ui-read-models-observability-security.ts +172 -0
- package/src/runtime/ui-read-models-observability-system.ts +217 -0
- package/src/runtime/ui-read-models-observability.ts +59 -0
- package/src/runtime/ui-read-models-operations.ts +203 -0
- package/src/runtime/ui-read-models.ts +61 -0
- package/src/runtime/ui-service-queries.ts +114 -0
- package/src/runtime/ui-services.ts +163 -0
- package/src/runtime/worktree/registry.ts +252 -0
- package/src/scripts/process-messages.ts +42 -0
- package/src/sessions/manager.ts +388 -0
- package/src/shell/blocking-input.ts +89 -0
- package/src/shell/ui-openers.ts +163 -0
- package/src/state/file-watcher.ts +294 -0
- package/src/state/index.ts +56 -0
- package/src/state/knowledge-injection.ts +214 -0
- package/src/state/memory-embedding-http.ts +642 -0
- package/src/state/memory-embeddings.ts +312 -0
- package/src/state/memory-ingest.ts +132 -0
- package/src/state/memory-registry.ts +111 -0
- package/src/state/memory-store-helpers.ts +160 -0
- package/src/state/memory-store.ts +728 -0
- package/src/state/memory-vector-store.ts +418 -0
- package/src/templates/manager.ts +187 -0
- package/src/tools/agent/index.ts +610 -0
- package/src/tools/agent/manager.ts +476 -0
- package/src/tools/analyze/git-modes.ts +380 -0
- package/src/tools/analyze/index.ts +128 -0
- package/src/tools/channel/agent-tools.ts +16 -0
- package/src/tools/channel/index.ts +268 -0
- package/src/tools/control/index.ts +90 -0
- package/src/tools/edit/core.ts +619 -0
- package/src/tools/edit/index.ts +4 -0
- package/src/tools/edit/phased.ts +33 -0
- package/src/tools/fetch/index.ts +3 -0
- package/src/tools/fetch/phased.ts +34 -0
- package/src/tools/fetch/runtime.ts +499 -0
- package/src/tools/index.ts +186 -0
- package/src/tools/mcp/index.ts +190 -0
- package/src/tools/remote-trigger/index.ts +130 -0
- package/src/tools/repl/index.ts +318 -0
- package/src/tools/shared/auto-heal.ts +282 -0
- package/src/tools/state/index.ts +688 -0
- package/src/tools/web-search/index.ts +38 -0
- package/src/tools/write/index.ts +604 -0
- package/src/tools/write/phased.ts +41 -0
- package/src/types/generated/foundation-client-types.ts +22 -0
- package/src/types/sql-js.d.ts +15 -0
- package/src/utils/splash-lines.ts +46 -0
- package/src/version.ts +17 -0
- package/src/watchers/index.ts +11 -0
- package/src/watchers/registry.ts +517 -0
- package/src/web-search/index.ts +26 -0
- package/src/web-search/provider-registry.ts +64 -0
- package/src/web-search/providers/brave.ts +100 -0
- package/src/web-search/providers/duckduckgo.ts +270 -0
- package/src/web-search/providers/exa.ts +77 -0
- package/src/web-search/providers/firecrawl.ts +90 -0
- package/src/web-search/providers/perplexity.ts +86 -0
- package/src/web-search/providers/searxng.ts +88 -0
- package/src/web-search/providers/shared.ts +249 -0
- package/src/web-search/providers/tavily.ts +90 -0
- package/src/web-search/service.ts +142 -0
- package/src/widget/index.ts +2 -0
- package/src/widget/types.ts +9 -0
- package/src/widget/widget.ts +8 -0
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
import type { ModelDefinition } from '../providers/registry.ts';
|
|
2
|
+
import type { FavoritesStore } from '@pellux/goodvibes-sdk/platform/providers/favorites';
|
|
3
|
+
import { EFFORT_DESCRIPTIONS } from '@pellux/goodvibes-sdk/platform/providers/effort-levels';
|
|
4
|
+
import { getQualityTier, getQualityTierFromScore, compositeScore, A_TIER_THRESHOLD } from '@pellux/goodvibes-sdk/platform/providers/model-benchmarks';
|
|
5
|
+
import type { BenchmarkStore } from '@pellux/goodvibes-sdk/platform/providers/model-benchmarks';
|
|
6
|
+
import type { ProviderRegistry } from '../providers/registry.ts';
|
|
7
|
+
|
|
8
|
+
export type PickerMode = 'model' | 'provider' | 'effort' | 'contextCap';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Pricing tier filter.
|
|
12
|
+
* 'paid' matches ModelDefinition tiers 'standard' and 'premium' for forward-compat
|
|
13
|
+
* with future CatalogModel tiers ('free' | 'paid' | 'subscription').
|
|
14
|
+
*/
|
|
15
|
+
export type CategoryFilter = 'all' | 'free' | 'paid' | 'subscription';
|
|
16
|
+
|
|
17
|
+
/** Model family grouping names. */
|
|
18
|
+
export type ModelFamily =
|
|
19
|
+
| 'GPT'
|
|
20
|
+
| 'Claude'
|
|
21
|
+
| 'Gemini'
|
|
22
|
+
| 'Llama'
|
|
23
|
+
| 'Qwen'
|
|
24
|
+
| 'GLM'
|
|
25
|
+
| 'MiniMax'
|
|
26
|
+
| 'DeepSeek'
|
|
27
|
+
| 'Mistral'
|
|
28
|
+
| 'Command'
|
|
29
|
+
| 'Grok'
|
|
30
|
+
| 'Kimi'
|
|
31
|
+
| 'Other';
|
|
32
|
+
|
|
33
|
+
/** Capability filter — subset of ModelDefinition capabilities. */
|
|
34
|
+
export type CapabilityFilter = 'reasoning' | 'toolUse' | 'multimodal' | 'none';
|
|
35
|
+
|
|
36
|
+
/** Benchmark score sort order. */
|
|
37
|
+
export type BenchmarkSort = 'none' | 'composite' | 'swe' | 'gpqa';
|
|
38
|
+
|
|
39
|
+
/** Group-by cycling order. */
|
|
40
|
+
export type GroupByMode = 'provider' | 'family' | 'pricingTier' | 'qualityTier';
|
|
41
|
+
|
|
42
|
+
// ── Family detection helpers ──────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
/** Patterns for detecting model family from id/displayName. */
|
|
45
|
+
const FAMILY_PATTERNS: Array<{ pattern: RegExp; family: ModelFamily }> = [
|
|
46
|
+
{ pattern: /claude/i, family: 'Claude' },
|
|
47
|
+
{ pattern: /gpt|\bo1\b|\bo3\b|\bo4\b/i, family: 'GPT' },
|
|
48
|
+
{ pattern: /gemini/i, family: 'Gemini' },
|
|
49
|
+
{ pattern: /llama/i, family: 'Llama' },
|
|
50
|
+
{ pattern: /qwen/i, family: 'Qwen' },
|
|
51
|
+
{ pattern: /glm|chatglm/i, family: 'GLM' },
|
|
52
|
+
{ pattern: /minimax|abab/i, family: 'MiniMax' },
|
|
53
|
+
{ pattern: /deepseek/i, family: 'DeepSeek' },
|
|
54
|
+
{ pattern: /mistral|mixtral/i, family: 'Mistral' },
|
|
55
|
+
{ pattern: /command|cohere/i, family: 'Command' },
|
|
56
|
+
{ pattern: /grok/i, family: 'Grok' },
|
|
57
|
+
{ pattern: /kimi|moonshot/i, family: 'Kimi' },
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
/** Detect the model family from id and displayName. */
|
|
61
|
+
export function detectFamily(model: ModelDefinition): ModelFamily {
|
|
62
|
+
const haystack = `${model.id} ${model.displayName}`;
|
|
63
|
+
for (const { pattern, family } of FAMILY_PATTERNS) {
|
|
64
|
+
if (pattern.test(haystack)) return family;
|
|
65
|
+
}
|
|
66
|
+
return 'Other';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Map ModelDefinition tier to CategoryFilter bucket.
|
|
71
|
+
* 'standard' and 'premium' both map to 'paid' for forward-compat.
|
|
72
|
+
*/
|
|
73
|
+
export function tierToCategoryFilter(tier: string | undefined): CategoryFilter {
|
|
74
|
+
if (tier === 'free') return 'free';
|
|
75
|
+
if (tier === 'subscription') return 'subscription';
|
|
76
|
+
return 'paid';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** A generic selectable item for non-model modes. */
|
|
80
|
+
export interface PickerItem {
|
|
81
|
+
id: string;
|
|
82
|
+
label: string;
|
|
83
|
+
detail?: string;
|
|
84
|
+
/** If true, this item is a group header (not selectable). */
|
|
85
|
+
isGroupHeader?: boolean;
|
|
86
|
+
/** Quality tier badge for model items: S/A/B/C. */
|
|
87
|
+
qualityTier?: string;
|
|
88
|
+
/** Whether this model is pinned/favorited. */
|
|
89
|
+
isPinned?: boolean;
|
|
90
|
+
/** True when model tier is free. */
|
|
91
|
+
isFree?: boolean;
|
|
92
|
+
/** True when this provider item has a configured API key. */
|
|
93
|
+
isConfigured?: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Provider IDs treated as "Popular" in the provider picker. */
|
|
97
|
+
export const POPULAR_PROVIDERS: ReadonlySet<string> = new Set([
|
|
98
|
+
'anthropic',
|
|
99
|
+
'google',
|
|
100
|
+
'groq',
|
|
101
|
+
'mistral',
|
|
102
|
+
'nvidia',
|
|
103
|
+
'ollama',
|
|
104
|
+
'openai',
|
|
105
|
+
'openrouter',
|
|
106
|
+
'synthetic',
|
|
107
|
+
]);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* ModelPickerModal - Multi-step interactive picker for model, provider, and effort.
|
|
111
|
+
* Supports three modes: 'model', 'provider', 'effort'.
|
|
112
|
+
*
|
|
113
|
+
* Stage 5 features:
|
|
114
|
+
* - Pricing tier filter: Free / Paid / Subscription / All
|
|
115
|
+
* - Family grouping: GPT, Claude, Gemini, Llama, Qwen, etc.
|
|
116
|
+
* - Capability filters: reasoning, toolUse, multimodal
|
|
117
|
+
* - Available-only toggle (filters to configured providers)
|
|
118
|
+
* - Benchmark sort: composite / SWE / GPQA
|
|
119
|
+
* - Group-by cycling: provider → family → pricingTier → qualityTier
|
|
120
|
+
* - Quality tier badge (S/A/B/C) from model-benchmarks
|
|
121
|
+
* - Pinned/favorite indicator
|
|
122
|
+
*/
|
|
123
|
+
export class ModelPickerModal {
|
|
124
|
+
constructor(
|
|
125
|
+
private readonly favoritesStore: Pick<FavoritesStore, 'getRecentModels'>,
|
|
126
|
+
private readonly benchmarkStore: Pick<BenchmarkStore, 'getBenchmarks'>,
|
|
127
|
+
private readonly providerRegistry: Pick<ProviderRegistry, 'getSyntheticModelInfoFromCatalog'>,
|
|
128
|
+
) {}
|
|
129
|
+
|
|
130
|
+
public active = false;
|
|
131
|
+
public mode: PickerMode = 'model';
|
|
132
|
+
public searchFocused = false;
|
|
133
|
+
/** Tracks the mode we came from, for back-navigation. */
|
|
134
|
+
public previousMode: PickerMode | null = null;
|
|
135
|
+
public selectedIndex = 0;
|
|
136
|
+
/** Scroll offset for the visible item window (tracks first visible item index). */
|
|
137
|
+
public scrollOffset = 0;
|
|
138
|
+
public models: ModelDefinition[] = [];
|
|
139
|
+
public providers: string[] = [];
|
|
140
|
+
public effortLevels: string[] = [];
|
|
141
|
+
/** The model chosen in model-mode, awaiting effort selection. */
|
|
142
|
+
public pendingModel: ModelDefinition | null = null;
|
|
143
|
+
/** The model awaiting context cap input (contextCap mode). */
|
|
144
|
+
public contextCapPendingModel: ModelDefinition | null = null;
|
|
145
|
+
/** Current input string in contextCap mode. */
|
|
146
|
+
public contextCapQuery = '';
|
|
147
|
+
|
|
148
|
+
// ── Search / filter ──────────────────────────────────────────────────────────
|
|
149
|
+
/** Current search query string (empty = no filter). */
|
|
150
|
+
public query = '';
|
|
151
|
+
/** Active pricing tier filter. */
|
|
152
|
+
public categoryFilter: CategoryFilter = 'all';
|
|
153
|
+
/** Active capability filter. */
|
|
154
|
+
public capabilityFilter: CapabilityFilter = 'none';
|
|
155
|
+
/** When true, only show models from providers with a configured API key. */
|
|
156
|
+
public availableOnly = true;
|
|
157
|
+
/** Set of provider names that have a configured key (used for availableOnly filter). */
|
|
158
|
+
public configuredProviders: Set<string> = new Set();
|
|
159
|
+
/** IDs of pinned/favorite models — shown at top of list. */
|
|
160
|
+
public pinnedIds: Set<string> = new Set();
|
|
161
|
+
/** IDs of recently used models — shown after pinned, before the rest. */
|
|
162
|
+
public recentIds: string[] = [];
|
|
163
|
+
/** Benchmark score sort order. */
|
|
164
|
+
public benchmarkSort: BenchmarkSort = 'none';
|
|
165
|
+
/** Current group-by mode. */
|
|
166
|
+
public groupBy: GroupByMode = 'provider';
|
|
167
|
+
|
|
168
|
+
// ── Category filter cycling ───────────────────────────────────────────────
|
|
169
|
+
private static readonly CATEGORY_CYCLE: CategoryFilter[] = ['all', 'free', 'paid', 'subscription'];
|
|
170
|
+
/** Cycle to next pricing tier filter. */
|
|
171
|
+
cycleCategory(): void {
|
|
172
|
+
const idx = ModelPickerModal.CATEGORY_CYCLE.indexOf(this.categoryFilter);
|
|
173
|
+
this.categoryFilter = ModelPickerModal.CATEGORY_CYCLE[(idx + 1) % ModelPickerModal.CATEGORY_CYCLE.length];
|
|
174
|
+
this._clampSelection();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ── Group-by cycling ──────────────────────────────────────────────────────
|
|
178
|
+
private static readonly GROUP_BY_CYCLE: GroupByMode[] = ['provider', 'family', 'pricingTier', 'qualityTier'];
|
|
179
|
+
/** Cycle to next group-by mode. */
|
|
180
|
+
cycleGroupBy(): void {
|
|
181
|
+
const idx = ModelPickerModal.GROUP_BY_CYCLE.indexOf(this.groupBy);
|
|
182
|
+
this.groupBy = ModelPickerModal.GROUP_BY_CYCLE[(idx + 1) % ModelPickerModal.GROUP_BY_CYCLE.length];
|
|
183
|
+
this._clampSelection();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ── Benchmark sort cycling ────────────────────────────────────────────────
|
|
187
|
+
private static readonly BENCHMARK_SORT_CYCLE: BenchmarkSort[] = ['none', 'composite', 'swe', 'gpqa'];
|
|
188
|
+
/** Cycle to next benchmark sort order. */
|
|
189
|
+
cycleBenchmarkSort(): void {
|
|
190
|
+
const idx = ModelPickerModal.BENCHMARK_SORT_CYCLE.indexOf(this.benchmarkSort);
|
|
191
|
+
this.benchmarkSort = ModelPickerModal.BENCHMARK_SORT_CYCLE[(idx + 1) % ModelPickerModal.BENCHMARK_SORT_CYCLE.length];
|
|
192
|
+
this._clampSelection();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Return true when a model is from a custom or discovered (local) provider.
|
|
197
|
+
* Local models have `contextWindowProvenance` set; catalog cloud models do not.
|
|
198
|
+
*/
|
|
199
|
+
isLocalModel(model: ModelDefinition): boolean {
|
|
200
|
+
return model.contextWindowProvenance !== undefined;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Enter context window cap input mode for a local model. */
|
|
204
|
+
enterContextCapMode(model: ModelDefinition): void {
|
|
205
|
+
this.previousMode = 'model';
|
|
206
|
+
this.contextCapPendingModel = model;
|
|
207
|
+
this.contextCapQuery = '';
|
|
208
|
+
this.mode = 'contextCap';
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Append a character to the context cap query. */
|
|
212
|
+
appendContextCapChar(ch: string): void {
|
|
213
|
+
// Only allow digits; limit to 9 characters (max representable: 999_999_999)
|
|
214
|
+
if (this.contextCapQuery.length >= 9) return;
|
|
215
|
+
if (/^[0-9]$/.test(ch)) {
|
|
216
|
+
this.contextCapQuery += ch;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Delete the last character from the context cap query. */
|
|
221
|
+
deleteContextCapChar(): void {
|
|
222
|
+
if (this.contextCapQuery.length > 0) {
|
|
223
|
+
this.contextCapQuery = this.contextCapQuery.slice(0, -1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Open showing all models — entry point for /model */
|
|
228
|
+
openAllModels(models: ModelDefinition[], currentModelId: string): void {
|
|
229
|
+
this.models = models;
|
|
230
|
+
this.mode = 'model';
|
|
231
|
+
this.active = true;
|
|
232
|
+
this.pendingModel = null;
|
|
233
|
+
this.searchFocused = false;
|
|
234
|
+
this.query = '';
|
|
235
|
+
this.categoryFilter = 'all';
|
|
236
|
+
this.capabilityFilter = 'none';
|
|
237
|
+
const filtered = this.getFilteredModels();
|
|
238
|
+
const idx = filtered.findIndex(m => m.id === currentModelId);
|
|
239
|
+
this.selectedIndex = idx >= 0 ? idx : 0;
|
|
240
|
+
this.scrollOffset = 0;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Open showing providers first — entry point for /provider */
|
|
244
|
+
openProviders(providers: string[], currentProvider: string): void {
|
|
245
|
+
this.previousMode = null;
|
|
246
|
+
this.providers = providers;
|
|
247
|
+
this.mode = 'provider';
|
|
248
|
+
this.active = true;
|
|
249
|
+
this.pendingModel = null;
|
|
250
|
+
this.searchFocused = false;
|
|
251
|
+
this.query = '';
|
|
252
|
+
this.categoryFilter = 'all';
|
|
253
|
+
this.capabilityFilter = 'none';
|
|
254
|
+
// Start selection at the top of the Popular providers group.
|
|
255
|
+
this.selectedIndex = 0;
|
|
256
|
+
this.scrollOffset = 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Transition to model list filtered by provider (called from provider mode Enter). */
|
|
260
|
+
showModelsForProvider(models: ModelDefinition[], _provider: string): void {
|
|
261
|
+
this.previousMode = 'provider';
|
|
262
|
+
this.models = models;
|
|
263
|
+
this.mode = 'model';
|
|
264
|
+
this.searchFocused = false;
|
|
265
|
+
this.query = '';
|
|
266
|
+
this.categoryFilter = 'all';
|
|
267
|
+
this.capabilityFilter = 'none';
|
|
268
|
+
// User explicitly chose this provider — disable availability filter so synthetic
|
|
269
|
+
// models (which have no real API key) are not filtered out.
|
|
270
|
+
this.availableOnly = false;
|
|
271
|
+
this.selectedIndex = 0;
|
|
272
|
+
this.scrollOffset = 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Transition to effort picker after model is chosen. */
|
|
276
|
+
showEffortPicker(model: ModelDefinition, currentEffort: string): void {
|
|
277
|
+
this.previousMode = 'model';
|
|
278
|
+
this.pendingModel = model;
|
|
279
|
+
this.searchFocused = false;
|
|
280
|
+
this.effortLevels = model.reasoningEffort ?? [];
|
|
281
|
+
this.mode = 'effort';
|
|
282
|
+
const idx = this.effortLevels.indexOf(currentEffort);
|
|
283
|
+
this.selectedIndex = idx >= 0 ? idx : 0;
|
|
284
|
+
this.scrollOffset = 0;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** Close the picker entirely. */
|
|
288
|
+
close(): void {
|
|
289
|
+
this.active = false;
|
|
290
|
+
this.mode = 'model';
|
|
291
|
+
this.models = [];
|
|
292
|
+
this.providers = [];
|
|
293
|
+
this.pendingModel = null;
|
|
294
|
+
this.contextCapPendingModel = null;
|
|
295
|
+
this.contextCapQuery = '';
|
|
296
|
+
this.searchFocused = false;
|
|
297
|
+
this.selectedIndex = 0;
|
|
298
|
+
this.scrollOffset = 0;
|
|
299
|
+
this.query = '';
|
|
300
|
+
this.categoryFilter = 'all';
|
|
301
|
+
this.capabilityFilter = 'none';
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ── Search helpers ─────────────────────────────────────────────────────────
|
|
305
|
+
|
|
306
|
+
/** Append a character to the search query and clamp selectedIndex. */
|
|
307
|
+
appendChar(ch: string): void {
|
|
308
|
+
this.query += ch;
|
|
309
|
+
this._clampSelection();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** Delete the last character from the search query and clamp selectedIndex. */
|
|
313
|
+
deleteChar(): void {
|
|
314
|
+
if (this.query.length > 0) {
|
|
315
|
+
this.query = this.query.slice(0, -1);
|
|
316
|
+
this._clampSelection();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** Clear the search query and clamp selectedIndex. */
|
|
321
|
+
clearQuery(): void {
|
|
322
|
+
this.query = '';
|
|
323
|
+
this._clampSelection();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
canFocusSearch(): boolean {
|
|
327
|
+
return this.mode === 'model' || this.mode === 'provider';
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
focusSearch(): void {
|
|
331
|
+
if (this.canFocusSearch()) this.searchFocused = true;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
blurSearch(): void {
|
|
335
|
+
this.searchFocused = false;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Set category filter and clamp selectedIndex. */
|
|
339
|
+
setCategoryFilter(filter: CategoryFilter): void {
|
|
340
|
+
this.categoryFilter = filter;
|
|
341
|
+
this._clampSelection();
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** Set capability filter and clamp selectedIndex. */
|
|
345
|
+
setCapabilityFilter(filter: CapabilityFilter): void {
|
|
346
|
+
this.capabilityFilter = filter;
|
|
347
|
+
this._clampSelection();
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/** Toggle the available-only filter. */
|
|
351
|
+
toggleAvailableOnly(): void {
|
|
352
|
+
this.availableOnly = !this.availableOnly;
|
|
353
|
+
this._clampSelection();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Split providers into two ordered groups: Popular, All.
|
|
358
|
+
* Each group is alphabetized. Popular contains providers in POPULAR_PROVIDERS;
|
|
359
|
+
* All contains the rest. Configuration status is shown via checkmarks in the
|
|
360
|
+
* renderer and does not affect grouping.
|
|
361
|
+
*/
|
|
362
|
+
getGroupedProviders(): { popular: string[]; all: string[] } {
|
|
363
|
+
const popular: string[] = [];
|
|
364
|
+
const all: string[] = [];
|
|
365
|
+
|
|
366
|
+
for (const p of this.providers) {
|
|
367
|
+
const pLower = p.toLowerCase();
|
|
368
|
+
if (POPULAR_PROVIDERS.has(pLower)) {
|
|
369
|
+
popular.push(p);
|
|
370
|
+
} else {
|
|
371
|
+
all.push(p);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
popular.sort((a, b) => a.localeCompare(b));
|
|
376
|
+
all.sort((a, b) => a.localeCompare(b));
|
|
377
|
+
|
|
378
|
+
return { popular, all };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Return providers matching the current query (case-insensitive substring), in grouped order. */
|
|
382
|
+
getFilteredProviders(): string[] {
|
|
383
|
+
const { popular, all } = this.getGroupedProviders();
|
|
384
|
+
const ordered = [...popular, ...all];
|
|
385
|
+
if (this.query.trim().length === 0) return ordered;
|
|
386
|
+
const q = this.query.toLowerCase();
|
|
387
|
+
return ordered.filter(p => p.toLowerCase().includes(q));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/** Return models matching all current filters, sorted per benchmarkSort. */
|
|
391
|
+
getFilteredModels(): ModelDefinition[] {
|
|
392
|
+
let result = this.models;
|
|
393
|
+
|
|
394
|
+
// Available-only filter
|
|
395
|
+
if (this.availableOnly && this.configuredProviders.size > 0) {
|
|
396
|
+
result = result.filter(m => this.configuredProviders.has(m.provider));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Pricing tier / category filter
|
|
400
|
+
if (this.categoryFilter === 'free') {
|
|
401
|
+
result = result.filter(m => m.tier === 'free');
|
|
402
|
+
} else if (this.categoryFilter === 'paid') {
|
|
403
|
+
result = result.filter(m => m.tier === 'standard' || m.tier === 'premium' || m.tier == null);
|
|
404
|
+
} else if (this.categoryFilter === 'subscription') {
|
|
405
|
+
result = result.filter(m => tierToCategoryFilter(m.tier) === 'subscription');
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Capability filter
|
|
409
|
+
if (this.capabilityFilter === 'reasoning') {
|
|
410
|
+
result = result.filter(m => m.capabilities?.reasoning === true);
|
|
411
|
+
} else if (this.capabilityFilter === 'toolUse') {
|
|
412
|
+
result = result.filter(m => m.capabilities?.toolCalling === true);
|
|
413
|
+
} else if (this.capabilityFilter === 'multimodal') {
|
|
414
|
+
result = result.filter(m => m.capabilities?.multimodal === true);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Query filter — fuzzy: every space-separated word must appear somewhere
|
|
418
|
+
if (this.query.trim().length > 0) {
|
|
419
|
+
const words = this.query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
420
|
+
result = result.filter(m => {
|
|
421
|
+
const haystack = `${m.id} ${m.displayName} ${m.provider}`.toLowerCase();
|
|
422
|
+
return words.every(w => haystack.includes(w));
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Benchmark sort
|
|
427
|
+
if (this.benchmarkSort !== 'none') {
|
|
428
|
+
result = [...result].sort((a, b) => {
|
|
429
|
+
let scoreA: number | null = null;
|
|
430
|
+
let scoreB: number | null = null;
|
|
431
|
+
|
|
432
|
+
// For synthetic models, use pre-computed bestCompositeScore from backend lookup
|
|
433
|
+
// (synthetic canonical slugs don't exist in ZeroEval benchmark data)
|
|
434
|
+
if (this.benchmarkSort === 'composite') {
|
|
435
|
+
if (a.provider === 'synthetic') {
|
|
436
|
+
scoreA = this.providerRegistry.getSyntheticModelInfoFromCatalog(a.id)?.bestCompositeScore ?? null;
|
|
437
|
+
} else {
|
|
438
|
+
const bA = this.benchmarkStore.getBenchmarks(a.id) ?? this.benchmarkStore.getBenchmarks(a.displayName);
|
|
439
|
+
scoreA = bA ? compositeScore(bA.benchmarks) : null;
|
|
440
|
+
}
|
|
441
|
+
if (b.provider === 'synthetic') {
|
|
442
|
+
scoreB = this.providerRegistry.getSyntheticModelInfoFromCatalog(b.id)?.bestCompositeScore ?? null;
|
|
443
|
+
} else {
|
|
444
|
+
const bB = this.benchmarkStore.getBenchmarks(b.id) ?? this.benchmarkStore.getBenchmarks(b.displayName);
|
|
445
|
+
scoreB = bB ? compositeScore(bB.benchmarks) : null;
|
|
446
|
+
}
|
|
447
|
+
} else {
|
|
448
|
+
// swe/gpqa sort — individual benchmark scores not available for synthetic models — only composite is cached
|
|
449
|
+
const bA = a.provider === 'synthetic' ? null : (this.benchmarkStore.getBenchmarks(a.id) ?? this.benchmarkStore.getBenchmarks(a.displayName));
|
|
450
|
+
const bB = b.provider === 'synthetic' ? null : (this.benchmarkStore.getBenchmarks(b.id) ?? this.benchmarkStore.getBenchmarks(b.displayName));
|
|
451
|
+
if (this.benchmarkSort === 'swe') {
|
|
452
|
+
scoreA = bA?.benchmarks.swe ?? null;
|
|
453
|
+
scoreB = bB?.benchmarks.swe ?? null;
|
|
454
|
+
} else if (this.benchmarkSort === 'gpqa') {
|
|
455
|
+
scoreA = bA?.benchmarks.gpqa ?? null;
|
|
456
|
+
scoreB = bB?.benchmarks.gpqa ?? null;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
// Models with no score sink to the end
|
|
460
|
+
if (scoreA == null && scoreB == null) return 0;
|
|
461
|
+
if (scoreA == null) return 1;
|
|
462
|
+
if (scoreB == null) return -1;
|
|
463
|
+
return scoreB - scoreA; // descending
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Synthetic sub-grouping: when groupBy is 'provider', order synthetic models so that
|
|
468
|
+
// "Top Models" (score ≥ 0.65) appear before "All Synthetic", each sub-group internally
|
|
469
|
+
// sorted: top by composite score desc, all alphabetically by id.
|
|
470
|
+
if (this.groupBy === 'provider' && this.benchmarkSort === 'none') {
|
|
471
|
+
const nonSynthetic = result.filter(m => m.provider !== 'synthetic');
|
|
472
|
+
const synthetic = result.filter(m => m.provider === 'synthetic');
|
|
473
|
+
|
|
474
|
+
if (synthetic.length > 0) {
|
|
475
|
+
const topModels = synthetic.filter(m => this._getSyntheticSubgroup(m) === 'top');
|
|
476
|
+
const allModels = synthetic.filter(m => this._getSyntheticSubgroup(m) === 'all');
|
|
477
|
+
|
|
478
|
+
// Sort top models by composite score descending
|
|
479
|
+
topModels.sort((a, b) => {
|
|
480
|
+
const sA = this.providerRegistry.getSyntheticModelInfoFromCatalog(a.id)?.bestCompositeScore ?? null;
|
|
481
|
+
const sB = this.providerRegistry.getSyntheticModelInfoFromCatalog(b.id)?.bestCompositeScore ?? null;
|
|
482
|
+
if (sA == null && sB == null) return 0;
|
|
483
|
+
if (sA == null) return 1;
|
|
484
|
+
if (sB == null) return -1;
|
|
485
|
+
return sB - sA;
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// Sort remaining alphabetically by id
|
|
489
|
+
allModels.sort((a, b) => a.id.localeCompare(b.id));
|
|
490
|
+
|
|
491
|
+
result = [...nonSynthetic, ...topModels, ...allModels];
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Boost recent (non-pinned) models to the front of the list,
|
|
496
|
+
// preserving relative order within the recent group and within the rest.
|
|
497
|
+
if (this.recentIds.length > 0) {
|
|
498
|
+
const recentSet = new Set(this.recentIds);
|
|
499
|
+
const recent = this.recentIds
|
|
500
|
+
.filter(id => result.some(m => m.id === id && !this.pinnedIds.has(id)))
|
|
501
|
+
.map(id => result.find(m => m.id === id)!)
|
|
502
|
+
.filter(Boolean);
|
|
503
|
+
const rest = result.filter(m => !recentSet.has(m.id) || this.pinnedIds.has(m.id));
|
|
504
|
+
result = [...recent, ...rest];
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return result;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Load recently used model IDs from favorites and cache them in recentIds.
|
|
512
|
+
* Call this when opening the picker to ensure recent models appear near the top.
|
|
513
|
+
*/
|
|
514
|
+
async loadRecentModels(n = 10): Promise<void> {
|
|
515
|
+
this.recentIds = await this.favoritesStore.getRecentModels(n);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Return the group key for a model under the current groupBy mode.
|
|
520
|
+
* Used for inserting group headers in getItems().
|
|
521
|
+
*
|
|
522
|
+
* For synthetic provider models with groupBy 'provider', returns sub-group keys:
|
|
523
|
+
* - 'Top Models' — benchmark composite score ≥ 0.65 (A-tier or S-tier)
|
|
524
|
+
* - 'All Synthetic' — remaining synthetic models
|
|
525
|
+
*/
|
|
526
|
+
getModelGroupKey(model: ModelDefinition): string {
|
|
527
|
+
switch (this.groupBy) {
|
|
528
|
+
case 'provider':
|
|
529
|
+
if (model.provider === 'synthetic') {
|
|
530
|
+
return this._getSyntheticSubgroup(model) === 'top' ? 'Top Models' : 'All Synthetic';
|
|
531
|
+
}
|
|
532
|
+
return model.provider;
|
|
533
|
+
case 'family': return detectFamily(model);
|
|
534
|
+
case 'pricingTier': return tierToCategoryFilter(model.tier);
|
|
535
|
+
case 'qualityTier': {
|
|
536
|
+
if (model.provider === 'synthetic') {
|
|
537
|
+
const info = this.providerRegistry.getSyntheticModelInfoFromCatalog(model.id);
|
|
538
|
+
return info?.bestCompositeScore != null ? getQualityTierFromScore(info.bestCompositeScore) : 'C';
|
|
539
|
+
}
|
|
540
|
+
const b = this.benchmarkStore.getBenchmarks(model.id) ?? this.benchmarkStore.getBenchmarks(model.displayName);
|
|
541
|
+
return b ? getQualityTier(b.benchmarks) : 'C';
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Classify a synthetic model as 'top' or 'all' based on benchmark composite score.
|
|
548
|
+
* 'top': has benchmark data and score ≥ 0.65 (A-tier or S-tier)
|
|
549
|
+
* 'all': no benchmark data or score < 0.65
|
|
550
|
+
*/
|
|
551
|
+
private _getSyntheticSubgroup(model: ModelDefinition): 'top' | 'all' {
|
|
552
|
+
const info = this.providerRegistry.getSyntheticModelInfoFromCatalog(model.id);
|
|
553
|
+
const score = info?.bestCompositeScore ?? null;
|
|
554
|
+
return score !== null && score >= A_TIER_THRESHOLD ? 'top' : 'all';
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/** Get the items for the current mode as a unified list. */
|
|
558
|
+
getItems(): PickerItem[] {
|
|
559
|
+
if (this.mode === 'model') {
|
|
560
|
+
const filtered = this.getFilteredModels();
|
|
561
|
+
|
|
562
|
+
// Separate pinned and unpinned
|
|
563
|
+
const pinned = filtered.filter(m => this.pinnedIds.has(m.id));
|
|
564
|
+
const unpinned = filtered.filter(m => !this.pinnedIds.has(m.id));
|
|
565
|
+
|
|
566
|
+
const items: PickerItem[] = [];
|
|
567
|
+
|
|
568
|
+
// Pinned section header (only if pinned models are in the filtered list)
|
|
569
|
+
if (pinned.length > 0) {
|
|
570
|
+
items.push({ id: '__header__pinned', label: 'Favorites', isGroupHeader: true });
|
|
571
|
+
for (const m of pinned) {
|
|
572
|
+
items.push(this._modelToItem(m, true));
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Grouped unpinned models
|
|
577
|
+
let lastGroupKey = '';
|
|
578
|
+
for (const m of unpinned) {
|
|
579
|
+
const groupKey = this.getModelGroupKey(m);
|
|
580
|
+
if (groupKey !== lastGroupKey) {
|
|
581
|
+
items.push({ id: `__header__${groupKey}`, label: groupKey, isGroupHeader: true });
|
|
582
|
+
lastGroupKey = groupKey;
|
|
583
|
+
}
|
|
584
|
+
items.push(this._modelToItem(m, false));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
return items;
|
|
588
|
+
}
|
|
589
|
+
if (this.mode === 'provider') {
|
|
590
|
+
const q = this.query.trim().toLowerCase();
|
|
591
|
+
const { popular, all } = this.getGroupedProviders();
|
|
592
|
+
|
|
593
|
+
const filterGroup = (group: string[]) =>
|
|
594
|
+
q.length === 0 ? group : group.filter(p => p.toLowerCase().includes(q));
|
|
595
|
+
|
|
596
|
+
const filteredPopular = filterGroup(popular);
|
|
597
|
+
const filteredAll = filterGroup(all);
|
|
598
|
+
|
|
599
|
+
const providerItems: PickerItem[] = [];
|
|
600
|
+
|
|
601
|
+
if (filteredPopular.length > 0) {
|
|
602
|
+
providerItems.push({ id: '__header__popular', label: 'Popular', isGroupHeader: true });
|
|
603
|
+
for (const p of filteredPopular) {
|
|
604
|
+
providerItems.push({ id: p, label: p, isConfigured: this.configuredProviders.has(p) });
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if (filteredAll.length > 0) {
|
|
608
|
+
providerItems.push({ id: '__header__all', label: 'All Providers', isGroupHeader: true });
|
|
609
|
+
for (const p of filteredAll) {
|
|
610
|
+
providerItems.push({ id: p, label: p, isConfigured: this.configuredProviders.has(p) });
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
return providerItems;
|
|
615
|
+
}
|
|
616
|
+
// effort mode
|
|
617
|
+
return this.effortLevels.map(e => ({ id: e, label: e, detail: EFFORT_DESCRIPTIONS[e] ?? '' }));
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/** Build a PickerItem for a model, including quality tier and pin status. */
|
|
621
|
+
private _modelToItem(model: ModelDefinition, isPinned: boolean): PickerItem {
|
|
622
|
+
// For synthetic models, derive quality tier from cached bestCompositeScore
|
|
623
|
+
// (synthetic canonical slugs don't exist in ZeroEval benchmark data)
|
|
624
|
+
let qualityTier: string | undefined;
|
|
625
|
+
let detail: string;
|
|
626
|
+
if (model.provider === 'synthetic') {
|
|
627
|
+
const synthInfo = this.providerRegistry.getSyntheticModelInfoFromCatalog(model.id);
|
|
628
|
+
if (synthInfo?.bestCompositeScore != null) {
|
|
629
|
+
qualityTier = getQualityTierFromScore(synthInfo.bestCompositeScore);
|
|
630
|
+
}
|
|
631
|
+
// Reuse synthInfo for provider count detail
|
|
632
|
+
detail = synthInfo !== null
|
|
633
|
+
? `${model.provider} [${synthInfo.keyedBackendCount} provider${synthInfo.keyedBackendCount !== 1 ? 's' : ''}]`
|
|
634
|
+
: model.provider;
|
|
635
|
+
} else {
|
|
636
|
+
detail = model.provider;
|
|
637
|
+
const b = this.benchmarkStore.getBenchmarks(model.id) ?? this.benchmarkStore.getBenchmarks(model.displayName);
|
|
638
|
+
qualityTier = b ? getQualityTier(b.benchmarks) : undefined;
|
|
639
|
+
}
|
|
640
|
+
const isFree = tierToCategoryFilter(model.tier) === 'free';
|
|
641
|
+
|
|
642
|
+
return {
|
|
643
|
+
id: model.id,
|
|
644
|
+
label: model.displayName,
|
|
645
|
+
detail,
|
|
646
|
+
qualityTier,
|
|
647
|
+
isPinned,
|
|
648
|
+
isFree,
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/** Get count of selectable (non-header) items in current mode. */
|
|
653
|
+
getItemCount(): number {
|
|
654
|
+
if (this.mode === 'model') return this.getFilteredModels().length;
|
|
655
|
+
if (this.mode === 'provider') return this.getFilteredProviders().length;
|
|
656
|
+
return this.effortLevels.length;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Move selection up (stops at 0 — no wrap to avoid going off-screen).
|
|
661
|
+
* Updates scrollOffset to keep selection visible.
|
|
662
|
+
*/
|
|
663
|
+
moveUp(maxVisible = 20): void {
|
|
664
|
+
const count = this.getItemCount();
|
|
665
|
+
if (count === 0) return;
|
|
666
|
+
if (this.selectedIndex > 0) {
|
|
667
|
+
this.selectedIndex--;
|
|
668
|
+
this._scrollToSelection(maxVisible);
|
|
669
|
+
}
|
|
670
|
+
// At index 0 — stop. Do NOT wrap to count-1 (that puts selection off-screen).
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Move selection down (wraps to 0 at bottom).
|
|
675
|
+
* Updates scrollOffset to keep selection visible.
|
|
676
|
+
*/
|
|
677
|
+
moveDown(maxVisible = 20): void {
|
|
678
|
+
const count = this.getItemCount();
|
|
679
|
+
if (count === 0) return;
|
|
680
|
+
this.selectedIndex = this.selectedIndex < count - 1
|
|
681
|
+
? this.selectedIndex + 1
|
|
682
|
+
: 0;
|
|
683
|
+
this._scrollToSelection(maxVisible);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/** Get the currently highlighted model, or null if not in model mode / empty. */
|
|
687
|
+
getSelected(): ModelDefinition | null {
|
|
688
|
+
if (this.mode !== 'model') return null;
|
|
689
|
+
const filtered = this.getFilteredModels();
|
|
690
|
+
if (filtered.length === 0) return null;
|
|
691
|
+
return filtered[this.selectedIndex] ?? null;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// ── Private helpers ────────────────────────────────────────────────────────
|
|
695
|
+
|
|
696
|
+
private _clampSelection(): void {
|
|
697
|
+
const count = this.getItemCount();
|
|
698
|
+
if (count === 0) {
|
|
699
|
+
this.selectedIndex = 0;
|
|
700
|
+
this.scrollOffset = 0;
|
|
701
|
+
} else if (this.selectedIndex >= count) {
|
|
702
|
+
this.selectedIndex = count - 1;
|
|
703
|
+
}
|
|
704
|
+
// Clamp scrollOffset too
|
|
705
|
+
const maxOffset = Math.max(0, count - 1);
|
|
706
|
+
if (this.scrollOffset > maxOffset) this.scrollOffset = maxOffset;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Adjust scrollOffset so selectedIndex is within the visible window [scrollOffset, scrollOffset + maxVisible).
|
|
711
|
+
* Called after every navigation action.
|
|
712
|
+
*/
|
|
713
|
+
_scrollToSelection(maxVisible: number): void {
|
|
714
|
+
if (this.selectedIndex < this.scrollOffset) {
|
|
715
|
+
// Selection moved above viewport — scroll up
|
|
716
|
+
this.scrollOffset = this.selectedIndex;
|
|
717
|
+
} else if (this.selectedIndex >= this.scrollOffset + maxVisible) {
|
|
718
|
+
// Selection moved below viewport — scroll down
|
|
719
|
+
this.scrollOffset = this.selectedIndex - maxVisible + 1;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
getSyntheticModelInfo(modelId: string) {
|
|
724
|
+
return this.providerRegistry.getSyntheticModelInfoFromCatalog(modelId);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
getBenchmarkEntry(model: ModelDefinition) {
|
|
728
|
+
return this.benchmarkStore.getBenchmarks(model.id) ?? this.benchmarkStore.getBenchmarks(model.displayName);
|
|
729
|
+
}
|
|
730
|
+
}
|