mixdog 1.3.1 → 1.3.2
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 -4
- package/package.json +2 -2
- package/scripts/native-release-status.mjs +238 -0
- package/src/defaults/shipped-history.json +5 -1
- package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
- package/src/defaults/skills/setup/SKILL.md +23 -1
- package/src/defaults/skills/setup/references/actions.md +50 -3
- package/src/defaults/skills/setup/references/surfaces.md +23 -3
- package/src/defaults/skills/setup-guide/SKILL.md +7 -3
- package/src/defaults/skills/visualize/SKILL.md +9 -6
- package/src/defaults/skills/visualize/references/craft.md +8 -1
- package/src/help.mjs +1 -1
- package/src/lib/keychain-cjs.cjs +4 -1
- package/src/lib/rules-builder.cjs +14 -7
- package/src/rules/agent-mode/AGENT_MODE.md +8 -5
- package/src/rules/agent-mode/MIXY.md +6 -8
- package/src/rules/lead/LEAD.md +2 -2
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/20-research.md +2 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
- package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
- package/src/runtime/agent/orchestrator/config.mjs +11 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
- package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +80 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +67 -38
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
- package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
- package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
- package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
- package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +12 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +17 -2
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +133 -38
- package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +14 -11
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +68 -18
- package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
- package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +230 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +136 -32
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +21 -9
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +189 -105
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +38 -5
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +99 -0
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +3 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +42 -10
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +120 -9
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +8 -3
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +36 -1
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +35 -13
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +6 -14
- package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +34 -21
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
- package/src/runtime/attachments/attachment-reference.mjs +155 -0
- package/src/runtime/attachments/limits.mjs +5 -1
- package/src/runtime/attachments/office-extract.mjs +3 -6
- package/src/runtime/attachments/pdf-extract.mjs +84 -10
- package/src/runtime/attachments/store.mjs +49 -30
- package/src/runtime/browser-bridge/client.mjs +73 -20
- package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
- package/src/runtime/channels/lib/scheduler.mjs +14 -7
- package/src/runtime/channels/lib/state-file.mjs +15 -15
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
- package/src/runtime/channels/lib/worker-main.mjs +3 -2
- package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
- package/src/runtime/effort-judge/judge-client.mjs +5 -2
- package/src/runtime/effort-judge/model-install.mjs +16 -8
- package/src/runtime/local-provider/asset-installer.mjs +10 -4
- package/src/runtime/local-provider/catalog.mjs +5 -2
- package/src/runtime/local-provider/registered-models.mjs +64 -27
- package/src/runtime/local-provider/server.mjs +2 -3
- package/src/runtime/media/adapters/image-api.mjs +89 -0
- package/src/runtime/media/auth.mjs +64 -1
- package/src/runtime/media/catalog.mjs +66 -4
- package/src/runtime/media/jobs.mjs +4 -0
- package/src/runtime/media/lanes.mjs +46 -5
- package/src/runtime/media/media-usage.mjs +17 -0
- package/src/runtime/media/renditions.mjs +15 -15
- package/src/runtime/media/store.mjs +36 -35
- package/src/runtime/media/tool.mjs +8 -1
- package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
- package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
- package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
- package/src/runtime/memory/lib/pg/process.mjs +8 -4
- package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
- package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
- package/src/runtime/office/core/journal.mjs +7 -14
- package/src/runtime/office/design/library/design-library-core.mjs +4 -16
- package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
- package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
- package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
- package/src/runtime/office/pdf/pdf-render.mjs +30 -18
- package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
- package/src/runtime/office/portable/portable-soffice.mjs +4 -0
- package/src/runtime/shared/agent-kind-migration.mjs +200 -0
- package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
- package/src/runtime/shared/agent-message-envelope.mjs +44 -0
- package/src/runtime/shared/agent-reap-state.d.mts +4 -0
- package/src/runtime/shared/agent-store.mjs +24 -7
- package/src/runtime/shared/agent-task-starts.mjs +27 -0
- package/src/runtime/shared/atomic-file.d.mts +50 -0
- package/src/runtime/shared/atomic-file.mjs +394 -132
- package/src/runtime/shared/background-tasks.mjs +7 -4
- package/src/runtime/shared/bot-hops.mjs +30 -0
- package/src/runtime/shared/bot-split-migration.mjs +1 -1
- package/src/runtime/shared/bounded-download.mjs +4 -2
- package/src/runtime/shared/config.mjs +39 -9
- package/src/runtime/shared/defaults-separation.mjs +6 -2
- package/src/runtime/shared/delegated-approval-host.mjs +74 -0
- package/src/runtime/shared/err-text.mjs +4 -0
- package/src/runtime/shared/error-presentation.mjs +22 -4
- package/src/runtime/shared/file-has-data.mjs +28 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
- package/src/runtime/shared/pending-agent-work.mjs +54 -0
- package/src/runtime/shared/process-lifecycle.mjs +8 -12
- package/src/runtime/shared/projects.mjs +50 -41
- package/src/runtime/shared/provider-accounts.mjs +17 -12
- package/src/runtime/shared/routine-trigger.d.mts +6 -1
- package/src/runtime/shared/routine-trigger.mjs +14 -6
- package/src/runtime/shared/run-child.d.mts +3 -0
- package/src/runtime/shared/run-child.mjs +24 -3
- package/src/runtime/shared/session-baseline-store.mjs +8 -2
- package/src/runtime/shared/singleton-owner.mjs +7 -6
- package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
- package/src/runtime/shared/staged-update.mjs +4 -2
- package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
- package/src/runtime/shared/tool-execution-contract.mjs +6 -0
- package/src/runtime/shared/transcript-metadata.mjs +28 -3
- package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
- package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
- package/src/runtime/shared/turn-snapshot.mjs +44 -2
- package/src/runtime/shared/user-cwd.mjs +9 -4
- package/src/runtime/shared/user-data-guard.mjs +41 -42
- package/src/runtime/shared/utf8-cut.mjs +10 -0
- package/src/runtime/shared/worktrees/activity-gate.mjs +269 -61
- package/src/runtime/shared/worktrees/registry.mjs +26 -26
- package/src/runtime/tidy/core-install.mjs +26 -4
- package/src/runtime/tidy/install.mjs +91 -23
- package/src/runtime/web-search/lib/config.mjs +4 -16
- package/src/session-runtime/agent-home-delivery.mjs +555 -199
- package/src/session-runtime/agent-room-delivery.mjs +143 -36
- package/src/session-runtime/agent-task-sessions.mjs +667 -165
- package/src/session-runtime/agent-tool-routing.mjs +1 -0
- package/src/session-runtime/boot/apis.mjs +45 -24
- package/src/session-runtime/boot/config.mjs +1 -0
- package/src/session-runtime/boot/facade.mjs +11 -1
- package/src/session-runtime/boot/infrastructure.mjs +14 -2
- package/src/session-runtime/boot/providers.mjs +2 -2
- package/src/session-runtime/boot/shared.mjs +12 -6
- package/src/session-runtime/boot/tools.mjs +2 -2
- package/src/session-runtime/bot-status.mjs +432 -0
- package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
- package/src/session-runtime/config-lifecycle.mjs +60 -55
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
- package/src/session-runtime/held-requests.mjs +36 -33
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +19 -4
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
- package/src/session-runtime/lifecycle/teardown.mjs +11 -3
- package/src/session-runtime/mcp-glue/connect.mjs +100 -186
- package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
- package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
- package/src/session-runtime/media-api.mjs +5 -2
- package/src/session-runtime/model-route/route-tuning.mjs +4 -1
- package/src/session-runtime/model-route/set-route.mjs +61 -1
- package/src/session-runtime/owned-automation-run.mjs +8 -1
- package/src/session-runtime/room-member-gate.mjs +16 -3
- package/src/session-runtime/route-resolution.mjs +16 -8
- package/src/session-runtime/route-state.mjs +1 -59
- package/src/session-runtime/routine-home-turn.mjs +5 -3
- package/src/session-runtime/runtime-bootstrap.mjs +5 -3
- package/src/session-runtime/runtime-paths.mjs +11 -5
- package/src/session-runtime/runtime-tunables.mjs +6 -0
- package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
- package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
- package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
- package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
- package/src/session-runtime/services/agent-tool.mjs +6 -0
- package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
- package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
- package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
- package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
- package/src/session-runtime/services/plugin-admin.mjs +26 -26
- package/src/session-runtime/services/provider-admin.mjs +14 -4
- package/src/session-runtime/services/schedule-access.mjs +33 -4
- package/src/session-runtime/services/seeds.mjs +4 -3
- package/src/session-runtime/services/usage-dashboard.mjs +1 -1
- package/src/session-runtime/services/usage-stats-model.mjs +2 -1
- package/src/session-runtime/session-create/materialize.mjs +2 -3
- package/src/session-runtime/session-create/session-options.mjs +15 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +63 -1
- package/src/session-runtime/settings-compaction-api.mjs +86 -39
- package/src/session-runtime/setup-tool/executor.mjs +8 -2
- package/src/session-runtime/setup-tool/settings-contract.mjs +31 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
- package/src/session-runtime/skills-api.mjs +12 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +265 -0
- package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
- package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
- package/src/session-runtime/tool-policy/policy-stage.mjs +165 -0
- package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
- package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
- package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
- package/src/session-runtime/tool-policy-refresh.mjs +47 -369
- package/src/session-runtime/tool-surface.mjs +5 -3
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +2 -1
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +519 -333
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +46 -46
- package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
- package/src/session-runtime/workspace/workspace-state.mjs +7 -6
- package/src/standalone/daemon-agent-control.mjs +4 -1
- package/src/standalone/daemon-session-control.mjs +51 -10
- package/src/standalone/daemon.mjs +28 -10
- package/src/standalone/local-session-runtime.mjs +22 -14
- package/src/standalone/session-client.mjs +7 -2
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-service.mjs +11 -0
- package/src/standalone/session-state-projection.mjs +19 -9
- package/src/standalone/session-tool-output.mjs +35 -9
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
- package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
- package/src/tui/app/slash-commands.mjs +1 -1
- package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
- package/src/tui/dist/index.mjs +529 -333
- package/src/tui/prompt-history-store.mjs +16 -21
- package/src/tui/session/context-state.mjs +4 -0
- package/src/tui/session/session-api/intake/abort.mjs +19 -1
- package/src/tui/session/session-api/media.mjs +2 -1
- package/src/tui/session/session-api/routes-agent-definitions.mjs +75 -0
- package/src/tui/session/session-api/routes-write.mjs +203 -0
- package/src/tui/session/session-api/routes.mjs +23 -247
- package/src/tui/session/session-api/settings.mjs +14 -1
- package/src/tui/session/session-flow/drain.mjs +28 -3
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
- package/src/tui/session/session-flow/steering.mjs +8 -3
- package/src/tui/session/tool-approval.mjs +185 -20
- package/src/tui/session/transcript-intake.mjs +2 -0
- package/src/tui/session/turn.mjs +23 -14
- package/src/tui/transcript-tool-failures.mjs +8 -2
- package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
- package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
- package/src/rules/agent-mode/ROUTINE.md +0 -6
|
@@ -40,8 +40,10 @@ import {
|
|
|
40
40
|
textContent,
|
|
41
41
|
} from './cursor-wire-request.mjs';
|
|
42
42
|
import { handleExecMessage, heartbeatFrame, sendToolResult } from './cursor-wire-exec.mjs';
|
|
43
|
+
import { releaseCursorNativeCall } from './cursor-native-context.mjs';
|
|
43
44
|
import { completionChunk, createStreamSink } from './cursor-wire-stream-sink.mjs';
|
|
44
45
|
import { createBridgeController } from './cursor-wire-stream-bridge.mjs';
|
|
46
|
+
import { markProviderRecoveryExhausted } from './retry-classifier.mjs';
|
|
45
47
|
import { TRANSPORT_SCOPE_DISPOSED } from './transport-scope.mjs';
|
|
46
48
|
|
|
47
49
|
export { clearModelCache, getCursorModels, getCursorUsage } from './cursor-wire-models.mjs';
|
|
@@ -70,16 +72,22 @@ function storeActiveRun(key, active) {
|
|
|
70
72
|
activeRuns.set(key, active);
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
// interval, and close the Cursor bridge it was holding open.
|
|
75
|
-
function closeActiveRun(key, active, error) {
|
|
76
|
-
if (!forgetActiveRun(key, active)) return false;
|
|
75
|
+
function disposeActiveRun(active, error) {
|
|
77
76
|
clearInterval(active.heartbeat);
|
|
77
|
+
for (const pending of active.pending) releaseCursorNativeCall(pending);
|
|
78
|
+
active.pending = [];
|
|
78
79
|
try {
|
|
79
80
|
active.bridge.close(error);
|
|
80
81
|
} catch {
|
|
81
82
|
/* already closing */
|
|
82
83
|
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Tear down one stored run: drop it from the registry, stop its 5s heartbeat
|
|
87
|
+
// interval, and close the Cursor bridge it was holding open.
|
|
88
|
+
function closeActiveRun(key, active, error) {
|
|
89
|
+
if (!forgetActiveRun(key, active)) return false;
|
|
90
|
+
disposeActiveRun(active, error);
|
|
83
91
|
return true;
|
|
84
92
|
}
|
|
85
93
|
|
|
@@ -458,6 +466,25 @@ function resumeRun(active, toolResults, userText, model, key) {
|
|
|
458
466
|
}
|
|
459
467
|
sendToolResult(active.bridge, pending, payload, result.isError !== true);
|
|
460
468
|
}
|
|
469
|
+
// Every pending call was already handed to the executor. Re-emitting the
|
|
470
|
+
// same batch without accepting a result makes the transcript rename its
|
|
471
|
+
// ids, breaks native authorization, and can loop without another model call.
|
|
472
|
+
// Partial progress is valid; an unchanged pending batch is a terminal
|
|
473
|
+
// handoff failure, not a transport retry or an invitation to execute again.
|
|
474
|
+
if (remaining.length > 0 && remaining.length === active.pending.length) {
|
|
475
|
+
const error = markProviderRecoveryExhausted(
|
|
476
|
+
cursorError(
|
|
477
|
+
`Cursor tool-result handoff made no progress: ${remaining.length} pending call(s) received no matching result. Stopped to avoid repeating tool execution.`,
|
|
478
|
+
{ status: 400, code: 'tool_result_no_progress' }
|
|
479
|
+
),
|
|
480
|
+
{ owner: 'cursor-wire', terminal: true }
|
|
481
|
+
);
|
|
482
|
+
// handleChatCompletion already detached this run; direct partial-batch
|
|
483
|
+
// resumes may still own its registry entry and expiry timer.
|
|
484
|
+
forgetActiveRun(key, active);
|
|
485
|
+
disposeActiveRun(active, error);
|
|
486
|
+
throw error;
|
|
487
|
+
}
|
|
461
488
|
active.pending = remaining;
|
|
462
489
|
active.pendingUserText = userTextDelivered ? '' : pendingUserText;
|
|
463
490
|
if (remaining.length > 0) {
|
|
@@ -35,7 +35,10 @@ async function loadCursorRuntime() {
|
|
|
35
35
|
function toCursorMessages(messages, providerName, { nativePdf } = {}) {
|
|
36
36
|
const output = [];
|
|
37
37
|
for (const message of messages || []) {
|
|
38
|
-
|
|
38
|
+
// This is a local envelope over Cursor's execution protocol, not an
|
|
39
|
+
// OpenAI request. Its pending executions and native capabilities require
|
|
40
|
+
// the exact original id, including ids longer than OpenAI's 40-char cap.
|
|
41
|
+
const converted = toOpenAIMessages([message], providerName, { nativePdf, preserveToolCallIds: true });
|
|
39
42
|
if (message?.role !== 'tool') {
|
|
40
43
|
output.push(...converted);
|
|
41
44
|
continue;
|
|
@@ -40,6 +40,7 @@ function sanitizeDiscoveryError(error, apiKey) {
|
|
|
40
40
|
if (apiKey) message = message.split(apiKey).join('[redacted]');
|
|
41
41
|
const out = new Error(message);
|
|
42
42
|
if (Number.isInteger(error?.status)) out.status = error.status;
|
|
43
|
+
if (error?.code === 'EPROVIDERTIMEOUT' || error?.name === 'TimeoutError') out.code = 'EPROVIDERTIMEOUT';
|
|
43
44
|
return out;
|
|
44
45
|
}
|
|
45
46
|
|
|
@@ -82,11 +83,13 @@ function withCustomModels(Base, discover) {
|
|
|
82
83
|
const first = rows.find((row) => !row.hidden);
|
|
83
84
|
if (first) this.defaultModel = first.id;
|
|
84
85
|
}
|
|
85
|
-
|
|
86
|
+
// `timeoutMs` lets an interactive caller wait longer than the default
|
|
87
|
+
// catalog timeout (slow gateways); the runtime refresh keeps the default.
|
|
88
|
+
async listModels({ signal = null, throwOnError = false, timeoutMs } = {}) {
|
|
86
89
|
let failure = null;
|
|
87
90
|
try {
|
|
88
91
|
this._assertCustomKey();
|
|
89
|
-
this._customDiscovered = await discover(this, signal);
|
|
92
|
+
this._customDiscovered = await discover(this, signal, timeoutMs);
|
|
90
93
|
this.customDiscoveryError = null;
|
|
91
94
|
} catch (error) {
|
|
92
95
|
if (signal?.aborted) throw error;
|
|
@@ -109,8 +112,8 @@ function withCustomModels(Base, discover) {
|
|
|
109
112
|
};
|
|
110
113
|
}
|
|
111
114
|
|
|
112
|
-
async function discoverAnthropicModels(provider, signal) {
|
|
113
|
-
const timeout = AbortSignal.timeout(
|
|
115
|
+
async function discoverAnthropicModels(provider, signal, timeoutMs = DISCOVERY_TIMEOUT_MS) {
|
|
116
|
+
const timeout = AbortSignal.timeout(timeoutMs);
|
|
114
117
|
const res = await fetch(`${provider.config.baseURL}/v1/models`, {
|
|
115
118
|
method: 'GET',
|
|
116
119
|
signal: signal ? AbortSignal.any([signal, timeout]) : timeout,
|
|
@@ -182,8 +185,8 @@ export async function createCustomProvider(id, config) {
|
|
|
182
185
|
}
|
|
183
186
|
class CompatBase extends OpenAICompatProvider {
|
|
184
187
|
messagesEngine = messagesEngine;
|
|
185
|
-
_fetchModelItems({ signal = null } = {}) {
|
|
186
|
-
return fetchCompatModelItems(this, { signal, keyless: this._customKeyless });
|
|
188
|
+
_fetchModelItems({ signal = null, timeoutMs } = {}) {
|
|
189
|
+
return fetchCompatModelItems(this, { signal, timeoutMs, keyless: this._customKeyless });
|
|
187
190
|
}
|
|
188
191
|
resolveWireRoute(model, ctx = {}) {
|
|
189
192
|
return resolveWireRoute(this.name, model, { ...ctx, override: cfg.modelWires?.[model] ?? null });
|
|
@@ -203,8 +206,8 @@ export async function createCustomProvider(id, config) {
|
|
|
203
206
|
});
|
|
204
207
|
}
|
|
205
208
|
}
|
|
206
|
-
const Custom = withCustomModels(CompatBase, (self, signal) =>
|
|
207
|
-
listCompatModels(self, { throwOnError: true, signal })
|
|
209
|
+
const Custom = withCustomModels(CompatBase, (self, signal, timeoutMs) =>
|
|
210
|
+
listCompatModels(self, { throwOnError: true, signal, timeoutMs })
|
|
208
211
|
);
|
|
209
212
|
provider = new Custom(providerId, engine);
|
|
210
213
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Diagnostic per-block prefix fingerprint of an Anthropic request: the tools,
|
|
2
|
+
// each system block (BP1/BP2/BP3/env, the routing prefix included) and the
|
|
3
|
+
// cache_control marker positions, as short hashes only — never any text, so
|
|
4
|
+
// it is safe in shipped builds. The last two requests per session are kept in
|
|
5
|
+
// memory so a usage-detected cache miss (session/loop/send-phase.mjs) can say
|
|
6
|
+
// which block or marker moved.
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
|
|
9
|
+
const HASH_CHARS = 12;
|
|
10
|
+
const MAX_SESSIONS = 256;
|
|
11
|
+
const bySession = new Map();
|
|
12
|
+
|
|
13
|
+
const hash = (value) =>
|
|
14
|
+
createHash('sha256')
|
|
15
|
+
.update(JSON.stringify(value ?? null))
|
|
16
|
+
.digest('hex')
|
|
17
|
+
.slice(0, HASH_CHARS);
|
|
18
|
+
|
|
19
|
+
const withoutMarker = (block) => {
|
|
20
|
+
if (!block || typeof block !== 'object') return block;
|
|
21
|
+
const { cache_control: _marker, ...rest } = block;
|
|
22
|
+
return rest;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const markerTtl = (marker) => (marker?.ttl ? String(marker.ttl) : '5m');
|
|
26
|
+
|
|
27
|
+
/** `{ tools, system: [hash…], markers: ['s1:1h', 'm12:5m', …] }` of a request body. */
|
|
28
|
+
export function anthropicPrefixFingerprint(body) {
|
|
29
|
+
const system = Array.isArray(body?.system) ? body.system : [];
|
|
30
|
+
const messages = Array.isArray(body?.messages) ? body.messages : [];
|
|
31
|
+
const markers = [];
|
|
32
|
+
system.forEach((block, index) => {
|
|
33
|
+
if (block?.cache_control) markers.push(`s${index}:${markerTtl(block.cache_control)}`);
|
|
34
|
+
});
|
|
35
|
+
messages.forEach((message, index) => {
|
|
36
|
+
const content = Array.isArray(message?.content) ? message.content : [];
|
|
37
|
+
const marked = content.find((block) => block?.cache_control);
|
|
38
|
+
if (marked) markers.push(`m${index}:${markerTtl(marked.cache_control)}`);
|
|
39
|
+
});
|
|
40
|
+
return { tools: hash(body?.tools || []), system: system.map((block) => hash(withoutMarker(block))), markers };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Keep `fingerprint` as the session's latest request (the one before it stays as previous). */
|
|
44
|
+
export function recordAnthropicPrefix(sessionId, fingerprint) {
|
|
45
|
+
if (!sessionId || !fingerprint) return;
|
|
46
|
+
const key = String(sessionId);
|
|
47
|
+
const previous = bySession.get(key)?.current || null;
|
|
48
|
+
bySession.delete(key);
|
|
49
|
+
bySession.set(key, { previous, current: fingerprint });
|
|
50
|
+
if (bySession.size > MAX_SESSIONS) bySession.delete(bySession.keys().next().value);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The session's latest fingerprint, or null. */
|
|
54
|
+
export function latestAnthropicPrefix(sessionId) {
|
|
55
|
+
return bySession.get(String(sessionId || ''))?.current || null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** `{ changedBlocks: 'tools,s3' | 'none', markersChanged }` between the session's
|
|
59
|
+
* last two requests, or null before it has two. */
|
|
60
|
+
export function anthropicPrefixChanges(sessionId) {
|
|
61
|
+
const entry = bySession.get(String(sessionId || ''));
|
|
62
|
+
if (!entry?.previous) return null;
|
|
63
|
+
const { previous, current } = entry;
|
|
64
|
+
const changed = [];
|
|
65
|
+
if (previous.tools !== current.tools) changed.push('tools');
|
|
66
|
+
const blocks = Math.max(previous.system.length, current.system.length);
|
|
67
|
+
for (let index = 0; index < blocks; index += 1) {
|
|
68
|
+
if (previous.system[index] !== current.system[index]) changed.push(`s${index}`);
|
|
69
|
+
}
|
|
70
|
+
// Message markers move every turn; only the system markers are a layout change.
|
|
71
|
+
const systemMarkers = (print) => print.markers.filter((marker) => marker.startsWith('s')).join(',');
|
|
72
|
+
return {
|
|
73
|
+
changedBlocks: changed.length ? changed.join(',') : 'none',
|
|
74
|
+
markersChanged: systemMarkers(previous) !== systemMarkers(current),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -82,6 +82,22 @@ function appendAnthropicCacheControl(content, ttl = ANTHROPIC_CACHE_TTL_VOLATILE
|
|
|
82
82
|
return next;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
// The builders lift the tail reminder off (splitTailReminder) before lowering and
|
|
86
|
+
// cache marking, then append it here as the final text block, so the message
|
|
87
|
+
// breakpoint stays on the block before it and the cached prefix is unchanged.
|
|
88
|
+
export function appendAnthropicTailReminder(anthropicMessages, reminder) {
|
|
89
|
+
if (!reminder) return anthropicMessages;
|
|
90
|
+
const block = { type: 'text', text: reminder };
|
|
91
|
+
const last = anthropicMessages[anthropicMessages.length - 1];
|
|
92
|
+
if (last?.role === 'user') {
|
|
93
|
+
const content = typeof last.content === 'string' ? [{ type: 'text', text: last.content }] : last.content || [];
|
|
94
|
+
last.content = [...content, block];
|
|
95
|
+
} else {
|
|
96
|
+
anthropicMessages.push({ role: 'user', content: [block] });
|
|
97
|
+
}
|
|
98
|
+
return anthropicMessages;
|
|
99
|
+
}
|
|
100
|
+
|
|
85
101
|
export function resolveAnthropicCacheTtls(opts) {
|
|
86
102
|
const strategy = opts?.cacheStrategy || {};
|
|
87
103
|
const pick = (layer, fallback) => {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// The tail reminder (session/tail-reminder-rules.mjs) rides the outgoing request
|
|
2
|
+
// as its last message, marked meta.source 'tail-reminder'. It is ephemeral: a
|
|
3
|
+
// provider builder that keeps per-message state (cache breakpoints, message
|
|
4
|
+
// counts, continuation indexes, tool-loop closure) lifts it off first with
|
|
5
|
+
// splitTailReminder, builds from the real history, and appends the reminder as
|
|
6
|
+
// the final wire element, so the history-derived prefix never contains it.
|
|
7
|
+
export const TAIL_REMINDER_META = 'tail-reminder';
|
|
8
|
+
|
|
9
|
+
export function splitTailReminder(messages) {
|
|
10
|
+
const last = Array.isArray(messages) ? messages[messages.length - 1] : null;
|
|
11
|
+
if (last?.role !== 'user' || last.meta?.source !== TAIL_REMINDER_META) return { messages, reminder: '' };
|
|
12
|
+
return { messages: messages.slice(0, -1), reminder: String(last.content || '') };
|
|
13
|
+
}
|
|
@@ -652,9 +652,17 @@ export function contentImageDescriptors(content) {
|
|
|
652
652
|
// one-line description.
|
|
653
653
|
// The page count (recorded by intake and by the read tool) rides on the part
|
|
654
654
|
// itself, so an inline part and its stored reference carry the same one.
|
|
655
|
+
// The text-layer character count (recorded with it) prices the text a native
|
|
656
|
+
// reader extracts on top of each page image.
|
|
655
657
|
function pdfDescriptor(sizeBytes, part) {
|
|
656
658
|
const pageCount = Math.floor(Number(part?.pageCount));
|
|
657
|
-
|
|
659
|
+
const textChars = Number(part?.textChars);
|
|
660
|
+
return {
|
|
661
|
+
mimeType: 'application/pdf',
|
|
662
|
+
sizeBytes,
|
|
663
|
+
...(pageCount > 0 ? { pageCount } : {}),
|
|
664
|
+
...(pageCount > 0 && Number.isFinite(textChars) && textChars >= 0 ? { textChars: Math.floor(textChars) } : {}),
|
|
665
|
+
};
|
|
658
666
|
}
|
|
659
667
|
|
|
660
668
|
export function contentFileDescriptors(content) {
|
|
@@ -974,6 +982,13 @@ function normalizeAnthropicPart(part) {
|
|
|
974
982
|
if (part?.type === 'text' && isAttachmentReference(part)) {
|
|
975
983
|
return { type: 'text', text: attachmentTextForPart(part) };
|
|
976
984
|
}
|
|
985
|
+
// A media reference (attachment-reference.mjs) is a text part whose
|
|
986
|
+
// `attachmentReference` metadata stays in saved history. It is not a
|
|
987
|
+
// Messages API text-block field, and the API rejects the whole request for it.
|
|
988
|
+
if (part?.type === 'text' && part.attachmentReference !== undefined) {
|
|
989
|
+
const { attachmentReference: _internal, ...wirePart } = part;
|
|
990
|
+
return wirePart;
|
|
991
|
+
}
|
|
977
992
|
return part;
|
|
978
993
|
}
|
|
979
994
|
|
|
@@ -13,8 +13,10 @@ import { beginLocalInference, localModelState } from '../../../local-provider/mo
|
|
|
13
13
|
|
|
14
14
|
export class MixdogLocalProvider {
|
|
15
15
|
static inputExcludesCache = false;
|
|
16
|
-
// The managed local runtime is text-only: PDFs lower to text
|
|
16
|
+
// The managed local runtime is text-only: PDFs lower to text and images to
|
|
17
|
+
// a placeholder (input-capabilities.mjs).
|
|
17
18
|
nativePdf = false;
|
|
19
|
+
takesImages = false;
|
|
18
20
|
|
|
19
21
|
constructor(config = {}, { ensureServer = ensureLocalProviderServer, runRequest = runLocalProviderRequest } = {}) {
|
|
20
22
|
this.name = 'mixdog-local';
|
|
@@ -111,6 +111,7 @@ export class ModelProxyProvider {
|
|
|
111
111
|
// Adapter traits are reported by the PC's real instance.
|
|
112
112
|
if (typeof this.config.modelProxy?.nativePdf === 'boolean') this.nativePdf = this.config.modelProxy.nativePdf;
|
|
113
113
|
if (this.config.modelProxy?.consumesReadWindows === true) this.consumesReadWindows = true;
|
|
114
|
+
if (this.config.modelProxy?.takesImages === false) this.takesImages = false;
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
#call(method, fields = {}, options = {}) {
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
// handshake-header projection, and the per-turn x-codex-turn-state guard.
|
|
4
4
|
// openai-oauth-ws.mjs owns the transport flow only.
|
|
5
5
|
import { createHash, randomUUID } from 'node:crypto';
|
|
6
|
-
import { existsSync, mkdirSync, readFileSync
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
7
7
|
import { join } from 'node:path';
|
|
8
|
+
import { writeFileAtomicSync } from '../../../shared/atomic-file.mjs';
|
|
8
9
|
import { cleanString } from '../../../shared/clean.mjs';
|
|
9
10
|
import { getPluginData } from '../config.mjs';
|
|
10
11
|
import { activateCodexTurnState } from './openai-turn-state.mjs';
|
|
@@ -77,15 +78,14 @@ function _codexInstallationId(sendOpts) {
|
|
|
77
78
|
const generated = randomUUID();
|
|
78
79
|
try {
|
|
79
80
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
} catch {
|
|
81
|
+
// Atomic create-if-absent; a damaged (empty/NUL) file is replaced whole.
|
|
82
|
+
if (!writeFileAtomicSync(file, generated, { createOnly: true, mode: 0o644 })) {
|
|
83
83
|
const winner = readFileSync(file, 'utf8').trim().toLowerCase();
|
|
84
84
|
if (UUID_RE.test(winner)) {
|
|
85
85
|
_installationId = winner;
|
|
86
86
|
return _installationId;
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
writeFileAtomicSync(file, generated, { mode: 0o644 });
|
|
89
89
|
}
|
|
90
90
|
} catch {}
|
|
91
91
|
_installationId = generated;
|
|
@@ -94,10 +94,14 @@ async function compatModelsError(name, res, apiKey = '') {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
// `keyless` omits the Authorization header entirely (keyless endpoints);
|
|
97
|
-
// `signal` aborts the request together with the list timeout
|
|
98
|
-
|
|
97
|
+
// `signal` aborts the request together with the list timeout; `timeoutMs`
|
|
98
|
+
// replaces the default list timeout for callers that wait on a slow catalog.
|
|
99
|
+
export async function fetchCompatModelItems(
|
|
100
|
+
provider,
|
|
101
|
+
{ signal = null, keyless = false, timeoutMs = MODEL_LIST_TIMEOUT_MS } = {}
|
|
102
|
+
) {
|
|
99
103
|
const name = provider.name;
|
|
100
|
-
const timeout = createTimeoutSignal(signal,
|
|
104
|
+
const timeout = createTimeoutSignal(signal, timeoutMs, `${name} model list`);
|
|
101
105
|
try {
|
|
102
106
|
const apiKey = keyless ? '' : resolveProviderApiKey(name, provider.config || provider);
|
|
103
107
|
const res = await fetch(`${String(provider.baseURL || '').replace(/\/+$/, '')}/models`, {
|
|
@@ -137,9 +141,9 @@ function nativeMode(m) {
|
|
|
137
141
|
return null;
|
|
138
142
|
}
|
|
139
143
|
|
|
140
|
-
export async function listCompatModels(provider, { throwOnError = false, signal = null } = {}) {
|
|
144
|
+
export async function listCompatModels(provider, { throwOnError = false, signal = null, timeoutMs } = {}) {
|
|
141
145
|
try {
|
|
142
|
-
const list = await provider._fetchModelItems({ signal });
|
|
146
|
+
const list = await provider._fetchModelItems({ signal, timeoutMs });
|
|
143
147
|
const models = [];
|
|
144
148
|
for (const m of list) {
|
|
145
149
|
const contextWindow = Number(
|
|
@@ -29,6 +29,7 @@ import { isCustomProviderName, resolveCustomReasoning } from './custom-reasoning
|
|
|
29
29
|
import { projectEffortConfiguration, withEffortConfigurationFallback } from './effort-configuration.mjs';
|
|
30
30
|
import { normalizeCacheKey } from '../agent-runtime/cache-strategy.mjs';
|
|
31
31
|
import { createProviderReplay } from './lib/provider-replay.mjs';
|
|
32
|
+
import { splitTailReminder } from './lib/tail-reminder-split.mjs';
|
|
32
33
|
import {
|
|
33
34
|
applyCompatToolChoice,
|
|
34
35
|
compatResponsesReplayProvider,
|
|
@@ -296,7 +297,13 @@ export function sendCompatResponses(provider, messages, useModel, tools, opts =
|
|
|
296
297
|
return withEffortConfigurationFallback(provider.name, useModel, opts, send);
|
|
297
298
|
}
|
|
298
299
|
|
|
299
|
-
async function sendCompatResponsesOnce(provider,
|
|
300
|
+
async function sendCompatResponsesOnce(provider, requestMessages, useModel, tools, opts) {
|
|
301
|
+
// The continuation state below is indexed by transcript position
|
|
302
|
+
// (seenMessageCount, reasoning messageIndex): the ephemeral tail reminder is
|
|
303
|
+
// not part of the transcript, so it is lifted off here and appended to the
|
|
304
|
+
// wire input last.
|
|
305
|
+
const { messages: transcript, reminder } = splitTailReminder(requestMessages);
|
|
306
|
+
let messages = transcript;
|
|
300
307
|
const replayProvider = compatResponsesReplayProvider(provider.name);
|
|
301
308
|
const signal = opts.signal || null;
|
|
302
309
|
if (signal?.aborted) {
|
|
@@ -320,6 +327,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
|
|
|
320
327
|
includeSystem: provider.config?.responsesSystemAsInstructions !== true,
|
|
321
328
|
});
|
|
322
329
|
const instructions = provider.config?.responsesSystemAsInstructions === true ? xaiSystemInstructions(messages) : '';
|
|
330
|
+
if (reminder) input.push({ role: 'user', content: [{ type: 'input_text', text: reminder }] });
|
|
323
331
|
const params = buildCompatResponsesParams({
|
|
324
332
|
provider,
|
|
325
333
|
useModel,
|
|
@@ -40,7 +40,8 @@ export function resolveCompatMaxOutputTokens(opts = {}) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export function toOpenAIMessages(transcript, providerName, options = {}) {
|
|
43
|
-
const messages =
|
|
43
|
+
const messages =
|
|
44
|
+
options.preserveToolCallIds === true ? transcript : withWireToolCallIds(transcript, OPENAI_CHAT_TOOL_CALL_IDS);
|
|
44
45
|
// NOTE: chat.completions has no equivalent slot for replaying reasoning
|
|
45
46
|
// encrypted_content the way the Responses API does (no `type:'reasoning'`
|
|
46
47
|
// input item). Whatever reasoningItems may be attached to assistant
|
|
@@ -41,7 +41,25 @@ function promptCacheForm(model) {
|
|
|
41
41
|
return openAiSupportsExtendedRetention(model) ? 'retention' : null;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
// The environment developer item buildRequestBody places first in `input`:
|
|
45
|
+
// the end of the session's stable prefix (tools + instructions + environment).
|
|
46
|
+
// Top-level `instructions` cannot carry a breakpoint, so this is the earliest
|
|
47
|
+
// place one fits.
|
|
48
|
+
function stablePrefixBlock(body) {
|
|
49
|
+
const first = Array.isArray(body.input) ? body.input[0] : null;
|
|
50
|
+
const content = first?.type === 'message' && first.role === 'developer' ? first.content : null;
|
|
51
|
+
const block = Array.isArray(content) && content.length === 1 ? content[0] : null;
|
|
52
|
+
return block?.type === 'input_text' && String(block.text || '').startsWith('<environment_context>') ? block : null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Public-API cache lifetime fields. GPT-5.6+: request ttl "30m" for the
|
|
57
|
+
* moving tail; `prefixTtl` '12h' (Lead class, cache-strategy.mjs
|
|
58
|
+
* resolveOpenAiPrefixCacheTtl) adds one explicit 12h breakpoint at the end of
|
|
59
|
+
* the stable prefix in the default implicit mode, so the implicit tail
|
|
60
|
+
* breakpoint stays 30m. Earlier models are unchanged.
|
|
61
|
+
*/
|
|
62
|
+
export function applyOpenAIDirectCachePolicy(body, model, storeResponses, { prefixTtl = null } = {}) {
|
|
45
63
|
body.store = storeResponses;
|
|
46
64
|
delete body.prompt_cache_retention;
|
|
47
65
|
delete body.prompt_cache_options;
|
|
@@ -49,7 +67,16 @@ export function applyOpenAIDirectCachePolicy(body, model, storeResponses) {
|
|
|
49
67
|
// response storage is disabled. The provider's default cache still applies.
|
|
50
68
|
if (!storeResponses) return body;
|
|
51
69
|
const form = promptCacheForm(model);
|
|
52
|
-
if (form === 'options')
|
|
53
|
-
|
|
70
|
+
if (form === 'options') {
|
|
71
|
+
body.prompt_cache_options = { ttl: '30m' };
|
|
72
|
+
const block = prefixTtl === '12h' ? stablePrefixBlock(body) : null;
|
|
73
|
+
if (block) {
|
|
74
|
+
const [first, ...rest] = body.input;
|
|
75
|
+
body.input = [
|
|
76
|
+
{ ...first, content: [{ ...block, prompt_cache_breakpoint: { mode: 'explicit', ttl: '12h' } }] },
|
|
77
|
+
...rest,
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
} else if (form === 'retention') body.prompt_cache_retention = '24h';
|
|
54
81
|
return body;
|
|
55
82
|
}
|
|
@@ -25,7 +25,7 @@ export function openAiCatalogMeta(model) {
|
|
|
25
25
|
// gpt-5.4 -> [5, 4]; gpt-6-astra -> [6, 0]; non-GPT ids -> null.
|
|
26
26
|
// A bare multi-digit major with no minor or family suffix (gpt-60) is not a
|
|
27
27
|
// generation id.
|
|
28
|
-
function gptVersion(id) {
|
|
28
|
+
export function gptVersion(id) {
|
|
29
29
|
const m = /^gpt-(\d+)(?:\.(\d+))?(?=-|$)/.exec(id);
|
|
30
30
|
if (!m || (m[1].length > 1 && m[2] === undefined && m[0] === id)) return null;
|
|
31
31
|
return [Number(m[1]), Number(m[2] || 0)];
|
|
@@ -142,7 +142,9 @@ export class OpenAIDirectProvider {
|
|
|
142
142
|
// Keep public response storage and model-specific cache options out of
|
|
143
143
|
// the shared OAuth payload. Storage opt-out still forces full frames in
|
|
144
144
|
// _computeDelta; retained output items make those frames self-contained.
|
|
145
|
-
applyOpenAIDirectCachePolicy(body, useModel, _envFlag('MIXDOG_OAI_STORE', true)
|
|
145
|
+
applyOpenAIDirectCachePolicy(body, useModel, _envFlag('MIXDOG_OAI_STORE', true), {
|
|
146
|
+
prefixTtl: opts.promptCachePrefixTtl || null,
|
|
147
|
+
});
|
|
146
148
|
// poolKey MUST be sessionId-only. Falling back to promptCacheKey would
|
|
147
149
|
// let unrelated raw sessions sharing the same provider-scoped cache
|
|
148
150
|
// bucket reuse each other's pooled socket and inherit lastResponseId
|
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
* The organization's remote config (`/api/v2/config` → providers.opencode-go)
|
|
5
5
|
* is the authority for the inference base URL, the request headers and the
|
|
6
6
|
* model catalog (the gateway's own `/models` is not served on this base).
|
|
7
|
+
* When that config lists no models at all (the console serves `models: {}` for
|
|
8
|
+
* an organization without overrides, as the OpenCode CLI sees it), the catalog
|
|
9
|
+
* is the models.dev `opencode-go` provider, the list the CLI itself shows.
|
|
7
10
|
* Requests run on the OpenCode Go gateway engines (opencode-go.mjs) with the
|
|
8
11
|
* access token as the bearer; a 401 refreshes the token once and retries.
|
|
9
12
|
*/
|
|
10
13
|
import { scrubOAuthSecrets } from './lib/oauth-token-utils.mjs';
|
|
11
|
-
import { getModelMetadataSync } from './model-catalog.mjs';
|
|
14
|
+
import { getModelMetadataSync, getModelsDevProviderModelsSync, loadModelsDevCatalog } from './model-catalog.mjs';
|
|
12
15
|
import { makeModelCache } from './model-cache.mjs';
|
|
13
16
|
import { OpenCodeGoProvider, WIRE_API_BY_NPM, resolveOpenCodeGoWireRoute } from './opencode-go.mjs';
|
|
14
17
|
import { fetchOpenCodeGoOAuthUsageSnapshot } from './opencode-go-usage.mjs';
|
|
@@ -90,11 +93,51 @@ function catalogRow(id, model, providerPackage) {
|
|
|
90
93
|
};
|
|
91
94
|
}
|
|
92
95
|
|
|
96
|
+
// A models.dev row in the remote config's model shape, for catalogRow.
|
|
97
|
+
function configModelFromModelsDev(row) {
|
|
98
|
+
const cost = isPlainObject(row.cost) ? row.cost : null;
|
|
99
|
+
const effort = Array.isArray(row.reasoning_options)
|
|
100
|
+
? row.reasoning_options.find((option) => option?.type === 'effort')?.values
|
|
101
|
+
: null;
|
|
102
|
+
return {
|
|
103
|
+
name: row.name,
|
|
104
|
+
...(typeof row.npm === 'string' ? { package: row.npm } : {}),
|
|
105
|
+
limit: row.limit,
|
|
106
|
+
...(cost
|
|
107
|
+
? { cost: { input: cost.input, output: cost.output, cache: { read: cost.cache_read, write: cost.cache_write } } }
|
|
108
|
+
: {}),
|
|
109
|
+
...(typeof row.reasoning === 'boolean'
|
|
110
|
+
? { capabilities: { reasoning: { supported: row.reasoning, ...(effort ? { effort } : {}) } } }
|
|
111
|
+
: {}),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// models.dev serves the Go models over the OpenAI-compatible package unless a row names its own.
|
|
116
|
+
const MODELS_DEV_PROVIDER_PACKAGE = '@ai-sdk/openai-compatible';
|
|
117
|
+
|
|
118
|
+
const listsGoModels = (json) => Object.keys(json?.providers?.[CONFIG_PROVIDER_KEY]?.models || {}).length > 0;
|
|
119
|
+
|
|
120
|
+
// The models.dev Go catalog, loaded first because the sync read is null on a cold cache.
|
|
121
|
+
// The loader swallows its own failure, so a missing catalog is a failed discovery
|
|
122
|
+
// (the last published roster stays), never an authoritative empty roster.
|
|
123
|
+
async function loadModelsDevGoModels() {
|
|
124
|
+
await loadModelsDevCatalog();
|
|
125
|
+
const models = getModelsDevProviderModelsSync(CONFIG_PROVIDER_KEY);
|
|
126
|
+
if (!models || Object.keys(models).length === 0) {
|
|
127
|
+
throw openCodeGoError(
|
|
128
|
+
`[${PROVIDER_ID}] the OpenCode organization config lists no models and the models.dev OpenCode Go catalog is unavailable`,
|
|
129
|
+
{ kind: 'catalog' }
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
return models;
|
|
133
|
+
}
|
|
134
|
+
|
|
93
135
|
/**
|
|
94
136
|
* The Go provider of a remote config response: `{ baseURL, headers, models }`
|
|
95
|
-
* with one catalog row per enabled model.
|
|
137
|
+
* with one catalog row per enabled model. A config that lists no models takes
|
|
138
|
+
* the models.dev Go models (`modelsDevModels`, id → row) instead.
|
|
96
139
|
*/
|
|
97
|
-
export function goConfigFromResponse(json) {
|
|
140
|
+
export function goConfigFromResponse(json, modelsDevModels = null) {
|
|
98
141
|
const entry = json?.providers?.[CONFIG_PROVIDER_KEY];
|
|
99
142
|
if (!isPlainObject(entry)) {
|
|
100
143
|
throw openCodeGoError(`[${PROVIDER_ID}] the OpenCode organization config has no OpenCode Go provider`, {
|
|
@@ -102,9 +145,20 @@ export function goConfigFromResponse(json) {
|
|
|
102
145
|
});
|
|
103
146
|
}
|
|
104
147
|
const providerPackage = typeof entry.package === 'string' ? entry.package : '';
|
|
105
|
-
const
|
|
148
|
+
const fallback = !listsGoModels(json) && isPlainObject(modelsDevModels);
|
|
149
|
+
const source = fallback
|
|
150
|
+
? Object.fromEntries(
|
|
151
|
+
Object.entries(modelsDevModels).map(([id, row]) => [
|
|
152
|
+
id,
|
|
153
|
+
isPlainObject(row) ? configModelFromModelsDev(row) : row,
|
|
154
|
+
])
|
|
155
|
+
)
|
|
156
|
+
: isPlainObject(entry.models)
|
|
157
|
+
? entry.models
|
|
158
|
+
: {};
|
|
159
|
+
const models = Object.entries(source)
|
|
106
160
|
.filter(([id, model]) => id && isPlainObject(model) && model.disabled !== true)
|
|
107
|
-
.map(([id, model]) => catalogRow(id, model, providerPackage));
|
|
161
|
+
.map(([id, model]) => catalogRow(id, model, fallback ? MODELS_DEV_PROVIDER_PACKAGE : providerPackage));
|
|
108
162
|
return {
|
|
109
163
|
baseURL:
|
|
110
164
|
typeof entry.settings?.baseURL === 'string' && entry.settings.baseURL
|
|
@@ -172,9 +226,8 @@ export class OpenCodeGoOAuthProvider {
|
|
|
172
226
|
const current = loadTokens();
|
|
173
227
|
return current?.account_id === tokens.account_id && current?.org_id === tokens.org_id;
|
|
174
228
|
});
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
);
|
|
229
|
+
const response = await consoleGetJson(CONFIG_URL, tokens, { fetchFn: this.config.fetchImpl, refresh: true });
|
|
230
|
+
const remote = goConfigFromResponse(response, listsGoModels(response) ? null : await loadModelsDevGoModels());
|
|
178
231
|
publish(remote.models, {
|
|
179
232
|
baseURL: remote.baseURL,
|
|
180
233
|
headers: remote.headers,
|
|
@@ -509,6 +509,15 @@ export function providerInputExcludesCache(name) {
|
|
|
509
509
|
export function providerNativePdf(name) {
|
|
510
510
|
return providerTakesNativePdf(providers.get(String(name || '').toLowerCase()));
|
|
511
511
|
}
|
|
512
|
+
/**
|
|
513
|
+
* Whether the named provider sends image input to its models: false only for
|
|
514
|
+
* an adapter that declares `takesImages = false` (the text-only local
|
|
515
|
+
* runtime, which lowers every image to a placeholder). A pure lookup; an
|
|
516
|
+
* unknown provider is treated as taking images, as attachments are.
|
|
517
|
+
*/
|
|
518
|
+
export function providerReadsImages(name) {
|
|
519
|
+
return providers.get(String(name || '').toLowerCase())?.takesImages !== false;
|
|
520
|
+
}
|
|
512
521
|
/**
|
|
513
522
|
* Whether the named provider's adapter declares `consumesReadWindows`: it
|
|
514
523
|
* needs the structured clip report of read results. A pure lookup; a proxy
|