@sayknow-cli/coding-agent 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/skc.js +4 -0
- package/dist/types/cli/mcp-cli.d.ts +25 -0
- package/dist/types/cli/notify-cli.d.ts +2 -0
- package/dist/types/cli/plugin-cli.d.ts +2 -0
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/commands/mcp.d.ts +70 -0
- package/dist/types/commands/plugin.d.ts +6 -0
- package/dist/types/commands/session.d.ts +6 -0
- package/dist/types/config/keybindings.d.ts +2 -2
- package/dist/types/config/model-profile-activation.d.ts +8 -1
- package/dist/types/config/settings-schema.d.ts +39 -2
- package/dist/types/deep-interview/plaintext-gate-guard.d.ts +11 -0
- package/dist/types/defaults/skc-defaults.d.ts +2 -13
- package/dist/types/extensibility/shared-events.d.ts +1 -0
- package/dist/types/extensibility/skc-plugins/compiler.d.ts +19 -0
- package/dist/types/extensibility/skc-plugins/constrained-hooks.d.ts +29 -0
- package/dist/types/extensibility/skc-plugins/index.d.ts +9 -0
- package/dist/types/extensibility/skc-plugins/injection.d.ts +9 -0
- package/dist/types/extensibility/skc-plugins/installer.d.ts +13 -0
- package/dist/types/extensibility/skc-plugins/mcp-policy.d.ts +26 -0
- package/dist/types/extensibility/skc-plugins/observability.d.ts +27 -0
- package/dist/types/extensibility/skc-plugins/prompt-appendix.d.ts +16 -0
- package/dist/types/extensibility/skc-plugins/registry.d.ts +32 -0
- package/dist/types/extensibility/skc-plugins/runtime-adapters.d.ts +64 -0
- package/dist/types/extensibility/skc-plugins/session-validation.d.ts +42 -0
- package/dist/types/extensibility/skc-plugins/types.d.ts +158 -2
- package/dist/types/extensibility/skc-plugins/validation.d.ts +8 -1
- package/dist/types/lsp/types.d.ts +2 -0
- package/dist/types/main.d.ts +2 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -1
- package/dist/types/modes/components/model-selector.d.ts +8 -0
- package/dist/types/modes/components/status-line/git-utils.d.ts +6 -0
- package/dist/types/modes/theme/defaults/index.d.ts +99 -0
- package/dist/types/notifications/attachment-registry.d.ts +17 -0
- package/dist/types/notifications/chat-adapters.d.ts +9 -0
- package/dist/types/notifications/config.d.ts +9 -1
- package/dist/types/notifications/engine.d.ts +59 -0
- package/dist/types/notifications/html-format.d.ts +11 -0
- package/dist/types/notifications/index.d.ts +149 -1
- package/dist/types/notifications/lifecycle-commands.d.ts +60 -0
- package/dist/types/notifications/lifecycle-control-runtime.d.ts +98 -0
- package/dist/types/notifications/lifecycle-orchestrator.d.ts +144 -0
- package/dist/types/notifications/managed-daemon.d.ts +48 -0
- package/dist/types/notifications/operator-runtime.d.ts +52 -0
- package/dist/types/notifications/rate-limit-pool.d.ts +2 -0
- package/dist/types/notifications/recent-activity.d.ts +35 -0
- package/dist/types/notifications/telegram-daemon.d.ts +133 -16
- package/dist/types/notifications/telegram-reference.d.ts +3 -1
- package/dist/types/notifications/threaded-inbound.d.ts +19 -0
- package/dist/types/notifications/threaded-render.d.ts +6 -1
- package/dist/types/notifications/topic-registry.d.ts +12 -9
- package/dist/types/runtime-mcp/types.d.ts +7 -0
- package/dist/types/sdk.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +16 -4
- package/dist/types/session/blob-store.d.ts +25 -0
- package/dist/types/session/session-manager.d.ts +57 -0
- package/dist/types/skc-runtime/launch-tmux.d.ts +1 -0
- package/dist/types/skc-runtime/psmux-detect.d.ts +78 -0
- package/dist/types/skc-runtime/ralplan-runtime.d.ts +1 -1
- package/dist/types/skc-runtime/team-runtime.d.ts +2 -0
- package/dist/types/skc-runtime/tmux-common.d.ts +30 -2
- package/dist/types/skc-runtime/tmux-sessions.d.ts +18 -0
- package/dist/types/slash-commands/helpers/fast-status-report.d.ts +6 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +9 -1
- package/dist/types/tools/composer-bash-policy.d.ts +14 -0
- package/dist/types/tools/fetch.d.ts +23 -0
- package/dist/types/tools/index.d.ts +4 -1
- package/dist/types/tools/telegram-send.d.ts +32 -0
- package/dist/types/utils/changelog.d.ts +1 -0
- package/dist/types/web/insane/bridge.d.ts +103 -0
- package/dist/types/web/insane/url-guard.d.ts +25 -0
- package/dist/types/web/scrapers/types.d.ts +5 -0
- package/dist/types/web/scrapers/utils.d.ts +7 -1
- package/dist/types/web/search/provider.d.ts +18 -1
- package/dist/types/web/search/providers/insane.d.ts +53 -0
- package/dist/types/web/search/providers/text-citations.d.ts +23 -0
- package/dist/types/web/search/types.d.ts +12 -4
- package/package.json +14 -10
- package/scripts/g004-tmux-smoke.ts +100 -0
- package/scripts/g005-daemon-smoke.ts +180 -0
- package/scripts/g011-daemon-path-smoke.ts +153 -0
- package/scripts/verify-insane-vendor.ts +132 -0
- package/src/cli/args.ts +1 -1
- package/src/cli/fast-help.ts +30 -2
- package/src/cli/mcp-cli.ts +272 -0
- package/src/cli/notify-cli.ts +152 -5
- package/src/cli/plugin-cli.ts +66 -3
- package/src/cli.ts +30 -12
- package/src/commands/mcp.ts +117 -0
- package/src/commands/plugin.ts +4 -0
- package/src/commands/session.ts +18 -0
- package/src/commands/team.ts +1 -1
- package/src/config/keybindings.ts +2 -2
- package/src/config/model-profile-activation.ts +55 -7
- package/src/config/settings-schema.ts +30 -1
- package/src/deep-interview/plaintext-gate-guard.ts +94 -0
- package/src/defaults/skc/extensions/grok-cli-vendor/biome.json +1 -1
- package/src/defaults/skc/skills/deep-interview/SKILL.md +7 -6
- package/src/defaults/skc/skills/ralplan/SKILL.md +11 -4
- package/src/defaults/skc/skills/team/SKILL.md +5 -3
- package/src/defaults/skc/skills/ultragoal/SKILL.md +41 -13
- package/src/defaults/skc-defaults.ts +2 -27
- package/src/export/html/index.ts +2 -2
- package/src/extensibility/extensions/runner.ts +1 -0
- package/src/extensibility/shared-events.ts +1 -0
- package/src/extensibility/skc-plugins/compiler.ts +351 -0
- package/src/extensibility/skc-plugins/constrained-hooks.ts +170 -0
- package/src/extensibility/skc-plugins/index.ts +9 -0
- package/src/extensibility/skc-plugins/injection.ts +109 -0
- package/src/extensibility/skc-plugins/installer.ts +434 -0
- package/src/extensibility/skc-plugins/loader.ts +3 -1
- package/src/extensibility/skc-plugins/mcp-policy.ts +239 -0
- package/src/extensibility/skc-plugins/observability.ts +84 -0
- package/src/extensibility/skc-plugins/paths.ts +1 -1
- package/src/extensibility/skc-plugins/prompt-appendix.ts +109 -0
- package/src/extensibility/skc-plugins/registry.ts +180 -0
- package/src/extensibility/skc-plugins/runtime-adapters.ts +234 -0
- package/src/extensibility/skc-plugins/schema.ts +250 -20
- package/src/extensibility/skc-plugins/session-validation.ts +147 -0
- package/src/extensibility/skc-plugins/types.ts +199 -3
- package/src/extensibility/skc-plugins/validation.ts +80 -0
- package/src/extensibility/skills.ts +15 -0
- package/src/hooks/skill-state.ts +57 -0
- package/src/internal-urls/docs-index.generated.ts +17 -13
- package/src/lsp/config.ts +16 -3
- package/src/lsp/defaults.json +7 -0
- package/src/lsp/types.ts +2 -0
- package/src/main.ts +14 -3
- package/src/modes/bridge/bridge-mode.ts +11 -0
- package/src/modes/components/assistant-message.ts +49 -1
- package/src/modes/components/custom-editor.ts +2 -0
- package/src/modes/components/footer.ts +2 -3
- package/src/modes/components/hook-editor.ts +1 -1
- package/src/modes/components/hook-selector.ts +67 -43
- package/src/modes/components/model-selector.ts +56 -11
- package/src/modes/components/status-line/git-utils.ts +25 -0
- package/src/modes/components/status-line.ts +10 -11
- package/src/modes/components/welcome.ts +2 -3
- package/src/modes/controllers/event-controller.ts +15 -0
- package/src/modes/controllers/extension-ui-controller.ts +0 -27
- package/src/modes/controllers/selector-controller.ts +53 -11
- package/src/modes/interactive-mode.ts +50 -3
- package/src/modes/shared/agent-wire/scopes.ts +1 -1
- package/src/modes/theme/defaults/gruvbox-dark.json +99 -0
- package/src/modes/theme/defaults/index.ts +2 -0
- package/src/modes/utils/context-usage.ts +2 -2
- package/src/modes/utils/hotkeys-markdown.ts +1 -1
- package/src/notifications/attachment-registry.ts +23 -0
- package/src/notifications/chat-adapters.ts +147 -0
- package/src/notifications/config.ts +23 -2
- package/src/notifications/engine.ts +100 -0
- package/src/notifications/html-format.ts +38 -0
- package/src/notifications/index.ts +417 -45
- package/src/notifications/lifecycle-commands.ts +238 -0
- package/src/notifications/lifecycle-control-runtime.ts +405 -0
- package/src/notifications/lifecycle-orchestrator.ts +358 -0
- package/src/notifications/managed-daemon.ts +163 -0
- package/src/notifications/operator-runtime.ts +171 -0
- package/src/notifications/rate-limit-pool.ts +19 -0
- package/src/notifications/recent-activity.ts +132 -0
- package/src/notifications/telegram-daemon.ts +984 -242
- package/src/notifications/telegram-reference.ts +25 -7
- package/src/notifications/threaded-inbound.ts +60 -4
- package/src/notifications/threaded-render.ts +20 -2
- package/src/notifications/topic-registry.ts +23 -9
- package/src/prompts/agents/executor.md +2 -2
- package/src/runtime-mcp/transports/stdio.ts +38 -4
- package/src/runtime-mcp/types.ts +7 -0
- package/src/sdk.ts +157 -10
- package/src/session/agent-session.ts +248 -125
- package/src/session/blob-store.ts +196 -8
- package/src/session/session-manager.ts +762 -12
- package/src/skc-runtime/launch-tmux.ts +85 -22
- package/src/skc-runtime/ledger-event-renderer.ts +1 -0
- package/src/skc-runtime/psmux-detect.ts +239 -0
- package/src/skc-runtime/ralplan-runtime.ts +2 -2
- package/src/skc-runtime/team-runtime.ts +56 -23
- package/src/skc-runtime/tmux-common.ts +88 -4
- package/src/skc-runtime/tmux-sessions.ts +111 -9
- package/src/skc-runtime/ultragoal-guard.ts +25 -8
- package/src/skc-runtime/ultragoal-runtime.ts +75 -15
- package/src/skc-runtime/workflow-manifest.generated.json +29 -0
- package/src/skc-runtime/workflow-manifest.ts +7 -2
- package/src/slash-commands/builtin-registry.ts +23 -3
- package/src/slash-commands/helpers/fast-status-report.ts +13 -3
- package/src/slash-commands/helpers/parse.ts +2 -1
- package/src/system-prompt.ts +9 -0
- package/src/task/executor.ts +31 -7
- package/src/task/index.ts +2 -0
- package/src/tools/ask.ts +5 -1
- package/src/tools/bash.ts +9 -0
- package/src/tools/composer-bash-policy.ts +96 -0
- package/src/tools/fetch.ts +94 -1
- package/src/tools/index.ts +6 -1
- package/src/tools/telegram-send.ts +137 -0
- package/src/utils/changelog.ts +8 -0
- package/src/web/insane/bridge.ts +350 -0
- package/src/web/insane/url-guard.ts +159 -0
- package/src/web/scrapers/types.ts +143 -45
- package/src/web/scrapers/utils.ts +70 -19
- package/src/web/search/provider.ts +77 -18
- package/src/web/search/providers/anthropic.ts +70 -3
- package/src/web/search/providers/codex.ts +1 -119
- package/src/web/search/providers/gemini.ts +99 -0
- package/src/web/search/providers/insane.ts +551 -0
- package/src/web/search/providers/openai-compatible.ts +66 -32
- package/src/web/search/providers/text-citations.ts +111 -0
- package/src/web/search/types.ts +13 -2
- package/vendor/insane-search/LICENSE +21 -0
- package/vendor/insane-search/MANIFEST.json +24 -0
- package/vendor/insane-search/engine/__init__.py +23 -0
- package/vendor/insane-search/engine/__main__.py +128 -0
- package/vendor/insane-search/engine/bias_check.py +183 -0
- package/vendor/insane-search/engine/executor.py +254 -0
- package/vendor/insane-search/engine/fetch_chain.py +725 -0
- package/vendor/insane-search/engine/learning.py +175 -0
- package/vendor/insane-search/engine/phase0.py +214 -0
- package/vendor/insane-search/engine/safety.py +91 -0
- package/vendor/insane-search/engine/templates/package.json +11 -0
- package/vendor/insane-search/engine/templates/playwright_mobile_chrome.js +188 -0
- package/vendor/insane-search/engine/templates/playwright_real_chrome.js +243 -0
- package/vendor/insane-search/engine/tests/test_hardening.py +57 -0
- package/vendor/insane-search/engine/tests/test_smoke.py +152 -0
- package/vendor/insane-search/engine/tests/test_u1.py +200 -0
- package/vendor/insane-search/engine/tests/test_u4.py +131 -0
- package/vendor/insane-search/engine/tests/test_u5.py +163 -0
- package/vendor/insane-search/engine/tests/test_u7.py +124 -0
- package/vendor/insane-search/engine/transport.py +211 -0
- package/vendor/insane-search/engine/url_transforms.py +98 -0
- package/vendor/insane-search/engine/validators.py +331 -0
- package/vendor/insane-search/engine/waf_detector.py +214 -0
- package/vendor/insane-search/engine/waf_profiles.yaml +162 -0
|
@@ -50,7 +50,11 @@ import {
|
|
|
50
50
|
type SummaryOptions,
|
|
51
51
|
shouldCompact,
|
|
52
52
|
} from "@sayknow-cli/agent-core/compaction";
|
|
53
|
-
import {
|
|
53
|
+
import {
|
|
54
|
+
DEFAULT_PRUNE_CONFIG,
|
|
55
|
+
pruneAssistantToolArguments,
|
|
56
|
+
pruneToolOutputs,
|
|
57
|
+
} from "@sayknow-cli/agent-core/compaction/pruning";
|
|
54
58
|
import type {
|
|
55
59
|
AssistantMessage,
|
|
56
60
|
Context,
|
|
@@ -127,7 +131,7 @@ import {
|
|
|
127
131
|
import { type AsyncJob, type AsyncJobDeliveryState, AsyncJobManager } from "../async";
|
|
128
132
|
import { reset as resetCapabilities } from "../capability";
|
|
129
133
|
import type { Rule } from "../capability/rule";
|
|
130
|
-
import { MODEL_ROLE_IDS, type ModelRegistry } from "../config/model-registry";
|
|
134
|
+
import { MODEL_ROLE_IDS, type ModelRegistry, SKC_MODEL_ASSIGNMENT_TARGETS } from "../config/model-registry";
|
|
131
135
|
import {
|
|
132
136
|
extractExplicitThinkingSelector,
|
|
133
137
|
formatModelSelectorValue,
|
|
@@ -286,6 +290,8 @@ import { ToolChoiceQueue } from "./tool-choice-queue";
|
|
|
286
290
|
import { YieldQueue } from "./yield-queue";
|
|
287
291
|
|
|
288
292
|
/** Session-specific events that extend the core AgentEvent */
|
|
293
|
+
export type AutoCompactionContinuationSkipReason = "auto_continue_disabled_non_resumable_tail";
|
|
294
|
+
|
|
289
295
|
export type AgentSessionEvent =
|
|
290
296
|
| AgentEvent
|
|
291
297
|
| { type: "auto_compaction_start"; reason: "threshold" | "overflow" | "idle"; action: "context-full" | "handoff" }
|
|
@@ -298,6 +304,7 @@ export type AgentSessionEvent =
|
|
|
298
304
|
errorMessage?: string;
|
|
299
305
|
/** True when compaction was skipped for a benign reason (no model, no candidates, nothing to compact). */
|
|
300
306
|
skipped?: boolean;
|
|
307
|
+
continuationSkipReason?: AutoCompactionContinuationSkipReason;
|
|
301
308
|
}
|
|
302
309
|
| {
|
|
303
310
|
type: "auto_retry_start";
|
|
@@ -418,6 +425,13 @@ export interface AgentSessionConfig {
|
|
|
418
425
|
* **MUST NOT** dispose it on their own teardown.
|
|
419
426
|
*/
|
|
420
427
|
ownedAsyncJobManager?: AsyncJobManager;
|
|
428
|
+
/**
|
|
429
|
+
* MCPManager whose lifecycle this session owns (top-level sessions that
|
|
430
|
+
* connected plugin-bundle MCP servers). Only the owned manager is
|
|
431
|
+
* disconnected on dispose; subagents and callers that merely observe the
|
|
432
|
+
* process-global manager **MUST NOT** dispose it on their own teardown.
|
|
433
|
+
*/
|
|
434
|
+
ownedMcpManager?: MCPManager;
|
|
421
435
|
/** Optional fork-context seed used to initialize a child session before its first prompt. */
|
|
422
436
|
forkContextSeed?: ForkContextSeed;
|
|
423
437
|
/** Optional provider state override. Fork-context children should omit this by default. */
|
|
@@ -955,6 +969,7 @@ export class AgentSession {
|
|
|
955
969
|
* this undefined and **MUST NOT** dispose the global instance on teardown.
|
|
956
970
|
*/
|
|
957
971
|
readonly #ownedAsyncJobManager: AsyncJobManager | undefined;
|
|
972
|
+
readonly #ownedMcpManager: MCPManager | undefined;
|
|
958
973
|
#pendingPythonMessages: PythonExecutionMessage[] = [];
|
|
959
974
|
#activeEvalExecutions = new Set<Promise<unknown>>();
|
|
960
975
|
#evalExecutionDisposing = false;
|
|
@@ -1084,6 +1099,16 @@ export class AgentSession {
|
|
|
1084
1099
|
#lastSuccessfulYieldToolCallId: string | undefined = undefined;
|
|
1085
1100
|
#promptGeneration = 0;
|
|
1086
1101
|
#providerSessionState = new Map<string, ProviderSessionState>();
|
|
1102
|
+
/**
|
|
1103
|
+
* Provider keys for which the Anthropic fast-mode auto-fallback fired this
|
|
1104
|
+
* session (the provider rejected `speed:"fast"` and we retried without it).
|
|
1105
|
+
* Provider/API-session scoped — matching the provider's own per-session
|
|
1106
|
+
* `fastModeDisabled` flag — NOT model-keyed. Transient (never persisted): it
|
|
1107
|
+
* suppresses the current-model fast indicator and dedups the one-time warning
|
|
1108
|
+
* WITHOUT mutating the user's intended `serviceTier`, so task subagents still
|
|
1109
|
+
* inherit the intended tier and a different provider still shows fast.
|
|
1110
|
+
*/
|
|
1111
|
+
#fastModeAutoDisabledProviderKeys = new Set<string>();
|
|
1087
1112
|
#hindsightSessionState: HindsightSessionState | undefined = undefined;
|
|
1088
1113
|
readonly rawSseDebugBuffer: RawSseDebugBuffer;
|
|
1089
1114
|
|
|
@@ -1158,6 +1183,7 @@ export class AgentSession {
|
|
|
1158
1183
|
// Power assertions are taken per turn (see #beginInFlight); nothing acquired here.
|
|
1159
1184
|
this.#evalKernelOwnerId = config.evalKernelOwnerId ?? `agent-session:${Snowflake.next()}`;
|
|
1160
1185
|
this.#ownedAsyncJobManager = config.ownedAsyncJobManager;
|
|
1186
|
+
this.#ownedMcpManager = config.ownedMcpManager;
|
|
1161
1187
|
this.#scopedModels = config.scopedModels ?? [];
|
|
1162
1188
|
this.#thinkingLevel = config.thinkingLevel;
|
|
1163
1189
|
this.#promptTemplates = config.promptTemplates ?? [];
|
|
@@ -1869,7 +1895,6 @@ export class AgentSession {
|
|
|
1869
1895
|
this.#resolveTtsrResume();
|
|
1870
1896
|
return;
|
|
1871
1897
|
}
|
|
1872
|
-
this.#ttsrAbortPending = false;
|
|
1873
1898
|
this.#perToolTtsrInjections.clear();
|
|
1874
1899
|
const ttsrSettings = this.#ttsrManager?.getSettings();
|
|
1875
1900
|
if (ttsrSettings?.contextMode === "discard" && targetAssistantIndex !== -1) {
|
|
@@ -1898,11 +1923,22 @@ export class AgentSession {
|
|
|
1898
1923
|
);
|
|
1899
1924
|
this.#markTtsrInjected(details.rules);
|
|
1900
1925
|
}
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1926
|
+
await this.#scheduleAgentContinue({
|
|
1927
|
+
delayMs: 0,
|
|
1928
|
+
generation,
|
|
1929
|
+
shouldContinue: () => {
|
|
1930
|
+
this.#ttsrAbortPending = false;
|
|
1931
|
+
return true;
|
|
1932
|
+
},
|
|
1933
|
+
onSkip: () => {
|
|
1934
|
+
this.#ttsrAbortPending = false;
|
|
1935
|
+
this.#resolveTtsrResume();
|
|
1936
|
+
},
|
|
1937
|
+
onError: () => {
|
|
1938
|
+
this.#ttsrAbortPending = false;
|
|
1939
|
+
this.#resolveTtsrResume();
|
|
1940
|
+
},
|
|
1941
|
+
});
|
|
1906
1942
|
},
|
|
1907
1943
|
{ delayMs: 50 },
|
|
1908
1944
|
);
|
|
@@ -1963,12 +1999,18 @@ export class AgentSession {
|
|
|
1963
1999
|
const currentGrantsAnthropicPriority =
|
|
1964
2000
|
this.serviceTier === "priority" || this.serviceTier === "claude-only";
|
|
1965
2001
|
if (assistantMsg.disabledFeatures?.includes("priority") && currentGrantsAnthropicPriority) {
|
|
1966
|
-
|
|
1967
|
-
this.
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
)
|
|
2002
|
+
// The provider auto-dropped `speed:"fast"` for the current model's
|
|
2003
|
+
// provider this turn. Record a transient, provider-scoped marker
|
|
2004
|
+
// instead of clearing the user's intended tier, so task subagents
|
|
2005
|
+
// still inherit it and a different provider still gets fast mode.
|
|
2006
|
+
// Warn once per provider until the user re-arms with `/fast on`.
|
|
2007
|
+
if (this.#markFastModeAutoDisabledForCurrentModel()) {
|
|
2008
|
+
this.emitNotice(
|
|
2009
|
+
"warning",
|
|
2010
|
+
"Priority/fast mode rejected for this model; retried without it. Fast mode is off for this model until you re-enable it with /fast on.",
|
|
2011
|
+
"priority",
|
|
2012
|
+
);
|
|
2013
|
+
}
|
|
1972
2014
|
}
|
|
1973
2015
|
// Resolve TTSR resume gate before checking for new deferred injections.
|
|
1974
2016
|
// Gate on #ttsrAbortPending, not stopReason: a non-TTSR abort (e.g. streaming
|
|
@@ -2214,7 +2256,7 @@ export class AgentSession {
|
|
|
2214
2256
|
#schedulePostPromptTask(
|
|
2215
2257
|
task: (signal: AbortSignal) => Promise<void>,
|
|
2216
2258
|
options?: { delayMs?: number; generation?: number; onSkip?: () => void },
|
|
2217
|
-
): void {
|
|
2259
|
+
): Promise<void> {
|
|
2218
2260
|
const delayMs = options?.delayMs ?? 0;
|
|
2219
2261
|
const signal = this.#postPromptTasksAbortController.signal;
|
|
2220
2262
|
const scheduled = (async () => {
|
|
@@ -2236,18 +2278,20 @@ export class AgentSession {
|
|
|
2236
2278
|
await task(signal);
|
|
2237
2279
|
})();
|
|
2238
2280
|
this.#trackPostPromptTask(scheduled);
|
|
2281
|
+
return scheduled;
|
|
2239
2282
|
}
|
|
2240
2283
|
|
|
2241
2284
|
#scheduleAgentContinue(options?: {
|
|
2242
2285
|
delayMs?: number;
|
|
2243
2286
|
generation?: number;
|
|
2287
|
+
skipCompactionCheck?: boolean;
|
|
2244
2288
|
shouldContinue?: () => boolean;
|
|
2245
2289
|
onSkip?: (reason: "generation_changed" | "aborted_signal" | "queue_drained") => void;
|
|
2246
2290
|
onError?: (error: unknown) => void;
|
|
2247
|
-
}): void {
|
|
2291
|
+
}): Promise<void> {
|
|
2248
2292
|
const scheduledGeneration = options?.generation;
|
|
2249
2293
|
const signal = this.#postPromptTasksAbortController.signal;
|
|
2250
|
-
this.#schedulePostPromptTask(
|
|
2294
|
+
return this.#schedulePostPromptTask(
|
|
2251
2295
|
async () => {
|
|
2252
2296
|
if (signal.aborted) {
|
|
2253
2297
|
options?.onSkip?.("aborted_signal");
|
|
@@ -2263,6 +2307,9 @@ export class AgentSession {
|
|
|
2263
2307
|
}
|
|
2264
2308
|
try {
|
|
2265
2309
|
await this.#maybeRestoreRetryFallbackPrimary();
|
|
2310
|
+
if (!options?.skipCompactionCheck) {
|
|
2311
|
+
await this.#checkEstimatedContextBeforePrompt();
|
|
2312
|
+
}
|
|
2266
2313
|
await this.agent.continue();
|
|
2267
2314
|
} catch (error) {
|
|
2268
2315
|
logger.warn("agent.continue failed after scheduling", {
|
|
@@ -2307,6 +2354,34 @@ export class AgentSession {
|
|
|
2307
2354
|
}
|
|
2308
2355
|
}
|
|
2309
2356
|
|
|
2357
|
+
#detectOverflowRetryContinuationSkip(): AutoCompactionContinuationSkipReason | undefined {
|
|
2358
|
+
this.#stripOverflowFailedTurnForRetry();
|
|
2359
|
+
if (this.#isResumableAgentTail()) return undefined;
|
|
2360
|
+
const compactionSettings = this.settings.getGroup("compaction");
|
|
2361
|
+
return compactionSettings.autoContinue === false ? "auto_continue_disabled_non_resumable_tail" : undefined;
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
#scheduleOverflowRetryContinuation(generation: number): void {
|
|
2365
|
+
this.#stripOverflowFailedTurnForRetry();
|
|
2366
|
+
if (this.#isResumableAgentTail()) {
|
|
2367
|
+
this.#scheduleAgentContinue({
|
|
2368
|
+
delayMs: 100,
|
|
2369
|
+
generation,
|
|
2370
|
+
onSkip: reason => this.#logCompactionContinuationSkipped("overflow_retry", reason),
|
|
2371
|
+
onError: error => this.#logCompactionContinuationError("overflow_retry", error),
|
|
2372
|
+
});
|
|
2373
|
+
return;
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
const compactionSettings = this.settings.getGroup("compaction");
|
|
2377
|
+
if (compactionSettings.autoContinue !== false) {
|
|
2378
|
+
this.#scheduleAutoContinuePrompt(generation);
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
this.#logCompactionContinuationSkipped("overflow_retry", "auto_continue_disabled_non_resumable_tail");
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2310
2385
|
#scheduleAutoContinuePrompt(generation: number): void {
|
|
2311
2386
|
const continuePrompt = async () => {
|
|
2312
2387
|
await this.#promptWithMessage(
|
|
@@ -3052,6 +3127,7 @@ export class AgentSession {
|
|
|
3052
3127
|
willRetry: event.willRetry,
|
|
3053
3128
|
errorMessage: event.errorMessage,
|
|
3054
3129
|
skipped: event.skipped,
|
|
3130
|
+
continuationSkipReason: event.continuationSkipReason,
|
|
3055
3131
|
});
|
|
3056
3132
|
} else if (event.type === "auto_retry_start") {
|
|
3057
3133
|
await this.#extensionRunner.emit({
|
|
@@ -3193,10 +3269,14 @@ export class AgentSession {
|
|
|
3193
3269
|
AsyncJobManager.setInstance(undefined);
|
|
3194
3270
|
}
|
|
3195
3271
|
}
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3272
|
+
// Only disconnect the MCP manager THIS session owns (top-level sessions that
|
|
3273
|
+
// connected plugin-bundle MCP servers). Subagents and callers that merely
|
|
3274
|
+
// observe the process-global manager must never tear down a manager they do
|
|
3275
|
+
// not own. Mirrors the ownedAsyncJobManager rule above.
|
|
3276
|
+
const ownedMcpManager = this.#ownedMcpManager;
|
|
3277
|
+
if (ownedMcpManager) {
|
|
3278
|
+
await ownedMcpManager.disconnectAll();
|
|
3279
|
+
if (MCPManager.instance() === ownedMcpManager) {
|
|
3200
3280
|
MCPManager.setInstance(undefined);
|
|
3201
3281
|
}
|
|
3202
3282
|
}
|
|
@@ -5557,7 +5637,7 @@ export class AgentSession {
|
|
|
5557
5637
|
}
|
|
5558
5638
|
|
|
5559
5639
|
#syncTodoPhasesFromBranch(): void {
|
|
5560
|
-
const phases = getLatestTodoPhasesFromEntries(this.sessionManager.
|
|
5640
|
+
const phases = getLatestTodoPhasesFromEntries(this.sessionManager.getActivePathEntriesCanonical());
|
|
5561
5641
|
// Strip completed/abandoned tasks — they were done in a previous run,
|
|
5562
5642
|
// so they have no bearing on progress tracking for the new turn.
|
|
5563
5643
|
for (const phase of phases) {
|
|
@@ -5566,6 +5646,42 @@ export class AgentSession {
|
|
|
5566
5646
|
this.setTodoPhases(phases.filter(p => p.tasks.length > 0));
|
|
5567
5647
|
}
|
|
5568
5648
|
|
|
5649
|
+
async #applyCompactionPostAppend(
|
|
5650
|
+
compactionEntryId: string,
|
|
5651
|
+
firstKeptEntryId: string,
|
|
5652
|
+
fromExtension?: boolean,
|
|
5653
|
+
): Promise<CompactionEntry | undefined> {
|
|
5654
|
+
const eviction = this.sessionManager.evictCompactedContent(firstKeptEntryId, compactionEntryId);
|
|
5655
|
+
if (eviction.evictedEntries > 0) await this.sessionManager.rewriteEntries();
|
|
5656
|
+
const sessionContext = this.buildDisplaySessionContext();
|
|
5657
|
+
this.agent.replaceMessages(sessionContext.messages);
|
|
5658
|
+
this.#syncTodoPhasesFromBranch();
|
|
5659
|
+
this.#closeCodexProviderSessionsForHistoryRewrite();
|
|
5660
|
+
|
|
5661
|
+
// Get the saved compaction entry for the hook without materializing all entries.
|
|
5662
|
+
const savedCompactionEntry = this.sessionManager.getEntryForFidelity(compactionEntryId) as
|
|
5663
|
+
| CompactionEntry
|
|
5664
|
+
| undefined;
|
|
5665
|
+
|
|
5666
|
+
if (this.#extensionRunner && savedCompactionEntry) {
|
|
5667
|
+
await this.#extensionRunner.emit({
|
|
5668
|
+
type: "session_compact",
|
|
5669
|
+
compactionEntry: savedCompactionEntry,
|
|
5670
|
+
fromExtension: fromExtension ?? false,
|
|
5671
|
+
});
|
|
5672
|
+
}
|
|
5673
|
+
|
|
5674
|
+
return savedCompactionEntry;
|
|
5675
|
+
}
|
|
5676
|
+
|
|
5677
|
+
async applyCompactionPostAppendForTests(
|
|
5678
|
+
compactionEntryId: string,
|
|
5679
|
+
firstKeptEntryId: string,
|
|
5680
|
+
fromExtension?: boolean,
|
|
5681
|
+
): Promise<CompactionEntry | undefined> {
|
|
5682
|
+
return this.#applyCompactionPostAppend(compactionEntryId, firstKeptEntryId, fromExtension);
|
|
5683
|
+
}
|
|
5684
|
+
|
|
5569
5685
|
#cloneTodoPhases(phases: TodoPhase[]): TodoPhase[] {
|
|
5570
5686
|
return phases.map(phase => ({
|
|
5571
5687
|
name: phase.name,
|
|
@@ -6195,33 +6311,81 @@ export class AgentSession {
|
|
|
6195
6311
|
return resolveServiceTier(this.#subagentServiceTier(), provider) === "priority";
|
|
6196
6312
|
}
|
|
6197
6313
|
|
|
6314
|
+
/**
|
|
6315
|
+
* Provider/API-session key used to scope the fast-mode auto-disable marker.
|
|
6316
|
+
* Mirrors the provider's own per-session `fastModeDisabled` scope (the key in
|
|
6317
|
+
* {@link #providerSessionState} cleared by `clearAnthropicFastModeFallback`),
|
|
6318
|
+
* so the marker is provider-scoped, never model-keyed. Returns `undefined`
|
|
6319
|
+
* when no model/provider is selected.
|
|
6320
|
+
*/
|
|
6321
|
+
#fastModeProviderKey(provider: string | undefined = this.model?.provider): string | undefined {
|
|
6322
|
+
return provider;
|
|
6323
|
+
}
|
|
6324
|
+
|
|
6325
|
+
/**
|
|
6326
|
+
* Record that the current model's provider had fast mode auto-dropped this
|
|
6327
|
+
* session. Returns `true` only when the provider key is newly marked, so the
|
|
6328
|
+
* caller emits the one-time warning exactly once per provider until re-arm.
|
|
6329
|
+
*/
|
|
6330
|
+
#markFastModeAutoDisabledForCurrentModel(): boolean {
|
|
6331
|
+
const key = this.#fastModeProviderKey();
|
|
6332
|
+
if (key === undefined) return false;
|
|
6333
|
+
if (this.#fastModeAutoDisabledProviderKeys.has(key)) return false;
|
|
6334
|
+
this.#fastModeAutoDisabledProviderKeys.add(key);
|
|
6335
|
+
return true;
|
|
6336
|
+
}
|
|
6337
|
+
|
|
6338
|
+
/** True when `provider`'s fast mode was auto-disabled this session. */
|
|
6339
|
+
#isFastModeAutoDisabledForProvider(provider?: string): boolean {
|
|
6340
|
+
const key = this.#fastModeProviderKey(provider);
|
|
6341
|
+
return key !== undefined && this.#fastModeAutoDisabledProviderKeys.has(key);
|
|
6342
|
+
}
|
|
6343
|
+
|
|
6344
|
+
/**
|
|
6345
|
+
* Re-arm fast mode after an auto-disable: clear the provider's sticky
|
|
6346
|
+
* `fastModeDisabled` fallback flag and the session auto-disable markers so the
|
|
6347
|
+
* next request carries `speed:"fast"` again and a future rejection can warn
|
|
6348
|
+
* once more. Called on explicit re-enable (`/fast on`, re-arming tier change),
|
|
6349
|
+
* never by the transient Q1 auto-disable path.
|
|
6350
|
+
*/
|
|
6351
|
+
#rearmFastMode(): void {
|
|
6352
|
+
clearAnthropicFastModeFallback(this.#providerSessionState);
|
|
6353
|
+
this.#fastModeAutoDisabledProviderKeys.clear();
|
|
6354
|
+
}
|
|
6355
|
+
|
|
6198
6356
|
/**
|
|
6199
6357
|
* True when the configured `serviceTier` resolves to `"priority"` for the
|
|
6200
|
-
* *currently selected model's provider
|
|
6201
|
-
* that
|
|
6202
|
-
*
|
|
6358
|
+
* *currently selected model's provider* AND fast mode was not auto-disabled
|
|
6359
|
+
* for that provider this session. This is the current-model EFFECTIVE
|
|
6360
|
+
* predicate (what the next request actually does); use {@link isFastForProvider}
|
|
6361
|
+
* for pure configured intent (e.g. subagent/`modelRoles` display rows).
|
|
6203
6362
|
*/
|
|
6204
6363
|
isFastModeActive(): boolean {
|
|
6205
|
-
|
|
6364
|
+
const provider = this.model?.provider;
|
|
6365
|
+
return this.isFastForProvider(provider) && !this.#isFastModeAutoDisabledForProvider(provider);
|
|
6206
6366
|
}
|
|
6207
6367
|
|
|
6208
6368
|
setServiceTier(serviceTier: ServiceTier | undefined): void {
|
|
6209
|
-
|
|
6210
|
-
//
|
|
6211
|
-
//
|
|
6212
|
-
//
|
|
6213
|
-
//
|
|
6214
|
-
// and the warning notice fires every turn.
|
|
6369
|
+
// Re-arming a priority-granting tier always clears the per-session
|
|
6370
|
+
// auto-fallback sticky disable AND the auto-disable markers so the next
|
|
6371
|
+
// request carries `speed: "fast"` again — even when the tier is unchanged
|
|
6372
|
+
// (re-selecting the same tier is a deliberate re-arm), and before the
|
|
6373
|
+
// no-op early-return below.
|
|
6215
6374
|
if (serviceTier === "priority" || serviceTier === "claude-only") {
|
|
6216
|
-
|
|
6375
|
+
this.#rearmFastMode();
|
|
6217
6376
|
}
|
|
6377
|
+
if (this.serviceTier === serviceTier) return;
|
|
6218
6378
|
this.agent.serviceTier = serviceTier;
|
|
6219
6379
|
this.sessionManager.appendServiceTierChange(serviceTier ?? null);
|
|
6220
6380
|
}
|
|
6221
6381
|
|
|
6222
6382
|
setFastMode(enabled: boolean): void {
|
|
6223
6383
|
if (enabled && this.isFastModeEnabled()) {
|
|
6224
|
-
//
|
|
6384
|
+
// Intent already grants fast mode under some scope — keep the user's
|
|
6385
|
+
// scoped value but still re-arm, so an explicit `/fast on` after a
|
|
6386
|
+
// provider auto-disable actually clears the sticky fallback + markers
|
|
6387
|
+
// (otherwise it is a silent no-op). No history append: intent is unchanged.
|
|
6388
|
+
this.#rearmFastMode();
|
|
6225
6389
|
return;
|
|
6226
6390
|
}
|
|
6227
6391
|
this.setServiceTier(enabled ? "priority" : undefined);
|
|
@@ -6279,19 +6443,23 @@ export class AgentSession {
|
|
|
6279
6443
|
async #pruneToolOutputs(): Promise<{ prunedCount: number; tokensSaved: number } | undefined> {
|
|
6280
6444
|
const branchEntries = this.sessionManager.getBranch();
|
|
6281
6445
|
const result = pruneToolOutputs(branchEntries, DEFAULT_PRUNE_CONFIG);
|
|
6282
|
-
|
|
6446
|
+
const argumentResult = pruneAssistantToolArguments(branchEntries, DEFAULT_PRUNE_CONFIG);
|
|
6447
|
+
const tokensSaved = result.tokensSaved + argumentResult.argumentTokensSaved;
|
|
6448
|
+
const prunedCount = result.prunedCount + argumentResult.argumentPrunedCount;
|
|
6449
|
+
if (prunedCount === 0) {
|
|
6283
6450
|
return undefined;
|
|
6284
6451
|
}
|
|
6285
6452
|
|
|
6286
6453
|
// getBranch() returns materialized copies for blob-externalized entries, so
|
|
6287
6454
|
// the pruning mutations must be written back into the canonical store.
|
|
6288
|
-
|
|
6455
|
+
const combined = [...result.prunedEntries, ...argumentResult.prunedEntries];
|
|
6456
|
+
this.sessionManager.applyEntryMessageUpdates(combined);
|
|
6289
6457
|
await this.sessionManager.rewriteEntries();
|
|
6290
6458
|
const sessionContext = this.buildDisplaySessionContext();
|
|
6291
6459
|
this.agent.replaceMessages(sessionContext.messages);
|
|
6292
6460
|
this.#syncTodoPhasesFromBranch();
|
|
6293
6461
|
this.#closeCodexProviderSessionsForHistoryRewrite();
|
|
6294
|
-
return
|
|
6462
|
+
return { prunedCount, tokensSaved };
|
|
6295
6463
|
}
|
|
6296
6464
|
|
|
6297
6465
|
/**
|
|
@@ -6409,7 +6577,7 @@ export class AgentSession {
|
|
|
6409
6577
|
throw new CompactionCancelledError();
|
|
6410
6578
|
}
|
|
6411
6579
|
|
|
6412
|
-
this.sessionManager.appendCompaction(
|
|
6580
|
+
const compactionEntryId = this.sessionManager.appendCompaction(
|
|
6413
6581
|
summary,
|
|
6414
6582
|
shortSummary,
|
|
6415
6583
|
firstKeptEntryId,
|
|
@@ -6418,24 +6586,7 @@ export class AgentSession {
|
|
|
6418
6586
|
fromExtension,
|
|
6419
6587
|
preserveData,
|
|
6420
6588
|
);
|
|
6421
|
-
|
|
6422
|
-
const sessionContext = this.buildDisplaySessionContext();
|
|
6423
|
-
this.agent.replaceMessages(sessionContext.messages);
|
|
6424
|
-
this.#syncTodoPhasesFromBranch();
|
|
6425
|
-
this.#closeCodexProviderSessionsForHistoryRewrite();
|
|
6426
|
-
|
|
6427
|
-
// Get the saved compaction entry for the hook
|
|
6428
|
-
const savedCompactionEntry = newEntries.find(e => e.type === "compaction" && e.summary === summary) as
|
|
6429
|
-
| CompactionEntry
|
|
6430
|
-
| undefined;
|
|
6431
|
-
|
|
6432
|
-
if (this.#extensionRunner && savedCompactionEntry) {
|
|
6433
|
-
await this.#extensionRunner.emit({
|
|
6434
|
-
type: "session_compact",
|
|
6435
|
-
compactionEntry: savedCompactionEntry,
|
|
6436
|
-
fromExtension,
|
|
6437
|
-
});
|
|
6438
|
-
}
|
|
6589
|
+
await this.#applyCompactionPostAppend(compactionEntryId, firstKeptEntryId, fromExtension);
|
|
6439
6590
|
|
|
6440
6591
|
const compactionResult: CompactionResult = {
|
|
6441
6592
|
summary,
|
|
@@ -6722,6 +6873,8 @@ export class AgentSession {
|
|
|
6722
6873
|
const compactionSettings = this.settings.getGroup("compaction");
|
|
6723
6874
|
if (compactionSettings.enabled && compactionSettings.strategy !== "off") {
|
|
6724
6875
|
await this.#runAutoCompaction("overflow", true);
|
|
6876
|
+
} else {
|
|
6877
|
+
this.#scheduleOverflowRetryContinuation(generation);
|
|
6725
6878
|
}
|
|
6726
6879
|
return;
|
|
6727
6880
|
}
|
|
@@ -6732,17 +6885,19 @@ export class AgentSession {
|
|
|
6732
6885
|
// Skip if this was an error (non-overflow errors don't have usage data)
|
|
6733
6886
|
if (assistantMessage.stopReason === "error") return;
|
|
6734
6887
|
let contextTokens = calculateContextTokens(assistantMessage.usage);
|
|
6735
|
-
|
|
6888
|
+
// Model maxTokens is a capability ceiling, not a per-turn reservation.
|
|
6889
|
+
// Auto maintenance should track actual context fullness.
|
|
6890
|
+
const autoCompactionOutputReserveTokens = 0;
|
|
6736
6891
|
// Cache-epoch invariant: pruning rewrites already-sent toolResult history,
|
|
6737
6892
|
// which breaks the provider prompt-cache prefix mid-epoch. Only prune at a
|
|
6738
6893
|
// sanctioned maintenance boundary, i.e. when the un-pruned context already
|
|
6739
6894
|
// crosses the compaction threshold. Pruning may then avert full compaction.
|
|
6740
|
-
if (!shouldCompact(contextTokens, contextWindow, compactionSettings,
|
|
6895
|
+
if (!shouldCompact(contextTokens, contextWindow, compactionSettings, autoCompactionOutputReserveTokens)) return;
|
|
6741
6896
|
const pruneResult = await this.#pruneToolOutputs();
|
|
6742
6897
|
if (pruneResult) {
|
|
6743
6898
|
contextTokens = Math.max(0, contextTokens - pruneResult.tokensSaved);
|
|
6744
6899
|
}
|
|
6745
|
-
if (shouldCompact(contextTokens, contextWindow, compactionSettings,
|
|
6900
|
+
if (shouldCompact(contextTokens, contextWindow, compactionSettings, autoCompactionOutputReserveTokens)) {
|
|
6746
6901
|
// Try promotion first — if a larger model is available, switch instead of compacting
|
|
6747
6902
|
const promoted = await this.#tryContextPromotion(assistantMessage);
|
|
6748
6903
|
if (!promoted) {
|
|
@@ -6820,14 +6975,16 @@ export class AgentSession {
|
|
|
6820
6975
|
if (!compactionSettings.enabled || compactionSettings.strategy === "off") return;
|
|
6821
6976
|
|
|
6822
6977
|
let contextTokens = this.#estimateContextTokensForCompaction(pendingMessages).tokens;
|
|
6823
|
-
|
|
6824
|
-
|
|
6978
|
+
// Model maxTokens is a capability ceiling, not a per-turn reservation.
|
|
6979
|
+
// Auto maintenance should track actual context fullness.
|
|
6980
|
+
const autoCompactionOutputReserveTokens = 0;
|
|
6981
|
+
if (!shouldCompact(contextTokens, contextWindow, compactionSettings, autoCompactionOutputReserveTokens)) return;
|
|
6825
6982
|
|
|
6826
6983
|
const pruneResult = await this.#pruneToolOutputs();
|
|
6827
6984
|
if (pruneResult) {
|
|
6828
6985
|
contextTokens = Math.max(0, contextTokens - pruneResult.tokensSaved);
|
|
6829
6986
|
}
|
|
6830
|
-
if (shouldCompact(contextTokens, contextWindow, compactionSettings,
|
|
6987
|
+
if (shouldCompact(contextTokens, contextWindow, compactionSettings, autoCompactionOutputReserveTokens)) {
|
|
6831
6988
|
await this.#runAutoCompaction("threshold", false, false, {
|
|
6832
6989
|
continueAfterMaintenance: false,
|
|
6833
6990
|
deferHandoffMaintenance: false,
|
|
@@ -7427,11 +7584,14 @@ export class AgentSession {
|
|
|
7427
7584
|
availableModels: Model[],
|
|
7428
7585
|
currentModel: Model | undefined,
|
|
7429
7586
|
): ResolvedModelRoleValue {
|
|
7587
|
+
const target = SKC_MODEL_ASSIGNMENT_TARGETS[role as keyof typeof SKC_MODEL_ASSIGNMENT_TARGETS];
|
|
7430
7588
|
const roleModelStr =
|
|
7431
|
-
|
|
7432
|
-
?
|
|
7433
|
-
|
|
7434
|
-
|
|
7589
|
+
target?.settingsPath === "task.agentModelOverrides"
|
|
7590
|
+
? this.settings.get("task.agentModelOverrides")[role]
|
|
7591
|
+
: role === "default"
|
|
7592
|
+
? (this.settings.getModelRole("default") ??
|
|
7593
|
+
(currentModel ? `${currentModel.provider}/${currentModel.id}` : undefined))
|
|
7594
|
+
: this.settings.getModelRole(role);
|
|
7435
7595
|
|
|
7436
7596
|
if (!roleModelStr) {
|
|
7437
7597
|
return { model: undefined, thinkingLevel: undefined, explicitThinkingLevel: false, warning: undefined };
|
|
@@ -7730,32 +7890,18 @@ export class AgentSession {
|
|
|
7730
7890
|
|
|
7731
7891
|
const preparation = prepareCompaction(pathEntries, compactionSettings);
|
|
7732
7892
|
if (!preparation) {
|
|
7893
|
+
const continuationSkipReason = willRetry ? this.#detectOverflowRetryContinuationSkip() : undefined;
|
|
7733
7894
|
await this.#emitSessionEvent({
|
|
7734
7895
|
type: "auto_compaction_end",
|
|
7735
7896
|
action,
|
|
7736
7897
|
result: undefined,
|
|
7737
7898
|
aborted: false,
|
|
7738
|
-
willRetry:
|
|
7899
|
+
willRetry: willRetry && !continuationSkipReason,
|
|
7739
7900
|
skipped: true,
|
|
7901
|
+
continuationSkipReason,
|
|
7740
7902
|
});
|
|
7741
7903
|
if (willRetry) {
|
|
7742
|
-
this.#
|
|
7743
|
-
if (this.#isResumableAgentTail()) {
|
|
7744
|
-
this.#scheduleAgentContinue({
|
|
7745
|
-
delayMs: 100,
|
|
7746
|
-
generation,
|
|
7747
|
-
onSkip: skipReason => this.#logCompactionContinuationSkipped("overflow_retry", skipReason),
|
|
7748
|
-
onError: error => this.#logCompactionContinuationError("overflow_retry", error),
|
|
7749
|
-
});
|
|
7750
|
-
} else {
|
|
7751
|
-
const tail = this.agent.state.messages.at(-1) as AssistantMessage | undefined;
|
|
7752
|
-
logger.warn("Auto-compaction continuation skipped", {
|
|
7753
|
-
source: "overflow_retry",
|
|
7754
|
-
reason: "not_resumable_tail",
|
|
7755
|
-
role: tail?.role,
|
|
7756
|
-
stopReason: tail?.stopReason,
|
|
7757
|
-
});
|
|
7758
|
-
}
|
|
7904
|
+
this.#scheduleOverflowRetryContinuation(generation);
|
|
7759
7905
|
} else if (continueAfterMaintenance && reason !== "idle" && this.agent.hasQueuedMessages()) {
|
|
7760
7906
|
this.#scheduleAgentContinue({
|
|
7761
7907
|
delayMs: 100,
|
|
@@ -7930,7 +8076,7 @@ export class AgentSession {
|
|
|
7930
8076
|
return;
|
|
7931
8077
|
}
|
|
7932
8078
|
|
|
7933
|
-
this.sessionManager.appendCompaction(
|
|
8079
|
+
const compactionEntryId = this.sessionManager.appendCompaction(
|
|
7934
8080
|
summary,
|
|
7935
8081
|
shortSummary,
|
|
7936
8082
|
firstKeptEntryId,
|
|
@@ -7939,24 +8085,7 @@ export class AgentSession {
|
|
|
7939
8085
|
fromExtension,
|
|
7940
8086
|
preserveData,
|
|
7941
8087
|
);
|
|
7942
|
-
|
|
7943
|
-
const sessionContext = this.buildDisplaySessionContext();
|
|
7944
|
-
this.agent.replaceMessages(sessionContext.messages);
|
|
7945
|
-
this.#syncTodoPhasesFromBranch();
|
|
7946
|
-
this.#closeCodexProviderSessionsForHistoryRewrite();
|
|
7947
|
-
|
|
7948
|
-
// Get the saved compaction entry for the hook
|
|
7949
|
-
const savedCompactionEntry = newEntries.find(e => e.type === "compaction" && e.summary === summary) as
|
|
7950
|
-
| CompactionEntry
|
|
7951
|
-
| undefined;
|
|
7952
|
-
|
|
7953
|
-
if (this.#extensionRunner && savedCompactionEntry) {
|
|
7954
|
-
await this.#extensionRunner.emit({
|
|
7955
|
-
type: "session_compact",
|
|
7956
|
-
compactionEntry: savedCompactionEntry,
|
|
7957
|
-
fromExtension,
|
|
7958
|
-
});
|
|
7959
|
-
}
|
|
8088
|
+
await this.#applyCompactionPostAppend(compactionEntryId, firstKeptEntryId, fromExtension);
|
|
7960
8089
|
|
|
7961
8090
|
const result: CompactionResult = {
|
|
7962
8091
|
summary,
|
|
@@ -7966,26 +8095,18 @@ export class AgentSession {
|
|
|
7966
8095
|
details,
|
|
7967
8096
|
preserveData,
|
|
7968
8097
|
};
|
|
7969
|
-
|
|
8098
|
+
const continuationSkipReason = willRetry ? this.#detectOverflowRetryContinuationSkip() : undefined;
|
|
8099
|
+
await this.#emitSessionEvent({
|
|
8100
|
+
type: "auto_compaction_end",
|
|
8101
|
+
action,
|
|
8102
|
+
result,
|
|
8103
|
+
aborted: false,
|
|
8104
|
+
willRetry: willRetry && !continuationSkipReason,
|
|
8105
|
+
continuationSkipReason,
|
|
8106
|
+
});
|
|
7970
8107
|
|
|
7971
8108
|
if (willRetry) {
|
|
7972
|
-
this.#
|
|
7973
|
-
if (!this.#isResumableAgentTail()) {
|
|
7974
|
-
const tail = this.agent.state.messages.at(-1) as AssistantMessage | undefined;
|
|
7975
|
-
logger.warn("Auto-compaction continuation skipped", {
|
|
7976
|
-
source: "overflow_retry",
|
|
7977
|
-
reason: "not_resumable_tail",
|
|
7978
|
-
role: tail?.role,
|
|
7979
|
-
stopReason: tail?.stopReason,
|
|
7980
|
-
});
|
|
7981
|
-
} else {
|
|
7982
|
-
this.#scheduleAgentContinue({
|
|
7983
|
-
delayMs: 100,
|
|
7984
|
-
generation,
|
|
7985
|
-
onSkip: reason => this.#logCompactionContinuationSkipped("overflow_retry", reason),
|
|
7986
|
-
onError: error => this.#logCompactionContinuationError("overflow_retry", error),
|
|
7987
|
-
});
|
|
7988
|
-
}
|
|
8109
|
+
this.#scheduleOverflowRetryContinuation(generation);
|
|
7989
8110
|
} else if (continueAfterMaintenance && reason !== "idle" && this.agent.hasQueuedMessages()) {
|
|
7990
8111
|
// Auto-compaction can complete while follow-up/steering/custom messages are waiting.
|
|
7991
8112
|
// Kick the loop so queued messages are actually delivered.
|
|
@@ -9582,7 +9703,7 @@ export class AgentSession {
|
|
|
9582
9703
|
cancelled: boolean;
|
|
9583
9704
|
}> {
|
|
9584
9705
|
const previousSessionFile = this.sessionFile;
|
|
9585
|
-
const selectedEntry = this.sessionManager.
|
|
9706
|
+
const selectedEntry = this.sessionManager.getEntryForFidelity(entryId);
|
|
9586
9707
|
|
|
9587
9708
|
if (selectedEntry?.type !== "message" || selectedEntry.message.role !== "user") {
|
|
9588
9709
|
throw new Error("Invalid entry ID for branching");
|
|
@@ -9680,7 +9801,7 @@ export class AgentSession {
|
|
|
9680
9801
|
throw new Error("No model available for summarization");
|
|
9681
9802
|
}
|
|
9682
9803
|
|
|
9683
|
-
const targetEntry = this.sessionManager.
|
|
9804
|
+
const targetEntry = this.sessionManager.getEntryForFidelity(targetId);
|
|
9684
9805
|
if (!targetEntry) {
|
|
9685
9806
|
throw new Error(`Entry ${targetId} not found`);
|
|
9686
9807
|
}
|
|
@@ -9836,9 +9957,11 @@ export class AgentSession {
|
|
|
9836
9957
|
|
|
9837
9958
|
for (const entry of entries) {
|
|
9838
9959
|
if (entry.type !== "message") continue;
|
|
9839
|
-
|
|
9960
|
+
const fidelityEntry = this.sessionManager.getEntryForFidelity(entry.id);
|
|
9961
|
+
if (fidelityEntry?.type !== "message") continue;
|
|
9962
|
+
if (fidelityEntry.message.role !== "user") continue;
|
|
9840
9963
|
|
|
9841
|
-
const text = this.#extractUserMessageText(
|
|
9964
|
+
const text = this.#extractUserMessageText(fidelityEntry.message.content);
|
|
9842
9965
|
if (text) {
|
|
9843
9966
|
result.push({ entryId: entry.id, text });
|
|
9844
9967
|
}
|