@oh-my-pi/pi-coding-agent 17.1.8 → 17.2.0
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/CHANGELOG.md +92 -0
- package/dist/{CHANGELOG-vt8ene9g.md → CHANGELOG-be1f2t8h.md} +92 -0
- package/dist/cli.js +9986 -9776
- package/dist/{template-dys3vk5b.js → template-8vdv6xb4.js} +1 -1
- package/dist/types/advisor/runtime.d.ts +8 -2
- package/dist/types/advisor/transcript-recorder.d.ts +15 -0
- package/dist/types/auto-thinking/classifier.d.ts +9 -2
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/session-picker.d.ts +14 -7
- package/dist/types/collab/guest.d.ts +21 -2
- package/dist/types/commands/launch.d.ts +6 -0
- package/dist/types/config/settings-schema.d.ts +63 -8
- package/dist/types/cursor-bridge-tools.d.ts +54 -0
- package/dist/types/cursor.d.ts +193 -8
- package/dist/types/edit/edit-clipboard.d.ts +19 -0
- package/dist/types/edit/hashline/diff.d.ts +9 -1
- package/dist/types/edit/index.d.ts +8 -1
- package/dist/types/edit/streaming.d.ts +8 -1
- package/dist/types/extensibility/extensions/runner.d.ts +19 -2
- package/dist/types/extensibility/extensions/types.d.ts +25 -1
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +2 -0
- package/dist/types/internal-urls/local-protocol.d.ts +3 -2
- package/dist/types/launch/terminal-output-worker-client.d.ts +5 -0
- package/dist/types/launch/terminal-output-worker-protocol.d.ts +14 -0
- package/dist/types/launch/terminal-output-worker.d.ts +1 -0
- package/dist/types/lsp/client.d.ts +2 -0
- package/dist/types/main.d.ts +2 -0
- package/dist/types/mcp/manager.d.ts +33 -4
- package/dist/types/modes/components/codex-reset-fireworks.d.ts +51 -0
- package/dist/types/modes/components/read-tool-group.d.ts +12 -0
- package/dist/types/modes/components/session-selector.d.ts +6 -0
- package/dist/types/modes/components/status-line/component.d.ts +23 -0
- package/dist/types/modes/components/tool-execution.d.ts +16 -7
- package/dist/types/modes/components/usage-row.d.ts +2 -0
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +26 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
- package/dist/types/modes/interactive-mode.d.ts +4 -2
- package/dist/types/modes/rpc/rpc-client.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +16 -0
- package/dist/types/modes/theme/theme.d.ts +12 -1
- package/dist/types/modes/types.d.ts +2 -1
- package/dist/types/sdk.d.ts +1 -0
- package/dist/types/session/agent-session-events.d.ts +2 -0
- package/dist/types/session/agent-session-types.d.ts +36 -1
- package/dist/types/session/agent-session.d.ts +4 -2
- package/dist/types/session/claude-session-store.d.ts +13 -0
- package/dist/types/session/codex-session-store.d.ts +14 -0
- package/dist/types/session/credential-pin.d.ts +58 -0
- package/dist/types/session/foreign-session-import.d.ts +15 -0
- package/dist/types/session/foreign-session-jsonl.d.ts +9 -0
- package/dist/types/session/foreign-session-store.d.ts +23 -0
- package/dist/types/session/session-advisors.d.ts +47 -2
- package/dist/types/session/session-entries.d.ts +19 -1
- package/dist/types/session/session-handoff.d.ts +4 -1
- package/dist/types/session/session-loader.d.ts +2 -0
- package/dist/types/session/session-maintenance.d.ts +1 -1
- package/dist/types/session/session-manager.d.ts +21 -0
- package/dist/types/session/session-tools.d.ts +25 -1
- package/dist/types/session/turn-recovery.d.ts +10 -4
- package/dist/types/system-prompt.d.ts +2 -1
- package/dist/types/task/executor.d.ts +11 -2
- package/dist/types/task/render.d.ts +7 -0
- package/dist/types/thinking.d.ts +18 -6
- package/dist/types/tools/acp-bridge.d.ts +28 -5
- package/dist/types/tools/grep.d.ts +17 -1
- package/dist/types/tools/hub/launch.d.ts +5 -1
- package/dist/types/tools/index.d.ts +4 -1
- package/dist/types/tools/path-utils.d.ts +19 -0
- package/dist/types/tools/read.d.ts +2 -0
- package/dist/types/tools/xdev.d.ts +2 -1
- package/dist/types/utils/changelog.d.ts +19 -0
- package/dist/types/utils/git.d.ts +10 -0
- package/dist/types/utils/jj.d.ts +11 -4
- package/dist/types/web/search/types.d.ts +2 -2
- package/package.json +12 -12
- package/src/advisor/runtime.ts +138 -12
- package/src/advisor/transcript-recorder.ts +56 -0
- package/src/auto-thinking/classifier.ts +48 -10
- package/src/cli/args.ts +6 -0
- package/src/cli/flag-tables.ts +2 -0
- package/src/cli/gallery-fixtures/fs.ts +25 -0
- package/src/cli/session-picker.ts +34 -17
- package/src/cli/ttsr-cli.ts +19 -1
- package/src/cli.ts +9 -0
- package/src/collab/guest.ts +37 -4
- package/src/collab/host.ts +1 -0
- package/src/commands/launch.ts +6 -0
- package/src/config/model-registry.ts +103 -25
- package/src/config/settings-schema.ts +65 -6
- package/src/config/settings.ts +25 -0
- package/src/cursor-bridge-tools.ts +81 -0
- package/src/cursor.ts +463 -12
- package/src/edit/edit-clipboard.ts +23 -0
- package/src/edit/hashline/diff.ts +49 -10
- package/src/edit/hashline/execute.ts +38 -6
- package/src/edit/hashline/filesystem.ts +27 -3
- package/src/edit/index.ts +12 -2
- package/src/edit/renderer.ts +4 -4
- package/src/edit/streaming.ts +17 -2
- package/src/export/html/template.js +1 -1
- package/src/extensibility/extensions/runner.ts +70 -0
- package/src/extensibility/extensions/types.ts +30 -0
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +12 -13
- package/src/internal-urls/local-protocol.ts +3 -2
- package/src/internal-urls/mcp-protocol.ts +4 -1
- package/src/launch/terminal-output-worker-client.ts +53 -0
- package/src/launch/terminal-output-worker-protocol.ts +11 -0
- package/src/launch/terminal-output-worker.ts +23 -0
- package/src/lsp/client.ts +18 -3
- package/src/lsp/index.ts +4 -0
- package/src/lsp/render.ts +1 -1
- package/src/main.ts +127 -56
- package/src/mcp/manager.ts +120 -18
- package/src/modes/acp/acp-agent.ts +15 -9
- package/src/modes/components/chat-transcript-builder.ts +30 -11
- package/src/modes/components/codex-reset-fireworks.ts +369 -0
- package/src/modes/components/read-tool-group.ts +159 -17
- package/src/modes/components/session-selector.ts +19 -3
- package/src/modes/components/status-line/component.ts +381 -54
- package/src/modes/components/tool-execution.ts +78 -31
- package/src/modes/components/usage-row.ts +10 -5
- package/src/modes/controllers/event-controller.ts +26 -4
- package/src/modes/controllers/mcp-command-controller.ts +68 -3
- package/src/modes/controllers/selector-controller.ts +94 -36
- package/src/modes/controllers/tan-command-controller.ts +14 -0
- package/src/modes/interactive-mode.ts +31 -17
- package/src/modes/rpc/rpc-client.ts +18 -0
- package/src/modes/rpc/rpc-mode.ts +16 -1
- package/src/modes/rpc/rpc-types.ts +11 -0
- package/src/modes/theme/theme.ts +151 -6
- package/src/modes/types.ts +2 -1
- package/src/modes/utils/ui-helpers.ts +38 -21
- package/src/prompts/system/auto-thinking-difficulty.md +4 -2
- package/src/prompts/system/plan-mode-active.md +2 -2
- package/src/prompts/system/system-prompt.md +3 -0
- package/src/prompts/system/xdev-mount-notice.md +1 -1
- package/src/prompts/tools/bash.md +15 -17
- package/src/prompts/tools/checkpoint.md +1 -1
- package/src/prompts/tools/glob.md +7 -6
- package/src/prompts/tools/grep.md +7 -6
- package/src/sdk.ts +178 -15
- package/src/session/agent-session-events.ts +1 -0
- package/src/session/agent-session-types.ts +40 -1
- package/src/session/agent-session.ts +302 -175
- package/src/session/claude-session-store.ts +426 -0
- package/src/session/codex-session-store.ts +673 -0
- package/src/session/credential-pin.ts +93 -0
- package/src/session/foreign-session-import.ts +52 -0
- package/src/session/foreign-session-jsonl.ts +29 -0
- package/src/session/foreign-session-store.ts +26 -0
- package/src/session/model-controls.ts +11 -3
- package/src/session/session-advisors.ts +140 -16
- package/src/session/session-entries.ts +21 -1
- package/src/session/session-handoff.ts +20 -3
- package/src/session/session-loader.ts +25 -9
- package/src/session/session-maintenance.ts +59 -11
- package/src/session/session-manager.ts +61 -0
- package/src/session/session-tools.ts +107 -5
- package/src/session/settings-stream-fn.ts +1 -0
- package/src/session/turn-recovery.ts +97 -51
- package/src/slash-commands/builtin-registry.ts +131 -3
- package/src/system-prompt.ts +3 -2
- package/src/task/executor.ts +17 -4
- package/src/task/render.ts +20 -4
- package/src/thinking.ts +29 -10
- package/src/tools/acp-bridge.ts +52 -8
- package/src/tools/browser.ts +5 -0
- package/src/tools/checkpoint.ts +0 -13
- package/src/tools/grep.ts +64 -8
- package/src/tools/hub/launch.ts +10 -15
- package/src/tools/index.ts +28 -4
- package/src/tools/path-utils.ts +88 -0
- package/src/tools/read.ts +3 -0
- package/src/tools/write.ts +9 -3
- package/src/tools/xdev.ts +39 -14
- package/src/utils/changelog.ts +144 -4
- package/src/utils/git.ts +61 -14
- package/src/utils/jj.ts +19 -13
- package/src/web/search/providers/codex.ts +34 -0
- package/src/web/search/types.ts +1 -1
|
@@ -19,7 +19,7 @@ import * as path from "node:path";
|
|
|
19
19
|
import { scheduler } from "node:timers/promises";
|
|
20
20
|
import { isPromise } from "node:util/types";
|
|
21
21
|
|
|
22
|
-
import type { InMemorySnapshotStore } from "@oh-my-pi/hashline";
|
|
22
|
+
import type { Clipboard, InMemorySnapshotStore } from "@oh-my-pi/hashline";
|
|
23
23
|
import {
|
|
24
24
|
type AfterToolCallContext,
|
|
25
25
|
type AfterToolCallResult,
|
|
@@ -95,7 +95,7 @@ import {
|
|
|
95
95
|
stringProperty,
|
|
96
96
|
withTimeout,
|
|
97
97
|
} from "@oh-my-pi/pi-utils";
|
|
98
|
-
import type
|
|
98
|
+
import { type AdvisorConfig, type AdvisorRuntimeStatus, loadAdvisorTranscriptCosts } from "../advisor";
|
|
99
99
|
import { type AsyncJob, AsyncJobManager } from "../async";
|
|
100
100
|
import { shouldEnableAppendOnlyContext } from "../config/append-only-context-mode";
|
|
101
101
|
import type { ModelRegistry } from "../config/model-registry";
|
|
@@ -249,6 +249,7 @@ import {
|
|
|
249
249
|
shouldEvaluateCodexAutoRedeem,
|
|
250
250
|
shouldPromptCodexAutoRedeem,
|
|
251
251
|
} from "./codex-auto-reset";
|
|
252
|
+
import { recordCredentialPin, seedCredentialPins } from "./credential-pin";
|
|
252
253
|
import { EvalRunner, type EvalRunnerHost } from "./eval-runner";
|
|
253
254
|
import {
|
|
254
255
|
collectPendingToolCalls,
|
|
@@ -398,6 +399,9 @@ type SetSessionNameWithTrigger = (
|
|
|
398
399
|
trigger?: SessionNameTrigger,
|
|
399
400
|
) => Promise<boolean>;
|
|
400
401
|
|
|
402
|
+
const kPersistedSessionEntryId = Symbol("persistedSessionEntryId");
|
|
403
|
+
type PersistedAssistantMessage = AssistantMessage & { [kPersistedSessionEntryId]?: string };
|
|
404
|
+
|
|
401
405
|
export class AgentSession {
|
|
402
406
|
readonly agent: Agent;
|
|
403
407
|
readonly sessionManager: SessionManager;
|
|
@@ -406,6 +410,8 @@ export class AgentSession {
|
|
|
406
410
|
getXdevToolEntries: () => Array<{ name: string; summary: string }>;
|
|
407
411
|
readonly yieldQueue: YieldQueue;
|
|
408
412
|
fileSnapshotStore?: InMemorySnapshotStore;
|
|
413
|
+
/** Per-session `CUT`/`PASTE` clipboard register shared across edit calls. */
|
|
414
|
+
editClipboard?: Clipboard;
|
|
409
415
|
|
|
410
416
|
#powerAssertion: MacOSPowerAssertion | undefined;
|
|
411
417
|
|
|
@@ -956,6 +962,7 @@ export class AgentSession {
|
|
|
956
962
|
scheduleAgentContinue: options => this.#scheduleAgentContinue(options),
|
|
957
963
|
waitForSessionMessagePersistence: message => this.#waitForSessionMessagePersistence(message),
|
|
958
964
|
appendSessionMessage: message => this.#appendSessionMessage(message),
|
|
965
|
+
persistedAssistantEntryId: message => (message as PersistedAssistantMessage)[kPersistedSessionEntryId],
|
|
959
966
|
sessionMessageAlreadyPersisted: message => this.#sessionMessageAlreadyPersisted(message),
|
|
960
967
|
setModelWithProviderSessionReset: model => this.#setModelWithProviderSessionReset(model),
|
|
961
968
|
resetCurrentResponsesProviderSession: reason => this.#resetCurrentResponsesProviderSession(reason),
|
|
@@ -1274,8 +1281,8 @@ export class AgentSession {
|
|
|
1274
1281
|
hasPendingNextTurnMessages: () => this.#pendingNextTurnMessages.length > 0,
|
|
1275
1282
|
convertToLlmForSideRequest: messages => this.#convertToLlmForSideRequest(messages),
|
|
1276
1283
|
effectiveServiceTier: model => this.#models.effectiveServiceTier(model),
|
|
1277
|
-
resolveContextPromotionTarget: (model, contextWindow) =>
|
|
1278
|
-
this.#maintenance.resolveContextPromotionTarget(model, contextWindow),
|
|
1284
|
+
resolveContextPromotionTarget: (model, contextWindow, signal) =>
|
|
1285
|
+
this.#maintenance.resolveContextPromotionTarget(model, contextWindow, signal),
|
|
1279
1286
|
resolveCompactionModelCandidates: (model, availableModels) =>
|
|
1280
1287
|
this.#maintenance.resolveCompactionModelCandidates(model, availableModels),
|
|
1281
1288
|
resolveRetryFallbackRole: (selector, model) => this.#recovery.resolveRetryFallbackRole(selector, model),
|
|
@@ -1290,12 +1297,17 @@ export class AgentSession {
|
|
|
1290
1297
|
this.#advisors = new SessionAdvisors(advisorsHost, {
|
|
1291
1298
|
enabled: this.settings.get("advisor.enabled"),
|
|
1292
1299
|
tools: config.advisorTools,
|
|
1300
|
+
createGrepTool: config.advisorCreateGrepTool,
|
|
1301
|
+
createEditTool: config.advisorCreateEditTool,
|
|
1302
|
+
getToolContext: config.advisorGetToolContext,
|
|
1303
|
+
mcpResources: config.advisorMcpResources,
|
|
1293
1304
|
watchdogPrompt: config.advisorWatchdogPrompt,
|
|
1294
1305
|
sharedInstructions: config.advisorSharedInstructions,
|
|
1295
1306
|
contextPrompt: config.advisorContextPrompt,
|
|
1296
1307
|
configs: config.advisorConfigs,
|
|
1297
1308
|
streamFn: config.advisorStreamFn,
|
|
1298
1309
|
transformProviderContext: config.transformProviderContext,
|
|
1310
|
+
initialCosts: config.initialAdvisorCosts,
|
|
1299
1311
|
});
|
|
1300
1312
|
|
|
1301
1313
|
const maintenanceHost: SessionMaintenanceHost = {
|
|
@@ -1401,7 +1413,10 @@ export class AgentSession {
|
|
|
1401
1413
|
},
|
|
1402
1414
|
resetTodoCycle: () => this.#todo.resetCycle(),
|
|
1403
1415
|
buildDisplaySessionContext: () => this.buildDisplaySessionContext(),
|
|
1404
|
-
|
|
1416
|
+
resetAdvisorSessionState: () => this.#advisors.resetSessionState(),
|
|
1417
|
+
drainAndDetachAdvisorRecorders: () => this.#advisors.drainAndDetachRecorders(),
|
|
1418
|
+
reattachAdvisorRecorderFeeds: () => this.#advisors.reattachRecorderFeeds(),
|
|
1419
|
+
clearAdvisorCost: () => this.#advisors.clearCost(),
|
|
1405
1420
|
syncTodoPhasesFromBranch: () => this.#todo.syncFromBranch(),
|
|
1406
1421
|
};
|
|
1407
1422
|
this.#handoff = new SessionHandoff(handoffHost);
|
|
@@ -2061,6 +2076,9 @@ export class AgentSession {
|
|
|
2061
2076
|
const cache = this.#persistedMessageKeys;
|
|
2062
2077
|
const wasFresh = cache !== undefined && cache.anchor === this.#persistedMessageKeysAnchor();
|
|
2063
2078
|
const entryId = this.sessionManager.appendMessage(message);
|
|
2079
|
+
if (message.role === "assistant") {
|
|
2080
|
+
(message as PersistedAssistantMessage)[kPersistedSessionEntryId] = entryId;
|
|
2081
|
+
}
|
|
2064
2082
|
const key = sessionMessagePersistenceKey(message);
|
|
2065
2083
|
if (wasFresh && cache && key) {
|
|
2066
2084
|
cache.keys.add(key);
|
|
@@ -2413,6 +2431,15 @@ export class AgentSession {
|
|
|
2413
2431
|
},
|
|
2414
2432
|
costUsd: assistantMsg.usage.cost.total,
|
|
2415
2433
|
});
|
|
2434
|
+
// Persist which account served this turn so a resumed process can
|
|
2435
|
+
// re-pin it and keep the provider's account-scoped prompt cache
|
|
2436
|
+
// warm (broker-mode sticky routing is process-local).
|
|
2437
|
+
recordCredentialPin(
|
|
2438
|
+
this.#modelRegistry.authStorage,
|
|
2439
|
+
this.sessionManager,
|
|
2440
|
+
this.sessionId,
|
|
2441
|
+
assistantMsg.provider,
|
|
2442
|
+
);
|
|
2416
2443
|
}
|
|
2417
2444
|
if (event.message.role === "toolResult") {
|
|
2418
2445
|
const { toolName, toolCallId, isError, content } = event.message;
|
|
@@ -2596,6 +2623,11 @@ export class AgentSession {
|
|
|
2596
2623
|
return;
|
|
2597
2624
|
}
|
|
2598
2625
|
|
|
2626
|
+
// Record quota exhaustion before deciding whether this failed turn may be
|
|
2627
|
+
// replayed. Visible/side-effecting output then remains terminal while its
|
|
2628
|
+
// credential is still blocked or rotated exactly once.
|
|
2629
|
+
await this.#recovery.recordUsageLimitOutcome(msg);
|
|
2630
|
+
|
|
2599
2631
|
let compactionResult = COMPACTION_CHECK_NONE;
|
|
2600
2632
|
let checkedCompaction = false;
|
|
2601
2633
|
if (activeGoal) {
|
|
@@ -3380,6 +3412,14 @@ export class AgentSession {
|
|
|
3380
3412
|
this.agent.setMetadataResolver((provider: string) =>
|
|
3381
3413
|
buildSessionMetadata(sid, provider, this.#modelRegistry.authStorage),
|
|
3382
3414
|
);
|
|
3415
|
+
// Restore the session's recorded provider accounts before the first
|
|
3416
|
+
// request routes: sticky rows are process-local under a remote auth
|
|
3417
|
+
// broker, and losing them re-ranks onto a different account, cold-missing
|
|
3418
|
+
// the account-scoped prompt cache. Skipped for fresh provider sessions —
|
|
3419
|
+
// those explicitly want new routing identity.
|
|
3420
|
+
if (!this.#freshProviderSessionId) {
|
|
3421
|
+
seedCredentialPins(this.#modelRegistry.authStorage, this.sessionManager, sid);
|
|
3422
|
+
}
|
|
3383
3423
|
// Keep every live advisor's provider identity in lockstep with the primary's
|
|
3384
3424
|
// across every session-boundary transition — including branch paths that
|
|
3385
3425
|
// skip conversation restore — so advisors never emit the previous
|
|
@@ -4337,6 +4377,7 @@ export class AgentSession {
|
|
|
4337
4377
|
this.agent.clearDeferredToolDirectives();
|
|
4338
4378
|
this.#toolChoiceQueue.clear();
|
|
4339
4379
|
this.#tools.clearAcpPermissionDecisions();
|
|
4380
|
+
this.#tools.resetAnnouncedMounts();
|
|
4340
4381
|
}
|
|
4341
4382
|
|
|
4342
4383
|
/**
|
|
@@ -5170,6 +5211,7 @@ export class AgentSession {
|
|
|
5170
5211
|
void this.dispose().finally(() => process.exit(0));
|
|
5171
5212
|
},
|
|
5172
5213
|
getContextUsage: () => this.getContextUsage(),
|
|
5214
|
+
getAsyncJobSnapshot: () => this.getAsyncJobSnapshot(),
|
|
5173
5215
|
waitForIdle: () => this.waitForIdle(),
|
|
5174
5216
|
newSession: async options => {
|
|
5175
5217
|
const success = await this.newSession({ parentSession: options?.parentSession });
|
|
@@ -5988,6 +6030,7 @@ export class AgentSession {
|
|
|
5988
6030
|
}
|
|
5989
6031
|
|
|
5990
6032
|
this.#disconnectFromAgent();
|
|
6033
|
+
let advisorRecordersDetached = false;
|
|
5991
6034
|
await this.abort();
|
|
5992
6035
|
this.#cancelOwnAsyncJobs();
|
|
5993
6036
|
this.#closeAllProviderSessions("new session");
|
|
@@ -5995,69 +6038,73 @@ export class AgentSession {
|
|
|
5995
6038
|
const bashTransition = this.#bash.beginSessionTransition({ persistDetached: options?.drop !== true });
|
|
5996
6039
|
let sessionTransitioned = false;
|
|
5997
6040
|
try {
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
}
|
|
6009
|
-
|
|
6041
|
+
advisorRecordersDetached = true;
|
|
6042
|
+
await this.#advisors.drainAndDetachRecorders();
|
|
6043
|
+
try {
|
|
6044
|
+
this.agent.reset();
|
|
6045
|
+
if (options?.drop && previousSessionFile) {
|
|
6046
|
+
try {
|
|
6047
|
+
await this.sessionManager.dropSession(previousSessionFile);
|
|
6048
|
+
} catch (err) {
|
|
6049
|
+
logger.error("Failed to delete session during /drop", { err });
|
|
6050
|
+
}
|
|
6051
|
+
} else {
|
|
6052
|
+
await this.sessionManager.flush();
|
|
6010
6053
|
}
|
|
6011
|
-
|
|
6012
|
-
|
|
6054
|
+
await this.sessionManager.newSession({
|
|
6055
|
+
...options,
|
|
6056
|
+
additionalDirectories: this.settings.get("workspace.additionalDirectories"),
|
|
6057
|
+
});
|
|
6058
|
+
this.#bash.markSessionTransition(bashTransition);
|
|
6059
|
+
// The new session owns the transcript from here, so the previous
|
|
6060
|
+
// conversation's advisor spend is retired with it. Clearing at the commit
|
|
6061
|
+
// point keeps the status line honest even if a later step below throws.
|
|
6062
|
+
this.#advisors.clearCost();
|
|
6063
|
+
sessionTransitioned = true;
|
|
6064
|
+
} finally {
|
|
6065
|
+
this.#bash.finishSessionTransition(bashTransition, sessionTransitioned);
|
|
6013
6066
|
}
|
|
6014
|
-
await this.sessionManager.newSession({
|
|
6015
|
-
...options,
|
|
6016
|
-
additionalDirectories: this.settings.get("workspace.additionalDirectories"),
|
|
6017
|
-
});
|
|
6018
|
-
this.#bash.markSessionTransition(bashTransition);
|
|
6019
|
-
// The new session owns the transcript from here, so the previous
|
|
6020
|
-
// conversation's advisor spend is retired with it. Clearing at the commit
|
|
6021
|
-
// point keeps the status line honest even if a later step below throws.
|
|
6022
|
-
this.#advisors.clearCost();
|
|
6023
|
-
sessionTransitioned = true;
|
|
6024
|
-
} finally {
|
|
6025
|
-
this.#bash.finishSessionTransition(bashTransition, sessionTransitioned);
|
|
6026
|
-
}
|
|
6027
6067
|
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6068
|
+
this.#clearSessionScopedToolState();
|
|
6069
|
+
this.#clearCheckpointRuntimeState();
|
|
6070
|
+
this.setTodoPhases([]);
|
|
6071
|
+
this.#freshProviderSessionId = undefined;
|
|
6072
|
+
this.#clearInheritedProviderPromptCacheKey();
|
|
6073
|
+
this.#syncAgentSessionId();
|
|
6074
|
+
this.#memory.rekeyForCurrentSessionId();
|
|
6075
|
+
await this.#memory.resetContextForNewTranscript();
|
|
6076
|
+
this.#pendingNextTurnMessages = [];
|
|
6077
|
+
this.#scheduledHiddenNextTurnGeneration = undefined;
|
|
6038
6078
|
|
|
6039
|
-
|
|
6040
|
-
|
|
6079
|
+
this.sessionManager.appendThinkingLevelChange(this.thinkingLevel, this.configuredThinkingLevel());
|
|
6080
|
+
this.sessionManager.appendServiceTierChange(this.#models.serviceTierEntry());
|
|
6041
6081
|
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6082
|
+
this.#todo.resetCycle();
|
|
6083
|
+
this.#planReferenceSent = false;
|
|
6084
|
+
this.#planReferencePath = "local://PLAN.md";
|
|
6085
|
+
this.#advisors.resetSessionState();
|
|
6086
|
+
advisorRecordersDetached = false;
|
|
6087
|
+
this.#reconnectToAgent();
|
|
6088
|
+
// The workspace-roots block must reflect the new session's directory set,
|
|
6089
|
+
// not the previous session's — refresh before the next turn goes out.
|
|
6090
|
+
await this.refreshBaseSystemPrompt();
|
|
6050
6091
|
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6092
|
+
// Emit session_switch event with reason "new" to hooks
|
|
6093
|
+
if (this.#extensionRunner) {
|
|
6094
|
+
await this.#extensionRunner.emit({
|
|
6095
|
+
type: "session_switch",
|
|
6096
|
+
reason: "new",
|
|
6097
|
+
previousSessionFile,
|
|
6098
|
+
});
|
|
6099
|
+
}
|
|
6059
6100
|
|
|
6060
|
-
|
|
6101
|
+
return true;
|
|
6102
|
+
} finally {
|
|
6103
|
+
if (advisorRecordersDetached) {
|
|
6104
|
+
if (sessionTransitioned) this.#advisors.resetSessionState();
|
|
6105
|
+
else this.#advisors.reattachRecorderFeeds();
|
|
6106
|
+
}
|
|
6107
|
+
}
|
|
6061
6108
|
}
|
|
6062
6109
|
|
|
6063
6110
|
/**
|
|
@@ -6093,59 +6140,70 @@ export class AgentSession {
|
|
|
6093
6140
|
await this.#bash.flushPending();
|
|
6094
6141
|
// Flush current session to ensure all entries are written
|
|
6095
6142
|
await this.sessionManager.flush();
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
// Fork the session (creates new session file with same entries)
|
|
6099
|
-
let forkResult: { oldSessionFile: string; newSessionFile: string } | undefined;
|
|
6143
|
+
let advisorRecordersDetached = false;
|
|
6100
6144
|
try {
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6145
|
+
advisorRecordersDetached = true;
|
|
6146
|
+
// Fork keeps the conversation, but still needs a quiet artifact boundary:
|
|
6147
|
+
// stop and settle in-flight advisors before muting their feeds.
|
|
6148
|
+
await this.#advisors.drainAndDetachRecorders();
|
|
6149
|
+
const bashTransition = this.#bash.beginSessionTransition();
|
|
6150
|
+
|
|
6151
|
+
// Fork the session (creates new session file with same entries)
|
|
6152
|
+
let forkResult: { oldSessionFile: string; newSessionFile: string } | undefined;
|
|
6153
|
+
try {
|
|
6154
|
+
forkResult = await this.sessionManager.fork();
|
|
6155
|
+
} catch (error) {
|
|
6156
|
+
this.#bash.finishSessionTransition(bashTransition, false);
|
|
6157
|
+
throw error;
|
|
6158
|
+
}
|
|
6159
|
+
if (!forkResult) {
|
|
6160
|
+
this.#bash.finishSessionTransition(bashTransition, false);
|
|
6161
|
+
return false;
|
|
6162
|
+
}
|
|
6163
|
+
this.#bash.markSessionTransition(bashTransition);
|
|
6164
|
+
this.#bash.finishSessionTransition(bashTransition, true);
|
|
6112
6165
|
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6166
|
+
// Copy artifacts directory if it exists
|
|
6167
|
+
const oldArtifactDir = forkResult.oldSessionFile.slice(0, -6);
|
|
6168
|
+
const newArtifactDir = forkResult.newSessionFile.slice(0, -6);
|
|
6116
6169
|
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6170
|
+
try {
|
|
6171
|
+
const oldDirStat = await fs.promises.stat(oldArtifactDir);
|
|
6172
|
+
if (oldDirStat.isDirectory()) {
|
|
6173
|
+
await fs.promises.cp(oldArtifactDir, newArtifactDir, { recursive: true });
|
|
6174
|
+
}
|
|
6175
|
+
} catch (err) {
|
|
6176
|
+
if (!isEnoent(err)) {
|
|
6177
|
+
logger.warn("Failed to copy artifacts during fork", {
|
|
6178
|
+
oldArtifactDir,
|
|
6179
|
+
newArtifactDir,
|
|
6180
|
+
error: err instanceof Error ? err.message : String(err),
|
|
6181
|
+
});
|
|
6182
|
+
}
|
|
6121
6183
|
}
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6184
|
+
|
|
6185
|
+
// Update agent session ID
|
|
6186
|
+
this.#freshProviderSessionId = undefined;
|
|
6187
|
+
this.#adoptInheritedProviderPromptCacheKey();
|
|
6188
|
+
this.#syncAgentSessionId();
|
|
6189
|
+
this.#memory.rekeyForCurrentSessionId();
|
|
6190
|
+
this.#advisors.reattachRecorderFeeds();
|
|
6191
|
+
advisorRecordersDetached = false;
|
|
6192
|
+
await this.#memory.resetContextForNewTranscript();
|
|
6193
|
+
|
|
6194
|
+
// Emit session_switch event with reason "fork" to hooks
|
|
6195
|
+
if (this.#extensionRunner) {
|
|
6196
|
+
await this.#extensionRunner.emit({
|
|
6197
|
+
type: "session_switch",
|
|
6198
|
+
reason: "fork",
|
|
6199
|
+
previousSessionFile,
|
|
6128
6200
|
});
|
|
6129
6201
|
}
|
|
6130
|
-
}
|
|
6131
|
-
|
|
6132
|
-
// Update agent session ID
|
|
6133
|
-
this.#freshProviderSessionId = undefined;
|
|
6134
|
-
this.#adoptInheritedProviderPromptCacheKey();
|
|
6135
|
-
this.#syncAgentSessionId();
|
|
6136
|
-
this.#memory.rekeyForCurrentSessionId();
|
|
6137
|
-
await this.#memory.resetContextForNewTranscript();
|
|
6138
6202
|
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
type: "session_switch",
|
|
6143
|
-
reason: "fork",
|
|
6144
|
-
previousSessionFile,
|
|
6145
|
-
});
|
|
6203
|
+
return true;
|
|
6204
|
+
} finally {
|
|
6205
|
+
if (advisorRecordersDetached) this.#advisors.reattachRecorderFeeds();
|
|
6146
6206
|
}
|
|
6147
|
-
|
|
6148
|
-
return true;
|
|
6149
6207
|
}
|
|
6150
6208
|
|
|
6151
6209
|
/** Move the active session and artifacts after enforcing mode transition invariants. */
|
|
@@ -6519,13 +6577,30 @@ export class AgentSession {
|
|
|
6519
6577
|
|
|
6520
6578
|
async #setModelWithProviderSessionReset(model: Model): Promise<void> {
|
|
6521
6579
|
const currentModel = this.model;
|
|
6580
|
+
const isChanging = !currentModel || !modelsAreEqual(currentModel, model);
|
|
6522
6581
|
if (currentModel) {
|
|
6523
6582
|
this.#closeProviderSessionsForModelSwitch(currentModel, model);
|
|
6524
|
-
if (
|
|
6583
|
+
if (isChanging) {
|
|
6525
6584
|
this.#clearInheritedProviderPromptCacheKey();
|
|
6526
6585
|
}
|
|
6527
6586
|
}
|
|
6528
6587
|
this.agent.setModel(model);
|
|
6588
|
+
// Model mutations driven through ModelControls (explicit /model, prewalk
|
|
6589
|
+
// hand-offs, retry-fallback, model cycling) funnel through this method,
|
|
6590
|
+
// so this is the single point that notifies subscribers (ACP config
|
|
6591
|
+
// sync, RPC, TUI status line) — callers that bypass ModelControls never
|
|
6592
|
+
// need to remember to notify separately. `switchSession`'s rollback
|
|
6593
|
+
// restores via `agent.setModel` directly and emits its own corrective
|
|
6594
|
+
// event.
|
|
6595
|
+
//
|
|
6596
|
+
// Fan-out uses the synchronous `#emit`, matching `thinking_level_changed`:
|
|
6597
|
+
// `model_changed` has no extension-facing hook (`#emitExtensionEvent`
|
|
6598
|
+
// never maps it), so routing it through `#emitSessionEvent` would only
|
|
6599
|
+
// add an extension-delivery await inside every model switch — including
|
|
6600
|
+
// retry-fallback on the error path.
|
|
6601
|
+
if (isChanging) {
|
|
6602
|
+
this.#emit({ type: "model_changed" });
|
|
6603
|
+
}
|
|
6529
6604
|
|
|
6530
6605
|
// Re-evaluate append-only context mode — provider or setting may have changed
|
|
6531
6606
|
this.#syncAppendOnlyContext(model);
|
|
@@ -7044,6 +7119,11 @@ export class AgentSession {
|
|
|
7044
7119
|
this.#scheduledHiddenNextTurnGeneration = undefined;
|
|
7045
7120
|
|
|
7046
7121
|
try {
|
|
7122
|
+
if (switchingToDifferentSession) {
|
|
7123
|
+
// Stop and settle in-flight advisors while the old-session feeds can
|
|
7124
|
+
// still observe message_end, then mute before swapping files.
|
|
7125
|
+
await this.#advisors.drainAndDetachRecorders();
|
|
7126
|
+
}
|
|
7047
7127
|
await this.sessionManager.setSessionFile(sessionPath);
|
|
7048
7128
|
this.#bash.markSessionTransition(bashTransition);
|
|
7049
7129
|
if (switchingToDifferentSession) {
|
|
@@ -7156,7 +7236,7 @@ export class AgentSession {
|
|
|
7156
7236
|
if (switchingToDifferentSession) {
|
|
7157
7237
|
await this.#memory.resetContextForNewTranscript();
|
|
7158
7238
|
}
|
|
7159
|
-
if (switchingToDifferentSession) {
|
|
7239
|
+
if (switchingToDifferentSession || didReloadConversationChange) {
|
|
7160
7240
|
this.#clearSessionScopedToolState();
|
|
7161
7241
|
}
|
|
7162
7242
|
this.#reconnectToAgent();
|
|
@@ -7179,9 +7259,14 @@ export class AgentSession {
|
|
|
7179
7259
|
error: String(refreshErr),
|
|
7180
7260
|
});
|
|
7181
7261
|
}
|
|
7182
|
-
//
|
|
7183
|
-
// an earlier
|
|
7184
|
-
|
|
7262
|
+
// Hand the ledger over to the session that just took over, and only once the
|
|
7263
|
+
// switch has committed: an earlier swap would be lost work if any step above
|
|
7264
|
+
// rolled it back. The target's own advisor transcripts are the record of what
|
|
7265
|
+
// it already spent, so a session with history resumes with its total instead
|
|
7266
|
+
// of restarting at zero.
|
|
7267
|
+
if (switchingToDifferentSession) {
|
|
7268
|
+
this.#advisors.restoreCost(await loadAdvisorTranscriptCosts(this.sessionFile));
|
|
7269
|
+
}
|
|
7185
7270
|
this.#bash.finishSessionTransition(bashTransition, true);
|
|
7186
7271
|
return true;
|
|
7187
7272
|
} catch (error) {
|
|
@@ -7202,13 +7287,32 @@ export class AgentSession {
|
|
|
7202
7287
|
this.#pendingRewindReport = previousPendingRewindReport;
|
|
7203
7288
|
this.#lastCompletedRewind = previousLastCompletedRewind;
|
|
7204
7289
|
this.#rewoundToolResultIds = previousRewoundToolResultIds;
|
|
7290
|
+
// The try block may have already reached #setModelWithProviderSessionReset
|
|
7291
|
+
// for the target session's model, which emits `model_changed` for it.
|
|
7292
|
+
// Restoring here bypasses that method (it also resets provider-session
|
|
7293
|
+
// state we're already unwinding above), so if the rollback actually
|
|
7294
|
+
// changes the model back, emit the corrective event ourselves —
|
|
7295
|
+
// otherwise ACP/RPC/TUI keep advertising the never-committed target.
|
|
7296
|
+
// Deferred until after restoreThinkingSnapshot below: #emit's listeners
|
|
7297
|
+
// (ACP's #handleLifetimeEvent -> #pushConfigOptionUpdate) read
|
|
7298
|
+
// session state synchronously before their first await, so emitting
|
|
7299
|
+
// here — before the target session's thinking level is unwound —
|
|
7300
|
+
// would push a { previousModel, target-session-thinking } config that
|
|
7301
|
+
// was never a real session state.
|
|
7302
|
+
let modelRolledBack = false;
|
|
7205
7303
|
if (previousModel) {
|
|
7304
|
+
const rolledBackModel = this.model;
|
|
7206
7305
|
this.agent.setModel(previousModel);
|
|
7306
|
+
modelRolledBack = !modelsAreEqual(rolledBackModel, previousModel);
|
|
7207
7307
|
}
|
|
7208
7308
|
this.#models.restoreThinkingSnapshot(previousThinkingLevel, previousAutoThinking, previousAutoResolvedLevel);
|
|
7209
7309
|
this.#models.restoreServiceTiers(previousServiceTierByFamily);
|
|
7310
|
+
if (modelRolledBack) {
|
|
7311
|
+
this.#emit({ type: "model_changed" });
|
|
7312
|
+
}
|
|
7210
7313
|
this.#todo.syncFromBranch();
|
|
7211
7314
|
this.#advisors.resetAllRuntimes();
|
|
7315
|
+
this.#advisors.reattachRecorderFeeds();
|
|
7212
7316
|
this.#reconnectToAgent();
|
|
7213
7317
|
try {
|
|
7214
7318
|
await this.#sessionSwitchReconciler?.();
|
|
@@ -7276,45 +7380,57 @@ export class AgentSession {
|
|
|
7276
7380
|
await this.#drainAutolearnCapture();
|
|
7277
7381
|
|
|
7278
7382
|
let sessionTransitioned = false;
|
|
7383
|
+
let advisorRecordersDetached = false;
|
|
7279
7384
|
try {
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7385
|
+
advisorRecordersDetached = true;
|
|
7386
|
+
await this.#advisors.drainAndDetachRecorders();
|
|
7387
|
+
try {
|
|
7388
|
+
if (!selectedEntry.parentId) {
|
|
7389
|
+
await this.sessionManager.newSession({ parentSession: previousSessionFile });
|
|
7390
|
+
} else {
|
|
7391
|
+
this.sessionManager.createBranchedSession(selectedEntry.parentId);
|
|
7392
|
+
}
|
|
7393
|
+
this.#bash.markSessionTransition(bashTransition);
|
|
7394
|
+
this.#advisors.clearCost();
|
|
7395
|
+
sessionTransitioned = true;
|
|
7396
|
+
} finally {
|
|
7397
|
+
this.#bash.finishSessionTransition(bashTransition, sessionTransitioned);
|
|
7284
7398
|
}
|
|
7285
|
-
this.#
|
|
7286
|
-
this.#
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
this.#
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
this.#todo.syncFromBranch();
|
|
7294
|
-
this.#freshProviderSessionId = undefined;
|
|
7295
|
-
this.#clearInheritedProviderPromptCacheKey();
|
|
7296
|
-
this.#syncAgentSessionId();
|
|
7297
|
-
this.#memory.rekeyForCurrentSessionId();
|
|
7298
|
-
await this.#memory.resetContextForNewTranscript();
|
|
7399
|
+
this.#clearSessionScopedToolState();
|
|
7400
|
+
this.#rehydrateCheckpointRewindState();
|
|
7401
|
+
this.#todo.syncFromBranch();
|
|
7402
|
+
this.#freshProviderSessionId = undefined;
|
|
7403
|
+
this.#clearInheritedProviderPromptCacheKey();
|
|
7404
|
+
this.#syncAgentSessionId();
|
|
7405
|
+
this.#memory.rekeyForCurrentSessionId();
|
|
7406
|
+
await this.#memory.resetContextForNewTranscript();
|
|
7299
7407
|
|
|
7300
|
-
|
|
7301
|
-
|
|
7408
|
+
// Reload messages from entries (works for both file and in-memory mode)
|
|
7409
|
+
const sessionContext = this.buildDisplaySessionContext();
|
|
7302
7410
|
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7411
|
+
// Emit session_branch event to hooks (after branch completes)
|
|
7412
|
+
if (this.#extensionRunner) {
|
|
7413
|
+
await this.#extensionRunner.emit({
|
|
7414
|
+
type: "session_branch",
|
|
7415
|
+
previousSessionFile,
|
|
7416
|
+
});
|
|
7417
|
+
}
|
|
7310
7418
|
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7419
|
+
if (!skipConversationRestore) {
|
|
7420
|
+
this.agent.replaceMessages(sessionContext.messages);
|
|
7421
|
+
this.#advisors.resetSessionState();
|
|
7422
|
+
this.#closeCodexProviderSessionsForHistoryRewrite();
|
|
7423
|
+
}
|
|
7316
7424
|
|
|
7317
|
-
|
|
7425
|
+
this.#advisors.reattachRecorderFeeds();
|
|
7426
|
+
advisorRecordersDetached = false;
|
|
7427
|
+
return { selectedText, selectedImages, cancelled: false };
|
|
7428
|
+
} finally {
|
|
7429
|
+
if (advisorRecordersDetached) {
|
|
7430
|
+
if (sessionTransitioned) this.#advisors.resetSessionState();
|
|
7431
|
+
else this.#advisors.reattachRecorderFeeds();
|
|
7432
|
+
}
|
|
7433
|
+
}
|
|
7318
7434
|
}
|
|
7319
7435
|
|
|
7320
7436
|
async branchFromBtw(
|
|
@@ -7378,44 +7494,55 @@ export class AgentSession {
|
|
|
7378
7494
|
await this.#drainAutolearnCapture();
|
|
7379
7495
|
|
|
7380
7496
|
let sessionTransitioned = false;
|
|
7497
|
+
let advisorRecordersDetached = false;
|
|
7381
7498
|
try {
|
|
7382
|
-
|
|
7383
|
-
this.#
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7499
|
+
advisorRecordersDetached = true;
|
|
7500
|
+
await this.#advisors.drainAndDetachRecorders();
|
|
7501
|
+
try {
|
|
7502
|
+
this.sessionManager.createBranchedSession(leafId);
|
|
7503
|
+
this.#bash.markSessionTransition(bashTransition);
|
|
7504
|
+
this.#advisors.clearCost();
|
|
7505
|
+
sessionTransitioned = true;
|
|
7506
|
+
} finally {
|
|
7507
|
+
this.#bash.finishSessionTransition(bashTransition, sessionTransitioned);
|
|
7508
|
+
}
|
|
7389
7509
|
|
|
7390
|
-
|
|
7510
|
+
this.#clearSessionScopedToolState();
|
|
7391
7511
|
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7512
|
+
this.#rehydrateCheckpointRewindState();
|
|
7513
|
+
this.sessionManager.appendMessage({
|
|
7514
|
+
role: "user",
|
|
7515
|
+
content: [{ type: "text", text: question }],
|
|
7516
|
+
timestamp: Date.now(),
|
|
7517
|
+
});
|
|
7518
|
+
this.sessionManager.appendMessage(sanitizeAssistantForReparentedHistory(assistantMessage));
|
|
7519
|
+
this.#todo.syncFromBranch();
|
|
7520
|
+
this.#freshProviderSessionId = undefined;
|
|
7521
|
+
this.#syncAgentSessionId();
|
|
7522
|
+
this.#memory.rekeyForCurrentSessionId();
|
|
7523
|
+
await this.#memory.resetContextForNewTranscript();
|
|
7404
7524
|
|
|
7405
|
-
|
|
7525
|
+
const sessionContext = this.buildDisplaySessionContext();
|
|
7406
7526
|
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7527
|
+
if (this.#extensionRunner) {
|
|
7528
|
+
await this.#extensionRunner.emit({
|
|
7529
|
+
type: "session_branch",
|
|
7530
|
+
previousSessionFile,
|
|
7531
|
+
});
|
|
7532
|
+
}
|
|
7413
7533
|
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7534
|
+
this.agent.replaceMessages(sessionContext.messages);
|
|
7535
|
+
this.#advisors.resetSessionState();
|
|
7536
|
+
this.#closeCodexProviderSessionsForHistoryRewrite();
|
|
7537
|
+
advisorRecordersDetached = false;
|
|
7417
7538
|
|
|
7418
|
-
|
|
7539
|
+
return { cancelled: false, sessionFile: this.sessionFile };
|
|
7540
|
+
} finally {
|
|
7541
|
+
if (advisorRecordersDetached) {
|
|
7542
|
+
if (sessionTransitioned) this.#advisors.resetSessionState();
|
|
7543
|
+
else this.#advisors.reattachRecorderFeeds();
|
|
7544
|
+
}
|
|
7545
|
+
}
|
|
7419
7546
|
}
|
|
7420
7547
|
|
|
7421
7548
|
// =========================================================================
|