mixdog 1.2.3 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/scripts/gate-local.mjs +6 -4
- package/scripts/lib/gate-scheduler.mjs +29 -11
- package/scripts/probe-provider-catalog.mjs +31 -0
- package/scripts/provider-pingpong-live.mjs +128 -38
- package/scripts/session-sweep.mjs +5 -25
- package/src/agents/maintainer/AGENT.md +1 -1
- package/src/agents/maintainer/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +2 -4
- package/src/agents/security/AGENT.md +1 -2
- package/src/agents/writer/AGENT.md +2 -3
- package/src/defaults/shipped-history.json +6 -1
- package/src/defaults/skills/image/SKILL.md +21 -23
- package/src/lib/keychain-cjs.cjs +13 -11
- package/src/rules/agent/AGENT.md +7 -5
- package/src/rules/lead/LEAD.md +7 -9
- package/src/rules/shared/45-destructive.md +4 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
- package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
- package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
- package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
- package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
- package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
- package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
- package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
- package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
- package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
- package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
- package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
- package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
- package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
- package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +136 -196
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
- package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
- package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
- package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
- package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
- package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
- package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
- package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
- package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
- package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
- package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
- package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
- package/src/runtime/attachments/store.d.mts +9 -0
- package/src/runtime/attachments/store.mjs +80 -9
- package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
- package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
- package/src/runtime/computer-bridge/action-schema.mjs +178 -178
- package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
- package/src/runtime/effort-judge/judge-client.mjs +21 -4
- package/src/runtime/effort-judge/judge-worker.mjs +4 -1
- package/src/runtime/github/tool.mjs +118 -17
- package/src/runtime/media/adapters/codex-image.mjs +140 -21
- package/src/runtime/media/catalog.mjs +4 -4
- package/src/runtime/media/chatgpt-usage.mjs +55 -0
- package/src/runtime/media/defaults.mjs +37 -0
- package/src/runtime/media/jobs.mjs +12 -2
- package/src/runtime/media/lanes.mjs +12 -0
- package/src/runtime/media/tool-defs.mjs +15 -4
- package/src/runtime/media/tool.mjs +41 -12
- package/src/runtime/media/upstream-error.mjs +72 -6
- package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
- package/src/runtime/memory/lib/pg/process.mjs +5 -7
- package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
- package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
- package/src/runtime/office/authoring/html-browser.mjs +18 -8
- package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
- package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
- package/src/runtime/office/core/office-write-ledger.mjs +1 -5
- package/src/runtime/office/index.mjs +2 -3
- package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
- package/src/runtime/session-search/session-search-ingest.mjs +1 -1
- package/src/runtime/shared/agent-reap-state.mjs +13 -0
- package/src/runtime/shared/atomic-file.d.mts +1 -1
- package/src/runtime/shared/background-tasks.mjs +6 -1
- package/src/runtime/shared/bounded-line-diff.mjs +11 -2
- package/src/runtime/shared/browser-launch.mjs +15 -0
- package/src/runtime/shared/err-text.mjs +42 -4
- package/src/runtime/shared/file-lock.mjs +6 -5
- package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
- package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
- package/src/runtime/shared/model-route-chain.d.mts +8 -0
- package/src/runtime/shared/model-route-chain.mjs +48 -0
- package/src/runtime/shared/model-route-fallback.mjs +22 -0
- package/src/runtime/shared/pid-liveness.mjs +12 -0
- package/src/runtime/shared/provider-api-key.mjs +6 -0
- package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
- package/src/runtime/shared/quiet-progress.d.mts +35 -0
- package/src/runtime/shared/quiet-progress.mjs +101 -0
- package/src/runtime/shared/quota-resume-store.mjs +32 -1
- package/src/runtime/shared/read-row-numbers.mjs +44 -0
- package/src/runtime/shared/remote-intent.mjs +2 -42
- package/src/runtime/shared/slow-span.mjs +8 -1
- package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
- package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
- package/src/runtime/shared/tool-output-budget.mjs +2 -0
- package/src/runtime/shared/tool-result-summary.mjs +16 -2
- package/src/runtime/shared/tool-status.mjs +3 -2
- package/src/runtime/shared/tool-surface.mjs +2 -3
- package/src/runtime/shared/tool-work-units.mjs +22 -15
- package/src/runtime/shared/transcript-metadata.mjs +49 -1
- package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
- package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
- package/src/runtime/shared/transcript-writer.mjs +14 -4
- package/src/runtime/shared/turn-changes.mjs +2 -1
- package/src/runtime/shared/turn-snapshot.mjs +11 -3
- package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
- package/src/runtime/shared/worktrees/carry.mjs +6 -4
- package/src/runtime/shared/worktrees/contract.mjs +27 -1
- package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
- package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
- package/src/runtime/shared/worktrees/git-head.mjs +22 -13
- package/src/runtime/shared/worktrees/include.mjs +125 -7
- package/src/runtime/shared/worktrees/lock.mjs +1 -1
- package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
- package/src/runtime/shared/worktrees/manager.mjs +378 -32
- package/src/runtime/shared/worktrees/owner.mjs +2 -1
- package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
- package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
- package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
- package/src/runtime/terminal-bridge/client.mjs +14 -10
- package/src/session-runtime/boot/apis.mjs +7 -1
- package/src/session-runtime/boot/config.mjs +2 -0
- package/src/session-runtime/boot/facade.mjs +3 -0
- package/src/session-runtime/boot/session.mjs +3 -2
- package/src/session-runtime/boot/tools.mjs +3 -0
- package/src/session-runtime/conversation-import/service.mjs +1 -1
- package/src/session-runtime/goal-facade-api.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
- package/src/session-runtime/internal-tool-executor.mjs +2 -0
- package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
- package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
- package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
- package/src/session-runtime/lifecycle/shared.mjs +5 -6
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
- package/src/session-runtime/lifecycle/teardown.mjs +7 -16
- package/src/session-runtime/media-api.mjs +8 -0
- package/src/session-runtime/model-route/route-ownership.mjs +60 -0
- package/src/session-runtime/model-route/route-persist.mjs +3 -2
- package/src/session-runtime/model-route/set-route.mjs +114 -34
- package/src/session-runtime/model-route/web-search-route.mjs +7 -2
- package/src/session-runtime/model-route-api.mjs +4 -2
- package/src/session-runtime/native-web-search/routes.mjs +37 -24
- package/src/session-runtime/native-web-search.mjs +9 -8
- package/src/session-runtime/provider-auth/setup.mjs +4 -0
- package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
- package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
- package/src/session-runtime/provider-models.mjs +1 -0
- package/src/session-runtime/provider-usage.mjs +4 -0
- package/src/session-runtime/route-resolution.mjs +3 -1
- package/src/session-runtime/runtime-core.mjs +4 -0
- package/src/session-runtime/runtime-facade.mjs +6 -0
- package/src/session-runtime/services/agent-task-status.mjs +2 -0
- package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
- package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
- package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
- package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
- package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
- package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
- package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
- package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
- package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
- package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
- package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
- package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
- package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
- package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
- package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
- package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
- package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
- package/src/session-runtime/services/agent-tool.mjs +4 -0
- package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
- package/src/session-runtime/services/provider-admin.mjs +77 -0
- package/src/session-runtime/session-create/session-options.mjs +7 -5
- package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
- package/src/session-runtime/session-transcript.mjs +4 -5
- package/src/session-runtime/session-turn-api.mjs +3 -9
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
- package/src/session-runtime/setup-tool/executor.mjs +23 -5
- package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
- package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
- package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
- package/src/session-runtime/tool-policy-refresh.mjs +83 -32
- package/src/session-runtime/turn/agent-ops.mjs +49 -2
- package/src/session-runtime/turn/side-question-ops.mjs +1 -4
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
- package/src/session-runtime/turn/turn-run.mjs +1 -36
- package/src/session-runtime/usage-stats-api.mjs +4 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
- package/src/session-runtime/workspace/admission-gate.mjs +44 -15
- package/src/session-runtime/workspace/project-branches.mjs +28 -36
- package/src/session-runtime/workspace/transition-steps.mjs +96 -95
- package/src/session-runtime/workspace/transitions.mjs +248 -68
- package/src/standalone/channel-transport.mjs +3 -4
- package/src/standalone/daemon-desktop-runtime.mjs +32 -1
- package/src/standalone/daemon-pg-stop.mjs +1 -3
- package/src/standalone/daemon-session-control.mjs +88 -0
- package/src/standalone/daemon-stored-session-views.mjs +23 -3
- package/src/standalone/daemon.mjs +2 -0
- package/src/standalone/local-session-runtime.mjs +11 -12
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-runtime-inline-host.mjs +2 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
- package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
- package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
- package/src/standalone/session-service/agent-tree.mjs +28 -2
- package/src/standalone/session-service/entries/session-loads.mjs +16 -5
- package/src/standalone/session-service/entries.mjs +1 -0
- package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
- package/src/standalone/session-service/quota-resume.mjs +28 -13
- package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
- package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
- package/src/standalone/session-tool-output.mjs +82 -0
- package/src/tui/app/app-view.jsx +2 -1
- package/src/tui/app/provider-setup/provider-items.mjs +8 -0
- package/src/tui/app/provider-setup-picker.mjs +15 -3
- package/src/tui/app/slash-commands.mjs +6 -0
- package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
- package/src/tui/components/Spinner.jsx +4 -0
- package/src/tui/components/SpinnerByline.jsx +21 -2
- package/src/tui/components/status-line/local-line.mjs +10 -2
- package/src/tui/dist/index.mjs +478 -251
- package/src/tui/session/active-tool-summary.mjs +1 -1
- package/src/tui/session/context-state.mjs +0 -3
- package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
- package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
- package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
- package/src/tui/session/quota-resume.mjs +140 -61
- package/src/tui/session/session-api/commands.mjs +4 -10
- package/src/tui/session/session-api/controls.mjs +12 -0
- package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
- package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
- package/src/tui/session/session-api/lifecycle.mjs +13 -11
- package/src/tui/session/session-api/media.mjs +2 -0
- package/src/tui/session/session-api/routes.mjs +81 -57
- package/src/tui/session/session-api/settings.mjs +3 -3
- package/src/tui/session/session-api/worktree.mjs +3 -2
- package/src/tui/session/session-flow/auto-clear.mjs +1 -3
- package/src/tui/session/session-flow/drain.mjs +6 -4
- package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
- package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
- package/src/tui/session/session-flow/queue.mjs +1 -1
- package/src/tui/session/tool-approval.mjs +17 -8
- package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
- package/src/tui/session/tui-steering-persist.mjs +3 -5
- package/src/tui/session/turn-quiet.mjs +53 -0
- package/src/tui/session/turn-stream.mjs +5 -1
- package/src/tui/session/turn.mjs +38 -31
- package/src/tui/session/worktree-setup-notice.mjs +38 -0
- package/src/tui/spinner-meta.mjs +10 -0
- package/src/tui/spinner-verbs.mjs +3 -0
- package/src/ui/statusline.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
- package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
- package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
- package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
- package/src/session-runtime/turn/share-ops.mjs +0 -77
- package/src/tui/session/cross-surface-share.mjs +0 -406
- package/src/tui/session/live-share/delta.mjs +0 -153
- package/src/tui/session/live-share/mirror.mjs +0 -106
- package/src/tui/session/live-share/owner.mjs +0 -254
- package/src/tui/session/live-share/retry.mjs +0 -54
- package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
- package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
- package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
- package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
- package/src/tui/session/live-share/viewer.mjs +0 -99
- package/src/tui/session/live-share/wire.mjs +0 -44
- package/src/tui/session/live-share.mjs +0 -154
- package/src/tui/session/shared-dir-watch.mjs +0 -69
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ChatGPT OAuth image adapter (`openai-oauth` lane).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Primary path: the subscription's Images endpoints on the Codex backend
|
|
5
|
+
* (`images/generations`, or `images/edits` when reference images are given),
|
|
6
|
+
* a plain JSON request answered with the finished image as base64.
|
|
7
|
+
*
|
|
8
|
+
* Fallback path, used only when those endpoints are not served (404/405/501,
|
|
9
|
+
* or the edge's HTML 403 for an unknown route): the hosted `image_generation`
|
|
10
|
+
* tool on the responses backend. Its final image arrives on the
|
|
11
|
+
* image_generation_call item; a stream that only produced partial preview
|
|
12
|
+
* frames fails instead of saving a draft as the result.
|
|
13
|
+
*
|
|
14
|
+
* Both paths use the chat provider's session, so the subscription login is the
|
|
15
|
+
* only credential involved. Usage-limit failures name the reset time, looked up
|
|
16
|
+
* from the account's usage summary when the failure itself omits it.
|
|
8
17
|
*/
|
|
9
18
|
import { randomBytes } from 'node:crypto';
|
|
10
19
|
import { resolveCodexAuth } from '../auth.mjs';
|
|
11
20
|
import { timeoutSignal } from '../bounded-signal.mjs';
|
|
21
|
+
import { chatgptLimitResetAt } from '../chatgpt-usage.mjs';
|
|
12
22
|
import { decodeBase64Media } from '../download.mjs';
|
|
13
23
|
import { mediaError } from '../lanes.mjs';
|
|
14
|
-
import { upstreamError } from '../upstream-error.mjs';
|
|
24
|
+
import { upstreamError, usageLimitError, usageLimitFromResponse, usageLimitInfo } from '../upstream-error.mjs';
|
|
15
25
|
import { responsesUsage, withReportedUsage } from '../media-usage.mjs';
|
|
16
26
|
import { CODEX_OAUTH_ORIGINATOR, CODEX_RESPONSES_URL } from '../../agent/orchestrator/providers/openai-oauth.mjs';
|
|
17
27
|
import {
|
|
@@ -21,6 +31,13 @@ import {
|
|
|
21
31
|
} from '../../agent/orchestrator/providers/codex-client-meta.mjs';
|
|
22
32
|
|
|
23
33
|
const REQUEST_TIMEOUT_MS = 400_000;
|
|
34
|
+
const LABEL = 'ChatGPT image';
|
|
35
|
+
export const CODEX_IMAGE_MODEL = 'gpt-image-2';
|
|
36
|
+
export const CODEX_IMAGES_GENERATIONS_URL = new URL('images/generations', CODEX_RESPONSES_URL).href;
|
|
37
|
+
export const CODEX_IMAGES_EDITS_URL = new URL('images/edits', CODEX_RESPONSES_URL).href;
|
|
38
|
+
const BACKGROUNDS = new Set(['transparent', 'opaque', 'auto']);
|
|
39
|
+
|
|
40
|
+
const dataUrl = (ref) => `data:${ref.mime || 'image/png'};base64,${ref.base64}`;
|
|
24
41
|
|
|
25
42
|
function imageTool(options = {}) {
|
|
26
43
|
const tool = { type: 'image_generation' };
|
|
@@ -28,9 +45,91 @@ function imageTool(options = {}) {
|
|
|
28
45
|
if (size && size !== 'auto') tool.size = size;
|
|
29
46
|
const quality = String(options.quality || 'auto');
|
|
30
47
|
if (quality && quality !== 'auto') tool.quality = quality;
|
|
48
|
+
if (options.background && options.background !== 'auto') tool.background = options.background;
|
|
31
49
|
return tool;
|
|
32
50
|
}
|
|
33
51
|
|
|
52
|
+
/** Images endpoint request: generation, or an edit when references are given. */
|
|
53
|
+
export function codexImagesRequest({ prompt, options = {}, references = [] }) {
|
|
54
|
+
const body = { prompt, model: CODEX_IMAGE_MODEL, size: 'auto', quality: 'auto' };
|
|
55
|
+
if (options.background) body.background = options.background;
|
|
56
|
+
if (!references.length) return { url: CODEX_IMAGES_GENERATIONS_URL, body };
|
|
57
|
+
return {
|
|
58
|
+
url: CODEX_IMAGES_EDITS_URL,
|
|
59
|
+
body: { images: references.map((ref) => ({ image_url: dataUrl(ref) })), ...body },
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function codexImagesRequestHeaders(auth) {
|
|
64
|
+
const headers = {
|
|
65
|
+
Authorization: `Bearer ${auth.access_token}`,
|
|
66
|
+
'Content-Type': 'application/json',
|
|
67
|
+
Accept: 'application/json',
|
|
68
|
+
originator: CODEX_OAUTH_ORIGINATOR,
|
|
69
|
+
'x-client-request-id': randomBytes(16).toString('hex'),
|
|
70
|
+
version: codexVersionHeader(),
|
|
71
|
+
'User-Agent': codexUserAgent(),
|
|
72
|
+
};
|
|
73
|
+
if (auth.account_id) headers['ChatGPT-Account-ID'] = auth.account_id;
|
|
74
|
+
return headers;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The endpoint is not served for this backend: a missing route or method, or
|
|
78
|
+
// the edge's HTML 403 page that unknown backend routes answer with. Auth,
|
|
79
|
+
// billing and limit failures come back as JSON and are reported, not retried.
|
|
80
|
+
function imagesEndpointUnavailable(res) {
|
|
81
|
+
if ([404, 405, 501].includes(res.status)) return true;
|
|
82
|
+
return res.status === 403 && !/json/i.test(res.headers.get('content-type') || '');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function imagesUsage(usage) {
|
|
86
|
+
const tokens = responsesUsage(usage);
|
|
87
|
+
const imageTokens = Math.trunc(Number(usage?.output_tokens_details?.image_tokens) || 0);
|
|
88
|
+
return imageTokens > 0 ? { ...tokens, outputImageTokens: imageTokens } : tokens;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function limitError(limit, { auth, fetchFn, lookupReset, signal }) {
|
|
92
|
+
const resetsAt = limit.resetsAt || (await lookupReset({ auth, limitId: limit.limitId, fetchFn, signal }));
|
|
93
|
+
return usageLimitError(LABEL, { limitId: limit.limitId, resetsAt });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function failedResponse(res, ctx) {
|
|
97
|
+
const text = await res.text().catch(() => '');
|
|
98
|
+
const limit = usageLimitFromResponse(res.status, text, res.headers);
|
|
99
|
+
if (limit) return await limitError(limit, ctx);
|
|
100
|
+
return upstreamError(LABEL, res.status, text);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Returns the image, or null when the Images endpoint is unavailable. */
|
|
104
|
+
async function generateViaImagesEndpoint({ prompt, options, references, signal }, ctx) {
|
|
105
|
+
const { url, body } = codexImagesRequest({ prompt, options, references });
|
|
106
|
+
const res = await ctx.fetchFn(url, {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
headers: codexImagesRequestHeaders(ctx.auth),
|
|
109
|
+
body: JSON.stringify(body),
|
|
110
|
+
redirect: 'error',
|
|
111
|
+
signal: timeoutSignal(signal, REQUEST_TIMEOUT_MS),
|
|
112
|
+
});
|
|
113
|
+
if (imagesEndpointUnavailable(res)) {
|
|
114
|
+
await res.body?.cancel().catch(() => {});
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
if (!res.ok) throw await failedResponse(res, ctx);
|
|
118
|
+
const json = await res.json().catch(() => null);
|
|
119
|
+
const usage = imagesUsage(json?.usage);
|
|
120
|
+
const b64 = json?.data?.[0]?.b64_json;
|
|
121
|
+
if (typeof b64 !== 'string' || !b64) {
|
|
122
|
+
throw withReportedUsage(mediaError(`${LABEL}: returned no image data`, 'MEDIA_EMPTY_RESULT', 502), usage);
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
bytes: decodeBase64Media(b64, LABEL),
|
|
126
|
+
mime: 'image/png',
|
|
127
|
+
revisedPrompt: null,
|
|
128
|
+
actualModel: CODEX_IMAGE_MODEL,
|
|
129
|
+
usage: usage || null,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
34
133
|
function collectImage(event, state) {
|
|
35
134
|
const item = event?.item;
|
|
36
135
|
// Terminal Responses events carry the orchestrator's token usage. It does
|
|
@@ -55,10 +154,7 @@ export function codexImageRequestBody({ model, prompt, options = {}, references
|
|
|
55
154
|
// Reference images ride as input_image parts on the user turn — the same
|
|
56
155
|
// shape the chat path uses for pasted images.
|
|
57
156
|
const content = [
|
|
58
|
-
...references.map((ref) => ({
|
|
59
|
-
type: 'input_image',
|
|
60
|
-
image_url: `data:${ref.mime || 'image/png'};base64,${ref.base64}`,
|
|
61
|
-
})),
|
|
157
|
+
...references.map((ref) => ({ type: 'input_image', image_url: dataUrl(ref) })),
|
|
62
158
|
{ type: 'input_text', text: prompt },
|
|
63
159
|
];
|
|
64
160
|
return {
|
|
@@ -91,7 +187,12 @@ export function codexImageRequestHeaders(auth) {
|
|
|
91
187
|
|
|
92
188
|
export async function generateImage(
|
|
93
189
|
{ model, prompt, options = {}, references = [], signal },
|
|
94
|
-
{
|
|
190
|
+
{
|
|
191
|
+
fetchFn = fetch,
|
|
192
|
+
resolveAuth = resolveCodexAuth,
|
|
193
|
+
warmVersion = warmCodexClientVersion,
|
|
194
|
+
lookupReset = chatgptLimitResetAt,
|
|
195
|
+
} = {}
|
|
95
196
|
) {
|
|
96
197
|
if (['size', 'quality', 'resolution', 'aspectRatio'].some((key) => options[key] && options[key] !== 'auto')) {
|
|
97
198
|
throw mediaError(
|
|
@@ -99,19 +200,28 @@ export async function generateImage(
|
|
|
99
200
|
'MEDIA_OPTION_UNSUPPORTED'
|
|
100
201
|
);
|
|
101
202
|
}
|
|
203
|
+
if (options.background && !BACKGROUNDS.has(options.background)) {
|
|
204
|
+
throw mediaError('background must be transparent, opaque or auto.', 'MEDIA_OPTION_UNSUPPORTED');
|
|
205
|
+
}
|
|
102
206
|
const auth = await resolveAuth();
|
|
103
207
|
// Discovery and generation must report the same client version; otherwise
|
|
104
208
|
// a newly discovered model can still be rejected by the Codex version gate.
|
|
105
209
|
await warmVersion();
|
|
210
|
+
const ctx = { auth, fetchFn, lookupReset, signal };
|
|
211
|
+
const image = await generateViaImagesEndpoint({ prompt, options, references, signal }, ctx);
|
|
212
|
+
return image || (await generateViaResponses({ model, prompt, options, references, signal }, ctx));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function generateViaResponses({ model, prompt, options, references, signal }, ctx) {
|
|
106
216
|
const body = codexImageRequestBody({ model, prompt, options, references });
|
|
107
|
-
const res = await fetchFn(CODEX_RESPONSES_URL, {
|
|
217
|
+
const res = await ctx.fetchFn(CODEX_RESPONSES_URL, {
|
|
108
218
|
method: 'POST',
|
|
109
|
-
headers: codexImageRequestHeaders(auth),
|
|
219
|
+
headers: codexImageRequestHeaders(ctx.auth),
|
|
110
220
|
body: JSON.stringify(body),
|
|
111
221
|
redirect: 'error',
|
|
112
222
|
signal: timeoutSignal(signal, REQUEST_TIMEOUT_MS),
|
|
113
223
|
});
|
|
114
|
-
if (!res.ok || !res.body) throw
|
|
224
|
+
if (!res.ok || !res.body) throw await failedResponse(res, ctx);
|
|
115
225
|
|
|
116
226
|
const reader = res.body.getReader();
|
|
117
227
|
const decoder = new TextDecoder();
|
|
@@ -136,7 +246,8 @@ export async function generateImage(
|
|
|
136
246
|
continue;
|
|
137
247
|
}
|
|
138
248
|
if (event?.type === 'response.failed' || event?.type === 'error') {
|
|
139
|
-
|
|
249
|
+
// A top-level `error` event carries code/type/resets_at on itself.
|
|
250
|
+
failure = event?.response?.error || event?.error || event;
|
|
140
251
|
}
|
|
141
252
|
collectImage(event, state);
|
|
142
253
|
}
|
|
@@ -147,15 +258,23 @@ export async function generateImage(
|
|
|
147
258
|
} catch {}
|
|
148
259
|
}
|
|
149
260
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
throw withReportedUsage(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
261
|
+
if (!state.final) {
|
|
262
|
+
const limit = failure && usageLimitInfo(failure, res.headers);
|
|
263
|
+
if (limit) throw withReportedUsage(await limitError(limit, ctx), state.usage);
|
|
264
|
+
const reason = (typeof failure === 'string' ? failure : failure?.message) || 'stream failed';
|
|
265
|
+
// A partial frame is a low-fidelity preview of an unfinished render; it is
|
|
266
|
+
// never saved as the result.
|
|
267
|
+
const error = state.partial
|
|
268
|
+
? mediaError(
|
|
269
|
+
`${LABEL}: generation stopped after a partial preview; no final image was produced${failure ? ` (${reason})` : ''}`,
|
|
270
|
+
'MEDIA_PARTIAL_ONLY',
|
|
271
|
+
502
|
|
272
|
+
)
|
|
273
|
+
: mediaError(`ChatGPT returned no image data${failure ? `: ${reason}` : ''}`, 'MEDIA_EMPTY_RESULT', 502);
|
|
274
|
+
throw withReportedUsage(error, state.usage);
|
|
156
275
|
}
|
|
157
276
|
return {
|
|
158
|
-
bytes: decodeBase64Media(
|
|
277
|
+
bytes: decodeBase64Media(state.final, LABEL),
|
|
159
278
|
mime: 'image/png',
|
|
160
279
|
revisedPrompt: state.revisedPrompt,
|
|
161
280
|
actualModel: state.actualModel || null,
|
|
@@ -145,12 +145,12 @@ export function projectMediaModels(lane, rows) {
|
|
|
145
145
|
result.image = orchestrator
|
|
146
146
|
? [
|
|
147
147
|
{
|
|
148
|
-
id: '
|
|
149
|
-
label: '
|
|
148
|
+
id: 'gpt-image-2',
|
|
149
|
+
label: 'GPT Image 2',
|
|
150
150
|
description:
|
|
151
|
-
'ChatGPT
|
|
151
|
+
'ChatGPT image engine. Output size/quality are chosen by ChatGPT; background can be transparent.',
|
|
152
152
|
requestModel: orchestrator.id,
|
|
153
|
-
controls: { maxReferences: 5 },
|
|
153
|
+
controls: { maxReferences: 5, background: ['auto', 'transparent', 'opaque'] },
|
|
154
154
|
},
|
|
155
155
|
]
|
|
156
156
|
: [];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatGPT subscription usage lookup.
|
|
3
|
+
*
|
|
4
|
+
* A usage-limit failure does not always say when the window reopens. The
|
|
5
|
+
* account's usage summary does: each metered limit lists its windows with
|
|
6
|
+
* `used_percent` and an epoch `reset_at`.
|
|
7
|
+
*/
|
|
8
|
+
import { timeoutSignal } from './bounded-signal.mjs';
|
|
9
|
+
import { codexUserAgent } from '../agent/orchestrator/providers/codex-client-meta.mjs';
|
|
10
|
+
|
|
11
|
+
export const CHATGPT_USAGE_URL = 'https://chatgpt.com/backend-api/wham/usage';
|
|
12
|
+
const LOOKUP_TIMEOUT_MS = 10_000;
|
|
13
|
+
|
|
14
|
+
function exhaustedResetAt(rateLimit) {
|
|
15
|
+
if (!rateLimit || typeof rateLimit !== 'object') return null;
|
|
16
|
+
const windows = [rateLimit.primary_window, rateLimit.secondary_window].filter((w) => Number(w?.reset_at) > 0);
|
|
17
|
+
const full = windows.filter((w) => Number(w.used_percent) >= 100);
|
|
18
|
+
const candidates = full.length ? full : rateLimit.limit_reached ? windows : [];
|
|
19
|
+
return candidates.length ? Math.max(...candidates.map((w) => Math.trunc(Number(w.reset_at)))) : null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Reset time (epoch seconds) of the exhausted limit in a usage summary. The
|
|
24
|
+
* limit named `limitId` wins; an image limit is next; the account's main
|
|
25
|
+
* window is last.
|
|
26
|
+
*/
|
|
27
|
+
export function limitResetFromUsage(payload, limitId = '') {
|
|
28
|
+
const extra = Array.isArray(payload?.additional_rate_limits) ? payload.additional_rate_limits : [];
|
|
29
|
+
const id = String(limitId).toLowerCase();
|
|
30
|
+
const names = (entry) => [entry?.metered_feature, entry?.limit_name].map((name) => String(name || '').toLowerCase());
|
|
31
|
+
const named =
|
|
32
|
+
(id && extra.find((entry) => names(entry).includes(id))) ||
|
|
33
|
+
extra.find((entry) => names(entry).some((name) => name.includes('image')));
|
|
34
|
+
return exhaustedResetAt(named ? named.rate_limit : payload?.rate_limit);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Look the reset time up for the signed-in account. A failed lookup yields
|
|
39
|
+
* null: the caller still reports the limit, just without a time.
|
|
40
|
+
*/
|
|
41
|
+
export async function chatgptLimitResetAt({ auth, limitId = '', fetchFn = fetch, signal } = {}) {
|
|
42
|
+
try {
|
|
43
|
+
const headers = { Authorization: `Bearer ${auth.access_token}`, 'User-Agent': codexUserAgent() };
|
|
44
|
+
if (auth.account_id) headers['ChatGPT-Account-Id'] = auth.account_id;
|
|
45
|
+
const res = await fetchFn(CHATGPT_USAGE_URL, {
|
|
46
|
+
headers,
|
|
47
|
+
redirect: 'error',
|
|
48
|
+
signal: timeoutSignal(signal, LOOKUP_TIMEOUT_MS),
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok) return null;
|
|
51
|
+
return limitResetFromUsage(await res.json(), limitId);
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -41,6 +41,43 @@ export function getMediaDefault(kind) {
|
|
|
41
41
|
return lane ? { kind: key, lane, model: text(row?.model) } : null;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
// Settings → Built-in → Media generation. Unlike the remembered selection above
|
|
45
|
+
// (rewritten by every generation), a pin is only ever written by the user:
|
|
46
|
+
// `{ lane, model, account }` per kind, where an empty model is the lane default
|
|
47
|
+
// and an empty account follows that provider's currently selected account.
|
|
48
|
+
const PINNED = 'pinned';
|
|
49
|
+
|
|
50
|
+
function readPins() {
|
|
51
|
+
const pins = readAll()[PINNED];
|
|
52
|
+
return pins && typeof pins === 'object' && !Array.isArray(pins) ? pins : {};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** `{ kind, lane, model, account }` for the kind, or null when it is on auto. */
|
|
56
|
+
export function getMediaPin(kind) {
|
|
57
|
+
const key = text(kind);
|
|
58
|
+
if (!MEDIA_KINDS.includes(key)) return null;
|
|
59
|
+
const row = readPins()[key];
|
|
60
|
+
const lane = text(row?.lane);
|
|
61
|
+
return lane ? { kind: key, lane, model: text(row?.model), account: text(row?.account) } : null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function getMediaPins() {
|
|
65
|
+
return Object.fromEntries(MEDIA_KINDS.map((kind) => [kind, getMediaPin(kind)]));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Pin one kind to a lane/model/account; an empty `lane` returns it to auto. */
|
|
69
|
+
export function setMediaPin({ kind, lane, model, account } = {}) {
|
|
70
|
+
const key = text(kind);
|
|
71
|
+
if (!MEDIA_KINDS.includes(key)) throw new TypeError(`kind must be one of ${MEDIA_KINDS.join(', ')}`);
|
|
72
|
+
const laneId = text(lane);
|
|
73
|
+
const { [key]: _previous, ...others } = readPins();
|
|
74
|
+
const pins = laneId ? { ...others, [key]: { lane: laneId, model: text(model), account: text(account) } } : others;
|
|
75
|
+
const path = defaultsPath();
|
|
76
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
77
|
+
writeJsonAtomicSync(path, { ...readAll(), [PINNED]: pins });
|
|
78
|
+
return getMediaPin(key);
|
|
79
|
+
}
|
|
80
|
+
|
|
44
81
|
/** Remember the lane (and model) for one kind. `model` may be empty: the lane default then applies. */
|
|
45
82
|
export function setMediaDefault({ kind, lane, model } = {}) {
|
|
46
83
|
const key = text(kind);
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { randomUUID } from 'node:crypto';
|
|
10
10
|
import { MAX_GENERATED_MEDIA_BYTES } from './download.mjs';
|
|
11
|
-
import { mediaError, resolveMediaRequest } from './lanes.mjs';
|
|
11
|
+
import { mediaError, mediaLaneAccountProvider, resolveMediaRequest } from './lanes.mjs';
|
|
12
|
+
import { withProviderAccount } from '../shared/provider-auth-binding.mjs';
|
|
12
13
|
import { saveMediaAsset } from './store.mjs';
|
|
13
14
|
import { setMediaDefault } from './defaults.mjs';
|
|
14
15
|
import { recordMediaUsage } from './media-usage.mjs';
|
|
@@ -77,8 +78,17 @@ async function runAdapter({ lane, kind, model, requestModel, prompt, options, re
|
|
|
77
78
|
/**
|
|
78
79
|
* Validate + start one generation. Returns the initial snapshot immediately;
|
|
79
80
|
* the caller polls getMediaJob for progress and the finished asset id.
|
|
81
|
+
* `account` runs the whole job (catalog check, credentials, adapter) as that
|
|
82
|
+
* connected account of the lane's provider, whatever the chat is using; an
|
|
83
|
+
* account that cannot serve the call fails it, never another account.
|
|
80
84
|
*/
|
|
81
|
-
export async function startMediaJob({
|
|
85
|
+
export async function startMediaJob(input = {}) {
|
|
86
|
+
const account = String(input?.account || '').trim();
|
|
87
|
+
const provider = account ? mediaLaneAccountProvider(input.lane) : '';
|
|
88
|
+
return provider ? withProviderAccount(provider, account, () => beginMediaJob(input)) : beginMediaJob(input);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function beginMediaJob({
|
|
82
92
|
lane: laneId,
|
|
83
93
|
kind,
|
|
84
94
|
model,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* an unauthenticated lane fails closed.
|
|
9
9
|
*/
|
|
10
10
|
import { hasAgentApiKey } from '../shared/provider-api-key.mjs';
|
|
11
|
+
import { ACCOUNT_PROVIDERS } from '../shared/provider-accounts.mjs';
|
|
11
12
|
// Credential probes are file-level checks: the catalog must not drag the whole
|
|
12
13
|
// provider graph in just to render lane availability.
|
|
13
14
|
import {
|
|
@@ -64,6 +65,7 @@ const LANES = Object.freeze([
|
|
|
64
65
|
image: Object.freeze({
|
|
65
66
|
controls: Object.freeze({
|
|
66
67
|
maxReferences: 5,
|
|
68
|
+
background: Object.freeze(['auto', 'transparent', 'opaque']),
|
|
67
69
|
}),
|
|
68
70
|
}),
|
|
69
71
|
}),
|
|
@@ -100,6 +102,13 @@ const LANES = Object.freeze([
|
|
|
100
102
|
|
|
101
103
|
const LANE_BY_ID = new Map(LANES.map((lane) => [lane.id, lane]));
|
|
102
104
|
|
|
105
|
+
/** The provider whose connected accounts a lane can generate through, or ''
|
|
106
|
+
* for a lane that authenticates with a single API key. */
|
|
107
|
+
export function mediaLaneAccountProvider(laneId) {
|
|
108
|
+
const provider = LANE_BY_ID.get(String(laneId || '').trim())?.auth.provider;
|
|
109
|
+
return ACCOUNT_PROVIDERS.includes(provider) ? provider : '';
|
|
110
|
+
}
|
|
111
|
+
|
|
103
112
|
const OAUTH_PROBES = Object.freeze({
|
|
104
113
|
'grok-oauth': hasGrokOAuthCredentials,
|
|
105
114
|
'openai-oauth': hasOpenAIOAuthCredentials,
|
|
@@ -143,6 +152,9 @@ export function createMediaLaneCatalog({ loadModels = loadMediaModels, authentic
|
|
|
143
152
|
authType: lane.auth.type,
|
|
144
153
|
authProvider: lane.auth.provider,
|
|
145
154
|
authenticated: signedIn,
|
|
155
|
+
// What the lane can generate once signed in; `kinds` lists only what its
|
|
156
|
+
// live catalog offers right now.
|
|
157
|
+
supportedKinds: MEDIA_KINDS.filter((kind) => lane[kind]),
|
|
146
158
|
kinds: [],
|
|
147
159
|
image: null,
|
|
148
160
|
video: null,
|
|
@@ -31,7 +31,7 @@ export const TOOL_DEFS = [
|
|
|
31
31
|
lane: {
|
|
32
32
|
type: 'string',
|
|
33
33
|
description:
|
|
34
|
-
'Lane id from list;
|
|
34
|
+
'Lane id from list; pass it when the user names a source. Omitted = the lane the user last chose for the kind, else the default signed-in lane.',
|
|
35
35
|
},
|
|
36
36
|
model: {
|
|
37
37
|
type: 'string',
|
|
@@ -44,10 +44,21 @@ export const TOOL_DEFS = [
|
|
|
44
44
|
description:
|
|
45
45
|
'generate: output file (png/jpg/mp4); relative to the project. status: copy a finished asset here.',
|
|
46
46
|
},
|
|
47
|
-
aspect: {
|
|
48
|
-
|
|
47
|
+
aspect: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: 'Aspect ratio, e.g. 16:9, 9:16, 1:1; only when the model lists aspectRatio, else omit.',
|
|
50
|
+
},
|
|
51
|
+
resolution: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
description: 'Resolution token (1k, 2k, 720p, 1080p); only when the model lists it, else omit.',
|
|
54
|
+
},
|
|
49
55
|
duration: { type: 'number', description: "video: seconds, within the model's listed durations." },
|
|
50
|
-
quality: { type: 'string', description: 'Quality token when the model lists one.' },
|
|
56
|
+
quality: { type: 'string', description: 'Quality token; only when the model lists one, else omit.' },
|
|
57
|
+
background: {
|
|
58
|
+
type: 'string',
|
|
59
|
+
enum: ['auto', 'transparent', 'opaque'],
|
|
60
|
+
description: 'image: transparent for real alpha; only when the model lists background, else omit.',
|
|
61
|
+
},
|
|
51
62
|
references: {
|
|
52
63
|
type: 'array',
|
|
53
64
|
items: { type: 'string' },
|
|
@@ -8,6 +8,7 @@ import { MEDIA_ACTIONS, MEDIA_KINDS } from './tool-defs.mjs';
|
|
|
8
8
|
import { clean } from '../shared/clean.mjs';
|
|
9
9
|
|
|
10
10
|
const POLL_MS = 750;
|
|
11
|
+
const DEFAULT_LANE = 'openai-oauth';
|
|
11
12
|
const TIMEOUT_MS = Object.freeze({ image: 180_000, video: 900_000 });
|
|
12
13
|
// OpenAI's image lane takes pixel sizes, not ratios; the placement still speaks in ratios.
|
|
13
14
|
const OPENAI_SIZE = Object.freeze({
|
|
@@ -36,6 +37,7 @@ async function mediaGraph(deps) {
|
|
|
36
37
|
jobs: await import('./jobs.mjs'),
|
|
37
38
|
store: await import('./store.mjs'),
|
|
38
39
|
defaults: await import('./defaults.mjs'),
|
|
40
|
+
accounts: await import('../shared/provider-auth-binding.mjs'),
|
|
39
41
|
};
|
|
40
42
|
return graph;
|
|
41
43
|
}
|
|
@@ -130,8 +132,9 @@ export function listMediaCatalog(lanes, { kind = '', model = '' } = {}, remember
|
|
|
130
132
|
|
|
131
133
|
/**
|
|
132
134
|
* Lane for a generate: the requested one, else the lane the user last chose
|
|
133
|
-
* for this kind (Studio selection or last generation), else the
|
|
134
|
-
* signed-in lane. `laneSource`
|
|
135
|
+
* for this kind (Studio selection or last generation), else the signed-in
|
|
136
|
+
* ChatGPT-subscription lane, else the first signed-in lane. `laneSource` is
|
|
137
|
+
* `first` for either default.
|
|
135
138
|
*/
|
|
136
139
|
function pickLane(lanes, kind, requested, remembered = null) {
|
|
137
140
|
const available = lanes.filter((lane) => lane.authenticated && lane.kinds.includes(kind));
|
|
@@ -153,9 +156,8 @@ function pickLane(lanes, kind, requested, remembered = null) {
|
|
|
153
156
|
);
|
|
154
157
|
}
|
|
155
158
|
const rememberedLane = remembered?.lane ? available.find((entry) => entry.id === remembered.lane) : null;
|
|
156
|
-
return rememberedLane
|
|
157
|
-
|
|
158
|
-
: { lane: available[0], laneSource: 'first' };
|
|
159
|
+
if (rememberedLane) return { lane: rememberedLane, laneSource: 'remembered' };
|
|
160
|
+
return { lane: available.find((entry) => entry.id === DEFAULT_LANE) || available[0], laneSource: 'first' };
|
|
159
161
|
}
|
|
160
162
|
|
|
161
163
|
function readRemembered(defaults, kind) {
|
|
@@ -166,6 +168,14 @@ function readRemembered(defaults, kind) {
|
|
|
166
168
|
}
|
|
167
169
|
}
|
|
168
170
|
|
|
171
|
+
function readPin(defaults, kind) {
|
|
172
|
+
try {
|
|
173
|
+
return defaults?.getMediaPin?.(kind) || null;
|
|
174
|
+
} catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
169
179
|
function allowed(controls, key) {
|
|
170
180
|
const list = controls?.[key];
|
|
171
181
|
return Array.isArray(list) && list.length ? list : null;
|
|
@@ -185,9 +195,13 @@ export function buildOptions(
|
|
|
185
195
|
lane,
|
|
186
196
|
kind,
|
|
187
197
|
controls,
|
|
188
|
-
{ aspect = '', resolution = '', duration = null, quality = '' } = {}
|
|
198
|
+
{ aspect = '', resolution = '', duration = null, quality = '', background = '' } = {}
|
|
189
199
|
) {
|
|
190
200
|
const options = {};
|
|
201
|
+
if (background) {
|
|
202
|
+
validateChoice(controls, 'background', background, 'background');
|
|
203
|
+
if (background !== 'auto') options.background = background;
|
|
204
|
+
}
|
|
191
205
|
if (lane.id === 'openai-oauth') {
|
|
192
206
|
if (!allowed(controls, 'size')) {
|
|
193
207
|
if ([aspect, resolution, quality].some((value) => value && value !== 'auto')) {
|
|
@@ -291,9 +305,21 @@ async function generate(args, { cwd, signal, deps, sessionId, sourceType }) {
|
|
|
291
305
|
const requestedPath = clean(args.path);
|
|
292
306
|
if (!requestedPath) throw new MediaToolError('generate requires path: where to write the file');
|
|
293
307
|
const target = fullPath(requestedPath, cwd);
|
|
294
|
-
const { lanes, jobs, store, defaults } = await mediaGraph(deps);
|
|
295
|
-
|
|
296
|
-
|
|
308
|
+
const { lanes, jobs, store, defaults, accounts } = await mediaGraph(deps);
|
|
309
|
+
// A generator the chat names (lane or model) wins for this call; otherwise
|
|
310
|
+
// the pinned default for the kind applies, and with none the remembered
|
|
311
|
+
// choice / ordered default. A pin never falls back: its lane, model and
|
|
312
|
+
// account errors surface as they are.
|
|
313
|
+
const pin = clean(args.lane) || clean(args.model) ? null : readPin(defaults, kind);
|
|
314
|
+
const remembered = pin ? null : readRemembered(defaults, kind);
|
|
315
|
+
const accountProvider = pin?.account ? lanes.mediaLaneAccountProvider?.(pin.lane) || '' : '';
|
|
316
|
+
const listLanes = () =>
|
|
317
|
+
accountProvider
|
|
318
|
+
? accounts.withProviderAccount(accountProvider, pin.account, () => lanes.listMediaLanes())
|
|
319
|
+
: lanes.listMediaLanes();
|
|
320
|
+
const picked = pickLane(await listLanes(), kind, pin ? pin.lane : clean(args.lane), remembered);
|
|
321
|
+
const { lane } = picked;
|
|
322
|
+
const laneSource = pin ? 'pinned' : picked.laneSource;
|
|
297
323
|
const spec = lane[kind];
|
|
298
324
|
// The remembered model only applies on the remembered lane and only while
|
|
299
325
|
// that lane still lists it; otherwise the lane default is the safe choice.
|
|
@@ -301,7 +327,7 @@ async function generate(args, { cwd, signal, deps, sessionId, sourceType }) {
|
|
|
301
327
|
laneSource === 'remembered' && remembered.model && spec.models.some((entry) => entry.id === remembered.model)
|
|
302
328
|
? remembered.model
|
|
303
329
|
: '';
|
|
304
|
-
const modelId = clean(args.model) || rememberedModel || spec.defaultModel;
|
|
330
|
+
const modelId = clean(args.model) || pin?.model || rememberedModel || spec.defaultModel;
|
|
305
331
|
const model = modelControls(lane, kind, modelId);
|
|
306
332
|
if (!model)
|
|
307
333
|
throw new MediaToolError(`model "${modelId}" is not available on ${lane.id} for ${kind}`, {
|
|
@@ -312,6 +338,7 @@ async function generate(args, { cwd, signal, deps, sessionId, sourceType }) {
|
|
|
312
338
|
resolution: clean(args.resolution),
|
|
313
339
|
duration: args.duration ?? null,
|
|
314
340
|
quality: clean(args.quality),
|
|
341
|
+
background: clean(args.background),
|
|
315
342
|
});
|
|
316
343
|
const references = await readReferences(args.references, cwd, model.controls);
|
|
317
344
|
const started = await jobs.startMediaJob({
|
|
@@ -323,6 +350,7 @@ async function generate(args, { cwd, signal, deps, sessionId, sourceType }) {
|
|
|
323
350
|
references,
|
|
324
351
|
sessionId,
|
|
325
352
|
sourceType,
|
|
353
|
+
...(accountProvider ? { account: pin.account } : {}),
|
|
326
354
|
});
|
|
327
355
|
const base = { lane: lane.id, model: modelId, laneSource, options, referenceCount: references.length, prompt };
|
|
328
356
|
if (args.wait === false) {
|
|
@@ -396,11 +424,12 @@ export async function executeMediaTool(
|
|
|
396
424
|
...listMediaCatalog(
|
|
397
425
|
await lanes.listMediaLanes(),
|
|
398
426
|
{ kind, model: clean(args.model) },
|
|
399
|
-
readRemembered(defaults, kind)
|
|
427
|
+
readPin(defaults, kind) || readRemembered(defaults, kind)
|
|
400
428
|
),
|
|
401
429
|
});
|
|
402
430
|
}
|
|
403
|
-
if (action === 'generate')
|
|
431
|
+
if (action === 'generate')
|
|
432
|
+
return mediaToolResult(await generate(args, { cwd, signal, deps, sessionId, sourceType }));
|
|
404
433
|
if (action === 'status') return mediaToolResult(await status(args, { cwd, deps }));
|
|
405
434
|
return mediaToolResult(await cancel(args, { deps }));
|
|
406
435
|
} catch (error) {
|