mixdog 1.1.2 → 1.2.1
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 +8 -5
- package/package.json +2 -1
- package/scripts/lib/run-node-tests.mjs +9 -0
- package/scripts/prune-desktop-runtime.mjs +3 -0
- package/scripts/test-direct.mjs +4 -2
- package/src/defaults/shipped-history.json +10 -0
- package/src/defaults/skills/pptx/SKILL.md +6 -6
- package/src/defaults/skills/pptx/references/review.md +6 -4
- package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
- package/src/defaults/skills/setup/references/actions.md +18 -5
- package/src/defaults/skills/visualize/SKILL.md +160 -0
- package/src/defaults/skills/visualize/references/craft.md +88 -0
- package/src/headless-command.mjs +56 -3
- package/src/headless-exec.mjs +17 -1
- package/src/help.mjs +2 -0
- package/src/rules/shared/60-verification.md +3 -1
- package/src/rules/shared/70-delivery.md +4 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -0
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -0
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
- package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +17 -11
- package/src/runtime/agent/orchestrator/config-storage.mjs +1 -0
- package/src/runtime/agent/orchestrator/config.mjs +19 -5
- package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +133 -15
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +55 -8
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +86 -8
- package/src/runtime/agent/orchestrator/mcp/client.mjs +474 -164
- package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
- package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
- package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +108 -17
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -12
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +444 -0
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +21 -6
- package/src/runtime/agent/orchestrator/providers/effort-rejection.mjs +244 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +41 -28
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +8 -40
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +51 -12
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +37 -2
- package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +82 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +556 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +251 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +69 -102
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +15 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +15 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/registry.mjs +47 -7
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +10 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +36 -3
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -11
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
- package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
- package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +16 -1
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +278 -84
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -3
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +9 -5
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +268 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +10 -3
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +24 -13
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +362 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +253 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
- package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/diagnostic.mjs +1 -7
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/refusal.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -4
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +21 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +22 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +9 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +37 -16
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +17 -4
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +90 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +22 -12
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +32 -3
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/message-ids.mjs +123 -0
- package/src/runtime/agent/orchestrator/session/message-ids.test-support.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +33 -22
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +10 -3
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +817 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +23 -12
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +202 -374
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +20 -3
- package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +48 -9
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +161 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +52 -2
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +32 -22
- package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +10 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-cache-policy.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +203 -33
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +32 -35
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +11 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +9 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +83 -68
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +8 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +20 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +16 -7
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +137 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +11 -10
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +21 -11
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +56 -13
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +58 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +25 -1
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +78 -5
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
- package/src/runtime/attachments/store.d.mts +3 -0
- package/src/runtime/attachments/store.mjs +38 -0
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
- package/src/runtime/channels/lib/worker-main.mjs +17 -14
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
- package/src/runtime/effort-judge/judge-client.mjs +56 -18
- package/src/runtime/memory/lib/memory.mjs +1 -1
- package/src/runtime/memory/lib/session-ingest.mjs +2 -2
- package/src/runtime/shared/atomic-file.mjs +33 -6
- package/src/runtime/shared/best-effort-stderr.mjs +8 -0
- package/src/runtime/shared/code-graph-state.mjs +12 -0
- package/src/runtime/shared/defaults-separation.mjs +2 -0
- package/src/runtime/shared/extension-scopes.mjs +5 -3
- package/src/runtime/shared/file-lock.mjs +37 -11
- package/src/runtime/shared/git-runner-worker.mjs +3 -2
- package/src/runtime/shared/git-runner.mjs +4 -3
- package/src/runtime/shared/llm/anthropic-effort.mjs +14 -0
- package/src/runtime/shared/llm/default-context-window.mjs +6 -0
- package/src/runtime/shared/llm/model-catalog-projection.mjs +5 -4
- package/src/runtime/shared/llm/model-catalog.mjs +240 -130
- package/src/runtime/shared/llm/provider-catalog-cache.mjs +36 -28
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +162 -0
- package/src/runtime/shared/llm/provider-seed-rosters.mjs +130 -0
- package/src/runtime/shared/model-proxy-mode.d.mts +3 -0
- package/src/runtime/shared/model-proxy-mode.mjs +19 -0
- package/src/runtime/shared/plugin-manifest.mjs +18 -9
- package/src/runtime/shared/pristine-execution-contract.json +9 -2
- package/src/runtime/shared/pristine-execution.mjs +28 -4
- package/src/runtime/shared/provider-accounts.mjs +125 -21
- package/src/runtime/shared/provider-api-key.mjs +33 -1
- package/src/runtime/shared/schedule-model-ref.mjs +11 -2
- package/src/runtime/shared/session-usage-totals.mjs +19 -0
- package/src/runtime/shared/sharp-electron-linux.mjs +25 -0
- package/src/runtime/shared/shell-display.mjs +9 -3
- package/src/runtime/shared/singleton-owner.mjs +36 -6
- package/src/runtime/shared/skill-mentions.d.mts +10 -0
- package/src/runtime/shared/skill-mentions.mjs +133 -0
- package/src/runtime/shared/skill-script-runtime.mjs +264 -0
- package/src/runtime/shared/statusline/statusline-segments.mjs +68 -14
- package/src/runtime/shared/tool-primitives.mjs +35 -2
- package/src/runtime/shared/tool-surface.mjs +7 -0
- package/src/runtime/shared/tool-work-units.mjs +14 -0
- package/src/runtime/shared/transcript-metadata.mjs +17 -1
- package/src/runtime/shared/turn-changes.mjs +791 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +346 -12
- package/src/runtime/shared/turn-snapshot.mjs +690 -81
- package/src/runtime/shared/turn-worktree-snapshot.mjs +185 -15
- package/src/runtime/shared/worker-requests.mjs +15 -2
- package/src/runtime/shared/worktrees/cache-cleanups.mjs +52 -0
- package/src/runtime/shared/worktrees/contract.mjs +551 -0
- package/src/runtime/shared/worktrees/disk.mjs +57 -0
- package/src/runtime/shared/worktrees/git.mjs +247 -0
- package/src/runtime/shared/worktrees/include.mjs +480 -0
- package/src/runtime/shared/worktrees/lock.mjs +46 -0
- package/src/runtime/shared/worktrees/maintenance.mjs +96 -0
- package/src/runtime/shared/worktrees/manager.mjs +1215 -0
- package/src/runtime/shared/worktrees/merge.mjs +182 -0
- package/src/runtime/shared/worktrees/owner.mjs +46 -0
- package/src/runtime/shared/worktrees/paths.mjs +62 -0
- package/src/runtime/shared/worktrees/registry.mjs +110 -0
- package/src/runtime/shared/worktrees/settings.mjs +84 -0
- package/src/runtime/shared/worktrees/slug.mjs +62 -0
- package/src/runtime/shared/worktrees/test-support.mjs +96 -0
- package/src/runtime/visualize-bridge/client.mjs +181 -0
- package/src/runtime/visualize-bridge/tool-defs.mjs +97 -0
- package/src/session-runtime/automation-agents.mjs +8 -2
- package/src/session-runtime/boot/apis.mjs +90 -0
- package/src/session-runtime/boot/config.mjs +7 -2
- package/src/session-runtime/boot/facade.mjs +21 -0
- package/src/session-runtime/boot/infrastructure.mjs +30 -18
- package/src/session-runtime/boot/session.mjs +1 -0
- package/src/session-runtime/boot/tools.mjs +4 -0
- package/src/session-runtime/config-lifecycle.mjs +10 -1
- package/src/session-runtime/conversation-import/discovery.mjs +698 -0
- package/src/session-runtime/conversation-import/service.mjs +369 -0
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +21 -6
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
- package/src/session-runtime/global-extensions.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +27 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +32 -1
- package/src/session-runtime/internal-tool-executor.mjs +9 -1
- package/src/session-runtime/lifecycle/session-catalog.mjs +8 -1
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +5 -0
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +21 -3
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +16 -0
- package/src/session-runtime/mcp-glue/connect.mjs +68 -16
- package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +122 -33
- package/src/session-runtime/mcp-glue/server-input.mjs +29 -0
- package/src/session-runtime/mcp-glue.mjs +22 -2
- package/src/session-runtime/model-route/route-persist.mjs +3 -0
- package/src/session-runtime/model-route/set-route.mjs +15 -2
- package/src/session-runtime/new-session-config.mjs +3 -2
- package/src/session-runtime/notification-bus.mjs +18 -3
- package/src/session-runtime/provider-auth/accounts.mjs +33 -15
- package/src/session-runtime/provider-models/row-hydration.mjs +2 -0
- package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
- package/src/session-runtime/provider-readiness.mjs +16 -10
- package/src/session-runtime/resource-extension-sync.mjs +45 -7
- package/src/session-runtime/resource-mcp-api.mjs +121 -84
- package/src/session-runtime/resource-plugins-api.mjs +29 -41
- package/src/session-runtime/resource-scope-decorate.mjs +6 -8
- package/src/session-runtime/resource-skills-api.mjs +23 -2
- package/src/session-runtime/route-resolution.mjs +10 -1
- package/src/session-runtime/route-state.mjs +16 -2
- package/src/session-runtime/runtime-core.mjs +5 -0
- package/src/session-runtime/runtime-facade.mjs +8 -0
- package/src/session-runtime/runtime-review-api.mjs +9 -0
- package/src/session-runtime/schedule-session-run.mjs +1 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +5 -0
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +3 -0
- package/src/session-runtime/services/agent-tool/job-views/job-lookup.mjs +1 -0
- package/src/session-runtime/services/agent-tool/job-views/spawn-meta.mjs +1 -0
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +15 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +1 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +10 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -7
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +2 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -0
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +1 -0
- package/src/session-runtime/services/agent-tool.mjs +1 -0
- package/src/session-runtime/services/channel-session-router.mjs +4 -1
- package/src/session-runtime/services/daemon-candidate.mjs +3 -2
- package/src/session-runtime/services/daemon-crash-capture/spawn-capture.mjs +55 -0
- package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
- package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
- package/src/session-runtime/services/provider-admin.mjs +64 -18
- package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
- package/src/session-runtime/session-create/session-options.mjs +10 -1
- package/src/session-runtime/session-turn-api.mjs +1 -0
- package/src/session-runtime/settings-api.mjs +4 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -2
- package/src/session-runtime/settings-worktree-api.mjs +17 -0
- package/src/session-runtime/setup-tool/executor.mjs +23 -5
- package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +4 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +38 -4
- package/src/session-runtime/skills-api.mjs +7 -3
- package/src/session-runtime/turn/agent-ops.mjs +12 -1
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +14 -3
- package/src/session-runtime/turn/turn-run/snapshot-tracker.mjs +20 -15
- package/src/session-runtime/turn/turn-run/turn-open.mjs +4 -5
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +29 -1
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +6 -1
- package/src/session-runtime/turn/turn-run.mjs +6 -7
- package/src/session-runtime/webhook-session-run.mjs +16 -4
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -3
- package/src/session-runtime/workspace/admission-gate.mjs +197 -0
- package/src/session-runtime/workspace/project-branches.mjs +136 -0
- package/src/session-runtime/workspace/transition-steps.mjs +364 -0
- package/src/session-runtime/workspace/transitions.mjs +651 -0
- package/src/session-runtime/workspace/workspace-state.mjs +112 -0
- package/src/skill-script-entry.mjs +36 -0
- package/src/standalone/channel-transport/http-routes.mjs +17 -0
- package/src/standalone/channel-transport.mjs +13 -1
- package/src/standalone/daemon-desktop-runtime.mjs +1 -0
- package/src/standalone/daemon-owner.mjs +372 -0
- package/src/standalone/daemon-stored-session-views.mjs +15 -4
- package/src/standalone/daemon.mjs +179 -8
- package/src/standalone/desktop-service-registry.mjs +20 -0
- package/src/standalone/local-session-runtime.mjs +11 -0
- package/src/standalone/session-client/attachment-calls.mjs +3 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +62 -0
- package/src/standalone/session-client/lease-heartbeat.mjs +47 -0
- package/src/standalone/session-client.mjs +104 -13
- package/src/standalone/session-protocol.mjs +21 -0
- package/src/standalone/session-proxy.mjs +3 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +4 -0
- package/src/standalone/session-service/agent-tree/agent-rehydrate.mjs +1 -0
- package/src/standalone/session-service/entries/lifecycle.mjs +6 -0
- package/src/standalone/session-service/projection/revisions.mjs +2 -0
- package/src/standalone/session-service/projection/transcript-window.mjs +149 -19
- package/src/standalone/session-service/projection/workspace.mjs +14 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +17 -4
- package/src/standalone/session-transport/call-route.mjs +13 -0
- package/src/standalone/session-transport/client-registry/client-grace.mjs +45 -3
- package/src/standalone/session-transport/client-registry/registration-replays.mjs +1 -0
- package/src/standalone/session-transport/client-registry.mjs +20 -3
- package/src/standalone/session-transport/routes.mjs +79 -2
- package/src/standalone/session-transport/stack.mjs +2 -0
- package/src/standalone/session-transport.mjs +24 -1
- package/src/tui/App.jsx +9 -1
- package/src/tui/app/app-view/floating-panel.jsx +9 -1
- package/src/tui/app/app-view.jsx +6 -0
- package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
- package/src/tui/app/message-selector.mjs +2 -1
- package/src/tui/app/model-options.mjs +37 -5
- package/src/tui/app/model-picker/provider-models-list.mjs +2 -2
- package/src/tui/app/model-picker.mjs +4 -2
- package/src/tui/app/skill-mention-palette.mjs +88 -0
- package/src/tui/app/slash-palette.mjs +23 -7
- package/src/tui/app/transcript-row-estimate.mjs +11 -3
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
- package/src/tui/app/use-prompt-state.mjs +5 -0
- package/src/tui/components/Message.jsx +22 -1
- package/src/tui/components/PromptInput.jsx +21 -3
- package/src/tui/components/SlashCommandPalette.jsx +12 -3
- package/src/tui/components/TranscriptItem.jsx +9 -1
- package/src/tui/components/prompt-input/key-handler.mjs +21 -8
- package/src/tui/components/user-message-skills.mjs +38 -0
- package/src/tui/dist/index.mjs +839 -207
- package/src/tui/index.jsx +10 -2
- package/src/tui/session/compaction-view.mjs +147 -0
- package/src/tui/session/context-state.mjs +6 -0
- package/src/tui/session/initial-state.mjs +3 -0
- package/src/tui/session/queue-helpers.mjs +7 -2
- package/src/tui/session/quota-resume.mjs +2 -1
- package/src/tui/session/session-api/commands.mjs +10 -2
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +4 -2
- package/src/tui/session/session-api/intake/rewind.mjs +2 -1
- package/src/tui/session/session-api/integrations.mjs +17 -0
- package/src/tui/session/session-api/lifecycle/dispose.mjs +6 -1
- package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -0
- package/src/tui/session/session-api/lifecycle/resume.mjs +3 -0
- package/src/tui/session/session-api/routes.mjs +10 -1
- package/src/tui/session/session-api/settings.mjs +9 -0
- package/src/tui/session/session-api/worktree.mjs +60 -0
- package/src/tui/session/session-api.mjs +2 -0
- package/src/tui/session/session-flow/auto-clear.mjs +31 -12
- package/src/tui/session/session-flow/drain.mjs +27 -3
- package/src/tui/session/session-flow/session-reset.mjs +4 -3
- package/src/tui/session/session-flow.mjs +2 -0
- package/src/tui/session/transcript-intake.mjs +14 -5
- package/src/tui/session/tui-steering-persist.mjs +25 -9
- package/src/tui/session/turn-stream.mjs +32 -4
- package/src/tui/session/turn-tool-cards.mjs +10 -2
- package/src/tui/session/turn.mjs +56 -10
- package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
- package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { parseJsonText, updateJsonAtomicSync } from '../../../shared/atomic-file.mjs';
|
|
4
|
+
import { resolvePluginData } from '../../../shared/plugin-paths.mjs';
|
|
5
|
+
|
|
6
|
+
// An OpenAI-compatible endpoint that rejects the requested reasoning effort
|
|
7
|
+
// (HTTP 400 naming the value) is replayed once at the nearest accepted level,
|
|
8
|
+
// and the rejection is remembered per provider+model so the level stops being
|
|
9
|
+
// sent (clamped before the request) and stops being offered (the sync reader).
|
|
10
|
+
|
|
11
|
+
const EFFORT_ORDER = Object.freeze(['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra']);
|
|
12
|
+
const FILE_NAME = 'effort-rejections.json';
|
|
13
|
+
// Per-provider request fields that can carry the effort next to `opts.effort`.
|
|
14
|
+
const EFFORT_OPT_KEYS = ['xaiReasoningEffort', 'openRouterReasoningEffort', 'deepseekReasoningEffort'];
|
|
15
|
+
const LEVEL_RE = new RegExp(`\\b(${EFFORT_ORDER.join('|')})\\b`, 'gi');
|
|
16
|
+
const LIST_RE =
|
|
17
|
+
/\b(?:supported|allowed|valid|accepted|available)\s+(?:values?|levels?|options?|efforts?)|(?:must|should|expected to) be one of|expected one of|one of|choose from|input should be/i;
|
|
18
|
+
const REJECT_RE =
|
|
19
|
+
/invalid|unsupported|not supported|does not support|doesn't support|not allowed|not a valid|unrecognized|must be one of|expected one of|supported values/i;
|
|
20
|
+
// Anthropic's `invalid_request_error` words a bad enum value as "Input should be 'low', ...".
|
|
21
|
+
const ANTHROPIC_REJECT_RE = /input should be|should be one of|not one of/i;
|
|
22
|
+
const EFFORT_RE = /reasoning[._ ]?effort|\beffort\b/i;
|
|
23
|
+
const REASONING_RE = /\breasoning\b/i;
|
|
24
|
+
// A request field other than the effort: `reasoning.summary`, `reasoning_content`,
|
|
25
|
+
// `thinking.type`, `budget_tokens`, ...
|
|
26
|
+
const OTHER_FIELD_RE = /\breasoning[._[](?!effort)\w+|(?:^|[\s'"`(])(?:thinking\.\w+|budget_tokens)\b/i;
|
|
27
|
+
// The mid-conversation effort update rejection belongs to effort-configuration.mjs.
|
|
28
|
+
const EFFORT_CONFIGURATION_RE = /mid-conversation|configuration_update|reasoning_effort_update/i;
|
|
29
|
+
/** The effort levels the Anthropic Messages wire accepts (`output_config.effort`). */
|
|
30
|
+
export const ANTHROPIC_EFFORT_LEVELS = Object.freeze(['low', 'medium', 'high', 'xhigh', 'max']);
|
|
31
|
+
|
|
32
|
+
const cache = new Map();
|
|
33
|
+
|
|
34
|
+
const filePath = () => join(resolvePluginData(), FILE_NAME);
|
|
35
|
+
const entryKey = (provider, model) =>
|
|
36
|
+
`${String(provider || '').trim()}:${String(model || '')
|
|
37
|
+
.trim()
|
|
38
|
+
.toLowerCase()}`;
|
|
39
|
+
const levelOf = (value) => {
|
|
40
|
+
const level = String(value ?? '')
|
|
41
|
+
.trim()
|
|
42
|
+
.toLowerCase();
|
|
43
|
+
return EFFORT_ORDER.includes(level) ? level : null;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// A rejection persisted by another process changes the file; the cached copy is
|
|
47
|
+
// only trusted while the file's mtime and size are unchanged.
|
|
48
|
+
function signature(file) {
|
|
49
|
+
try {
|
|
50
|
+
const stat = statSync(file);
|
|
51
|
+
return `${stat.mtimeMs}:${stat.size}`;
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function load(file) {
|
|
58
|
+
const sig = signature(file);
|
|
59
|
+
const cached = cache.get(file);
|
|
60
|
+
if (cached && cached.sig === sig) return cached.data;
|
|
61
|
+
let data = null;
|
|
62
|
+
try {
|
|
63
|
+
data = parseJsonText(readFileSync(file, 'utf8'));
|
|
64
|
+
} catch {}
|
|
65
|
+
const valid =
|
|
66
|
+
data?.version === 1 && data.models && typeof data.models === 'object' ? data : { version: 1, models: {} };
|
|
67
|
+
cache.set(file, { sig, data: valid });
|
|
68
|
+
return valid;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function addRejection(data, key, level, allowed) {
|
|
72
|
+
const models = { ...data.models };
|
|
73
|
+
const prev = models[key] || {};
|
|
74
|
+
const rejected = new Set(prev.rejected || []);
|
|
75
|
+
if (level) rejected.add(level);
|
|
76
|
+
const nextAllowed = allowed?.length ? allowed : prev.allowed;
|
|
77
|
+
models[key] = { rejected: [...rejected], ...(nextAllowed?.length ? { allowed: nextAllowed } : {}) };
|
|
78
|
+
return { version: 1, models };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function entry(provider, model) {
|
|
82
|
+
return load(filePath()).models[entryKey(provider, model)] || null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Levels this provider+model is known not to accept (rejected, or outside a
|
|
86
|
+
* list the endpoint named). Sync, for the runtime effort catalog. */
|
|
87
|
+
export function rejectedEffortLevelsSync(provider, model) {
|
|
88
|
+
const found = entry(provider, model);
|
|
89
|
+
const rejected = new Set(found?.rejected || []);
|
|
90
|
+
if (found?.allowed?.length) for (const level of EFFORT_ORDER) if (!found.allowed.includes(level)) rejected.add(level);
|
|
91
|
+
return rejected;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Remember a rejected level (and the allowed list the endpoint named, if any). */
|
|
95
|
+
export function recordEffortRejection(provider, model, level, allowed = null) {
|
|
96
|
+
const file = filePath();
|
|
97
|
+
const key = entryKey(provider, model);
|
|
98
|
+
const normalized = levelOf(level);
|
|
99
|
+
try {
|
|
100
|
+
const data = updateJsonAtomicSync(
|
|
101
|
+
file,
|
|
102
|
+
(cur) =>
|
|
103
|
+
addRejection(cur?.version === 1 && cur.models ? cur : { version: 1, models: {} }, key, normalized, allowed),
|
|
104
|
+
{ lock: true, timeoutMs: 1000 }
|
|
105
|
+
);
|
|
106
|
+
cache.set(file, { sig: signature(file), data });
|
|
107
|
+
} catch {
|
|
108
|
+
cache.set(file, { sig: signature(file), data: addRejection(load(file), key, normalized, allowed) });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Forget what was loaded from disk (a process restart, for tests). */
|
|
113
|
+
export function resetEffortRejectionCache() {
|
|
114
|
+
cache.clear();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const collect = (error) => {
|
|
118
|
+
const nested = error?.error?.error && typeof error.error.error === 'object' ? error.error.error : null;
|
|
119
|
+
return [error, error?.error, nested].filter((part) => part && typeof part === 'object');
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const hasLevel = (text) => new RegExp(LEVEL_RE.source, 'i').test(text);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* A 400-class provider error that rejects the reasoning effort, as
|
|
126
|
+
* `{ allowed }` (levels the message lists, or null), else null. It must be
|
|
127
|
+
* effort-specific: the `param` names the effort field, or the message names the
|
|
128
|
+
* effort field together with a level, or (given the `requested` level) the
|
|
129
|
+
* message calls that level invalid while talking about reasoning. A rejection
|
|
130
|
+
* of another reasoning field (`reasoning.summary`, `reasoning.include`) never matches.
|
|
131
|
+
*/
|
|
132
|
+
export function detectEffortRejection(error, requested = null) {
|
|
133
|
+
const status = [error?.status, error?.httpStatus, error?.response?.status].map(Number).find((value) => value > 0);
|
|
134
|
+
if (status !== 400 && status !== 422) return null;
|
|
135
|
+
const parts = collect(error);
|
|
136
|
+
const param = parts.map((part) => String(part.param ?? '')).join(' ');
|
|
137
|
+
const text = parts
|
|
138
|
+
.flatMap((part) => [part.message, part.code, part.param])
|
|
139
|
+
.filter(Boolean)
|
|
140
|
+
.join(' ');
|
|
141
|
+
if (EFFORT_CONFIGURATION_RE.test(text)) return null;
|
|
142
|
+
const anthropic = parts.some((part) => part.type === 'invalid_request_error') || /invalid_request_error/.test(text);
|
|
143
|
+
if (!REJECT_RE.test(text) && !(anthropic && ANTHROPIC_REJECT_RE.test(text))) return null;
|
|
144
|
+
const level = levelOf(requested);
|
|
145
|
+
const targeted =
|
|
146
|
+
/effort/i.test(param) ||
|
|
147
|
+
(!OTHER_FIELD_RE.test(`${param} ${text}`) &&
|
|
148
|
+
((EFFORT_RE.test(text) && hasLevel(text)) ||
|
|
149
|
+
(level && REASONING_RE.test(text) && new RegExp(`\\b${level}\\b`, 'i').test(text))));
|
|
150
|
+
if (!targeted) return null;
|
|
151
|
+
const list = LIST_RE.exec(text);
|
|
152
|
+
const allowed = list
|
|
153
|
+
? [...new Set([...text.slice(list.index + list[0].length).matchAll(LEVEL_RE)].map((m) => m[1].toLowerCase()))]
|
|
154
|
+
: [];
|
|
155
|
+
return { allowed: allowed.length ? allowed : null };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* The nearest lower level not in `rejected`; with `allowHigher` (the accepted
|
|
160
|
+
* set is known) the nearest higher one when nothing lower is left.
|
|
161
|
+
*/
|
|
162
|
+
export function nearestAcceptedEffort(requested, rejected = new Set(), { allowHigher = false } = {}) {
|
|
163
|
+
const from = EFFORT_ORDER.indexOf(requested);
|
|
164
|
+
if (from < 0) return null;
|
|
165
|
+
const open = EFFORT_ORDER.filter((level, index) => index !== from && !rejected.has(level));
|
|
166
|
+
const lower = open.filter((level) => EFFORT_ORDER.indexOf(level) < from).at(-1);
|
|
167
|
+
return lower ?? (allowHigher ? (open[0] ?? null) : null);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const requestedEffort = (opts, configEffort) => levelOf(opts?.effort ?? configEffort);
|
|
171
|
+
|
|
172
|
+
function withEffort(opts, level) {
|
|
173
|
+
const next = { ...opts, effort: level };
|
|
174
|
+
for (const key of EFFORT_OPT_KEYS) if (opts?.[key] !== undefined) next[key] = level;
|
|
175
|
+
return next;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// The rejected set seen by a transport that only takes `levels` of the ladder.
|
|
179
|
+
function rejectedWithin(provider, model, levels) {
|
|
180
|
+
const rejected = rejectedEffortLevelsSync(provider, model);
|
|
181
|
+
if (levels) for (const level of EFFORT_ORDER) if (!levels.includes(level)) rejected.add(level);
|
|
182
|
+
return rejected;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** `opts` with a level already known to be rejected stepped down; unchanged otherwise. */
|
|
186
|
+
export function clampEffortOpts(provider, model, opts, configEffort, levels = null) {
|
|
187
|
+
const requested = requestedEffort(opts, configEffort);
|
|
188
|
+
if (!requested || (levels && !levels.includes(requested))) return opts;
|
|
189
|
+
const rejected = rejectedWithin(provider, model, levels);
|
|
190
|
+
if (!rejected.has(requested)) return opts;
|
|
191
|
+
const level = nearestAcceptedEffort(requested, rejected, { allowHigher: Boolean(entry(provider, model)?.allowed) });
|
|
192
|
+
return level ? withEffort(opts, level) : opts;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const STREAM_CALLBACKS = ['onStreamDelta', 'onTextDelta', 'onToolCall'];
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Runs `send(opts)` with known-rejected levels clamped first; when the model
|
|
199
|
+
* rejects the effort, remembers it and replays the request once at the nearest
|
|
200
|
+
* accepted level. Never replays after output reached the caller, and never
|
|
201
|
+
* replays the replay. `levels` limits the ladder to what the transport's wire
|
|
202
|
+
* accepts. A send re-entered from inside a wrapped send (a transport's own
|
|
203
|
+
* replays call `send` again) passes straight through: the outer wrapper owns it.
|
|
204
|
+
*/
|
|
205
|
+
export async function withEffortRejectionFallback(provider, model, opts, configEffort, send, { levels = null } = {}) {
|
|
206
|
+
if (opts?._effortRejectionActive) return send(opts);
|
|
207
|
+
let streamed = false;
|
|
208
|
+
const tracked = { ...opts, _effortRejectionActive: true };
|
|
209
|
+
for (const name of STREAM_CALLBACKS) {
|
|
210
|
+
const callback = opts?.[name];
|
|
211
|
+
if (typeof callback === 'function') {
|
|
212
|
+
tracked[name] = (...args) => {
|
|
213
|
+
streamed = true;
|
|
214
|
+
return callback(...args);
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const first = clampEffortOpts(provider, model, tracked, configEffort, levels);
|
|
219
|
+
try {
|
|
220
|
+
return await send(first);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
const requested = requestedEffort(first, configEffort);
|
|
223
|
+
const rejection = detectEffortRejection(error, requested);
|
|
224
|
+
const emitted =
|
|
225
|
+
streamed || error?.liveTextEmitted === true || error?.emittedToolCall === true || error?.unsafeToRetry === true;
|
|
226
|
+
if (!rejection || !requested || (levels && !levels.includes(requested))) throw error;
|
|
227
|
+
recordEffortRejection(provider, model, requested, rejection.allowed);
|
|
228
|
+
if (emitted) throw error;
|
|
229
|
+
const level = nearestAcceptedEffort(requested, rejectedWithin(provider, model, levels), {
|
|
230
|
+
allowHigher: Boolean(entry(provider, model)?.allowed),
|
|
231
|
+
});
|
|
232
|
+
if (!level) throw error;
|
|
233
|
+
process.stderr.write(
|
|
234
|
+
`[${provider}] ${model} rejected reasoning effort '${requested}'; retrying once at '${level}'\n`
|
|
235
|
+
);
|
|
236
|
+
try {
|
|
237
|
+
return await send(withEffort(first, level));
|
|
238
|
+
} catch (retryError) {
|
|
239
|
+
const again = detectEffortRejection(retryError, level);
|
|
240
|
+
if (again) recordEffortRejection(provider, model, level, again.allowed);
|
|
241
|
+
throw retryError;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GoogleGenerativeAI } from '@google/generative-ai';
|
|
2
|
-
import {
|
|
2
|
+
import { reloadProviderApiKey, resolveProviderApiKey } from '../../../shared/provider-api-key.mjs';
|
|
3
3
|
import { canFallbackNonStreaming, emitProviderRetryStage, withRetry } from './retry-classifier.mjs';
|
|
4
4
|
import { noteErrorUsage } from './lib/note-error-usage.mjs';
|
|
5
5
|
import { traceNonStreamingFallback } from './lib/transport-fallback-trace.mjs';
|
|
@@ -153,8 +153,9 @@ export class GeminiProvider {
|
|
|
153
153
|
this._createGenAI =
|
|
154
154
|
typeof config.createGenAI === 'function' ? config.createGenAI : (apiKey) => new GoogleGenerativeAI(apiKey);
|
|
155
155
|
this._modelCache = config.modelCache || _modelCache;
|
|
156
|
-
|
|
157
|
-
this.
|
|
156
|
+
this._injectedGenAI = Boolean(config.genAI);
|
|
157
|
+
this._genAIKey = resolveProviderApiKey('gemini', config);
|
|
158
|
+
this.genAI = config.genAI || this._createGenAI(this._genAIKey);
|
|
158
159
|
// Warm a kept-alive socket to the Gemini REST API so the first cache/
|
|
159
160
|
// generateContent request skips the cold TLS handshake. Best-effort.
|
|
160
161
|
this._preconnect('https://generativelanguage.googleapis.com');
|
|
@@ -162,12 +163,13 @@ export class GeminiProvider {
|
|
|
162
163
|
|
|
163
164
|
reloadApiKey() {
|
|
164
165
|
try {
|
|
165
|
-
const newKey =
|
|
166
|
+
const newKey = reloadProviderApiKey('gemini', this.config);
|
|
166
167
|
if (newKey) {
|
|
167
|
-
// Keep this.config in sync so REST/cache paths
|
|
168
|
-
// key
|
|
169
|
-
// the stale key after a rotation; genAI alone is not enough.
|
|
168
|
+
// Keep this.config in sync so REST/cache paths don't keep using the
|
|
169
|
+
// stale key after a rotation; genAI alone is not enough.
|
|
170
170
|
this.config = { ...(this.config || {}), apiKey: newKey };
|
|
171
|
+
this._injectedGenAI = false;
|
|
172
|
+
this._genAIKey = newKey;
|
|
171
173
|
this.genAI = this._createGenAI(newKey);
|
|
172
174
|
}
|
|
173
175
|
return newKey || '';
|
|
@@ -178,7 +180,18 @@ export class GeminiProvider {
|
|
|
178
180
|
}
|
|
179
181
|
|
|
180
182
|
_getApiKey() {
|
|
181
|
-
return this.config
|
|
183
|
+
return resolveProviderApiKey('gemini', this.config);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// SDK client for the currently resolved key; rebuilt when the key changed
|
|
187
|
+
// since construction (e.g. a keyless-constructed instance).
|
|
188
|
+
_currentGenAI() {
|
|
189
|
+
const key = this._getApiKey();
|
|
190
|
+
if (!this._injectedGenAI && key !== this._genAIKey) {
|
|
191
|
+
this._genAIKey = key;
|
|
192
|
+
this.genAI = this._createGenAI(key);
|
|
193
|
+
}
|
|
194
|
+
return this.genAI;
|
|
182
195
|
}
|
|
183
196
|
|
|
184
197
|
/**
|
|
@@ -673,7 +686,7 @@ export class GeminiProvider {
|
|
|
673
686
|
|
|
674
687
|
async _streamViaSdk(stream) {
|
|
675
688
|
const { opts, signal, useModel, systemInstruction, geminiTools, toolConfig, generationConfig, contents } = stream;
|
|
676
|
-
const genModel = this.
|
|
689
|
+
const genModel = this._currentGenAI().getGenerativeModel({
|
|
677
690
|
model: useModel,
|
|
678
691
|
systemInstruction,
|
|
679
692
|
tools: geminiTools,
|
|
@@ -714,7 +727,7 @@ export class GeminiProvider {
|
|
|
714
727
|
const cached = this._modelCache.loadSync();
|
|
715
728
|
if (cached) return cached;
|
|
716
729
|
// Dynamic lookup via Gemini v1beta /models. Requires API key.
|
|
717
|
-
const apiKey = this.
|
|
730
|
+
const apiKey = this._getApiKey();
|
|
718
731
|
if (!apiKey) return MODELS; // no key — return minimal static list
|
|
719
732
|
try {
|
|
720
733
|
return await this._fetchAndCacheModels(apiKey);
|
|
@@ -738,26 +751,26 @@ export class GeminiProvider {
|
|
|
738
751
|
|
|
739
752
|
// Force a catalog refresh (ignores the 24h disk TTL). De-duped via
|
|
740
753
|
// _modelRefreshInFlight so concurrent callers share one HTTP round-trip.
|
|
741
|
-
//
|
|
754
|
+
// Resolves null when there is no key; fetch/normalize failures reject so
|
|
755
|
+
// callers (registry refresh) report them.
|
|
742
756
|
async _refreshModelCache() {
|
|
743
757
|
if (_modelRefreshInFlight) return _modelRefreshInFlight;
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
return enriched;
|
|
752
|
-
} catch (err) {
|
|
753
|
-
if (!process.env.MIXDOG_QUIET_PROVIDER_LOG)
|
|
754
|
-
process.stderr.write(`[gemini] catalog refresh failed (${err.message})\n`);
|
|
755
|
-
return null;
|
|
756
|
-
} finally {
|
|
757
|
-
_modelRefreshInFlight = null;
|
|
758
|
-
}
|
|
758
|
+
const refresh = (async () => {
|
|
759
|
+
const apiKey = this._getApiKey();
|
|
760
|
+
if (!apiKey) return null; // no key — nothing to refresh
|
|
761
|
+
const enriched = await this._fetchAndCacheModels(apiKey);
|
|
762
|
+
if (!process.env.MIXDOG_QUIET_PROVIDER_LOG)
|
|
763
|
+
process.stderr.write(`[gemini] catalog refreshed (${enriched.length} models)\n`);
|
|
764
|
+
return enriched;
|
|
759
765
|
})();
|
|
760
|
-
|
|
766
|
+
// Clear only after the shared promise is published: a refresh that settles
|
|
767
|
+
// synchronously (no key) must not leave its settled promise memoized.
|
|
768
|
+
_modelRefreshInFlight = refresh;
|
|
769
|
+
try {
|
|
770
|
+
return await refresh;
|
|
771
|
+
} finally {
|
|
772
|
+
if (_modelRefreshInFlight === refresh) _modelRefreshInFlight = null;
|
|
773
|
+
}
|
|
761
774
|
}
|
|
762
775
|
|
|
763
776
|
async isAvailable() {
|
|
@@ -766,7 +779,7 @@ export class GeminiProvider {
|
|
|
766
779
|
controller.abort(providerTimeoutError('Gemini availability probe', GEMINI_AVAILABILITY_TIMEOUT_MS));
|
|
767
780
|
}, GEMINI_AVAILABILITY_TIMEOUT_MS);
|
|
768
781
|
try {
|
|
769
|
-
const model = this.
|
|
782
|
+
const model = this._currentGenAI().getGenerativeModel({ model: DEFAULT_MODEL });
|
|
770
783
|
const generation = Promise.resolve(model.generateContent('hi', { signal: controller.signal }));
|
|
771
784
|
generation.catch(() => {});
|
|
772
785
|
await Promise.race([
|
|
@@ -3,7 +3,7 @@ import { createNpmVersionSource, maxSemver } from './npm-cli-version.mjs';
|
|
|
3
3
|
// Grok CLI client version for the cli-chat-proxy version gate (HTTP 426).
|
|
4
4
|
// Effective = env override, else max(floor, learned-from-426, live npm latest
|
|
5
5
|
// of the official @xai-official/grok CLI).
|
|
6
|
-
export const GROK_CLI_VERSION_FLOOR = '1.0.
|
|
6
|
+
export const GROK_CLI_VERSION_FLOOR = '1.0.52';
|
|
7
7
|
export const GROK_CLI_NPM_PACKAGE = '@xai-official/grok';
|
|
8
8
|
|
|
9
9
|
const live = createNpmVersionSource(GROK_CLI_NPM_PACKAGE, { persistKey: 'grok-cli' });
|
|
@@ -10,6 +10,7 @@ import { boundProviderAuthPath } from '../../../shared/provider-auth-binding.mjs
|
|
|
10
10
|
import { createTimeoutSignal } from '../stall-policy.mjs';
|
|
11
11
|
import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
|
|
12
12
|
import { grokClientVersionHeaders } from './grok-client-version.mjs';
|
|
13
|
+
import { modelProxyClientMode, serverModelCredentialsDisabledError } from '../../../shared/model-proxy-mode.mjs';
|
|
13
14
|
import {
|
|
14
15
|
accountIdentityFields,
|
|
15
16
|
decodeJwtPayload,
|
|
@@ -174,6 +175,7 @@ export function _mtimeMs(path) {
|
|
|
174
175
|
// mixdog's own login store (grok-oauth.json). Single writer, accurate
|
|
175
176
|
// numeric expires_at from refresh.
|
|
176
177
|
export function _loadOwnTokens() {
|
|
178
|
+
if (modelProxyClientMode()) return null;
|
|
177
179
|
const path = getOwnTokenPath();
|
|
178
180
|
if (!existsSync(path)) return null;
|
|
179
181
|
try {
|
|
@@ -375,6 +377,7 @@ async function _postRefreshWithRetry(tokens) {
|
|
|
375
377
|
// single-use. Hold a cross-process lease across the re-read, exchange, and
|
|
376
378
|
// atomic save so only one process can spend a generation.
|
|
377
379
|
export async function refreshTokens(tokens, { force = false } = {}) {
|
|
380
|
+
if (modelProxyClientMode()) throw serverModelCredentialsDisabledError('Grok OAuth credentials');
|
|
378
381
|
if (!tokens?.refresh_token) {
|
|
379
382
|
throw new Error('[grok-oauth] refresh token not available — open /providers in mixdog to sign in again');
|
|
380
383
|
}
|
|
@@ -79,7 +79,13 @@ function resolveLatestGeminiModel() {
|
|
|
79
79
|
export async function ensureLatestGeminiModel(provider) {
|
|
80
80
|
let model = resolveLatestGeminiModel();
|
|
81
81
|
if (model) return model;
|
|
82
|
-
|
|
82
|
+
try {
|
|
83
|
+
await provider._refreshModelCache();
|
|
84
|
+
} catch (err) {
|
|
85
|
+
throw new Error(`[gemini] model catalog refresh failed — cannot resolve default model (${err.message})`, {
|
|
86
|
+
cause: err,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
83
89
|
model = resolveLatestGeminiModel();
|
|
84
90
|
if (model) return model;
|
|
85
91
|
throw new Error('[gemini] model catalog unavailable after warmup — cannot resolve default model');
|
|
@@ -6,6 +6,7 @@ import { scrubOAuthSecrets } from './lib/oauth-token-utils.mjs';
|
|
|
6
6
|
import { PROVIDER_MAX_BEFORE_WARN_MS, STALL_ABORT_S, STALL_TICK_MS } from '../stall-policy.mjs';
|
|
7
7
|
import { PACKAGE_VERSION } from '../../../web-search/lib/package-version.mjs';
|
|
8
8
|
import { DEFAULT_MODEL } from './mimo-oauth-tokens.mjs';
|
|
9
|
+
import { MIMO_SEED_MODELS, mimoSeedRow as seedRow } from '../../../shared/llm/provider-seed-rosters.mjs';
|
|
9
10
|
|
|
10
11
|
const MIMO_EFFORT_LEVELS = Object.freeze(['minimal', 'low', 'medium', 'high']);
|
|
11
12
|
const MIMO_DEFAULT_TEMPERATURE = 1.0;
|
|
@@ -15,25 +16,12 @@ const MIMO_DEFAULT_MAX_OUTPUT_TOKENS = 128_000;
|
|
|
15
16
|
export const MIMO_FIRST_BYTE_TIMEOUT_MS = Math.min(300_000, PROVIDER_MAX_BEFORE_WARN_MS);
|
|
16
17
|
export const MIMO_SEMANTIC_IDLE_TIMEOUT_MS = Math.min(480_000, Math.max(10_000, STALL_ABORT_S * 1000 - STALL_TICK_MS));
|
|
17
18
|
|
|
18
|
-
// Local roster used when /models fails or comes back empty.
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
export const SEED_MODELS = Object.freeze(
|
|
22
|
-
[
|
|
23
|
-
['mimo-v2.6-pro', 'MiMo-V2.6-Pro', SEED_CONTEXT],
|
|
24
|
-
['mimo-v2.6-flash', 'MiMo-V2.6-Flash', SEED_CONTEXT],
|
|
25
|
-
['mimo-v2.6-pro-ultraspeed', 'MiMo-V2.6-Pro-Ultraspeed', SEED_CONTEXT],
|
|
26
|
-
['mimo-v2.5-pro', 'MiMo-V2.5-Pro', SEED_CONTEXT],
|
|
27
|
-
['mimo-v2.5', 'MiMo-V2.5', SEED_CONTEXT],
|
|
28
|
-
['mimo-v2-pro', 'MiMo-V2-Pro', SEED_CONTEXT],
|
|
29
|
-
['mimo-v2-omni', 'MiMo-V2-Omni', 262_144],
|
|
30
|
-
].map(([id, display_name, context_window]) =>
|
|
31
|
-
Object.freeze({ id, display_name, context_window, max_output_tokens: SEED_OUTPUT })
|
|
32
|
-
)
|
|
33
|
-
);
|
|
19
|
+
// Local roster used when /models fails or comes back empty. Its limits are not
|
|
20
|
+
// discovered data: decorateModelRows applies them only where nothing fetched did.
|
|
21
|
+
export const SEED_MODELS = MIMO_SEED_MODELS;
|
|
34
22
|
|
|
35
23
|
export function seedModelItems() {
|
|
36
|
-
return SEED_MODELS.map((
|
|
24
|
+
return SEED_MODELS.map(({ id, display_name }) => ({ id, display_name }));
|
|
37
25
|
}
|
|
38
26
|
|
|
39
27
|
// Speech/transcription ids cannot serve a text chat turn.
|
|
@@ -50,28 +38,8 @@ export function chooseDefaultModel(ids) {
|
|
|
50
38
|
return chat[0] || DEFAULT_MODEL;
|
|
51
39
|
}
|
|
52
40
|
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
function seedRow(model) {
|
|
56
|
-
const id = String(model || '').toLowerCase();
|
|
57
|
-
let seed = SEED_MODELS.find((item) => item.id === id) || null;
|
|
58
|
-
if (!seed) {
|
|
59
|
-
for (const item of SEED_MODELS) {
|
|
60
|
-
if (id.startsWith(`${item.id}-`) && (!seed || item.id.length > seed.id.length)) seed = item;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
if (!seed) return null;
|
|
64
|
-
return {
|
|
65
|
-
id: String(model),
|
|
66
|
-
contextWindow: seed.context_window,
|
|
67
|
-
outputTokens: seed.max_output_tokens,
|
|
68
|
-
reasoning: true,
|
|
69
|
-
vision: true,
|
|
70
|
-
inputModalities: ['text', 'image'],
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Fill the gaps a /models row leaves (names, limits, effort levels).
|
|
41
|
+
// Fill the gaps a /models row leaves (names, limits, effort levels); seeds
|
|
42
|
+
// never replace a value the row already carries.
|
|
75
43
|
export function decorateModelRows(rows, items) {
|
|
76
44
|
const display = new Map();
|
|
77
45
|
for (const item of items || []) {
|
|
@@ -89,7 +57,7 @@ export function decorateModelRows(rows, items) {
|
|
|
89
57
|
...(seed && row.reasoning === undefined ? { reasoning: seed.reasoning } : {}),
|
|
90
58
|
...(seed && row.vision === undefined ? { vision: seed.vision } : {}),
|
|
91
59
|
...(seed && row.inputModalities === undefined ? { inputModalities: seed.inputModalities } : {}),
|
|
92
|
-
reasoningLevels: [...MIMO_EFFORT_LEVELS],
|
|
60
|
+
reasoningLevels: row.reasoningLevels?.length ? row.reasoningLevels : [...MIMO_EFFORT_LEVELS],
|
|
93
61
|
reasoningContentField: 'reasoning_content',
|
|
94
62
|
};
|
|
95
63
|
});
|
|
@@ -8,6 +8,7 @@ import { getPluginData } from '../config.mjs';
|
|
|
8
8
|
import { writeJsonAtomicSync } from '../../../shared/atomic-file.mjs';
|
|
9
9
|
import { boundProviderAuthPath } from '../../../shared/provider-auth-binding.mjs';
|
|
10
10
|
import { accountIdentityFields, fileMtimeMs, scrubOAuthSecrets } from './lib/oauth-token-utils.mjs';
|
|
11
|
+
import { modelProxyClientMode } from '../../../shared/model-proxy-mode.mjs';
|
|
11
12
|
|
|
12
13
|
const DEFAULT_PLATFORM_ORIGIN = 'https://platform.xiaomimimo.com';
|
|
13
14
|
const DEFAULT_BASE_URL = 'https://api.xiaomimimo.com/v1';
|
|
@@ -98,6 +99,7 @@ export function getKeyName() {
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
export function loadTokens() {
|
|
102
|
+
if (modelProxyClientMode()) return null;
|
|
101
103
|
const path = getOwnTokenPath();
|
|
102
104
|
if (!existsSync(path)) return null;
|
|
103
105
|
try {
|
|
@@ -10,6 +10,7 @@ import { noteErrorUsage } from './lib/note-error-usage.mjs';
|
|
|
10
10
|
import { fileMtimeMs, scrubOAuthSecrets } from './lib/oauth-token-utils.mjs';
|
|
11
11
|
import { OpenAICompatProvider, preloadOpenAICompatRuntime } from './openai-compat.mjs';
|
|
12
12
|
import { fetchCompatModelItems, listCompatModels } from './openai-compat-models.mjs';
|
|
13
|
+
import { makeModelCache } from './model-cache.mjs';
|
|
13
14
|
import {
|
|
14
15
|
SOURCE_HEADER,
|
|
15
16
|
ensureTokenPlanBaseUrl,
|
|
@@ -29,6 +30,23 @@ import {
|
|
|
29
30
|
|
|
30
31
|
const isUnauthorized = (err) => Number(err?.httpStatus || err?.status) === 401;
|
|
31
32
|
|
|
33
|
+
// The discovered roster (what /models returned, never seed values) is
|
|
34
|
+
// persisted so the shared sync lookup sees what listModels found.
|
|
35
|
+
const mimoModelCache = makeModelCache({ fileName: 'mimo-oauth-models.json', ttlMs: 24 * 60 * 60 * 1000, version: 1 });
|
|
36
|
+
|
|
37
|
+
function rosterRow(item) {
|
|
38
|
+
const contextWindow = Number(item.context_window ?? item.max_context_window ?? item.context_length ?? 0);
|
|
39
|
+
const outputTokens = Number(item.max_output_tokens ?? item.output_tokens ?? 0);
|
|
40
|
+
const name = typeof item.display_name === 'string' ? item.display_name.trim() : '';
|
|
41
|
+
return {
|
|
42
|
+
id: item.id,
|
|
43
|
+
provider: 'mimo-oauth',
|
|
44
|
+
...(name ? { name } : {}),
|
|
45
|
+
...(contextWindow > 0 ? { contextWindow } : {}),
|
|
46
|
+
...(outputTokens > 0 ? { outputTokens } : {}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
32
50
|
// Strip the key from an error (message plus any echoed gateway body).
|
|
33
51
|
function scrubErrorSecrets(err, apiKey) {
|
|
34
52
|
if (!err || typeof err !== 'object' || !apiKey) return err;
|
|
@@ -101,6 +119,7 @@ export class MimoOAuthProvider {
|
|
|
101
119
|
_inner = null;
|
|
102
120
|
_innerKey = null;
|
|
103
121
|
_rosterItems = [];
|
|
122
|
+
_rosterSeq = 0;
|
|
104
123
|
_defaultModelKey = null;
|
|
105
124
|
_defaultModel = null;
|
|
106
125
|
|
|
@@ -143,7 +162,7 @@ export class MimoOAuthProvider {
|
|
|
143
162
|
clientOptions: { organization: null, project: null },
|
|
144
163
|
extraHeaders: { ...SOURCE_HEADER, Accept: 'application/json' },
|
|
145
164
|
});
|
|
146
|
-
inner._fetchModelItems = (args) => this._fetchRoster(inner, args);
|
|
165
|
+
inner._fetchModelItems = async (args) => (await this._fetchRoster(inner, args)).items;
|
|
147
166
|
redactClientErrors(inner.client, apiKey);
|
|
148
167
|
this._inner = inner;
|
|
149
168
|
this._innerKey = key;
|
|
@@ -153,15 +172,28 @@ export class MimoOAuthProvider {
|
|
|
153
172
|
// Chat models from /models; a failed or empty listing falls back to the local
|
|
154
173
|
// seed roster. Only a rejected key is surfaced.
|
|
155
174
|
async _fetchRoster(inner, args) {
|
|
175
|
+
// Only the latest request, fetched with the still-active key, publishes.
|
|
176
|
+
const apiKey = inner.apiKey;
|
|
177
|
+
const seq = ++this._rosterSeq;
|
|
178
|
+
const publish = mimoModelCache.beginSave(() => loadTokens()?.apiKey === apiKey);
|
|
156
179
|
let items = [];
|
|
157
180
|
try {
|
|
158
181
|
items = (await fetchCompatModelItems(inner, args)).filter((item) => isChatModelId(item?.id));
|
|
159
182
|
} catch (err) {
|
|
160
183
|
if (isUnauthorized(err)) throw err;
|
|
161
184
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
185
|
+
// `published` is false when disk kept a newer roster; the seed fallback
|
|
186
|
+
// publishes nothing. `_listRows` revalidates `seq` and the key before
|
|
187
|
+
// touching shared state, since enrichment runs after this returns.
|
|
188
|
+
let published = true;
|
|
189
|
+
if (items.length) published = publish(items.map(rosterRow));
|
|
190
|
+
else items = seedModelItems();
|
|
191
|
+
return { items, published, seq, apiKey };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Still the latest request, fetched with the still-active key.
|
|
195
|
+
_isCurrentRoster({ published, seq, apiKey }) {
|
|
196
|
+
return published && seq === this._rosterSeq && loadTokens()?.apiKey === apiKey;
|
|
165
197
|
}
|
|
166
198
|
|
|
167
199
|
// Shared send/list error shaping, also applied to credential setup failures.
|
|
@@ -180,19 +212,26 @@ export class MimoOAuthProvider {
|
|
|
180
212
|
// Configured model wins; otherwise pick from this credential's own roster.
|
|
181
213
|
async _pickDefaultModel(inner) {
|
|
182
214
|
if (this._defaultModel && this._defaultModelKey === this._innerKey) return this._defaultModel;
|
|
183
|
-
await this._listRows(inner);
|
|
184
|
-
this._defaultModel = chooseDefaultModel(
|
|
215
|
+
const rows = await this._listRows(inner);
|
|
216
|
+
this._defaultModel = chooseDefaultModel(rows.map((row) => row.id));
|
|
185
217
|
this._defaultModelKey = this._innerKey;
|
|
186
218
|
return this._defaultModel;
|
|
187
219
|
}
|
|
188
220
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
221
|
+
// The request keeps its own items and rows; only a request that is still
|
|
222
|
+
// current publishes them to the shared in-memory roster and metadata.
|
|
193
223
|
async _listRows(inner) {
|
|
194
|
-
|
|
195
|
-
|
|
224
|
+
let fetched = null;
|
|
225
|
+
const request = Object.create(inner);
|
|
226
|
+
request._fetchModelItems = async (args) => {
|
|
227
|
+
fetched = await this._fetchRoster(inner, args);
|
|
228
|
+
return fetched.items;
|
|
229
|
+
};
|
|
230
|
+
const rows = decorateModelRows(await listCompatModels(request, { throwOnError: true }), fetched.items);
|
|
231
|
+
if (this._isCurrentRoster(fetched)) {
|
|
232
|
+
this._rosterItems = fetched.items;
|
|
233
|
+
inner._enrichedModels = rows;
|
|
234
|
+
}
|
|
196
235
|
return rows;
|
|
197
236
|
}
|
|
198
237
|
|