shortcutxl 0.2.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/README.md +59 -0
- package/agent-docs/README.md +397 -0
- package/agent-docs/docs/compaction.md +390 -0
- package/agent-docs/docs/custom-provider.md +580 -0
- package/agent-docs/docs/development.md +69 -0
- package/agent-docs/docs/extensions.md +1971 -0
- package/agent-docs/docs/json.md +79 -0
- package/agent-docs/docs/keybindings.md +174 -0
- package/agent-docs/docs/models.md +293 -0
- package/agent-docs/docs/packages.md +209 -0
- package/agent-docs/docs/prompt-templates.md +67 -0
- package/agent-docs/docs/providers.md +186 -0
- package/agent-docs/docs/rpc.md +1317 -0
- package/agent-docs/docs/sdk.md +962 -0
- package/agent-docs/docs/session.md +412 -0
- package/agent-docs/docs/settings.md +223 -0
- package/agent-docs/docs/shell-aliases.md +13 -0
- package/agent-docs/docs/skills.md +231 -0
- package/agent-docs/docs/terminal-setup.md +70 -0
- package/agent-docs/docs/termux.md +127 -0
- package/agent-docs/docs/themes.md +295 -0
- package/agent-docs/docs/tree.md +219 -0
- package/agent-docs/docs/tui.md +887 -0
- package/agent-docs/docs/windows.md +17 -0
- package/agent-docs/examples/README.md +25 -0
- package/agent-docs/examples/extensions/README.md +205 -0
- package/agent-docs/examples/extensions/antigravity-image-gen.ts +447 -0
- package/agent-docs/examples/extensions/auto-commit-on-exit.ts +49 -0
- package/agent-docs/examples/extensions/bash-spawn-hook.ts +30 -0
- package/agent-docs/examples/extensions/bookmark.ts +50 -0
- package/agent-docs/examples/extensions/built-in-tool-renderer.ts +256 -0
- package/agent-docs/examples/extensions/claude-rules.ts +86 -0
- package/agent-docs/examples/extensions/commands.ts +75 -0
- package/agent-docs/examples/extensions/confirm-destructive.ts +59 -0
- package/agent-docs/examples/extensions/custom-compaction.ts +126 -0
- package/agent-docs/examples/extensions/custom-footer.ts +63 -0
- package/agent-docs/examples/extensions/custom-header.ts +73 -0
- package/agent-docs/examples/extensions/custom-provider-anthropic/index.ts +660 -0
- package/agent-docs/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
- package/agent-docs/examples/extensions/custom-provider-anthropic/package.json +19 -0
- package/agent-docs/examples/extensions/custom-provider-gitlab-duo/index.ts +362 -0
- package/agent-docs/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
- package/agent-docs/examples/extensions/custom-provider-gitlab-duo/test.ts +88 -0
- package/agent-docs/examples/extensions/custom-provider-qwen-cli/index.ts +349 -0
- package/agent-docs/examples/extensions/custom-provider-qwen-cli/package.json +16 -0
- package/agent-docs/examples/extensions/dirty-repo-guard.ts +56 -0
- package/agent-docs/examples/extensions/doom-overlay/README.md +46 -0
- package/agent-docs/examples/extensions/doom-overlay/doom/build.sh +152 -0
- package/agent-docs/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
- package/agent-docs/examples/extensions/doom-overlay/doom-component.ts +133 -0
- package/agent-docs/examples/extensions/doom-overlay/doom-engine.ts +186 -0
- package/agent-docs/examples/extensions/doom-overlay/doom-keys.ts +108 -0
- package/agent-docs/examples/extensions/doom-overlay/index.ts +74 -0
- package/agent-docs/examples/extensions/doom-overlay/wad-finder.ts +51 -0
- package/agent-docs/examples/extensions/dynamic-resources/SKILL.md +8 -0
- package/agent-docs/examples/extensions/dynamic-resources/dynamic.json +79 -0
- package/agent-docs/examples/extensions/dynamic-resources/dynamic.md +5 -0
- package/agent-docs/examples/extensions/dynamic-resources/index.ts +15 -0
- package/agent-docs/examples/extensions/dynamic-tools.ts +77 -0
- package/agent-docs/examples/extensions/event-bus.ts +43 -0
- package/agent-docs/examples/extensions/file-trigger.ts +41 -0
- package/agent-docs/examples/extensions/git-checkpoint.ts +53 -0
- package/agent-docs/examples/extensions/handoff.ts +155 -0
- package/agent-docs/examples/extensions/hello.ts +25 -0
- package/agent-docs/examples/extensions/inline-bash.ts +94 -0
- package/agent-docs/examples/extensions/input-transform.ts +43 -0
- package/agent-docs/examples/extensions/interactive-shell.ts +209 -0
- package/agent-docs/examples/extensions/mac-system-theme.ts +47 -0
- package/agent-docs/examples/extensions/message-renderer.ts +59 -0
- package/agent-docs/examples/extensions/minimal-mode.ts +430 -0
- package/agent-docs/examples/extensions/modal-editor.ts +90 -0
- package/agent-docs/examples/extensions/model-status.ts +31 -0
- package/agent-docs/examples/extensions/notify.ts +55 -0
- package/agent-docs/examples/extensions/overlay-qa-tests.ts +936 -0
- package/agent-docs/examples/extensions/overlay-test.ts +159 -0
- package/agent-docs/examples/extensions/permission-gate.ts +37 -0
- package/agent-docs/examples/extensions/pirate.ts +47 -0
- package/agent-docs/examples/extensions/plan-mode/README.md +65 -0
- package/agent-docs/examples/extensions/plan-mode/index.ts +363 -0
- package/agent-docs/examples/extensions/plan-mode/utils.ts +173 -0
- package/agent-docs/examples/extensions/preset.ts +418 -0
- package/agent-docs/examples/extensions/protected-paths.ts +30 -0
- package/agent-docs/examples/extensions/qna.ts +122 -0
- package/agent-docs/examples/extensions/question.ts +278 -0
- package/agent-docs/examples/extensions/questionnaire.ts +440 -0
- package/agent-docs/examples/extensions/rainbow-editor.ts +90 -0
- package/agent-docs/examples/extensions/reload-runtime.ts +37 -0
- package/agent-docs/examples/extensions/rpc-demo.ts +124 -0
- package/agent-docs/examples/extensions/sandbox/index.ts +324 -0
- package/agent-docs/examples/extensions/sandbox/package-lock.json +92 -0
- package/agent-docs/examples/extensions/sandbox/package.json +19 -0
- package/agent-docs/examples/extensions/send-user-message.ts +97 -0
- package/agent-docs/examples/extensions/session-name.ts +27 -0
- package/agent-docs/examples/extensions/shutdown-command.ts +69 -0
- package/agent-docs/examples/extensions/snake.ts +343 -0
- package/agent-docs/examples/extensions/space-invaders.ts +566 -0
- package/agent-docs/examples/extensions/ssh.ts +233 -0
- package/agent-docs/examples/extensions/status-line.ts +40 -0
- package/agent-docs/examples/extensions/subagent/README.md +172 -0
- package/agent-docs/examples/extensions/subagent/agents/planner.md +37 -0
- package/agent-docs/examples/extensions/subagent/agents/reviewer.md +35 -0
- package/agent-docs/examples/extensions/subagent/agents/scout.md +50 -0
- package/agent-docs/examples/extensions/subagent/agents/worker.md +24 -0
- package/agent-docs/examples/extensions/subagent/agents.ts +130 -0
- package/agent-docs/examples/extensions/subagent/index.ts +1068 -0
- package/agent-docs/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
- package/agent-docs/examples/extensions/subagent/prompts/implement.md +10 -0
- package/agent-docs/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
- package/agent-docs/examples/extensions/summarize.ts +206 -0
- package/agent-docs/examples/extensions/system-prompt-header.ts +17 -0
- package/agent-docs/examples/extensions/timed-confirm.ts +72 -0
- package/agent-docs/examples/extensions/titlebar-spinner.ts +58 -0
- package/agent-docs/examples/extensions/todo.ts +314 -0
- package/agent-docs/examples/extensions/tool-override.ts +146 -0
- package/agent-docs/examples/extensions/tools.ts +145 -0
- package/agent-docs/examples/extensions/trigger-compact.ts +40 -0
- package/agent-docs/examples/extensions/truncated-tool.ts +194 -0
- package/agent-docs/examples/extensions/widget-placement.ts +17 -0
- package/agent-docs/examples/extensions/with-deps/index.ts +37 -0
- package/agent-docs/examples/extensions/with-deps/package-lock.json +31 -0
- package/agent-docs/examples/extensions/with-deps/package.json +22 -0
- package/agent-docs/examples/rpc-extension-ui.ts +654 -0
- package/agent-docs/examples/sdk/01-minimal.ts +22 -0
- package/agent-docs/examples/sdk/02-custom-model.ts +48 -0
- package/agent-docs/examples/sdk/03-custom-prompt.ts +55 -0
- package/agent-docs/examples/sdk/04-skills.ts +53 -0
- package/agent-docs/examples/sdk/05-tools.ts +56 -0
- package/agent-docs/examples/sdk/06-extensions.ts +88 -0
- package/agent-docs/examples/sdk/07-context-files.ts +40 -0
- package/agent-docs/examples/sdk/08-prompt-templates.ts +47 -0
- package/agent-docs/examples/sdk/09-api-keys-and-oauth.ts +48 -0
- package/agent-docs/examples/sdk/10-settings.ts +54 -0
- package/agent-docs/examples/sdk/11-sessions.ts +48 -0
- package/agent-docs/examples/sdk/12-full-control.ts +82 -0
- package/agent-docs/examples/sdk/README.md +144 -0
- package/agent-docs/xll-skill.md +61 -0
- package/agent-docs/xll-spec.md +110 -0
- package/dist/cli/args.js +290 -0
- package/dist/cli/config-selector.js +31 -0
- package/dist/cli/file-processor.js +79 -0
- package/dist/cli/list-models.js +92 -0
- package/dist/cli/package-commands.js +210 -0
- package/dist/cli/report-settings-errors.js +11 -0
- package/dist/cli/session-picker.js +34 -0
- package/dist/cli.js +19 -0
- package/dist/config.js +288 -0
- package/dist/core/abort.js +15 -0
- package/dist/core/agent-loop.js +352 -0
- package/dist/core/agent-session.js +2019 -0
- package/dist/core/agent.js +410 -0
- package/dist/core/auth-storage.js +456 -0
- package/dist/core/bash-executor.js +222 -0
- package/dist/core/compaction/branch-summarization.js +242 -0
- package/dist/core/compaction/compaction.js +610 -0
- package/dist/core/compaction/index.js +7 -0
- package/dist/core/compaction/utils.js +139 -0
- package/dist/core/defaults.js +6 -0
- package/dist/core/diagnostics.js +2 -0
- package/dist/core/event-bus.js +25 -0
- package/dist/core/exec.js +71 -0
- package/dist/core/export-html/ansi-to-html.js +256 -0
- package/dist/core/export-html/index.js +238 -0
- package/dist/core/export-html/session-view-model.js +342 -0
- package/dist/core/export-html/template.css +1110 -0
- package/dist/core/export-html/template.html +76 -0
- package/dist/core/export-html/template.js +1990 -0
- package/dist/core/export-html/tool-renderer.js +63 -0
- package/dist/core/export-html/vendor/highlight.min.js +7725 -0
- package/dist/core/export-html/vendor/marked.min.js +1803 -0
- package/dist/core/extensions/index.js +9 -0
- package/dist/core/extensions/loader.js +422 -0
- package/dist/core/extensions/runner.js +651 -0
- package/dist/core/extensions/types.js +35 -0
- package/dist/core/extensions/wrapper.js +102 -0
- package/dist/core/footer-data-provider.js +162 -0
- package/dist/core/index.js +9 -0
- package/dist/core/keybindings.js +153 -0
- package/dist/core/messages.js +133 -0
- package/dist/core/model-registry.js +539 -0
- package/dist/core/model-resolver.js +370 -0
- package/dist/core/package-manager.js +1485 -0
- package/dist/core/prompt-templates.js +253 -0
- package/dist/core/resolve-config-value.js +59 -0
- package/dist/core/resource-loader.js +700 -0
- package/dist/core/sdk.js +197 -0
- package/dist/core/session-bash.js +99 -0
- package/dist/core/session-compaction.js +165 -0
- package/dist/core/session-manager.js +1153 -0
- package/dist/core/session-models.js +99 -0
- package/dist/core/session-retry.js +155 -0
- package/dist/core/settings-manager.js +572 -0
- package/dist/core/skills.js +382 -0
- package/dist/core/slash-commands.js +31 -0
- package/dist/core/system-prompt.js +161 -0
- package/dist/core/theme.js +770 -0
- package/dist/core/timings.js +26 -0
- package/dist/core/tools/bash.js +258 -0
- package/dist/core/tools/edit-diff.js +245 -0
- package/dist/core/tools/edit.js +148 -0
- package/dist/core/tools/find.js +208 -0
- package/dist/core/tools/grep.js +246 -0
- package/dist/core/tools/index.js +67 -0
- package/dist/core/tools/ls.js +123 -0
- package/dist/core/tools/path-utils.js +81 -0
- package/dist/core/tools/read.js +160 -0
- package/dist/core/tools/truncate.js +70 -0
- package/dist/core/tools/write.js +82 -0
- package/dist/custom/agents/action.js +13 -0
- package/dist/custom/agents/document-reader.js +70 -0
- package/dist/custom/agents/general.js +26 -0
- package/dist/custom/agents/index.js +49 -0
- package/dist/custom/agents/installation.js +13 -0
- package/dist/custom/agents/types.js +7 -0
- package/dist/custom/auth/refresh-timer.js +33 -0
- package/dist/custom/auth/shortcut-oauth.js +145 -0
- package/dist/custom/constants.js +21 -0
- package/dist/custom/context/workbook-summary.js +73 -0
- package/dist/custom/credits/shortcut-credits.js +29 -0
- package/dist/custom/cron/cron-daemon-entry.js +18 -0
- package/dist/custom/cron/daemon-ipc.js +131 -0
- package/dist/custom/cron/daemon.js +224 -0
- package/dist/custom/cron/jobs.js +226 -0
- package/dist/custom/cron/run-log.js +51 -0
- package/dist/custom/cron/schedule.js +72 -0
- package/dist/custom/cron/status-line.js +98 -0
- package/dist/custom/cron/store.js +87 -0
- package/dist/custom/cron/types.js +8 -0
- package/dist/custom/dev/index.js +59 -0
- package/dist/custom/dev/trace-export.js +58 -0
- package/dist/custom/ensure-excel.js +63 -0
- package/dist/custom/excel-config.js +36 -0
- package/dist/custom/preflight.js +422 -0
- package/dist/custom/prompts/action.js +100 -0
- package/dist/custom/prompts/api.js +66 -0
- package/dist/custom/prompts/installation.js +124 -0
- package/dist/custom/prompts/shared.js +138 -0
- package/dist/custom/providers/llm-usage.js +42 -0
- package/dist/custom/providers/message-converter.js +74 -0
- package/dist/custom/providers/provider-ids.js +9 -0
- package/dist/custom/providers/register-openai-codex-provider.js +27 -0
- package/dist/custom/providers/register-shortcut-provider.js +52 -0
- package/dist/custom/providers/shortcut-invoke.js +117 -0
- package/dist/custom/providers/shortcut-stream.js +252 -0
- package/dist/custom/providers/sse-protocol.js +38 -0
- package/dist/custom/sync-xll.js +130 -0
- package/dist/custom/tools/cron.js +413 -0
- package/dist/custom/tools/excel-exec.js +167 -0
- package/dist/custom/tools/excel-range.js +50 -0
- package/dist/custom/tools/llm-analysis.js +265 -0
- package/dist/custom/tools/render-helpers.js +38 -0
- package/dist/custom/tools/switch-mode.js +94 -0
- package/dist/custom/tools/task/agents.js +6 -0
- package/dist/custom/tools/task/index.js +8 -0
- package/dist/custom/tools/task/render.js +348 -0
- package/dist/custom/tools/task/subprocess.js +320 -0
- package/dist/custom/tools/task/task.js +205 -0
- package/dist/custom/tools/todo-list.js +195 -0
- package/dist/custom/tracing/session-upload.js +93 -0
- package/dist/index.js +45 -0
- package/dist/main.js +613 -0
- package/dist/migrations.js +265 -0
- package/dist/modes/index.js +8 -0
- package/dist/modes/interactive/components/armin.js +337 -0
- package/dist/modes/interactive/components/assistant-message.js +94 -0
- package/dist/modes/interactive/components/bash-execution.js +171 -0
- package/dist/modes/interactive/components/bordered-loader.js +51 -0
- package/dist/modes/interactive/components/branch-summary-message.js +45 -0
- package/dist/modes/interactive/components/compaction-summary-message.js +46 -0
- package/dist/modes/interactive/components/config-selector.js +488 -0
- package/dist/modes/interactive/components/countdown-timer.js +33 -0
- package/dist/modes/interactive/components/custom-editor.js +93 -0
- package/dist/modes/interactive/components/custom-message.js +81 -0
- package/dist/modes/interactive/components/daxnuts.js +140 -0
- package/dist/modes/interactive/components/diff.js +133 -0
- package/dist/modes/interactive/components/dynamic-border.js +21 -0
- package/dist/modes/interactive/components/extension-editor.js +105 -0
- package/dist/modes/interactive/components/extension-input.js +61 -0
- package/dist/modes/interactive/components/extension-selector.js +78 -0
- package/dist/modes/interactive/components/footer.js +309 -0
- package/dist/modes/interactive/components/index.js +33 -0
- package/dist/modes/interactive/components/keybinding-hints.js +61 -0
- package/dist/modes/interactive/components/layout.js +64 -0
- package/dist/modes/interactive/components/login-dialog.js +148 -0
- package/dist/modes/interactive/components/model-selector.js +237 -0
- package/dist/modes/interactive/components/oauth-selector.js +111 -0
- package/dist/modes/interactive/components/session-selector-search.js +157 -0
- package/dist/modes/interactive/components/session-selector.js +860 -0
- package/dist/modes/interactive/components/settings-selector.js +123 -0
- package/dist/modes/interactive/components/show-images-selector.js +35 -0
- package/dist/modes/interactive/components/skill-invocation-message.js +48 -0
- package/dist/modes/interactive/components/theme-selector.js +47 -0
- package/dist/modes/interactive/components/thinking-selector.js +47 -0
- package/dist/modes/interactive/components/tool-execution.js +789 -0
- package/dist/modes/interactive/components/tool-group.js +106 -0
- package/dist/modes/interactive/components/tree-selector.js +962 -0
- package/dist/modes/interactive/components/user-message-selector.js +115 -0
- package/dist/modes/interactive/components/user-message.js +48 -0
- package/dist/modes/interactive/components/visual-truncate.js +33 -0
- package/dist/modes/interactive/file-attachments.js +135 -0
- package/dist/modes/interactive/interactive-mode.js +3775 -0
- package/dist/modes/interactive/theme/dark.json +85 -0
- package/dist/modes/interactive/theme/light.json +85 -0
- package/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/dist/modes/interactive/theme/theme.js +177 -0
- package/dist/modes/print-mode.js +101 -0
- package/dist/modes/rpc/rpc-client.js +387 -0
- package/dist/modes/rpc/rpc-mode.js +509 -0
- package/dist/modes/rpc/rpc-types.js +8 -0
- package/dist/subagent-entry.js +145 -0
- package/dist/tool-names.js +34 -0
- package/dist/tui/autocomplete.js +596 -0
- package/dist/tui/components/box.js +104 -0
- package/dist/tui/components/cancellable-loader.js +35 -0
- package/dist/tui/components/editor.js +1679 -0
- package/dist/tui/components/image.js +69 -0
- package/dist/tui/components/input.js +433 -0
- package/dist/tui/components/loader.js +49 -0
- package/dist/tui/components/markdown.js +629 -0
- package/dist/tui/components/select-list.js +152 -0
- package/dist/tui/components/settings-list.js +185 -0
- package/dist/tui/components/spacer.js +23 -0
- package/dist/tui/components/text.js +89 -0
- package/dist/tui/components/truncated-text.js +51 -0
- package/dist/tui/editor-component.js +2 -0
- package/dist/tui/fuzzy.js +107 -0
- package/dist/tui/get-east-asian-width/index.js +32 -0
- package/dist/tui/get-east-asian-width/lookup.js +404 -0
- package/dist/tui/index.js +32 -0
- package/dist/tui/keybindings.js +114 -0
- package/dist/tui/keys.js +959 -0
- package/dist/tui/kill-ring.js +44 -0
- package/dist/tui/stdin-buffer.js +317 -0
- package/dist/tui/terminal-image.js +288 -0
- package/dist/tui/terminal.js +249 -0
- package/dist/tui/tui/autocomplete.js +596 -0
- package/dist/tui/tui/components/box.js +106 -0
- package/dist/tui/tui/components/cancellable-loader.js +35 -0
- package/dist/tui/tui/components/editor.js +1679 -0
- package/dist/tui/tui/components/image.js +69 -0
- package/dist/tui/tui/components/input.js +433 -0
- package/dist/tui/tui/components/loader.js +49 -0
- package/dist/tui/tui/components/markdown.js +629 -0
- package/dist/tui/tui/components/select-list.js +152 -0
- package/dist/tui/tui/components/settings-list.js +185 -0
- package/dist/tui/tui/components/spacer.js +23 -0
- package/dist/tui/tui/components/text.js +91 -0
- package/dist/tui/tui/components/truncated-text.js +51 -0
- package/dist/tui/tui/editor-component.js +2 -0
- package/dist/tui/tui/fuzzy.js +107 -0
- package/dist/tui/tui/get-east-asian-width/index.js +32 -0
- package/dist/tui/tui/get-east-asian-width/lookup.js +404 -0
- package/dist/tui/tui/index.js +32 -0
- package/dist/tui/tui/keybindings.js +114 -0
- package/dist/tui/tui/keys.js +959 -0
- package/dist/tui/tui/kill-ring.js +44 -0
- package/dist/tui/tui/stdin-buffer.js +317 -0
- package/dist/tui/tui/terminal-image.js +288 -0
- package/dist/tui/tui/terminal.js +249 -0
- package/dist/tui/tui/tui.js +955 -0
- package/dist/tui/tui/undo-stack.js +25 -0
- package/dist/tui/tui/utils.js +800 -0
- package/dist/tui/tui.js +955 -0
- package/dist/tui/undo-stack.js +25 -0
- package/dist/tui/utils.js +800 -0
- package/dist/utils/changelog.js +87 -0
- package/dist/utils/clipboard-image.js +164 -0
- package/dist/utils/clipboard-native.js +14 -0
- package/dist/utils/clipboard.js +67 -0
- package/dist/utils/frontmatter.js +26 -0
- package/dist/utils/git.js +166 -0
- package/dist/utils/image-convert.js +35 -0
- package/dist/utils/image-resize.js +183 -0
- package/dist/utils/mime.js +26 -0
- package/dist/utils/photon.js +121 -0
- package/dist/utils/shell.js +217 -0
- package/dist/utils/sleep.js +17 -0
- package/dist/utils/tools-manager.js +259 -0
- package/package.json +78 -0
- package/skills/excel-com-api/SKILL.md +74 -0
- package/skills/excel-com-api/excel-type-library.py +27767 -0
- package/skills/excel-com-api/office-type-library.py +10867 -0
- package/skills/integrations/SKILL.md +138 -0
- package/skills/integrations/alphasense.md +457 -0
- package/skills/integrations/bloomberg.md +803 -0
- package/skills/integrations/calcbench.md +315 -0
- package/skills/integrations/capiq.md +848 -0
- package/skills/integrations/dynamics-365-finance.md +354 -0
- package/skills/integrations/earnings_transcripts.md +387 -0
- package/skills/integrations/factset.md +758 -0
- package/skills/integrations/ice-fixed-income.md +344 -0
- package/skills/integrations/moodys-analytics.md +313 -0
- package/skills/integrations/morningstar.md +433 -0
- package/skills/integrations/nasdaq-data-link.md +249 -0
- package/skills/integrations/pitchbook.md +413 -0
- package/skills/integrations/preqin.md +422 -0
- package/skills/integrations/quickbooks.md +289 -0
- package/skills/integrations/quickfs.md +314 -0
- package/skills/integrations/refinitiv.md +473 -0
- package/skills/integrations/sage-intacct.md +401 -0
- package/skills/integrations/visible-alpha.md +320 -0
- package/skills/integrations/xero.md +393 -0
- package/skills/integrations/ycharts.md +306 -0
- package/skills/pdf-creation/SKILL.md +93 -0
- package/skills/pdf-extraction/SKILL.md +32 -0
- package/skills/powerpoint-creation/SKILL.md +110 -0
- package/skills/sec-edgar/SKILL.md +127 -0
- package/skills/sec-edgar/sec_to_pdf.py +109 -0
- package/xll/ShortcutXL.xll +0 -0
- package/xll/modules/debug_render.py +272 -0
- package/xll/modules/gameboy.py +241 -0
- package/xll/modules/pong.py +188 -0
- package/xll/modules/shortcut_xl/__init__.py +18 -0
- package/xll/modules/shortcut_xl/_categorize.py +200 -0
- package/xll/modules/shortcut_xl/_com.py +108 -0
- package/xll/modules/shortcut_xl/_format.py +252 -0
- package/xll/modules/shortcut_xl/_log.py +12 -0
- package/xll/modules/shortcut_xl/_managed.py +116 -0
- package/xll/modules/shortcut_xl/_registry.py +44 -0
- package/xll/modules/shortcut_xl/_threading.py +161 -0
- package/xll/modules/shortcut_xl/_tracking.py +283 -0
- package/xll/modules/stocks.py +100 -0
- package/xll/python3.dll +0 -0
- package/xll/python312.dll +0 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model registry - manages built-in and custom models, provides API key resolution.
|
|
3
|
+
*/
|
|
4
|
+
import { getModels, getProviders, registerApiProvider, registerOAuthProvider, resetApiProviders, resetOAuthProviders } from '@mariozechner/pi-ai';
|
|
5
|
+
import { Type } from '@sinclair/typebox';
|
|
6
|
+
import AjvModule from 'ajv';
|
|
7
|
+
import { existsSync, readFileSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { getAgentDir } from '../config.js';
|
|
10
|
+
import { clearConfigValueCache, resolveConfigValue, resolveHeaders } from './resolve-config-value.js';
|
|
11
|
+
const Ajv = AjvModule.default || AjvModule;
|
|
12
|
+
// Schema for OpenRouter routing preferences
|
|
13
|
+
const OpenRouterRoutingSchema = Type.Object({
|
|
14
|
+
only: Type.Optional(Type.Array(Type.String())),
|
|
15
|
+
order: Type.Optional(Type.Array(Type.String()))
|
|
16
|
+
});
|
|
17
|
+
// Schema for Vercel AI Gateway routing preferences
|
|
18
|
+
const VercelGatewayRoutingSchema = Type.Object({
|
|
19
|
+
only: Type.Optional(Type.Array(Type.String())),
|
|
20
|
+
order: Type.Optional(Type.Array(Type.String()))
|
|
21
|
+
});
|
|
22
|
+
// Schema for OpenAI compatibility settings
|
|
23
|
+
const OpenAICompletionsCompatSchema = Type.Object({
|
|
24
|
+
supportsStore: Type.Optional(Type.Boolean()),
|
|
25
|
+
supportsDeveloperRole: Type.Optional(Type.Boolean()),
|
|
26
|
+
supportsReasoningEffort: Type.Optional(Type.Boolean()),
|
|
27
|
+
supportsUsageInStreaming: Type.Optional(Type.Boolean()),
|
|
28
|
+
maxTokensField: Type.Optional(Type.Union([Type.Literal('max_completion_tokens'), Type.Literal('max_tokens')])),
|
|
29
|
+
requiresToolResultName: Type.Optional(Type.Boolean()),
|
|
30
|
+
requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),
|
|
31
|
+
requiresThinkingAsText: Type.Optional(Type.Boolean()),
|
|
32
|
+
requiresMistralToolIds: Type.Optional(Type.Boolean()),
|
|
33
|
+
thinkingFormat: Type.Optional(Type.Union([Type.Literal('openai'), Type.Literal('zai'), Type.Literal('qwen')])),
|
|
34
|
+
openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
|
|
35
|
+
vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema)
|
|
36
|
+
});
|
|
37
|
+
const OpenAIResponsesCompatSchema = Type.Object({
|
|
38
|
+
// Reserved for future use
|
|
39
|
+
});
|
|
40
|
+
const OpenAICompatSchema = Type.Union([OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema]);
|
|
41
|
+
// Schema for custom model definition
|
|
42
|
+
// Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)
|
|
43
|
+
const ModelDefinitionSchema = Type.Object({
|
|
44
|
+
id: Type.String({ minLength: 1 }),
|
|
45
|
+
name: Type.Optional(Type.String({ minLength: 1 })),
|
|
46
|
+
api: Type.Optional(Type.String({ minLength: 1 })),
|
|
47
|
+
reasoning: Type.Optional(Type.Boolean()),
|
|
48
|
+
input: Type.Optional(Type.Array(Type.Union([Type.Literal('text'), Type.Literal('image')]))),
|
|
49
|
+
cost: Type.Optional(Type.Object({
|
|
50
|
+
input: Type.Number(),
|
|
51
|
+
output: Type.Number(),
|
|
52
|
+
cacheRead: Type.Number(),
|
|
53
|
+
cacheWrite: Type.Number()
|
|
54
|
+
})),
|
|
55
|
+
contextWindow: Type.Optional(Type.Number()),
|
|
56
|
+
maxTokens: Type.Optional(Type.Number()),
|
|
57
|
+
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
58
|
+
compat: Type.Optional(OpenAICompatSchema)
|
|
59
|
+
});
|
|
60
|
+
// Schema for per-model overrides (all fields optional, merged with built-in model)
|
|
61
|
+
const ModelOverrideSchema = Type.Object({
|
|
62
|
+
name: Type.Optional(Type.String({ minLength: 1 })),
|
|
63
|
+
reasoning: Type.Optional(Type.Boolean()),
|
|
64
|
+
input: Type.Optional(Type.Array(Type.Union([Type.Literal('text'), Type.Literal('image')]))),
|
|
65
|
+
cost: Type.Optional(Type.Object({
|
|
66
|
+
input: Type.Optional(Type.Number()),
|
|
67
|
+
output: Type.Optional(Type.Number()),
|
|
68
|
+
cacheRead: Type.Optional(Type.Number()),
|
|
69
|
+
cacheWrite: Type.Optional(Type.Number())
|
|
70
|
+
})),
|
|
71
|
+
contextWindow: Type.Optional(Type.Number()),
|
|
72
|
+
maxTokens: Type.Optional(Type.Number()),
|
|
73
|
+
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
74
|
+
compat: Type.Optional(OpenAICompatSchema)
|
|
75
|
+
});
|
|
76
|
+
const ProviderConfigSchema = Type.Object({
|
|
77
|
+
baseUrl: Type.Optional(Type.String({ minLength: 1 })),
|
|
78
|
+
apiKey: Type.Optional(Type.String({ minLength: 1 })),
|
|
79
|
+
api: Type.Optional(Type.String({ minLength: 1 })),
|
|
80
|
+
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
81
|
+
authHeader: Type.Optional(Type.Boolean()),
|
|
82
|
+
models: Type.Optional(Type.Array(ModelDefinitionSchema)),
|
|
83
|
+
modelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema))
|
|
84
|
+
});
|
|
85
|
+
const ModelsConfigSchema = Type.Object({
|
|
86
|
+
providers: Type.Record(Type.String(), ProviderConfigSchema)
|
|
87
|
+
});
|
|
88
|
+
function emptyCustomModelsResult(error) {
|
|
89
|
+
return { models: [], overrides: new Map(), modelOverrides: new Map(), error };
|
|
90
|
+
}
|
|
91
|
+
function mergeCompat(baseCompat, overrideCompat) {
|
|
92
|
+
if (!overrideCompat)
|
|
93
|
+
return baseCompat;
|
|
94
|
+
const base = baseCompat;
|
|
95
|
+
const override = overrideCompat;
|
|
96
|
+
const merged = { ...base, ...override };
|
|
97
|
+
const baseCompletions = base;
|
|
98
|
+
const overrideCompletions = override;
|
|
99
|
+
const mergedCompletions = merged;
|
|
100
|
+
if (baseCompletions?.openRouterRouting || overrideCompletions.openRouterRouting) {
|
|
101
|
+
mergedCompletions.openRouterRouting = {
|
|
102
|
+
...baseCompletions?.openRouterRouting,
|
|
103
|
+
...overrideCompletions.openRouterRouting
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (baseCompletions?.vercelGatewayRouting || overrideCompletions.vercelGatewayRouting) {
|
|
107
|
+
mergedCompletions.vercelGatewayRouting = {
|
|
108
|
+
...baseCompletions?.vercelGatewayRouting,
|
|
109
|
+
...overrideCompletions.vercelGatewayRouting
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return merged;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Deep merge a model override into a model.
|
|
116
|
+
* Handles nested objects (cost, compat) by merging rather than replacing.
|
|
117
|
+
*/
|
|
118
|
+
function applyModelOverride(model, override) {
|
|
119
|
+
const result = { ...model };
|
|
120
|
+
// Simple field overrides
|
|
121
|
+
if (override.name !== undefined)
|
|
122
|
+
result.name = override.name;
|
|
123
|
+
if (override.reasoning !== undefined)
|
|
124
|
+
result.reasoning = override.reasoning;
|
|
125
|
+
if (override.input !== undefined)
|
|
126
|
+
result.input = override.input;
|
|
127
|
+
if (override.contextWindow !== undefined)
|
|
128
|
+
result.contextWindow = override.contextWindow;
|
|
129
|
+
if (override.maxTokens !== undefined)
|
|
130
|
+
result.maxTokens = override.maxTokens;
|
|
131
|
+
// Merge cost (partial override)
|
|
132
|
+
if (override.cost) {
|
|
133
|
+
result.cost = {
|
|
134
|
+
input: override.cost.input ?? model.cost.input,
|
|
135
|
+
output: override.cost.output ?? model.cost.output,
|
|
136
|
+
cacheRead: override.cost.cacheRead ?? model.cost.cacheRead,
|
|
137
|
+
cacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// Merge headers
|
|
141
|
+
if (override.headers) {
|
|
142
|
+
const resolvedHeaders = resolveHeaders(override.headers);
|
|
143
|
+
result.headers = resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers;
|
|
144
|
+
}
|
|
145
|
+
// Deep merge compat
|
|
146
|
+
result.compat = mergeCompat(model.compat, override.compat);
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
/** Clear the config value command cache. Exported for testing. */
|
|
150
|
+
export const clearApiKeyCache = clearConfigValueCache;
|
|
151
|
+
/**
|
|
152
|
+
* Model registry - loads and manages models, resolves API keys via AuthStorage.
|
|
153
|
+
*/
|
|
154
|
+
export class ModelRegistry {
|
|
155
|
+
authStorage;
|
|
156
|
+
modelsJsonPath;
|
|
157
|
+
models = [];
|
|
158
|
+
customProviderApiKeys = new Map();
|
|
159
|
+
registeredProviders = new Map();
|
|
160
|
+
loadError = undefined;
|
|
161
|
+
constructor(authStorage, modelsJsonPath = join(getAgentDir(), 'models.json')) {
|
|
162
|
+
this.authStorage = authStorage;
|
|
163
|
+
this.modelsJsonPath = modelsJsonPath;
|
|
164
|
+
// Set up fallback resolver for custom provider API keys
|
|
165
|
+
this.authStorage.setFallbackResolver((provider) => {
|
|
166
|
+
const keyConfig = this.customProviderApiKeys.get(provider);
|
|
167
|
+
if (keyConfig) {
|
|
168
|
+
return resolveConfigValue(keyConfig);
|
|
169
|
+
}
|
|
170
|
+
return undefined;
|
|
171
|
+
});
|
|
172
|
+
// Load models
|
|
173
|
+
this.loadModels();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Reload models from disk (built-in + custom from models.json).
|
|
177
|
+
*/
|
|
178
|
+
refresh() {
|
|
179
|
+
this.customProviderApiKeys.clear();
|
|
180
|
+
this.loadError = undefined;
|
|
181
|
+
// Ensure dynamic API/OAuth registrations are rebuilt from current provider state.
|
|
182
|
+
resetApiProviders();
|
|
183
|
+
resetOAuthProviders();
|
|
184
|
+
this.loadModels();
|
|
185
|
+
for (const [providerName, config] of this.registeredProviders.entries()) {
|
|
186
|
+
this.applyProviderConfig(providerName, config);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get any error from loading models.json (undefined if no error).
|
|
191
|
+
*/
|
|
192
|
+
getError() {
|
|
193
|
+
return this.loadError;
|
|
194
|
+
}
|
|
195
|
+
loadModels() {
|
|
196
|
+
// Load custom models and overrides from models.json
|
|
197
|
+
const { models: customModels, overrides, modelOverrides, error } = this.modelsJsonPath
|
|
198
|
+
? this.loadCustomModels(this.modelsJsonPath)
|
|
199
|
+
: emptyCustomModelsResult();
|
|
200
|
+
if (error) {
|
|
201
|
+
this.loadError = error;
|
|
202
|
+
// Keep built-in models even if custom models failed to load
|
|
203
|
+
}
|
|
204
|
+
const builtInModels = this.loadBuiltInModels(overrides, modelOverrides);
|
|
205
|
+
let combined = this.mergeCustomModels(builtInModels, customModels);
|
|
206
|
+
// Let OAuth providers modify their models (e.g., update baseUrl)
|
|
207
|
+
for (const oauthProvider of this.authStorage.getOAuthProviders()) {
|
|
208
|
+
const cred = this.authStorage.get(oauthProvider.id);
|
|
209
|
+
if (cred?.type === 'oauth' && oauthProvider.modifyModels) {
|
|
210
|
+
combined = oauthProvider.modifyModels(combined, cred);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
this.models = combined;
|
|
214
|
+
}
|
|
215
|
+
/** Load built-in models and apply provider/model overrides */
|
|
216
|
+
loadBuiltInModels(overrides, modelOverrides) {
|
|
217
|
+
return getProviders().flatMap((provider) => {
|
|
218
|
+
const models = getModels(provider);
|
|
219
|
+
const providerOverride = overrides.get(provider);
|
|
220
|
+
const perModelOverrides = modelOverrides.get(provider);
|
|
221
|
+
return models.map((m) => {
|
|
222
|
+
let model = m;
|
|
223
|
+
// Apply provider-level baseUrl/headers override
|
|
224
|
+
if (providerOverride) {
|
|
225
|
+
const resolvedHeaders = resolveHeaders(providerOverride.headers);
|
|
226
|
+
model = {
|
|
227
|
+
...model,
|
|
228
|
+
baseUrl: providerOverride.baseUrl ?? model.baseUrl,
|
|
229
|
+
headers: resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
// Apply per-model override
|
|
233
|
+
const modelOverride = perModelOverrides?.get(m.id);
|
|
234
|
+
if (modelOverride) {
|
|
235
|
+
model = applyModelOverride(model, modelOverride);
|
|
236
|
+
}
|
|
237
|
+
return model;
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/** Merge custom models into built-in list by provider+id (custom wins on conflicts). */
|
|
242
|
+
mergeCustomModels(builtInModels, customModels) {
|
|
243
|
+
const merged = [...builtInModels];
|
|
244
|
+
for (const customModel of customModels) {
|
|
245
|
+
const existingIndex = merged.findIndex((m) => m.provider === customModel.provider && m.id === customModel.id);
|
|
246
|
+
if (existingIndex >= 0) {
|
|
247
|
+
merged[existingIndex] = customModel;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
merged.push(customModel);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return merged;
|
|
254
|
+
}
|
|
255
|
+
loadCustomModels(modelsJsonPath) {
|
|
256
|
+
if (!existsSync(modelsJsonPath)) {
|
|
257
|
+
return emptyCustomModelsResult();
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
const content = readFileSync(modelsJsonPath, 'utf-8');
|
|
261
|
+
const config = JSON.parse(content);
|
|
262
|
+
// Validate schema
|
|
263
|
+
const ajv = new Ajv();
|
|
264
|
+
const validate = ajv.compile(ModelsConfigSchema);
|
|
265
|
+
if (!validate(config)) {
|
|
266
|
+
const errors = validate.errors
|
|
267
|
+
?.map((e) => ` - ${e.instancePath || 'root'}: ${e.message}`)
|
|
268
|
+
.join('\n') || 'Unknown schema error';
|
|
269
|
+
return emptyCustomModelsResult(`Invalid models.json schema:\n${errors}\n\nFile: ${modelsJsonPath}`);
|
|
270
|
+
}
|
|
271
|
+
// Additional validation
|
|
272
|
+
this.validateConfig(config);
|
|
273
|
+
const overrides = new Map();
|
|
274
|
+
const modelOverrides = new Map();
|
|
275
|
+
for (const [providerName, providerConfig] of Object.entries(config.providers)) {
|
|
276
|
+
// Apply provider-level baseUrl/headers/apiKey override to built-in models when configured.
|
|
277
|
+
if (providerConfig.baseUrl || providerConfig.headers || providerConfig.apiKey) {
|
|
278
|
+
overrides.set(providerName, {
|
|
279
|
+
baseUrl: providerConfig.baseUrl,
|
|
280
|
+
headers: providerConfig.headers,
|
|
281
|
+
apiKey: providerConfig.apiKey
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
// Store API key for fallback resolver.
|
|
285
|
+
if (providerConfig.apiKey) {
|
|
286
|
+
this.customProviderApiKeys.set(providerName, providerConfig.apiKey);
|
|
287
|
+
}
|
|
288
|
+
if (providerConfig.modelOverrides) {
|
|
289
|
+
modelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return { models: this.parseModels(config), overrides, modelOverrides, error: undefined };
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
if (error instanceof SyntaxError) {
|
|
296
|
+
return emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\n\nFile: ${modelsJsonPath}`);
|
|
297
|
+
}
|
|
298
|
+
return emptyCustomModelsResult(`Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsJsonPath}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
validateConfig(config) {
|
|
302
|
+
for (const [providerName, providerConfig] of Object.entries(config.providers)) {
|
|
303
|
+
const hasProviderApi = !!providerConfig.api;
|
|
304
|
+
const models = providerConfig.models ?? [];
|
|
305
|
+
const hasModelOverrides = providerConfig.modelOverrides && Object.keys(providerConfig.modelOverrides).length > 0;
|
|
306
|
+
if (models.length === 0) {
|
|
307
|
+
// Override-only config: needs baseUrl OR modelOverrides (or both)
|
|
308
|
+
if (!providerConfig.baseUrl && !hasModelOverrides) {
|
|
309
|
+
throw new Error(`Provider ${providerName}: must specify "baseUrl", "modelOverrides", or "models".`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
// Custom models are merged into provider models and require endpoint + auth.
|
|
314
|
+
if (!providerConfig.baseUrl) {
|
|
315
|
+
throw new Error(`Provider ${providerName}: "baseUrl" is required when defining custom models.`);
|
|
316
|
+
}
|
|
317
|
+
if (!providerConfig.apiKey) {
|
|
318
|
+
throw new Error(`Provider ${providerName}: "apiKey" is required when defining custom models.`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
for (const modelDef of models) {
|
|
322
|
+
const hasModelApi = !!modelDef.api;
|
|
323
|
+
if (!hasProviderApi && !hasModelApi) {
|
|
324
|
+
throw new Error(`Provider ${providerName}, model ${modelDef.id}: no "api" specified. Set at provider or model level.`);
|
|
325
|
+
}
|
|
326
|
+
if (!modelDef.id)
|
|
327
|
+
throw new Error(`Provider ${providerName}: model missing "id"`);
|
|
328
|
+
// Validate contextWindow/maxTokens only if provided (they have defaults)
|
|
329
|
+
if (modelDef.contextWindow !== undefined && modelDef.contextWindow <= 0)
|
|
330
|
+
throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);
|
|
331
|
+
if (modelDef.maxTokens !== undefined && modelDef.maxTokens <= 0)
|
|
332
|
+
throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
parseModels(config) {
|
|
337
|
+
const models = [];
|
|
338
|
+
for (const [providerName, providerConfig] of Object.entries(config.providers)) {
|
|
339
|
+
const modelDefs = providerConfig.models ?? [];
|
|
340
|
+
if (modelDefs.length === 0)
|
|
341
|
+
continue; // Override-only, no custom models
|
|
342
|
+
// Store API key config for fallback resolver
|
|
343
|
+
if (providerConfig.apiKey) {
|
|
344
|
+
this.customProviderApiKeys.set(providerName, providerConfig.apiKey);
|
|
345
|
+
}
|
|
346
|
+
for (const modelDef of modelDefs) {
|
|
347
|
+
const api = modelDef.api || providerConfig.api;
|
|
348
|
+
if (!api)
|
|
349
|
+
continue;
|
|
350
|
+
// Merge headers: provider headers are base, model headers override
|
|
351
|
+
// Resolve env vars and shell commands in header values
|
|
352
|
+
const providerHeaders = resolveHeaders(providerConfig.headers);
|
|
353
|
+
const modelHeaders = resolveHeaders(modelDef.headers);
|
|
354
|
+
let headers = providerHeaders || modelHeaders ? { ...providerHeaders, ...modelHeaders } : undefined;
|
|
355
|
+
// If authHeader is true, add Authorization header with resolved API key
|
|
356
|
+
if (providerConfig.authHeader && providerConfig.apiKey) {
|
|
357
|
+
const resolvedKey = resolveConfigValue(providerConfig.apiKey);
|
|
358
|
+
if (resolvedKey) {
|
|
359
|
+
headers = { ...headers, Authorization: `Bearer ${resolvedKey}` };
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
// baseUrl is validated to exist for providers with models
|
|
363
|
+
// Apply defaults for optional fields
|
|
364
|
+
const defaultCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
365
|
+
models.push({
|
|
366
|
+
id: modelDef.id,
|
|
367
|
+
name: modelDef.name ?? modelDef.id,
|
|
368
|
+
api: api,
|
|
369
|
+
provider: providerName,
|
|
370
|
+
baseUrl: providerConfig.baseUrl,
|
|
371
|
+
reasoning: modelDef.reasoning ?? false,
|
|
372
|
+
input: (modelDef.input ?? ['text']),
|
|
373
|
+
cost: modelDef.cost ?? defaultCost,
|
|
374
|
+
contextWindow: modelDef.contextWindow ?? 128000,
|
|
375
|
+
maxTokens: modelDef.maxTokens ?? 16384,
|
|
376
|
+
headers,
|
|
377
|
+
compat: modelDef.compat
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return models;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Get all models (built-in + custom).
|
|
385
|
+
* If models.json had errors, returns only built-in models.
|
|
386
|
+
*/
|
|
387
|
+
getAll() {
|
|
388
|
+
return this.models;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Get only models that have auth configured.
|
|
392
|
+
* This is a fast check that doesn't refresh OAuth tokens.
|
|
393
|
+
*/
|
|
394
|
+
getAvailable() {
|
|
395
|
+
return this.models.filter((m) => this.authStorage.hasAuth(m.provider));
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Find a model by provider and ID.
|
|
399
|
+
*/
|
|
400
|
+
find(provider, modelId) {
|
|
401
|
+
return this.models.find((m) => m.provider === provider && m.id === modelId);
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Get API key for a model.
|
|
405
|
+
*/
|
|
406
|
+
async getApiKey(model) {
|
|
407
|
+
return this.authStorage.getApiKey(model.provider);
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Get API key for a provider.
|
|
411
|
+
*/
|
|
412
|
+
async getApiKeyForProvider(provider) {
|
|
413
|
+
return this.authStorage.getApiKey(provider);
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Check if a model is using OAuth credentials (subscription).
|
|
417
|
+
*/
|
|
418
|
+
isUsingOAuth(model) {
|
|
419
|
+
const cred = this.authStorage.get(model.provider);
|
|
420
|
+
return cred?.type === 'oauth';
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Register a provider dynamically (from extensions).
|
|
424
|
+
*
|
|
425
|
+
* If provider has models: replaces all existing models for this provider.
|
|
426
|
+
* If provider has only baseUrl/headers: overrides existing models' URLs.
|
|
427
|
+
* If provider has oauth: registers OAuth provider for /login support.
|
|
428
|
+
*/
|
|
429
|
+
registerProvider(providerName, config) {
|
|
430
|
+
this.registeredProviders.set(providerName, config);
|
|
431
|
+
this.applyProviderConfig(providerName, config);
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Unregister a previously registered provider.
|
|
435
|
+
*
|
|
436
|
+
* Removes the provider from the registry and reloads models from disk so that
|
|
437
|
+
* built-in models overridden by this provider are restored to their original state.
|
|
438
|
+
* Also resets dynamic OAuth and API stream registrations before reapplying
|
|
439
|
+
* remaining dynamic providers.
|
|
440
|
+
* Has no effect if the provider was never registered.
|
|
441
|
+
*/
|
|
442
|
+
unregisterProvider(providerName) {
|
|
443
|
+
if (!this.registeredProviders.has(providerName))
|
|
444
|
+
return;
|
|
445
|
+
this.registeredProviders.delete(providerName);
|
|
446
|
+
this.customProviderApiKeys.delete(providerName);
|
|
447
|
+
this.refresh();
|
|
448
|
+
}
|
|
449
|
+
applyProviderConfig(providerName, config) {
|
|
450
|
+
// Register OAuth provider if provided
|
|
451
|
+
if (config.oauth) {
|
|
452
|
+
// Ensure the OAuth provider ID matches the provider name
|
|
453
|
+
const oauthProvider = {
|
|
454
|
+
...config.oauth,
|
|
455
|
+
id: providerName
|
|
456
|
+
};
|
|
457
|
+
registerOAuthProvider(oauthProvider);
|
|
458
|
+
}
|
|
459
|
+
if (config.streamSimple) {
|
|
460
|
+
if (!config.api) {
|
|
461
|
+
throw new Error(`Provider ${providerName}: "api" is required when registering streamSimple.`);
|
|
462
|
+
}
|
|
463
|
+
const streamSimple = config.streamSimple;
|
|
464
|
+
registerApiProvider({
|
|
465
|
+
api: config.api,
|
|
466
|
+
stream: (model, context, options) => streamSimple(model, context, options),
|
|
467
|
+
streamSimple
|
|
468
|
+
}, `provider:${providerName}`);
|
|
469
|
+
}
|
|
470
|
+
// Store API key for auth resolution
|
|
471
|
+
if (config.apiKey) {
|
|
472
|
+
this.customProviderApiKeys.set(providerName, config.apiKey);
|
|
473
|
+
}
|
|
474
|
+
if (config.models && config.models.length > 0) {
|
|
475
|
+
// Full replacement: remove existing models for this provider
|
|
476
|
+
this.models = this.models.filter((m) => m.provider !== providerName);
|
|
477
|
+
// Validate required fields
|
|
478
|
+
if (!config.baseUrl) {
|
|
479
|
+
throw new Error(`Provider ${providerName}: "baseUrl" is required when defining models.`);
|
|
480
|
+
}
|
|
481
|
+
if (!config.apiKey && !config.oauth) {
|
|
482
|
+
throw new Error(`Provider ${providerName}: "apiKey" or "oauth" is required when defining models.`);
|
|
483
|
+
}
|
|
484
|
+
// Parse and add new models
|
|
485
|
+
for (const modelDef of config.models) {
|
|
486
|
+
const api = modelDef.api || config.api;
|
|
487
|
+
if (!api) {
|
|
488
|
+
throw new Error(`Provider ${providerName}, model ${modelDef.id}: no "api" specified.`);
|
|
489
|
+
}
|
|
490
|
+
// Merge headers
|
|
491
|
+
const providerHeaders = resolveHeaders(config.headers);
|
|
492
|
+
const modelHeaders = resolveHeaders(modelDef.headers);
|
|
493
|
+
let headers = providerHeaders || modelHeaders ? { ...providerHeaders, ...modelHeaders } : undefined;
|
|
494
|
+
// If authHeader is true, add Authorization header
|
|
495
|
+
if (config.authHeader && config.apiKey) {
|
|
496
|
+
const resolvedKey = resolveConfigValue(config.apiKey);
|
|
497
|
+
if (resolvedKey) {
|
|
498
|
+
headers = { ...headers, Authorization: `Bearer ${resolvedKey}` };
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
this.models.push({
|
|
502
|
+
id: modelDef.id,
|
|
503
|
+
name: modelDef.name,
|
|
504
|
+
api: api,
|
|
505
|
+
provider: providerName,
|
|
506
|
+
baseUrl: config.baseUrl,
|
|
507
|
+
reasoning: modelDef.reasoning,
|
|
508
|
+
input: modelDef.input,
|
|
509
|
+
cost: modelDef.cost,
|
|
510
|
+
contextWindow: modelDef.contextWindow,
|
|
511
|
+
maxTokens: modelDef.maxTokens,
|
|
512
|
+
headers,
|
|
513
|
+
compat: modelDef.compat
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
// Apply OAuth modifyModels if credentials exist (e.g., to update baseUrl)
|
|
517
|
+
if (config.oauth?.modifyModels) {
|
|
518
|
+
const cred = this.authStorage.get(providerName);
|
|
519
|
+
if (cred?.type === 'oauth') {
|
|
520
|
+
this.models = config.oauth.modifyModels(this.models, cred);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
else if (config.baseUrl) {
|
|
525
|
+
// Override-only: update baseUrl/headers for existing models
|
|
526
|
+
const resolvedHeaders = resolveHeaders(config.headers);
|
|
527
|
+
this.models = this.models.map((m) => {
|
|
528
|
+
if (m.provider !== providerName)
|
|
529
|
+
return m;
|
|
530
|
+
return {
|
|
531
|
+
...m,
|
|
532
|
+
baseUrl: config.baseUrl ?? m.baseUrl,
|
|
533
|
+
headers: resolvedHeaders ? { ...m.headers, ...resolvedHeaders } : m.headers
|
|
534
|
+
};
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
//# sourceMappingURL=model-registry.js.map
|