@cjhyy/code-shell-core 0.5.0-rc.2 → 0.6.0-rc.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 +13 -10
- package/dist/agent/agent-definition-registry.d.ts +3 -0
- package/dist/agent/agent-definition-registry.js +3 -1
- package/dist/agent/agent-definition.d.ts +15 -0
- package/dist/agent/agent-definition.js +27 -3
- package/dist/arena/context/context-tools.js +47 -4
- package/dist/arena/ledger.js +9 -1
- package/dist/arena/strategies/utils.d.ts +1 -4
- package/dist/arena/strategies/utils.js +7 -84
- package/dist/automation/cron-expr.d.ts +10 -0
- package/dist/automation/cron-expr.js +23 -5
- package/dist/automation/runner.d.ts +21 -4
- package/dist/automation/runner.js +48 -12
- package/dist/automation/scheduler.d.ts +38 -0
- package/dist/automation/scheduler.js +89 -12
- package/dist/automation/store.js +5 -2
- package/dist/capability-control/disabled-lists.d.ts +25 -0
- package/dist/capability-control/disabled-lists.js +57 -0
- package/dist/capability-control/overlay.d.ts +15 -0
- package/dist/capability-control/overlay.js +27 -0
- package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
- package/dist/cc-orchestrator/agent-adapter.js +133 -0
- package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
- package/dist/cc-orchestrator/cc-capability.js +53 -0
- package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
- package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
- package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
- package/dist/cc-orchestrator/codex-session-history.js +187 -0
- package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
- package/dist/cc-orchestrator/external-agent-changes.js +214 -0
- package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
- package/dist/cc-orchestrator/external-agent-driver.js +69 -0
- package/dist/cc-orchestrator/index.d.ts +8 -0
- package/dist/cc-orchestrator/index.js +8 -0
- package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
- package/dist/cc-orchestrator/relevance-judge.js +29 -0
- package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
- package/dist/cc-orchestrator/session-discovery.js +125 -0
- package/dist/cc-orchestrator/session-history.d.ts +19 -0
- package/dist/cc-orchestrator/session-history.js +67 -0
- package/dist/cli/agent-server-stdio.d.ts +15 -1
- package/dist/cli/agent-server-stdio.js +115 -17
- package/dist/cli/agent-server-tcp.js +40 -26
- package/dist/context/compaction.d.ts +56 -0
- package/dist/context/compaction.js +186 -0
- package/dist/context/manager.js +25 -4
- package/dist/cost-tracker.js +5 -61
- package/dist/credentials/cipher.d.ts +49 -0
- package/dist/credentials/cipher.js +45 -0
- package/dist/credentials/cookie-jar.d.ts +24 -0
- package/dist/credentials/cookie-jar.js +40 -0
- package/dist/credentials/index.d.ts +7 -0
- package/dist/credentials/index.js +5 -0
- package/dist/credentials/inject-credential-tool.d.ts +20 -0
- package/dist/credentials/inject-credential-tool.js +130 -0
- package/dist/credentials/store.d.ts +72 -0
- package/dist/credentials/store.js +184 -0
- package/dist/credentials/types.d.ts +56 -0
- package/dist/credentials/use-credential-tool.d.ts +29 -0
- package/dist/credentials/use-credential-tool.js +205 -0
- package/dist/credentials/use-gate.d.ts +56 -0
- package/dist/credentials/use-gate.js +52 -0
- package/dist/data/model-metadata.d.ts +77 -0
- package/dist/data/model-metadata.js +56 -0
- package/dist/data/model-metadata.json +216 -0
- package/dist/data/openrouter-models.d.ts +18 -7
- package/dist/data/openrouter-models.js +35 -8
- package/dist/engine/aux-key.d.ts +10 -0
- package/dist/engine/aux-key.js +11 -0
- package/dist/engine/dynamic-tool-defs.d.ts +19 -0
- package/dist/engine/dynamic-tool-defs.js +36 -0
- package/dist/engine/engine.d.ts +267 -138
- package/dist/engine/engine.js +957 -191
- package/dist/engine/friendly-error.d.ts +18 -0
- package/dist/engine/friendly-error.js +63 -0
- package/dist/engine/goal.d.ts +145 -0
- package/dist/engine/goal.js +144 -0
- package/dist/engine/image-policy.d.ts +13 -0
- package/dist/engine/image-policy.js +24 -0
- package/dist/engine/model-connections-pool.d.ts +17 -0
- package/dist/engine/model-connections-pool.js +66 -0
- package/dist/engine/model-facade.d.ts +10 -0
- package/dist/engine/model-facade.js +25 -0
- package/dist/engine/patch-orphaned-tools.js +3 -0
- package/dist/engine/resolve-llm-config.d.ts +16 -0
- package/dist/engine/resolve-llm-config.js +44 -0
- package/dist/engine/runtime.js +2 -1
- package/dist/engine/sandbox-cache-key.d.ts +10 -0
- package/dist/engine/sandbox-cache-key.js +9 -0
- package/dist/engine/sandbox-config.d.ts +31 -0
- package/dist/engine/sandbox-config.js +38 -0
- package/dist/engine/session-usage.d.ts +19 -0
- package/dist/engine/session-usage.js +25 -0
- package/dist/engine/steer-queue.d.ts +32 -0
- package/dist/engine/steer-queue.js +26 -0
- package/dist/engine/streaming-tool-queue.d.ts +12 -0
- package/dist/engine/streaming-tool-queue.js +50 -10
- package/dist/engine/turn-loop.d.ts +67 -3
- package/dist/engine/turn-loop.js +292 -41
- package/dist/engine/types.d.ts +175 -0
- package/dist/engine/types.js +13 -0
- package/dist/external-agents/config.d.ts +2 -0
- package/dist/external-agents/config.js +15 -0
- package/dist/external-agents/types.d.ts +31 -0
- package/dist/external-agents/types.js +1 -0
- package/dist/git/utils.js +11 -6
- package/dist/git/worktree.d.ts +48 -0
- package/dist/git/worktree.js +86 -10
- package/dist/hooks/goal-stop-hook.d.ts +28 -0
- package/dist/hooks/goal-stop-hook.js +186 -9
- package/dist/hooks/registry.d.ts +8 -0
- package/dist/hooks/registry.js +19 -0
- package/dist/hooks/shell-runner.js +10 -21
- package/dist/index.d.ts +49 -6
- package/dist/index.js +60 -4
- package/dist/llm/capabilities/param-specs.d.ts +14 -0
- package/dist/llm/capabilities/param-specs.js +62 -0
- package/dist/llm/capabilities/rules.js +4 -0
- package/dist/llm/capabilities/types.d.ts +10 -0
- package/dist/llm/client-base.d.ts +28 -1
- package/dist/llm/client-base.js +119 -13
- package/dist/llm/model-cache.js +4 -2
- package/dist/llm/model-pool.d.ts +14 -0
- package/dist/llm/model-pool.js +13 -0
- package/dist/llm/provider-auth.d.ts +41 -0
- package/dist/llm/provider-auth.js +76 -0
- package/dist/llm/provider-catalog.d.ts +4 -0
- package/dist/llm/providers/anthropic.js +64 -14
- package/dist/llm/providers/openai.d.ts +36 -0
- package/dist/llm/providers/openai.js +257 -51
- package/dist/llm/reasoning-setting.d.ts +3 -3
- package/dist/llm/reasoning-setting.js +9 -1
- package/dist/llm/stream-watchdog.js +5 -1
- package/dist/llm/token-counter.js +9 -2
- package/dist/llm/types.d.ts +4 -0
- package/dist/logging/sanitize-messages.js +22 -0
- package/dist/lsp/manager.d.ts +1 -1
- package/dist/lsp/manager.js +40 -10
- package/dist/model-catalog/builtin.d.ts +12 -0
- package/dist/model-catalog/builtin.js +407 -0
- package/dist/model-catalog/gen-connections.d.ts +20 -0
- package/dist/model-catalog/gen-connections.js +28 -0
- package/dist/model-catalog/index.d.ts +41 -0
- package/dist/model-catalog/index.js +90 -0
- package/dist/model-catalog/params.d.ts +20 -0
- package/dist/model-catalog/params.js +45 -0
- package/dist/model-catalog/resolve.d.ts +48 -0
- package/dist/model-catalog/resolve.js +33 -0
- package/dist/model-catalog/save-entry.d.ts +32 -0
- package/dist/model-catalog/save-entry.js +104 -0
- package/dist/model-catalog/types.d.ts +561 -0
- package/dist/model-catalog/types.js +93 -0
- package/dist/model-catalog/upsert.d.ts +9 -0
- package/dist/model-catalog/upsert.js +8 -0
- package/dist/onboarding.d.ts +12 -82
- package/dist/onboarding.js +61 -326
- package/dist/plugins/gitOps.d.ts +19 -0
- package/dist/plugins/gitOps.js +73 -4
- package/dist/plugins/installer/checkUpdate.d.ts +16 -0
- package/dist/plugins/installer/checkUpdate.js +32 -0
- package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
- package/dist/plugins/installer/codex/convertCommands.js +46 -0
- package/dist/plugins/installer/codex/convertMcp.d.ts +5 -2
- package/dist/plugins/installer/codex/convertMcp.js +45 -5
- package/dist/plugins/installer/install.js +25 -1
- package/dist/plugins/installer/installFromArchive.d.ts +43 -0
- package/dist/plugins/installer/installFromArchive.js +134 -0
- package/dist/plugins/installer/installFromSource.js +8 -2
- package/dist/plugins/installer/loadPluginAgents.js +6 -2
- package/dist/plugins/installer/loadPluginMcp.d.ts +9 -2
- package/dist/plugins/installer/loadPluginMcp.js +35 -2
- package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
- package/dist/plugins/installer/pruneDisabled.js +73 -0
- package/dist/plugins/installer/types.d.ts +5 -2
- package/dist/plugins/installer/types.js +1 -0
- package/dist/plugins/installer/uninstall.js +4 -0
- package/dist/plugins/installer/unzip.d.ts +14 -0
- package/dist/plugins/installer/unzip.js +82 -0
- package/dist/plugins/installer/update.d.ts +14 -0
- package/dist/plugins/installer/update.js +53 -21
- package/dist/plugins/loadPluginHooks.d.ts +47 -1
- package/dist/plugins/loadPluginHooks.js +73 -1
- package/dist/plugins/marketplaceManager.d.ts +7 -0
- package/dist/plugins/marketplaceManager.js +20 -0
- package/dist/plugins/pluginCommandHook.js +4 -18
- package/dist/plugins/pluginContent.d.ts +30 -0
- package/dist/plugins/pluginContent.js +83 -0
- package/dist/plugins/pluginInstaller.d.ts +13 -0
- package/dist/plugins/pluginInstaller.js +42 -8
- package/dist/plugins/schemas.js +1 -0
- package/dist/plugins/types.d.ts +6 -0
- package/dist/preset/index.d.ts +7 -1
- package/dist/preset/index.js +96 -6
- package/dist/product/types.d.ts +1 -1
- package/dist/prompt/composer.d.ts +27 -0
- package/dist/prompt/composer.js +67 -21
- package/dist/prompt/instruction-scanner.js +5 -3
- package/dist/prompt/section-loader.js +1 -0
- package/dist/prompt/sections/base.md +1 -0
- package/dist/prompt/sections/browser.md +10 -0
- package/dist/prompt/sections/coding.md +4 -0
- package/dist/protocol/chat-session-manager.d.ts +8 -2
- package/dist/protocol/chat-session-manager.js +36 -0
- package/dist/protocol/chat-session.d.ts +65 -0
- package/dist/protocol/chat-session.js +94 -2
- package/dist/protocol/client.d.ts +27 -0
- package/dist/protocol/client.js +38 -0
- package/dist/protocol/server.d.ts +112 -0
- package/dist/protocol/server.js +586 -16
- package/dist/protocol/transport.js +3 -2
- package/dist/protocol/types.d.ts +46 -0
- package/dist/protocol/types.js +16 -0
- package/dist/quota/credentials.d.ts +3 -0
- package/dist/quota/credentials.js +80 -0
- package/dist/quota/index.d.ts +36 -0
- package/dist/quota/index.js +155 -0
- package/dist/quota/types.d.ts +48 -0
- package/dist/quota/types.js +13 -0
- package/dist/review/review-prompt.d.ts +28 -0
- package/dist/review/review-prompt.js +81 -0
- package/dist/run/FileRunStore.js +8 -3
- package/dist/run/RunApprovalBackend.js +25 -5
- package/dist/run/RunManager.d.ts +12 -0
- package/dist/run/RunManager.js +35 -0
- package/dist/run/factory.d.ts +1 -1
- package/dist/runtime/background-shell.d.ts +139 -0
- package/dist/runtime/background-shell.js +495 -0
- package/dist/runtime/output-clean.d.ts +24 -0
- package/dist/runtime/output-clean.js +41 -0
- package/dist/runtime/ring-file.d.ts +64 -0
- package/dist/runtime/ring-file.js +174 -0
- package/dist/runtime/safe-spawn.js +15 -34
- package/dist/runtime/spawn-common.d.ts +148 -0
- package/dist/runtime/spawn-common.js +303 -0
- package/dist/runtime/truncate-output.d.ts +22 -0
- package/dist/runtime/truncate-output.js +49 -0
- package/dist/runtime/utf8-cut.d.ts +11 -0
- package/dist/runtime/utf8-cut.js +23 -0
- package/dist/services/auto-dream.d.ts +4 -0
- package/dist/services/auto-dream.js +26 -26
- package/dist/services/diagnostics.d.ts +1 -2
- package/dist/services/diagnostics.js +12 -7
- package/dist/services/extract-memories.d.ts +14 -1
- package/dist/services/extract-memories.js +45 -6
- package/dist/services/memory-orchestrator.d.ts +21 -0
- package/dist/services/memory-orchestrator.js +125 -50
- package/dist/services/session-memory.js +24 -12
- package/dist/session/file-history.d.ts +124 -1
- package/dist/session/file-history.js +222 -6
- package/dist/session/memory.d.ts +116 -2
- package/dist/session/memory.js +250 -28
- package/dist/session/session-manager.d.ts +40 -0
- package/dist/session/session-manager.js +113 -3
- package/dist/session/simple-diff.d.ts +23 -0
- package/dist/session/simple-diff.js +84 -0
- package/dist/session/transcript.d.ts +25 -1
- package/dist/session/transcript.js +35 -2
- package/dist/session/undo-target.d.ts +67 -0
- package/dist/session/undo-target.js +144 -0
- package/dist/settings/disk-defaults.d.ts +9 -2
- package/dist/settings/disk-defaults.js +11 -2
- package/dist/settings/feature-flags.d.ts +64 -0
- package/dist/settings/feature-flags.js +61 -0
- package/dist/settings/manager.d.ts +68 -1
- package/dist/settings/manager.js +266 -29
- package/dist/settings/migrate-config.d.ts +45 -0
- package/dist/settings/migrate-config.js +125 -0
- package/dist/settings/schema-export.d.ts +25 -0
- package/dist/settings/schema-export.js +38 -0
- package/dist/settings/schema.d.ts +1186 -771
- package/dist/settings/schema.js +268 -97
- package/dist/skills/scanner.d.ts +9 -0
- package/dist/skills/scanner.js +30 -2
- package/dist/stt/resolve-transcribe.d.ts +31 -0
- package/dist/stt/resolve-transcribe.js +108 -0
- package/dist/stt/transcribe.d.ts +51 -0
- package/dist/stt/transcribe.js +65 -0
- package/dist/tool-system/browser-bridge.d.ts +226 -0
- package/dist/tool-system/browser-bridge.js +163 -0
- package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
- package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
- package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
- package/dist/tool-system/builtin/agent-notifications.js +9 -3
- package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
- package/dist/tool-system/builtin/agent-output-file.js +72 -0
- package/dist/tool-system/builtin/agent-registry.d.ts +12 -0
- package/dist/tool-system/builtin/agent-registry.js +8 -0
- package/dist/tool-system/builtin/agent.d.ts +21 -1
- package/dist/tool-system/builtin/agent.js +489 -42
- package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
- package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
- package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
- package/dist/tool-system/builtin/apply-patch/index.js +0 -15
- package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
- package/dist/tool-system/builtin/background-jobs.js +124 -0
- package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
- package/dist/tool-system/builtin/background-shell-tools.js +108 -0
- package/dist/tool-system/builtin/background-work.d.ts +67 -0
- package/dist/tool-system/builtin/background-work.js +86 -0
- package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
- package/dist/tool-system/builtin/bash-output-style.js +40 -0
- package/dist/tool-system/builtin/bash.d.ts +5 -2
- package/dist/tool-system/builtin/bash.js +98 -62
- package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
- package/dist/tool-system/builtin/browser-tools.js +312 -0
- package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
- package/dist/tool-system/builtin/cancel-goal.js +64 -0
- package/dist/tool-system/builtin/check-quota.d.ts +15 -0
- package/dist/tool-system/builtin/check-quota.js +34 -0
- package/dist/tool-system/builtin/config.js +7 -0
- package/dist/tool-system/builtin/cron.d.ts +7 -0
- package/dist/tool-system/builtin/cron.js +55 -3
- package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
- package/dist/tool-system/builtin/drive-claude-code.js +157 -0
- package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
- package/dist/tool-system/builtin/edit-model-catalog.js +94 -0
- package/dist/tool-system/builtin/edit.js +20 -16
- package/dist/tool-system/builtin/eol.d.ts +29 -0
- package/dist/tool-system/builtin/eol.js +37 -0
- package/dist/tool-system/builtin/file-cache.d.ts +6 -0
- package/dist/tool-system/builtin/file-cache.js +8 -0
- package/dist/tool-system/builtin/generate-image.d.ts +35 -0
- package/dist/tool-system/builtin/generate-image.js +278 -50
- package/dist/tool-system/builtin/generate-video.d.ts +55 -0
- package/dist/tool-system/builtin/generate-video.js +361 -0
- package/dist/tool-system/builtin/glob.js +0 -7
- package/dist/tool-system/builtin/grep.js +6 -8
- package/dist/tool-system/builtin/image-providers.d.ts +86 -0
- package/dist/tool-system/builtin/image-providers.js +190 -0
- package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
- package/dist/tool-system/builtin/image-uploader.js +74 -0
- package/dist/tool-system/builtin/index.d.ts +7 -1
- package/dist/tool-system/builtin/index.js +249 -25
- package/dist/tool-system/builtin/mcp-tools.js +23 -3
- package/dist/tool-system/builtin/memory.js +45 -7
- package/dist/tool-system/builtin/notebook-edit.js +0 -7
- package/dist/tool-system/builtin/powershell.js +4 -1
- package/dist/tool-system/builtin/read.js +10 -10
- package/dist/tool-system/builtin/repl.js +4 -1
- package/dist/tool-system/builtin/skill.js +9 -0
- package/dist/tool-system/builtin/sleep.js +3 -2
- package/dist/tool-system/builtin/tool-search.js +25 -7
- package/dist/tool-system/builtin/video-providers.d.ts +154 -0
- package/dist/tool-system/builtin/video-providers.js +235 -0
- package/dist/tool-system/builtin/web-fetch.js +12 -2
- package/dist/tool-system/builtin/web-search.js +21 -7
- package/dist/tool-system/builtin/worktree.d.ts +2 -1
- package/dist/tool-system/builtin/worktree.js +31 -4
- package/dist/tool-system/builtin/write.js +0 -6
- package/dist/tool-system/context.d.ts +154 -6
- package/dist/tool-system/executor.d.ts +3 -1
- package/dist/tool-system/executor.js +172 -88
- package/dist/tool-system/investigation-guard.js +1 -1
- package/dist/tool-system/mcp-manager.d.ts +42 -4
- package/dist/tool-system/mcp-manager.js +186 -20
- package/dist/tool-system/path-policy.d.ts +5 -0
- package/dist/tool-system/path-policy.js +307 -8
- package/dist/tool-system/permission.d.ts +36 -1
- package/dist/tool-system/permission.js +281 -69
- package/dist/tool-system/plan-mode-allowlist.d.ts +13 -2
- package/dist/tool-system/plan-mode-allowlist.js +24 -2
- package/dist/tool-system/registry.d.ts +1 -0
- package/dist/tool-system/registry.js +16 -2
- package/dist/tool-system/sandbox/index.d.ts +8 -0
- package/dist/tool-system/sandbox/index.js +7 -2
- package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
- package/dist/tool-system/validate-tool-metadata.js +63 -0
- package/dist/types.d.ts +217 -6
- package/dist/updater.js +20 -9
- package/dist/utils/envUtils.d.ts +0 -9
- package/dist/utils/envUtils.js +3 -28
- package/dist/utils/exec.d.ts +40 -0
- package/dist/utils/exec.js +144 -0
- package/dist/utils/json.d.ts +12 -0
- package/dist/utils/json.js +92 -0
- package/dist/utils/theme.d.ts +1 -1
- package/dist/utils/theme.js +1 -1
- package/dist/utils/toolDisplay.js +0 -1
- package/package.json +13 -7
- package/dist/agent/coordinator.d.ts +0 -49
- package/dist/agent/coordinator.js +0 -77
- package/dist/settings/manager.test.js +0 -73
- package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
- package/dist/tool-system/builtin/remote-trigger.js +0 -54
- package/dist/tool-system/builtin/send-message.d.ts +0 -6
- package/dist/tool-system/builtin/send-message.js +0 -47
- /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EOL (line-ending) helpers for file-editing tools.
|
|
3
|
+
*
|
|
4
|
+
* Windows files are typically CRLF (`\r\n`); the model emits LF (`\n`). The
|
|
5
|
+
* file tools match the model's strings against file content and write the
|
|
6
|
+
* result back. Without normalization:
|
|
7
|
+
* - an LF `old_string` never matches a CRLF file → "old_string not found";
|
|
8
|
+
* - a successful write that re-joins with LF silently converts a CRLF file
|
|
9
|
+
* to LF, so `git diff` shows the whole file changed (and an .editorconfig
|
|
10
|
+
* /prettier may flip it right back → churn).
|
|
11
|
+
*
|
|
12
|
+
* The contract these helpers enforce:
|
|
13
|
+
* 1. Detect the file's dominant EOL.
|
|
14
|
+
* 2. Compare/replace in LF space (normalize both file content and the
|
|
15
|
+
* model's needle to LF first).
|
|
16
|
+
* 3. Write back in the ORIGINAL EOL so the file's line-ending style is
|
|
17
|
+
* preserved.
|
|
18
|
+
*/
|
|
19
|
+
export type Eol = "\r\n" | "\n";
|
|
20
|
+
/**
|
|
21
|
+
* The file's dominant line ending. CRLF if the content contains ANY `\r\n`
|
|
22
|
+
* (Windows editors are all-or-nothing in practice); otherwise LF. Empty/no-
|
|
23
|
+
* newline content defaults to LF.
|
|
24
|
+
*/
|
|
25
|
+
export declare function detectEol(content: string): Eol;
|
|
26
|
+
/** Collapse all CRLF (and lone CR) to LF for comparison/replacement. */
|
|
27
|
+
export declare function toLf(s: string): string;
|
|
28
|
+
/** Re-apply an EOL to LF-normalized text. No-op for LF. */
|
|
29
|
+
export declare function applyEol(s: string, eol: Eol): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EOL (line-ending) helpers for file-editing tools.
|
|
3
|
+
*
|
|
4
|
+
* Windows files are typically CRLF (`\r\n`); the model emits LF (`\n`). The
|
|
5
|
+
* file tools match the model's strings against file content and write the
|
|
6
|
+
* result back. Without normalization:
|
|
7
|
+
* - an LF `old_string` never matches a CRLF file → "old_string not found";
|
|
8
|
+
* - a successful write that re-joins with LF silently converts a CRLF file
|
|
9
|
+
* to LF, so `git diff` shows the whole file changed (and an .editorconfig
|
|
10
|
+
* /prettier may flip it right back → churn).
|
|
11
|
+
*
|
|
12
|
+
* The contract these helpers enforce:
|
|
13
|
+
* 1. Detect the file's dominant EOL.
|
|
14
|
+
* 2. Compare/replace in LF space (normalize both file content and the
|
|
15
|
+
* model's needle to LF first).
|
|
16
|
+
* 3. Write back in the ORIGINAL EOL so the file's line-ending style is
|
|
17
|
+
* preserved.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* The file's dominant line ending. CRLF if the content contains ANY `\r\n`
|
|
21
|
+
* (Windows editors are all-or-nothing in practice); otherwise LF. Empty/no-
|
|
22
|
+
* newline content defaults to LF.
|
|
23
|
+
*/
|
|
24
|
+
export function detectEol(content) {
|
|
25
|
+
return content.includes("\r\n") ? "\r\n" : "\n";
|
|
26
|
+
}
|
|
27
|
+
/** Collapse all CRLF (and lone CR) to LF for comparison/replacement. */
|
|
28
|
+
export function toLf(s) {
|
|
29
|
+
return s.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
30
|
+
}
|
|
31
|
+
/** Re-apply an EOL to LF-normalized text. No-op for LF. */
|
|
32
|
+
export function applyEol(s, eol) {
|
|
33
|
+
if (eol === "\n")
|
|
34
|
+
return s;
|
|
35
|
+
// s is already LF-normalized by callers; map every LF back to CRLF.
|
|
36
|
+
return s.replace(/\n/g, "\r\n");
|
|
37
|
+
}
|
|
@@ -5,6 +5,12 @@ declare class FileStateCache {
|
|
|
5
5
|
/** Invalidate a specific path (after Write/Edit). */
|
|
6
6
|
invalidate(filePath: string): void;
|
|
7
7
|
clear(): void;
|
|
8
|
+
/**
|
|
9
|
+
* True if a cache entry for `filePath` is currently held. Pure key-presence
|
|
10
|
+
* check — does NOT stat/self-heal like `get()`, so a test can assert a manual
|
|
11
|
+
* `invalidate()` actually removed the key without the mtime path masking it.
|
|
12
|
+
*/
|
|
13
|
+
has(filePath: string): boolean;
|
|
8
14
|
get size(): number;
|
|
9
15
|
}
|
|
10
16
|
export declare const fileCache: FileStateCache;
|
|
@@ -32,6 +32,14 @@ class FileStateCache {
|
|
|
32
32
|
clear() {
|
|
33
33
|
this.cache.clear();
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* True if a cache entry for `filePath` is currently held. Pure key-presence
|
|
37
|
+
* check — does NOT stat/self-heal like `get()`, so a test can assert a manual
|
|
38
|
+
* `invalidate()` actually removed the key without the mtime path masking it.
|
|
39
|
+
*/
|
|
40
|
+
has(filePath) {
|
|
41
|
+
return this.cache.has(filePath);
|
|
42
|
+
}
|
|
35
43
|
get size() {
|
|
36
44
|
return this.cache.size;
|
|
37
45
|
}
|
|
@@ -20,6 +20,41 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import type { ToolDefinition } from "../../types.js";
|
|
22
22
|
import type { ToolContext } from "../context.js";
|
|
23
|
+
/** A configured imageGen/videoGen instance (subset used here). */
|
|
24
|
+
interface GenInstance {
|
|
25
|
+
id: string;
|
|
26
|
+
kind: string;
|
|
27
|
+
baseUrl: string;
|
|
28
|
+
apiKey?: string;
|
|
29
|
+
defaultModel?: string;
|
|
30
|
+
catalogId?: string;
|
|
31
|
+
apiKeyRef?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Effective key for an instance: its own `apiKey`, or — when empty and
|
|
35
|
+
* `apiKeyRef` is set — the key of the referenced instance in the same list
|
|
36
|
+
* (reuse-key feature). Returns undefined when neither yields a key.
|
|
37
|
+
*/
|
|
38
|
+
export declare function effectiveApiKey(inst: GenInstance, list: GenInstance[]): string | undefined;
|
|
23
39
|
export declare const generateImageToolDef: ToolDefinition;
|
|
40
|
+
/**
|
|
41
|
+
* List the configured, usable image providers for a workspace (TODO 7.1) —
|
|
42
|
+
* either `imageGen.providers[]` ids+kinds, or the back-compat LLM-provider
|
|
43
|
+
* kinds. Used to build a dynamic tool description so the model sees which
|
|
44
|
+
* backends are actually available. Returns [] on any read error.
|
|
45
|
+
*/
|
|
46
|
+
export declare function listConfiguredImageProviders(cwd?: string): Array<{
|
|
47
|
+
id?: string;
|
|
48
|
+
kind: string;
|
|
49
|
+
catalogId?: string;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Build the GenerateImage tool description for a workspace, appending the
|
|
53
|
+
* configured providers so the model knows what's available and which `provider`
|
|
54
|
+
* values are valid (TODO 7.1). Falls back to the static description when none
|
|
55
|
+
* are configured (the guard hides the tool in that case anyway).
|
|
56
|
+
*/
|
|
57
|
+
export declare function generateImageToolDefFor(cwd: string): ToolDefinition;
|
|
24
58
|
export declare function isGenerateImageAvailable(cwd?: string, nowMs?: number): boolean;
|
|
25
59
|
export declare function generateImageTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
|
|
60
|
+
export {};
|
|
@@ -18,18 +18,58 @@
|
|
|
18
18
|
*
|
|
19
19
|
* Uses the native `fetch` (codeshell does not depend on the `openai` SDK).
|
|
20
20
|
*/
|
|
21
|
-
import { writeFile, mkdir } from "node:fs/promises";
|
|
22
|
-
import { join } from "node:path";
|
|
21
|
+
import { writeFile, mkdir, readFile } from "node:fs/promises";
|
|
22
|
+
import { join, isAbsolute, resolve as resolvePath, basename, extname } from "node:path";
|
|
23
|
+
import { randomBytes } from "node:crypto";
|
|
23
24
|
import { SettingsManager } from "../../settings/manager.js";
|
|
25
|
+
import { getImageProvider, DEFAULT_IMAGE_MODEL, } from "./image-providers.js";
|
|
26
|
+
import { getMergedCatalog, findCatalogEntry } from "../../model-catalog/index.js";
|
|
27
|
+
import { genInstancesFromConnections } from "../../model-catalog/gen-connections.js";
|
|
28
|
+
/**
|
|
29
|
+
* Effective key for an instance: its own `apiKey`, or — when empty and
|
|
30
|
+
* `apiKeyRef` is set — the key of the referenced instance in the same list
|
|
31
|
+
* (reuse-key feature). Returns undefined when neither yields a key.
|
|
32
|
+
*/
|
|
33
|
+
export function effectiveApiKey(inst, list) {
|
|
34
|
+
if (inst.apiKey)
|
|
35
|
+
return inst.apiKey;
|
|
36
|
+
if (inst.apiKeyRef) {
|
|
37
|
+
const ref = list.find((p) => p.id === inst.apiKeyRef);
|
|
38
|
+
if (ref?.apiKey)
|
|
39
|
+
return ref.apiKey;
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve a ResolvedImageProvider from a candidate list whose entries already
|
|
45
|
+
* carry a direct `apiKey` (the unified store dereferences credentials upfront).
|
|
46
|
+
* `prefer` selects by id (explicit → no silent fallback); else `def` then the
|
|
47
|
+
* first usable. Shared by the unified-store path.
|
|
48
|
+
*/
|
|
49
|
+
function resolveFromGenList(list, prefer, def) {
|
|
50
|
+
const usable = (p) => !!p.apiKey && getImageProvider(p.kind) !== null;
|
|
51
|
+
const credsOf = (p) => ({ baseUrl: p.baseUrl, apiKey: p.apiKey });
|
|
52
|
+
if (prefer) {
|
|
53
|
+
const chosen = list.find((p) => p.id === prefer);
|
|
54
|
+
if (chosen && usable(chosen))
|
|
55
|
+
return { kind: chosen.kind, creds: credsOf(chosen), defaultModel: chosen.defaultModel };
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const preferred = def ? list.find((p) => p.id === def) : undefined;
|
|
59
|
+
const chosen = (preferred && usable(preferred) ? preferred : undefined) ?? list.find(usable);
|
|
60
|
+
return chosen ? { kind: chosen.kind, creds: credsOf(chosen), defaultModel: chosen.defaultModel } : null;
|
|
61
|
+
}
|
|
24
62
|
const DEFAULT_SIZE = "1024x1024";
|
|
25
63
|
const DEFAULT_QUALITY = "auto";
|
|
26
|
-
|
|
64
|
+
/** Provider `kind`s that have an image adapter, in resolution preference. */
|
|
65
|
+
const IMAGE_PROVIDER_KINDS = ["openai", "google"];
|
|
27
66
|
export const generateImageToolDef = {
|
|
28
67
|
name: "GenerateImage",
|
|
29
|
-
description: "Generate an image from a text prompt
|
|
30
|
-
"Saves a PNG into the workspace and returns its
|
|
31
|
-
"that path on later turns.
|
|
32
|
-
"
|
|
68
|
+
description: "Generate an image from a text prompt, or edit/re-imagine existing image(s) by passing " +
|
|
69
|
+
"`referenceImages` (image-to-image). Saves a PNG into the workspace and returns its " +
|
|
70
|
+
"absolute path; read or reference that path on later turns. Defaults to the OpenAI Images " +
|
|
71
|
+
"API (gpt-image-2); requires a matching provider configured in settings. " +
|
|
72
|
+
"For raster assets (photos, illustrations, mockups, textures) — not for " +
|
|
33
73
|
"SVG/vector icons or anything better built directly in code.",
|
|
34
74
|
inputSchema: {
|
|
35
75
|
type: "object",
|
|
@@ -48,17 +88,100 @@ export const generateImageToolDef = {
|
|
|
48
88
|
enum: ["low", "medium", "high", "auto"],
|
|
49
89
|
description: "Render quality (default auto). Use low for drafts, high for final assets.",
|
|
50
90
|
},
|
|
91
|
+
provider: {
|
|
92
|
+
type: "string",
|
|
93
|
+
description: "Image provider to use. With imageGen configured, this is the instance `id` " +
|
|
94
|
+
"(e.g. \"gemini\"); otherwise it's a provider kind (e.g. \"openai\"). " +
|
|
95
|
+
"Defaults to the configured default / first available. Only specify to override.",
|
|
96
|
+
},
|
|
97
|
+
model: {
|
|
98
|
+
type: "string",
|
|
99
|
+
description: "Image model id (e.g. \"gpt-image-2\"). Defaults to the provider's default model. " +
|
|
100
|
+
"Only specify to override.",
|
|
101
|
+
},
|
|
102
|
+
referenceImages: {
|
|
103
|
+
type: "array",
|
|
104
|
+
items: { type: "string" },
|
|
105
|
+
description: "Optional workspace image path(s) to use as visual references (image-to-image / " +
|
|
106
|
+
"edit). When provided, the prompt edits/re-imagines these inputs instead of " +
|
|
107
|
+
"generating from scratch — use it to keep a subject, style, or composition. " +
|
|
108
|
+
"Paths are relative to the workspace (or absolute). PNG/JPEG/WebP, up to 16.",
|
|
109
|
+
},
|
|
51
110
|
},
|
|
52
111
|
required: ["prompt"],
|
|
53
112
|
},
|
|
54
113
|
};
|
|
55
|
-
/**
|
|
56
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Resolve an image provider from settings (TODO 7.1). Preference order:
|
|
116
|
+
*
|
|
117
|
+
* 1. `imageGen.providers[]` — the canonical, LLM-decoupled config. `prefer`
|
|
118
|
+
* selects an instance by its `id`; otherwise `imageGen.defaultProvider`,
|
|
119
|
+
* else the first entry. Each instance names its own adapter `kind`.
|
|
120
|
+
* 2. Fallback (no `imageGen`): scan LLM `providers[]` for an image-capable
|
|
121
|
+
* `kind` — keeps existing configs working with no migration. Here
|
|
122
|
+
* `prefer` is treated as a kind.
|
|
123
|
+
*
|
|
124
|
+
* Returns null when nothing usable is configured (or the requested one lacks
|
|
125
|
+
* a key / has no adapter).
|
|
126
|
+
*/
|
|
127
|
+
function resolveImageProvider(cwd, prefer) {
|
|
57
128
|
const settings = new SettingsManager(cwd, "full").get();
|
|
58
|
-
|
|
59
|
-
|
|
129
|
+
// 0. Unified store (统一模型接入方案): modelConnections (tag=image) +
|
|
130
|
+
// credentials. Takes precedence over the legacy imageGen.providers[] so the
|
|
131
|
+
// unified connection page drives image generation. Falls through to the
|
|
132
|
+
// legacy paths below when no image connection is configured.
|
|
133
|
+
const conns = settings.modelConnections;
|
|
134
|
+
const creds = settings.credentials;
|
|
135
|
+
if (Array.isArray(conns) && conns.some((c) => c.tag === "image")) {
|
|
136
|
+
const list = genInstancesFromConnections(conns, (Array.isArray(creds) ? creds : []), getMergedCatalog(), "image");
|
|
137
|
+
const def = settings.defaults?.image;
|
|
138
|
+
const resolved = resolveFromGenList(list, prefer, def);
|
|
139
|
+
if (resolved)
|
|
140
|
+
return resolved;
|
|
141
|
+
if (prefer)
|
|
142
|
+
return null; // explicit request not usable → don't silently fall back
|
|
143
|
+
}
|
|
144
|
+
// 1. Canonical imageGen config.
|
|
145
|
+
const imageGen = settings.imageGen;
|
|
146
|
+
if (imageGen && Array.isArray(imageGen.providers) && imageGen.providers.length > 0) {
|
|
147
|
+
const list = imageGen.providers;
|
|
148
|
+
const usable = (p) => !!effectiveApiKey(p, list) && getImageProvider(p.kind) !== null;
|
|
149
|
+
const credsOf = (p) => ({ baseUrl: p.baseUrl, apiKey: effectiveApiKey(p, list) });
|
|
150
|
+
if (prefer) {
|
|
151
|
+
// Explicit request — respect the user's intent. If that exact instance
|
|
152
|
+
// isn't usable (no key / no adapter), DON'T silently use another one.
|
|
153
|
+
const chosen = list.find((p) => p.id === prefer);
|
|
154
|
+
if (chosen && usable(chosen)) {
|
|
155
|
+
return { kind: chosen.kind, creds: credsOf(chosen), defaultModel: chosen.defaultModel };
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
// No explicit request: prefer defaultProvider, but if it isn't usable
|
|
160
|
+
// (e.g. configured but no key yet) fall back to the first usable entry,
|
|
161
|
+
// rather than erroring. (User-confirmed: default-with-no-key → fall back.)
|
|
162
|
+
const preferred = imageGen.defaultProvider
|
|
163
|
+
? list.find((p) => p.id === imageGen.defaultProvider)
|
|
164
|
+
: undefined;
|
|
165
|
+
const chosen = (preferred && usable(preferred) ? preferred : undefined) ?? list.find(usable);
|
|
166
|
+
if (chosen) {
|
|
167
|
+
return { kind: chosen.kind, creds: credsOf(chosen), defaultModel: chosen.defaultModel };
|
|
168
|
+
}
|
|
60
169
|
return null;
|
|
61
|
-
|
|
170
|
+
}
|
|
171
|
+
// 2. Back-compat: resolve from legacy LLM providers[] by kind. The field was
|
|
172
|
+
// dropped from the schema; un-migrated settings.json still carry it via the
|
|
173
|
+
// schema's .passthrough(), so read it through an inline cast.
|
|
174
|
+
const legacyProviders = settings.providers ?? [];
|
|
175
|
+
const kinds = prefer ? [prefer] : [...IMAGE_PROVIDER_KINDS];
|
|
176
|
+
for (const kind of kinds) {
|
|
177
|
+
if (!prefer && !IMAGE_PROVIDER_KINDS.includes(kind))
|
|
178
|
+
continue;
|
|
179
|
+
const provider = legacyProviders.find((p) => p.kind === kind);
|
|
180
|
+
if (provider && provider.apiKey) {
|
|
181
|
+
return { kind, creds: { baseUrl: provider.baseUrl, apiKey: provider.apiKey } };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
62
185
|
}
|
|
63
186
|
/**
|
|
64
187
|
* Tool-visibility guard: GenerateImage needs a kind:"openai" provider with a
|
|
@@ -73,13 +196,69 @@ function resolveOpenAIProvider(cwd) {
|
|
|
73
196
|
*/
|
|
74
197
|
const availCache = new Map();
|
|
75
198
|
const AVAIL_TTL_MS = 1000;
|
|
199
|
+
/**
|
|
200
|
+
* List the configured, usable image providers for a workspace (TODO 7.1) —
|
|
201
|
+
* either `imageGen.providers[]` ids+kinds, or the back-compat LLM-provider
|
|
202
|
+
* kinds. Used to build a dynamic tool description so the model sees which
|
|
203
|
+
* backends are actually available. Returns [] on any read error.
|
|
204
|
+
*/
|
|
205
|
+
export function listConfiguredImageProviders(cwd = process.cwd()) {
|
|
206
|
+
try {
|
|
207
|
+
const settings = new SettingsManager(cwd, "full").get();
|
|
208
|
+
const imageGen = settings.imageGen;
|
|
209
|
+
if (imageGen?.providers?.length) {
|
|
210
|
+
const list = imageGen.providers;
|
|
211
|
+
return list
|
|
212
|
+
.filter((p) => !!effectiveApiKey(p, list) && getImageProvider(p.kind) !== null)
|
|
213
|
+
.map((p) => ({ id: p.id, kind: p.kind, catalogId: p.catalogId }));
|
|
214
|
+
}
|
|
215
|
+
// Legacy LLM providers[] back-compat (field dropped from schema; read via
|
|
216
|
+
// .passthrough() with an inline cast).
|
|
217
|
+
const legacyProviders = settings.providers ?? [];
|
|
218
|
+
return legacyProviders
|
|
219
|
+
.filter((p) => p.apiKey &&
|
|
220
|
+
IMAGE_PROVIDER_KINDS.includes(p.kind))
|
|
221
|
+
.map((p) => ({ kind: p.kind }));
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return [];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Build the GenerateImage tool description for a workspace, appending the
|
|
229
|
+
* configured providers so the model knows what's available and which `provider`
|
|
230
|
+
* values are valid (TODO 7.1). Falls back to the static description when none
|
|
231
|
+
* are configured (the guard hides the tool in that case anyway).
|
|
232
|
+
*/
|
|
233
|
+
export function generateImageToolDefFor(cwd) {
|
|
234
|
+
const providers = listConfiguredImageProviders(cwd);
|
|
235
|
+
if (providers.length === 0)
|
|
236
|
+
return generateImageToolDef;
|
|
237
|
+
const names = providers.map((p) => p.id ?? p.kind).join(", ");
|
|
238
|
+
// Per-instance params hints from the catalog (paramsDoc) — so the model knows
|
|
239
|
+
// what each configured model accepts (different models differ).
|
|
240
|
+
const catalog = getMergedCatalog();
|
|
241
|
+
const paramLines = providers
|
|
242
|
+
.map((p) => {
|
|
243
|
+
const entry = findCatalogEntry(catalog, p.catalogId, p.kind);
|
|
244
|
+
return entry?.paramsDoc ? ` - ${p.id ?? p.kind}: ${entry.paramsDoc}` : null;
|
|
245
|
+
})
|
|
246
|
+
.filter((x) => x !== null);
|
|
247
|
+
const paramsBlock = paramLines.length ? `\nParams per provider:\n${paramLines.join("\n")}` : "";
|
|
248
|
+
return {
|
|
249
|
+
...generateImageToolDef,
|
|
250
|
+
description: generateImageToolDef.description +
|
|
251
|
+
` Configured provider(s): ${names}. Pass \`provider\` to pick one.` +
|
|
252
|
+
paramsBlock,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
76
255
|
export function isGenerateImageAvailable(cwd = process.cwd(), nowMs = Date.now()) {
|
|
77
256
|
const hit = availCache.get(cwd);
|
|
78
257
|
if (hit && nowMs - hit.at < AVAIL_TTL_MS)
|
|
79
258
|
return hit.value;
|
|
80
259
|
let value = false;
|
|
81
260
|
try {
|
|
82
|
-
value =
|
|
261
|
+
value = resolveImageProvider(cwd) !== null;
|
|
83
262
|
}
|
|
84
263
|
catch {
|
|
85
264
|
value = false;
|
|
@@ -87,6 +266,48 @@ export function isGenerateImageAvailable(cwd = process.cwd(), nowMs = Date.now()
|
|
|
87
266
|
availCache.set(cwd, { at: nowMs, value });
|
|
88
267
|
return value;
|
|
89
268
|
}
|
|
269
|
+
/** Map a file extension to an image MIME type the image APIs accept. */
|
|
270
|
+
const IMAGE_MIME_BY_EXT = {
|
|
271
|
+
".png": "image/png",
|
|
272
|
+
".jpg": "image/jpeg",
|
|
273
|
+
".jpeg": "image/jpeg",
|
|
274
|
+
".webp": "image/webp",
|
|
275
|
+
".gif": "image/gif",
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Read reference-image paths (workspace-relative or absolute) into decoded
|
|
279
|
+
* {@link InputImage}s for image-to-image. Returns either the loaded images or a
|
|
280
|
+
* user-facing error string (bad path, unreadable, unsupported type, too many).
|
|
281
|
+
*/
|
|
282
|
+
async function loadReferenceImages(paths, cwd) {
|
|
283
|
+
if (paths.length > 16) {
|
|
284
|
+
return { ok: false, error: `too many reference images (${paths.length}); max is 16` };
|
|
285
|
+
}
|
|
286
|
+
const images = [];
|
|
287
|
+
for (const p of paths) {
|
|
288
|
+
if (typeof p !== "string" || !p.trim()) {
|
|
289
|
+
return { ok: false, error: "referenceImages entries must be non-empty path strings" };
|
|
290
|
+
}
|
|
291
|
+
const ext = extname(p).toLowerCase();
|
|
292
|
+
const mimeType = IMAGE_MIME_BY_EXT[ext];
|
|
293
|
+
if (!mimeType) {
|
|
294
|
+
return {
|
|
295
|
+
ok: false,
|
|
296
|
+
error: `unsupported reference image type "${ext || "(none)"}" for ${p}; use PNG/JPEG/WebP/GIF`,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
const abs = isAbsolute(p) ? p : resolvePath(cwd, p);
|
|
300
|
+
let bytes;
|
|
301
|
+
try {
|
|
302
|
+
bytes = await readFile(abs);
|
|
303
|
+
}
|
|
304
|
+
catch (err) {
|
|
305
|
+
return { ok: false, error: `could not read reference image ${p}: ${err.message}` };
|
|
306
|
+
}
|
|
307
|
+
images.push({ filename: basename(abs), mimeType, bytes });
|
|
308
|
+
}
|
|
309
|
+
return { ok: true, images };
|
|
310
|
+
}
|
|
90
311
|
export async function generateImageTool(args, ctx) {
|
|
91
312
|
const prompt = args.prompt;
|
|
92
313
|
if (typeof prompt !== "string" || !prompt.trim()) {
|
|
@@ -94,51 +315,58 @@ export async function generateImageTool(args, ctx) {
|
|
|
94
315
|
}
|
|
95
316
|
const size = typeof args.size === "string" ? args.size : DEFAULT_SIZE;
|
|
96
317
|
const quality = typeof args.quality === "string" ? args.quality : DEFAULT_QUALITY;
|
|
318
|
+
const preferKind = typeof args.provider === "string" && args.provider ? args.provider : undefined;
|
|
319
|
+
const overrideModel = typeof args.model === "string" && args.model ? args.model : undefined;
|
|
97
320
|
const cwd = ctx?.cwd ?? process.cwd();
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
resp = await fetch(`${baseUrl}/images/generations`, {
|
|
108
|
-
method: "POST",
|
|
109
|
-
headers: {
|
|
110
|
-
Authorization: `Bearer ${provider.apiKey}`,
|
|
111
|
-
"Content-Type": "application/json",
|
|
112
|
-
},
|
|
113
|
-
body: JSON.stringify({ model: MODEL, prompt, size, quality, n: 1 }),
|
|
114
|
-
signal: ctx?.signal,
|
|
115
|
-
});
|
|
321
|
+
// Optional reference images → image-to-image. Resolve + decode before the
|
|
322
|
+
// provider call so a bad path fails fast with a clear message.
|
|
323
|
+
let inputImages;
|
|
324
|
+
if (Array.isArray(args.referenceImages) && args.referenceImages.length > 0) {
|
|
325
|
+
const loaded = await loadReferenceImages(args.referenceImages, cwd);
|
|
326
|
+
if (!loaded.ok)
|
|
327
|
+
return `Error: ${loaded.error}`;
|
|
328
|
+
inputImages = loaded.images;
|
|
116
329
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
330
|
+
const resolved = resolveImageProvider(cwd, preferKind);
|
|
331
|
+
if (!resolved) {
|
|
332
|
+
return preferKind
|
|
333
|
+
? `Error: no image provider "${preferKind}" is available (unknown id/kind, or it has no API key). Configure it in your code-shell settings, or omit \`provider\` to use the default.`
|
|
334
|
+
: 'Error: no image provider available. Configure an image provider (including an apiKey) ' +
|
|
335
|
+
"in your code-shell settings to use GenerateImage.";
|
|
123
336
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
catch (err) {
|
|
129
|
-
return `Error: could not parse image API response: ${err.message}`;
|
|
337
|
+
const adapter = getImageProvider(resolved.kind);
|
|
338
|
+
if (!adapter) {
|
|
339
|
+
return `Error: image generation is not supported for provider kind "${resolved.kind}".`;
|
|
130
340
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
341
|
+
// Model precedence: call arg > instance defaultModel (imageGen) > kind default.
|
|
342
|
+
const model = overrideModel ?? resolved.defaultModel ?? DEFAULT_IMAGE_MODEL[resolved.kind] ?? "gpt-image-2";
|
|
343
|
+
const result = await adapter.generate({
|
|
344
|
+
prompt,
|
|
345
|
+
size,
|
|
346
|
+
quality,
|
|
347
|
+
model,
|
|
348
|
+
creds: resolved.creds,
|
|
349
|
+
inputImages,
|
|
350
|
+
signal: ctx?.signal,
|
|
351
|
+
});
|
|
352
|
+
if (!result.ok) {
|
|
353
|
+
return `Error generating image: ${result.error}`;
|
|
135
354
|
}
|
|
136
355
|
try {
|
|
137
356
|
const dir = join(cwd, ".code-shell", "generated_images");
|
|
138
357
|
await mkdir(dir, { recursive: true });
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
358
|
+
// Timestamp keeps names sortable/recognizable; the random suffix prevents
|
|
359
|
+
// collisions when multiple GenerateImage calls run concurrently in one turn
|
|
360
|
+
// (Date.now() alone repeats within the same millisecond → writeFile would
|
|
361
|
+
// silently overwrite and drop an image).
|
|
362
|
+
const path = join(dir, `${Date.now()}-${randomBytes(3).toString("hex")}.png`);
|
|
363
|
+
await writeFile(path, Buffer.from(result.b64, "base64"));
|
|
364
|
+
// Name the provider/model actually used, so the user/agent knows which
|
|
365
|
+
// image backend produced this (esp. when a default fell back to another).
|
|
366
|
+
const mode = inputImages?.length
|
|
367
|
+
? ` from ${inputImages.length} reference image(s)`
|
|
368
|
+
: "";
|
|
369
|
+
return `Generated image with ${resolved.kind} (${model})${mode}, saved to ${path}`;
|
|
142
370
|
}
|
|
143
371
|
catch (err) {
|
|
144
372
|
return `Error saving generated image: ${err.message}`;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in GenerateVideo tool (TODO 7.1 块3) — text-to-video via a
|
|
3
|
+
* {@link VideoProvider} adapter (submit / poll / download).
|
|
4
|
+
*
|
|
5
|
+
* Video generation is always slow (tens of seconds to minutes), so this tool
|
|
6
|
+
* is fire-and-forget by design: it submits the job, returns a handle
|
|
7
|
+
* immediately, and polls in the BACKGROUND. When the job finishes it writes
|
|
8
|
+
* the file to `<cwd>/.code-shell/generated_videos/` and enqueues a completion
|
|
9
|
+
* notification (same notificationQueue path as background agents / shells), so
|
|
10
|
+
* the main turn is never blocked (consistent with TODO 3.2 / 4.1).
|
|
11
|
+
*
|
|
12
|
+
* Concrete provider adapters (Seedance / Kling) are not wired yet — their
|
|
13
|
+
* private APIs need confirmed docs. Until then the only resolvable provider is
|
|
14
|
+
* the test-injected fake, so in production this tool is dormant (returns a
|
|
15
|
+
* "no video provider configured" message) rather than half-working.
|
|
16
|
+
*/
|
|
17
|
+
import type { ToolDefinition } from "../../types.js";
|
|
18
|
+
import type { ToolContext } from "../context.js";
|
|
19
|
+
import { type VideoProvider, type VideoProviderCreds } from "./video-providers.js";
|
|
20
|
+
import { type ImageUploader, type UploaderCreds } from "./image-uploader.js";
|
|
21
|
+
/**
|
|
22
|
+
* Normalize image inputs (URLs or local paths) into public URLs the provider
|
|
23
|
+
* can consume. `images[]` wins over the single `image`. Local paths are
|
|
24
|
+
* uploaded via the injected {@link ImageUploader}; URLs pass through. Caps at
|
|
25
|
+
* {@link MAX_IMAGES} (fal reference-to-video allows up to 9).
|
|
26
|
+
*/
|
|
27
|
+
export declare function __normalizeImagesForTests(images: string[] | undefined, image: string | undefined, uploader: ImageUploader, creds: UploaderCreds, signal?: AbortSignal): Promise<{
|
|
28
|
+
ok: true;
|
|
29
|
+
urls: string[];
|
|
30
|
+
} | {
|
|
31
|
+
ok: false;
|
|
32
|
+
error: string;
|
|
33
|
+
}>;
|
|
34
|
+
export declare const generateVideoToolDef: ToolDefinition;
|
|
35
|
+
export declare function __setVideoProviderForTests(p: VideoProvider | null): void;
|
|
36
|
+
export declare function isGenerateVideoAvailable(cwd?: string, nowMs?: number): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* List configured, usable video providers (TODO 7.1). Returns [] when no
|
|
39
|
+
* adapters are wired (VIDEO_PROVIDER_KINDS empty) or none configured.
|
|
40
|
+
*/
|
|
41
|
+
export declare function listConfiguredVideoProviders(cwd?: string): Array<{
|
|
42
|
+
id?: string;
|
|
43
|
+
kind: string;
|
|
44
|
+
catalogId?: string;
|
|
45
|
+
}>;
|
|
46
|
+
/** Dynamic GenerateVideo description naming configured providers (TODO 7.1). */
|
|
47
|
+
export declare function generateVideoToolDefFor(cwd: string): ToolDefinition;
|
|
48
|
+
interface ResolvedVideoProvider {
|
|
49
|
+
kind: string;
|
|
50
|
+
creds: VideoProviderCreds;
|
|
51
|
+
defaultModel?: string;
|
|
52
|
+
}
|
|
53
|
+
export declare function __resolveVideoProviderForTests(cwd: string, preferKind?: string): ResolvedVideoProvider | null;
|
|
54
|
+
export declare function generateVideoTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
|
|
55
|
+
export {};
|