@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
package/dist/prompt/composer.js
CHANGED
|
@@ -31,8 +31,13 @@ export class PromptComposer {
|
|
|
31
31
|
*/
|
|
32
32
|
buildUserContextMessage() {
|
|
33
33
|
const instructions = this.getInstructions();
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
// NOTE: memory is intentionally NOT here. It used to be, but memory mutates
|
|
35
|
+
// constantly (extraction, recall usage++/lastUsed, approve/demote), and this
|
|
36
|
+
// message sits in the cacheable system prefix — so every memory change
|
|
37
|
+
// invalidated the whole prefix and re-billed it. Memory now rides
|
|
38
|
+
// buildDynamicContextMessage (tail, past the cache breakpoint), same as the
|
|
39
|
+
// skills listing and git status which had the identical problem.
|
|
40
|
+
if (!instructions)
|
|
36
41
|
return null;
|
|
37
42
|
// Local date, not UTC — toISOString() is UTC and would show the wrong
|
|
38
43
|
// "today" for users whose timezone has crossed midnight (review-2026-05-30).
|
|
@@ -40,10 +45,7 @@ export class PromptComposer {
|
|
|
40
45
|
const ymd = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
41
46
|
const currentDate = `Today's date is ${ymd}.`;
|
|
42
47
|
let content = `<system-reminder>\n${currentDate}\n\n`;
|
|
43
|
-
|
|
44
|
-
content += `${instructions}\n\n`;
|
|
45
|
-
if (memoryContext)
|
|
46
|
-
content += `${memoryContext}\n`;
|
|
48
|
+
content += `${instructions}\n`;
|
|
47
49
|
content += `</system-reminder>`;
|
|
48
50
|
return { role: "user", content };
|
|
49
51
|
}
|
|
@@ -87,6 +89,38 @@ export class PromptComposer {
|
|
|
87
89
|
}
|
|
88
90
|
return gitStatus;
|
|
89
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Per-turn dynamic context, delivered as a trailing <system-reminder> user
|
|
94
|
+
* message rather than baked into the system prefix.
|
|
95
|
+
*
|
|
96
|
+
* Holds the two things that change *within* a session — the skills listing
|
|
97
|
+
* (changes when a skill is installed/disabled) and the git-status snapshot
|
|
98
|
+
* (changes whenever the working tree changes). Keeping them out of the
|
|
99
|
+
* system prompt means installing a skill or editing a file no longer
|
|
100
|
+
* invalidates the cached system prefix. Placed at the END of the messages
|
|
101
|
+
* array (after the user task) so it sits past the conversation's cache
|
|
102
|
+
* breakpoint — a change here never re-bills the history prefix.
|
|
103
|
+
*/
|
|
104
|
+
async buildDynamicContextMessage() {
|
|
105
|
+
const skills = scanSkills(this.options.cwd, {
|
|
106
|
+
disabledSkills: this.options.disabledSkills,
|
|
107
|
+
disabledPlugins: this.options.disabledPlugins,
|
|
108
|
+
skillAllowlist: this.options.skillAllowlist,
|
|
109
|
+
});
|
|
110
|
+
const skillsListing = buildSkillListing(skills);
|
|
111
|
+
const gitStatus = await this.buildSystemContext();
|
|
112
|
+
// Memory rides here (tail, past the cache breakpoint) — not the system
|
|
113
|
+
// prefix — so a memory change (extraction / recall usage++ / approve) never
|
|
114
|
+
// re-bills the cached prefix. See buildUserContextMessage for the rationale.
|
|
115
|
+
const memoryContext = this.getMemoryContext();
|
|
116
|
+
const parts = [skillsListing, gitStatus, memoryContext].filter(Boolean);
|
|
117
|
+
if (parts.length === 0)
|
|
118
|
+
return null;
|
|
119
|
+
return {
|
|
120
|
+
role: "user",
|
|
121
|
+
content: `<system-reminder>\n${parts.join("\n\n")}\n</system-reminder>`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
90
124
|
invalidateCache(sectionName) {
|
|
91
125
|
this.sectionCache.invalidate(sectionName);
|
|
92
126
|
if (!sectionName) {
|
|
@@ -129,25 +163,31 @@ export class PromptComposer {
|
|
|
129
163
|
},
|
|
130
164
|
});
|
|
131
165
|
}
|
|
132
|
-
// Behavioral instructions — loaded from preset's section files
|
|
166
|
+
// Behavioral instructions — loaded from preset's section files. Pass the
|
|
167
|
+
// turn's effective tool names so tool-gated sections (e.g. "browser") drop
|
|
168
|
+
// when their tools are disabled: browser capability = tools + instructions
|
|
169
|
+
// as one on/off unit.
|
|
170
|
+
const activeToolNames = tools.map((t) => t.name);
|
|
133
171
|
sections.push({
|
|
134
172
|
name: "behavior",
|
|
173
|
+
// cacheBreak: this section's content varies by activeToolNames (tool-gated
|
|
174
|
+
// sections like "browser" drop when their tools are off). The cache is
|
|
175
|
+
// keyed by section NAME only, so without cacheBreak a reused composer could
|
|
176
|
+
// serve a stale behavior block across an on/off change. Recompute always —
|
|
177
|
+
// it's a cheap string join, and it makes the browser on/off unit correct
|
|
178
|
+
// regardless of composer lifetime.
|
|
179
|
+
cacheBreak: true,
|
|
135
180
|
compute: () => {
|
|
136
181
|
const preset = this.options.preset ?? resolveAgentPreset();
|
|
137
|
-
return buildPresetSystemPrompt(preset);
|
|
138
|
-
},
|
|
139
|
-
});
|
|
140
|
-
// Skills listing
|
|
141
|
-
sections.push({
|
|
142
|
-
name: "skills",
|
|
143
|
-
compute: () => {
|
|
144
|
-
const skills = scanSkills(this.options.cwd, {
|
|
145
|
-
disabledSkills: this.options.disabledSkills,
|
|
146
|
-
disabledPlugins: this.options.disabledPlugins,
|
|
147
|
-
});
|
|
148
|
-
return buildSkillListing(skills);
|
|
182
|
+
return buildPresetSystemPrompt(preset, activeToolNames);
|
|
149
183
|
},
|
|
150
184
|
});
|
|
185
|
+
// Skills listing is intentionally NOT a system section: it changes when a
|
|
186
|
+
// skill is installed/disabled, which would invalidate the whole cached
|
|
187
|
+
// system prefix on every change. It rides in the per-turn dynamic-context
|
|
188
|
+
// message instead (buildDynamicContextMessage). Same reasoning keeps the
|
|
189
|
+
// git-status snapshot out of the system prefix — see buildSystemContext's
|
|
190
|
+
// callers.
|
|
151
191
|
// Append system prompt
|
|
152
192
|
if (this.options.appendSystemPrompt) {
|
|
153
193
|
sections.push({
|
|
@@ -183,8 +223,14 @@ export class PromptComposer {
|
|
|
183
223
|
}
|
|
184
224
|
getMemoryContext() {
|
|
185
225
|
try {
|
|
186
|
-
|
|
187
|
-
|
|
226
|
+
// Two-layer injection (用户拍板): a compact index merging GLOBAL +
|
|
227
|
+
// PROJECT memories. Global memories are now surfaced every session
|
|
228
|
+
// regardless of cwd (the fix for "global memory never shows up"); the
|
|
229
|
+
// model reads full bodies on demand via MemoryRead.
|
|
230
|
+
return MemoryManager.buildInjectionIndex({
|
|
231
|
+
projectDir: this.options.cwd,
|
|
232
|
+
maxAgeDays: this.options.memoriesMaxAgeDays,
|
|
233
|
+
});
|
|
188
234
|
}
|
|
189
235
|
catch {
|
|
190
236
|
return "";
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { readFileSync, existsSync, readdirSync, statSync } from "node:fs";
|
|
18
18
|
import { join, dirname, resolve } from "node:path";
|
|
19
19
|
import { execSync } from "node:child_process";
|
|
20
|
-
import {
|
|
20
|
+
import { userHome } from "../settings/manager.js";
|
|
21
21
|
// ─── Public API ─────────────────────────────────────────────────────
|
|
22
22
|
/**
|
|
23
23
|
* Scan for instruction files from cwd up to the project root,
|
|
@@ -32,8 +32,10 @@ export function scanInstructions(cwd, options = {}) {
|
|
|
32
32
|
const configDirs = [".codeshell", ...(options.scanDirs ?? []), ".claude"];
|
|
33
33
|
const entries = [];
|
|
34
34
|
// 1. User-level instructions
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
// userHome() (not raw homedir(), bun-cached) so a test/host HOME override
|
|
36
|
+
// scans the intended user-level dirs, not the developer's real ~/.code-shell.
|
|
37
|
+
const homeConfigDir = join(userHome(), ".code-shell");
|
|
38
|
+
const homeCompatDir = join(userHome(), ".claude");
|
|
37
39
|
for (const name of allNames) {
|
|
38
40
|
tryAddFile(join(homeConfigDir, name), "user", -1, entries);
|
|
39
41
|
}
|
|
@@ -13,6 +13,7 @@ const BUILTIN_SECTIONS = {
|
|
|
13
13
|
base: readSectionFile("base"),
|
|
14
14
|
orchestration: readSectionFile("orchestration"),
|
|
15
15
|
coding: readSectionFile("coding"),
|
|
16
|
+
browser: readSectionFile("browser"),
|
|
16
17
|
tone: readSectionFile("tone"),
|
|
17
18
|
};
|
|
18
19
|
/** Registry for custom sections added at runtime. */
|
|
@@ -31,5 +31,6 @@ When you encounter an obstacle, do not use destructive actions as a shortcut to
|
|
|
31
31
|
- To search for files use Glob instead of find or ls
|
|
32
32
|
- To search the content of files, use Grep instead of grep or rg
|
|
33
33
|
- Reserve using the Bash exclusively for system commands and terminal operations that require shell execution.
|
|
34
|
+
- For long-lived processes that don't exit on their own — a dev server (`npm run dev`, `vite`), a watcher, a tunnel — call Bash with `run_in_background: true`. It returns a `shell_id` immediately instead of blocking until a timeout. Then use `BashOutput(shell_id)` to read its logs (e.g. to confirm it started or to see an error), `ListShells()` to see what's running, and `KillShell(shell_id)` to stop it. Never run such a command in the foreground — it will just block until it's killed. Plain one-shot commands (build, test, git) stay foreground.
|
|
34
35
|
- Break down and manage multi-step work with the TodoWrite tool. Pass the complete todo list each call; rewrite it as items move pending → in_progress → completed.
|
|
35
36
|
- You can call multiple tools in a single response. If you intend to call multiple tools and there are no dependencies between them, make all independent tool calls in parallel.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Browser automation (browser_observe / browser_act / browser_navigate)
|
|
2
|
+
- When a task needs you to operate a real web page — search a site, open a result, read/extract an article, fill a form — drive the built-in browser panel with the three browser tools. They run on the panel's logged-in session, so the user's existing logins are reused.
|
|
3
|
+
- You do NOT need the user to open the panel first: if none is open, just call `browser_navigate{url}` and the panel opens automatically. After navigating, `browser_act{action:"wait"}` then `browser_observe`.
|
|
4
|
+
- The loop is observe → act → re-observe: ALWAYS `browser_observe` first (default mode `snapshot`) to see the page's interactive elements (each tagged `[ref=eN]`), then `browser_act` on elements BY THAT ref: `{action:"click",ref}`, `{action:"type",ref,text}`, `{action:"select",ref,value}` (native `<select>`), `{action:"hover",ref}`. Refs are only valid for the most recent snapshot — after any navigation, content-loading click, or `{action:"scroll"}`, run `{action:"wait"}` then `browser_observe` again. If an action says a ref is stale, re-observe.
|
|
5
|
+
- To submit a search: `browser_act{action:"type",ref,text}` into the search box, then `browser_act{action:"press_key",key:"Enter"}`, then `{action:"wait"}` + `browser_observe`. `press_key` also does Tab / Escape / arrows / combos like `Control+a`.
|
|
6
|
+
- To extract/summarize page content, navigate/click to it, `browser_act{action:"wait"}`, then `browser_observe{mode:"read"}` — cleaned readable text to summarize (long pages truncate; `{action:"scroll"}` + read again). For the real link/image/video URLs the snapshot omits, use `browser_observe{mode:"extract"}` (each image/video tagged [ref=imgN/vidN]).
|
|
7
|
+
- To SEE an actual image's content (e.g. a 小红书 笔记配图 or product photo), `browser_observe{mode:"extract"}` to get image refs, then `browser_observe{mode:"image", refs:["img3"]}` — it loads the real pixels (works behind hotlink protection). A vidN ref grabs the video's current frame. To see the rendered layout/canvas/chart, `browser_observe{mode:"vision"}` (optionally `ref` for one region). Use images sparingly — they cost tokens; prefer snapshot/read. (Both need a vision-capable model; on a non-vision model they're skipped.) Do NOT repeat `vision` on the same page hoping for a clearer view — one screenshot is all you get. If snapshot/screenshot don't reveal what you need (infinite-scroll/canvas feeds), scroll + re-observe or extract the URLs and act on them — don't loop screenshots.
|
|
8
|
+
- Multiple tabs: `browser_act{action:"list_tabs"}` shows open tabs (tabId/url/title/active); `browser_act{action:"switch_tab", tabId}` makes another the active one (then re-observe). Any action also accepts `tabId` to target a specific tab (it switches first). Refs are per-tab — re-observe after switching.
|
|
9
|
+
- If `browser_observe` reports a sign-in is required (or you hit a login wall / 2FA), STOP and ask the user to log in manually in the browser panel, then continue — do not attempt to enter credentials yourself. Sensitive actions (payment, delete, entering card/password values) require user approval.
|
|
10
|
+
- These tools need the desktop app's browser panel; if they report unavailable, the environment has no panel (headless) — say so rather than retrying.
|
|
@@ -26,6 +26,10 @@ The default job in this preset is software engineering in the current working di
|
|
|
26
26
|
- When referencing specific functions or pieces of code include the pattern file_path:line_number to allow the user to easily navigate to the source code location.
|
|
27
27
|
- When referencing GitHub issues or pull requests, use the owner/repo#123 format so they render as clickable links.
|
|
28
28
|
|
|
29
|
+
## Opening URLs and local previews
|
|
30
|
+
- To show the user a web page or a local dev-server preview, print the address in your reply as a bare URL or a markdown link (e.g. `http://localhost:5173` or [预览](http://localhost:5173)) — do NOT wrap it in backticks. The desktop app turns a link in your answer into a clickable link that opens inside its built-in browser panel; backtick-wrapped URLs render as plain code and are not clickable.
|
|
31
|
+
- Do NOT run shell commands to open a URL (`open <url>` on macOS, `xdg-open` on Linux, `start <url>` on Windows). Those launch the user's external system browser and bypass the in-app browser panel. Start the dev server, then just tell the user the address as a link.
|
|
32
|
+
|
|
29
33
|
## Coding tools
|
|
30
34
|
- Use git/worktree/LSP/notebook tools when they help, but treat them as optional helpers rather than core assumptions.
|
|
31
35
|
- If the user asks for help or feedback, point them to /help and the project repository.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ChatSession } from "./chat-session.js";
|
|
2
2
|
import type { Engine } from "../engine/engine.js";
|
|
3
3
|
import type { EngineRuntime } from "../engine/runtime.js";
|
|
4
|
-
import type { EngineConfig } from "../engine/
|
|
5
|
-
export type EngineConfigSlice = Pick<EngineConfig, "permissionMode" | "preset" | "customSystemPrompt" | "appendSystemPrompt" | "goal" | "maxTurns" | "maxContextTokens" | "cwd">;
|
|
4
|
+
import type { EngineConfig } from "../engine/types.js";
|
|
5
|
+
export type EngineConfigSlice = Pick<EngineConfig, "permissionMode" | "preset" | "customSystemPrompt" | "appendSystemPrompt" | "goal" | "maxTurns" | "maxContextTokens" | "cwd" | "projectTrusted">;
|
|
6
6
|
export interface ChatSessionManagerOptions {
|
|
7
7
|
/**
|
|
8
8
|
* Shared runtime, supplied here so callers and engineFactory closures
|
|
@@ -33,6 +33,12 @@ export declare class ChatSessionManager {
|
|
|
33
33
|
forEachSession(fn: (s: ChatSession) => void): void;
|
|
34
34
|
close(sessionId: string): void;
|
|
35
35
|
closeAll(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Await-able shutdown. Cancels every session and reaps every background
|
|
38
|
+
* shell, *waiting* for the kill grace so a caller that exits the process
|
|
39
|
+
* immediately afterward (the TUI REPL) doesn't orphan detached dev servers.
|
|
40
|
+
*/
|
|
41
|
+
closeAllAsync(): Promise<void>;
|
|
36
42
|
sessionCount(): number;
|
|
37
43
|
sweepIdle(): void;
|
|
38
44
|
startIdleSweeper(intervalMs?: number): void;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ChatSession } from "./chat-session.js";
|
|
2
|
+
import { backgroundShellManager } from "../runtime/background-shell.js";
|
|
3
|
+
import { clearAgentOutputFiles } from "../tool-system/builtin/agent-output-file.js";
|
|
2
4
|
export class ChatSessionManager {
|
|
3
5
|
sessions = new Map();
|
|
4
6
|
factory;
|
|
@@ -14,6 +16,17 @@ export class ChatSessionManager {
|
|
|
14
16
|
const existing = this.sessions.get(sessionId);
|
|
15
17
|
if (existing) {
|
|
16
18
|
existing.lastActivityAt = Date.now();
|
|
19
|
+
// Re-apply the per-send permission mode so a pill change on an
|
|
20
|
+
// already-running session takes effect on the NEXT turn. Without this the
|
|
21
|
+
// engine kept whatever mode it was first created with — changing the pill
|
|
22
|
+
// on a resumed session was silently ignored at enforcement time (#11
|
|
23
|
+
// secondary: "档位 doesn't take effect after first send"). setPermissionMode
|
|
24
|
+
// reconfigures the live permission backend, so it's safe between turns.
|
|
25
|
+
if (slice.permissionMode &&
|
|
26
|
+
typeof existing.engine.getPermissionMode === "function" &&
|
|
27
|
+
existing.engine.getPermissionMode() !== slice.permissionMode) {
|
|
28
|
+
existing.engine.setPermissionMode(slice.permissionMode);
|
|
29
|
+
}
|
|
17
30
|
return existing;
|
|
18
31
|
}
|
|
19
32
|
if (this.sessions.size >= this.maxSessions) {
|
|
@@ -47,8 +60,31 @@ export class ChatSessionManager {
|
|
|
47
60
|
this.sessions.delete(sessionId);
|
|
48
61
|
}
|
|
49
62
|
closeAll() {
|
|
63
|
+
// Fire-and-forget variant for callers that can't await (e.g. AgentServer
|
|
64
|
+
// teardown inside a sync stop path). The TUI exit path uses closeAllAsync()
|
|
65
|
+
// below so the SIGTERM→SIGKILL grace actually completes before the process
|
|
66
|
+
// exits — otherwise startInkRepl's process.exit(0) races the kill and the
|
|
67
|
+
// detached shells leak as orphans.
|
|
68
|
+
void this.closeAllAsync();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Await-able shutdown. Cancels every session and reaps every background
|
|
72
|
+
* shell, *waiting* for the kill grace so a caller that exits the process
|
|
73
|
+
* immediately afterward (the TUI REPL) doesn't orphan detached dev servers.
|
|
74
|
+
*/
|
|
75
|
+
async closeAllAsync() {
|
|
50
76
|
for (const id of [...this.sessions.keys()])
|
|
51
77
|
this.close(id);
|
|
78
|
+
// App/worker shutdown — reap every background shell so a detached
|
|
79
|
+
// `npm run dev` doesn't outlive the process as an orphan holding a port
|
|
80
|
+
// (design §6 / §难点1). NOTE: deliberately NOT in close()/sweepIdle() —
|
|
81
|
+
// an idle chat tab must keep its dev server alive (§6 "切走再回来 server 还在").
|
|
82
|
+
await backgroundShellManager.killAll();
|
|
83
|
+
// Background-agent output files are a debugging convenience, not durable
|
|
84
|
+
// state — wipe them on shutdown so ~/.code-shell/agents doesn't grow
|
|
85
|
+
// unbounded across runs. (notificationQueue, the real result path, is
|
|
86
|
+
// in-memory and already gone.)
|
|
87
|
+
await clearAgentOutputFiles();
|
|
52
88
|
}
|
|
53
89
|
sessionCount() {
|
|
54
90
|
return this.sessions.size;
|
|
@@ -13,6 +13,10 @@ export interface TurnOpts {
|
|
|
13
13
|
/** Goal mode for this turn — forwarded to engine.run (loop-until-done).
|
|
14
14
|
* String objective or full GoalConfig (objective + optional budgets). */
|
|
15
15
|
goal?: string | import("../engine/goal.js").GoalConfig;
|
|
16
|
+
/** Marks this turn as a synthetic system-reminder injection (background-job
|
|
17
|
+
* completion notification) rather than the user's own input — persisted so
|
|
18
|
+
* the disk reader skips it as a user bubble on replay. See Engine.run. */
|
|
19
|
+
injected?: boolean;
|
|
16
20
|
}
|
|
17
21
|
/**
|
|
18
22
|
* One ChatSession per UI chat tab. Owns a single Engine, an AbortController
|
|
@@ -42,8 +46,32 @@ export declare class ChatSession {
|
|
|
42
46
|
* session-isolation research flagged. null = nothing pending.
|
|
43
47
|
*/
|
|
44
48
|
private pendingModel;
|
|
49
|
+
/**
|
|
50
|
+
* Set by cancel() so the in-flight turn's abort error resolves as a clean
|
|
51
|
+
* "cancelled" result instead of rejecting (which the RPC layer would surface
|
|
52
|
+
* as a scary red Error in the UI for what was a user-initiated Stop). The
|
|
53
|
+
* onboarding flow cancels + immediately re-runs the same task; without this
|
|
54
|
+
* the cancelled first run popped "Error: Request cancelled".
|
|
55
|
+
*/
|
|
56
|
+
private cancelledActive;
|
|
57
|
+
/**
|
|
58
|
+
* Sticky flag: the user cancelled (Stop) and has not started a new turn
|
|
59
|
+
* since. cancel() leaves the session idle (active=null), so isBusy() can't
|
|
60
|
+
* distinguish "naturally idle" from "user just stopped me". A background-job
|
|
61
|
+
* completion that lands in this window must NOT auto-resume the session —
|
|
62
|
+
* that would defeat the Stop. Cleared the moment a real turn is enqueued
|
|
63
|
+
* (the user is engaging again) so normal wakeups resume working afterward.
|
|
64
|
+
*/
|
|
65
|
+
private cancelledSinceLastTurn;
|
|
45
66
|
constructor(opts: ChatSessionOptions);
|
|
46
67
|
enqueueTurn(task: string, opts: TurnOpts): Promise<EngineResult>;
|
|
68
|
+
/**
|
|
69
|
+
* True when the user hit Stop and hasn't started a new turn since. The server
|
|
70
|
+
* consults this before auto-waking an idle session on a background-job
|
|
71
|
+
* completion, so a download finishing right after Stop doesn't restart the
|
|
72
|
+
* agent the user just halted.
|
|
73
|
+
*/
|
|
74
|
+
wasCancelledSinceLastTurn(): boolean;
|
|
47
75
|
/**
|
|
48
76
|
* Abort the in-flight turn and drain queued turns.
|
|
49
77
|
*
|
|
@@ -54,6 +82,34 @@ export declare class ChatSession {
|
|
|
54
82
|
*/
|
|
55
83
|
cancel(): void;
|
|
56
84
|
isBusy(): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Extend the in-flight goal run's turn/budget ceilings (TODO 3.1). Delegates
|
|
87
|
+
* to the engine, which forwards to the active TurnLoop. Returns null when no
|
|
88
|
+
* run is active (or the run has no extendable loop). Mirrors the cancel()
|
|
89
|
+
* mid-run control path.
|
|
90
|
+
*/
|
|
91
|
+
extendGoalRun(opts: {
|
|
92
|
+
addTurns?: number;
|
|
93
|
+
addTokenBudget?: number;
|
|
94
|
+
addTimeBudgetMs?: number;
|
|
95
|
+
addStopBlocks?: number;
|
|
96
|
+
}): {
|
|
97
|
+
maxTurns: number;
|
|
98
|
+
tokenBudget?: number;
|
|
99
|
+
timeBudgetMs?: number;
|
|
100
|
+
maxStopBlocks: number;
|
|
101
|
+
} | null;
|
|
102
|
+
/**
|
|
103
|
+
* Read this session's persisted active goal (state.activeGoal), or undefined
|
|
104
|
+
* when none. Cheap — reads only state.json. The host calls this on session
|
|
105
|
+
* load to re-surface the goal block + Cancel button after a reload.
|
|
106
|
+
*/
|
|
107
|
+
getGoal(): import("../engine/goal.js").GoalConfig | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Clear this session's persisted active goal (CC /goal clear). Works idle or
|
|
110
|
+
* mid-run. Returns true if a goal was actually cleared.
|
|
111
|
+
*/
|
|
112
|
+
clearGoal(): boolean;
|
|
57
113
|
/**
|
|
58
114
|
* Switch this session's active model (per-session, not worker-global).
|
|
59
115
|
* Applies immediately when idle; defers to the next run boundary when a
|
|
@@ -61,6 +117,15 @@ export declare class ChatSession {
|
|
|
61
117
|
* running LLM client.
|
|
62
118
|
*/
|
|
63
119
|
requestModelSwitch(key: string): void;
|
|
120
|
+
/**
|
|
121
|
+
* Perform the actual model switch for this session: rotate the engine's model
|
|
122
|
+
* and reset the session's cumulative usage on disk — a different model has a
|
|
123
|
+
* different prompt cache, so the old cache-hit stats no longer apply. The
|
|
124
|
+
* renderer zeroes its own cumulative display when it issues the switch (it's
|
|
125
|
+
* renderer-initiated), so no stream event is needed here. Shared by the idle
|
|
126
|
+
* path and the deferred run-boundary path.
|
|
127
|
+
*/
|
|
128
|
+
private applyModelSwitch;
|
|
64
129
|
queueDepth(): number;
|
|
65
130
|
private pump;
|
|
66
131
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isAbortError } from "../llm/client-base.js";
|
|
1
2
|
/**
|
|
2
3
|
* One ChatSession per UI chat tab. Owns a single Engine, an AbortController
|
|
3
4
|
* for the active turn, and a FIFO queue so a fast second send waits for the
|
|
@@ -26,6 +27,23 @@ export class ChatSession {
|
|
|
26
27
|
* session-isolation research flagged. null = nothing pending.
|
|
27
28
|
*/
|
|
28
29
|
pendingModel = null;
|
|
30
|
+
/**
|
|
31
|
+
* Set by cancel() so the in-flight turn's abort error resolves as a clean
|
|
32
|
+
* "cancelled" result instead of rejecting (which the RPC layer would surface
|
|
33
|
+
* as a scary red Error in the UI for what was a user-initiated Stop). The
|
|
34
|
+
* onboarding flow cancels + immediately re-runs the same task; without this
|
|
35
|
+
* the cancelled first run popped "Error: Request cancelled".
|
|
36
|
+
*/
|
|
37
|
+
cancelledActive = false;
|
|
38
|
+
/**
|
|
39
|
+
* Sticky flag: the user cancelled (Stop) and has not started a new turn
|
|
40
|
+
* since. cancel() leaves the session idle (active=null), so isBusy() can't
|
|
41
|
+
* distinguish "naturally idle" from "user just stopped me". A background-job
|
|
42
|
+
* completion that lands in this window must NOT auto-resume the session —
|
|
43
|
+
* that would defeat the Stop. Cleared the moment a real turn is enqueued
|
|
44
|
+
* (the user is engaging again) so normal wakeups resume working afterward.
|
|
45
|
+
*/
|
|
46
|
+
cancelledSinceLastTurn = false;
|
|
29
47
|
constructor(opts) {
|
|
30
48
|
this.id = opts.id;
|
|
31
49
|
this.engine = opts.engine;
|
|
@@ -33,11 +51,24 @@ export class ChatSession {
|
|
|
33
51
|
}
|
|
34
52
|
enqueueTurn(task, opts) {
|
|
35
53
|
this.lastActivityAt = Date.now();
|
|
54
|
+
// The user (or a wakeup the guard already let through) is starting a turn —
|
|
55
|
+
// clear the post-Stop suppression so future background-job completions
|
|
56
|
+
// wake the session again.
|
|
57
|
+
this.cancelledSinceLastTurn = false;
|
|
36
58
|
return new Promise((resolve, reject) => {
|
|
37
59
|
this.queue.push({ task, opts, resolve, reject });
|
|
38
60
|
this.pump();
|
|
39
61
|
});
|
|
40
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* True when the user hit Stop and hasn't started a new turn since. The server
|
|
65
|
+
* consults this before auto-waking an idle session on a background-job
|
|
66
|
+
* completion, so a download finishing right after Stop doesn't restart the
|
|
67
|
+
* agent the user just halted.
|
|
68
|
+
*/
|
|
69
|
+
wasCancelledSinceLastTurn() {
|
|
70
|
+
return this.cancelledSinceLastTurn;
|
|
71
|
+
}
|
|
41
72
|
/**
|
|
42
73
|
* Abort the in-flight turn and drain queued turns.
|
|
43
74
|
*
|
|
@@ -47,6 +78,12 @@ export class ChatSession {
|
|
|
47
78
|
* are always rejected regardless.
|
|
48
79
|
*/
|
|
49
80
|
cancel() {
|
|
81
|
+
// Mark the in-flight turn as user-cancelled so pump()'s catch resolves it
|
|
82
|
+
// as a clean aborted result rather than rejecting (→ UI Error).
|
|
83
|
+
if (this.active)
|
|
84
|
+
this.cancelledActive = true;
|
|
85
|
+
// Suppress auto-wakeup until the user engages again (see the field doc).
|
|
86
|
+
this.cancelledSinceLastTurn = true;
|
|
50
87
|
this.controller?.abort();
|
|
51
88
|
// Drain queued turns as cancelled
|
|
52
89
|
const drained = this.queue.splice(0);
|
|
@@ -57,6 +94,30 @@ export class ChatSession {
|
|
|
57
94
|
isBusy() {
|
|
58
95
|
return this.active !== null;
|
|
59
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Extend the in-flight goal run's turn/budget ceilings (TODO 3.1). Delegates
|
|
99
|
+
* to the engine, which forwards to the active TurnLoop. Returns null when no
|
|
100
|
+
* run is active (or the run has no extendable loop). Mirrors the cancel()
|
|
101
|
+
* mid-run control path.
|
|
102
|
+
*/
|
|
103
|
+
extendGoalRun(opts) {
|
|
104
|
+
return this.engine.extendGoalRun(opts);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Read this session's persisted active goal (state.activeGoal), or undefined
|
|
108
|
+
* when none. Cheap — reads only state.json. The host calls this on session
|
|
109
|
+
* load to re-surface the goal block + Cancel button after a reload.
|
|
110
|
+
*/
|
|
111
|
+
getGoal() {
|
|
112
|
+
return this.engine.getGoal(this.id);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Clear this session's persisted active goal (CC /goal clear). Works idle or
|
|
116
|
+
* mid-run. Returns true if a goal was actually cleared.
|
|
117
|
+
*/
|
|
118
|
+
clearGoal() {
|
|
119
|
+
return this.engine.clearGoal(this.id);
|
|
120
|
+
}
|
|
60
121
|
/**
|
|
61
122
|
* Switch this session's active model (per-session, not worker-global).
|
|
62
123
|
* Applies immediately when idle; defers to the next run boundary when a
|
|
@@ -68,7 +129,19 @@ export class ChatSession {
|
|
|
68
129
|
this.pendingModel = key;
|
|
69
130
|
return;
|
|
70
131
|
}
|
|
132
|
+
this.applyModelSwitch(key);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Perform the actual model switch for this session: rotate the engine's model
|
|
136
|
+
* and reset the session's cumulative usage on disk — a different model has a
|
|
137
|
+
* different prompt cache, so the old cache-hit stats no longer apply. The
|
|
138
|
+
* renderer zeroes its own cumulative display when it issues the switch (it's
|
|
139
|
+
* renderer-initiated), so no stream event is needed here. Shared by the idle
|
|
140
|
+
* path and the deferred run-boundary path.
|
|
141
|
+
*/
|
|
142
|
+
applyModelSwitch(key) {
|
|
71
143
|
this.engine.switchModel(key);
|
|
144
|
+
this.engine.resetSessionUsage(this.id);
|
|
72
145
|
}
|
|
73
146
|
queueDepth() {
|
|
74
147
|
return this.queue.length;
|
|
@@ -80,6 +153,7 @@ export class ChatSession {
|
|
|
80
153
|
if (!next)
|
|
81
154
|
return;
|
|
82
155
|
this.active = next;
|
|
156
|
+
this.cancelledActive = false;
|
|
83
157
|
this.controller = new AbortController();
|
|
84
158
|
try {
|
|
85
159
|
const onStream = next.opts.onStream ?? this.defaultOnStream;
|
|
@@ -89,21 +163,39 @@ export class ChatSession {
|
|
|
89
163
|
signal: this.controller.signal,
|
|
90
164
|
onStream,
|
|
91
165
|
goal: next.opts.goal,
|
|
166
|
+
injected: next.opts.injected,
|
|
92
167
|
});
|
|
93
168
|
this.lastActivityAt = Date.now();
|
|
94
169
|
next.resolve(result);
|
|
95
170
|
}
|
|
96
171
|
catch (err) {
|
|
97
|
-
|
|
172
|
+
// A user-initiated cancel (Stop, or the onboarding cancel+rerun flow)
|
|
173
|
+
// aborts the in-flight run. That's not a failure — resolve it as a clean
|
|
174
|
+
// aborted result so the RPC layer doesn't surface "Error: Request
|
|
175
|
+
// cancelled" in the UI. Only abort errors on a cancelled turn are
|
|
176
|
+
// swallowed this way; a genuine error still rejects.
|
|
177
|
+
if (this.cancelledActive && (isAbortError(err) || this.controller?.signal.aborted)) {
|
|
178
|
+
next.resolve({
|
|
179
|
+
text: "",
|
|
180
|
+
reason: "aborted_streaming",
|
|
181
|
+
sessionId: this.id,
|
|
182
|
+
turnCount: 0,
|
|
183
|
+
usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
next.reject(err);
|
|
188
|
+
}
|
|
98
189
|
}
|
|
99
190
|
finally {
|
|
100
191
|
this.active = null;
|
|
101
192
|
this.controller = null;
|
|
193
|
+
this.cancelledActive = false;
|
|
102
194
|
// Run boundary: apply any model switch that was deferred because it was
|
|
103
195
|
// requested mid-run. Done here (not in pump) so it still applies when
|
|
104
196
|
// no further turn is queued.
|
|
105
197
|
if (this.pendingModel !== null) {
|
|
106
|
-
this.
|
|
198
|
+
this.applyModelSwitch(this.pendingModel);
|
|
107
199
|
this.pendingModel = null;
|
|
108
200
|
}
|
|
109
201
|
// Drain the next turn if one is waiting.
|
|
@@ -64,6 +64,33 @@ export declare class AgentClient {
|
|
|
64
64
|
* Legacy form: cancel(reason?)
|
|
65
65
|
*/
|
|
66
66
|
cancel(sessionId?: string, reason?: string): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Clear a session's persisted active goal (CC `/goal clear`). Returns whether
|
|
69
|
+
* a goal was actually cleared (false = there was none).
|
|
70
|
+
*/
|
|
71
|
+
goalClear(sessionId?: string): Promise<boolean>;
|
|
72
|
+
/**
|
|
73
|
+
* Read a session's persisted active goal objective, or null when there's
|
|
74
|
+
* none. The host calls this on session load to re-surface the goal block +
|
|
75
|
+
* Cancel button after a reload (a persistent goal isn't replayed from the
|
|
76
|
+
* transcript, so the live stream never re-announces it).
|
|
77
|
+
*/
|
|
78
|
+
goalGet(sessionId: string): Promise<string | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Steer an in-flight run: queue a user message spliced in at the next
|
|
81
|
+
* turn-loop step (不打断 — does not abort the current step). `id` is a stable
|
|
82
|
+
* host-side handle that rides through to the steer_injected event and lets
|
|
83
|
+
* unsteer() revoke a still-pending entry. Mirrors the server's handleSteer +
|
|
84
|
+
* the desktop preload's steer(); without it the SDK can't reach the method
|
|
85
|
+
* (request() is private) — the protocol was asymmetric after the steer merge.
|
|
86
|
+
*/
|
|
87
|
+
steer(sessionId: string, text: string, id?: string): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Revoke a still-pending steer entry by id (before the loop consumes it).
|
|
90
|
+
* Returns false when the loop already consumed it (not an error — it will
|
|
91
|
+
* arrive as a normal user bubble).
|
|
92
|
+
*/
|
|
93
|
+
unsteer(sessionId: string, id: string): Promise<boolean>;
|
|
67
94
|
/**
|
|
68
95
|
* Update runtime configuration on the server.
|
|
69
96
|
*/
|
package/dist/protocol/client.js
CHANGED
|
@@ -99,6 +99,44 @@ export class AgentClient {
|
|
|
99
99
|
async cancel(sessionId, reason) {
|
|
100
100
|
await this.request(Methods.Cancel, { sessionId, reason });
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Clear a session's persisted active goal (CC `/goal clear`). Returns whether
|
|
104
|
+
* a goal was actually cleared (false = there was none).
|
|
105
|
+
*/
|
|
106
|
+
async goalClear(sessionId) {
|
|
107
|
+
const res = (await this.request(Methods.GoalClear, { sessionId }));
|
|
108
|
+
return res?.cleared === true;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Read a session's persisted active goal objective, or null when there's
|
|
112
|
+
* none. The host calls this on session load to re-surface the goal block +
|
|
113
|
+
* Cancel button after a reload (a persistent goal isn't replayed from the
|
|
114
|
+
* transcript, so the live stream never re-announces it).
|
|
115
|
+
*/
|
|
116
|
+
async goalGet(sessionId) {
|
|
117
|
+
const res = (await this.request(Methods.GoalGet, { sessionId }));
|
|
118
|
+
return res?.goal ?? null;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Steer an in-flight run: queue a user message spliced in at the next
|
|
122
|
+
* turn-loop step (不打断 — does not abort the current step). `id` is a stable
|
|
123
|
+
* host-side handle that rides through to the steer_injected event and lets
|
|
124
|
+
* unsteer() revoke a still-pending entry. Mirrors the server's handleSteer +
|
|
125
|
+
* the desktop preload's steer(); without it the SDK can't reach the method
|
|
126
|
+
* (request() is private) — the protocol was asymmetric after the steer merge.
|
|
127
|
+
*/
|
|
128
|
+
async steer(sessionId, text, id) {
|
|
129
|
+
await this.request(Methods.Steer, { sessionId, text, id });
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Revoke a still-pending steer entry by id (before the loop consumes it).
|
|
133
|
+
* Returns false when the loop already consumed it (not an error — it will
|
|
134
|
+
* arrive as a normal user bubble).
|
|
135
|
+
*/
|
|
136
|
+
async unsteer(sessionId, id) {
|
|
137
|
+
const res = (await this.request(Methods.Unsteer, { sessionId, id }));
|
|
138
|
+
return res?.removed === true;
|
|
139
|
+
}
|
|
102
140
|
/**
|
|
103
141
|
* Update runtime configuration on the server.
|
|
104
142
|
*/
|