@oh-my-pi/pi-coding-agent 17.2.4 → 17.2.6
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 +69 -0
- package/dist/{CHANGELOG-bpmhv26t.md → CHANGELOG-gs76k6wc.md} +69 -0
- package/dist/cli.js +4438 -3962
- package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
- package/dist/types/cli/args.d.ts +4 -1
- package/dist/types/cli/browser-relay-cli.d.ts +15 -0
- package/dist/types/cli/command-help.d.ts +99 -0
- package/dist/types/cli/gc-cli.d.ts +1 -0
- package/dist/types/cli/help-extra.d.ts +2 -0
- package/dist/types/cli/thinking-levels.d.ts +5 -0
- package/dist/types/cli/update-cli.d.ts +13 -0
- package/dist/types/commands/browser-relay.d.ts +38 -0
- package/dist/types/commands/commit.d.ts +3 -0
- package/dist/types/commands/complete.d.ts +1 -1
- package/dist/types/commands/completions.d.ts +6 -0
- package/dist/types/commands/grep.d.ts +3 -0
- package/dist/types/commands/join.d.ts +4 -0
- package/dist/types/commands/launch-help.d.ts +171 -0
- package/dist/types/commands/launch.d.ts +5 -1
- package/dist/types/commands/models.d.ts +3 -0
- package/dist/types/commands/say.d.ts +10 -0
- package/dist/types/commands/worktree.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/model-discovery.d.ts +2 -2
- package/dist/types/config/models-config-schema-bundle.d.ts +3 -0
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/models-config.d.ts +1 -0
- package/dist/types/config/service-tier.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +69 -21
- package/dist/types/cursor-bridge-tools.d.ts +1 -1
- package/dist/types/cursor.d.ts +7 -4
- package/dist/types/edit/index.d.ts +3 -3
- package/dist/types/edit/modes/replace.d.ts +22 -15
- package/dist/types/edit/renderer.d.ts +1 -1
- package/dist/types/eval/py/kernel.d.ts +3 -1
- package/dist/types/eval/py/spawn-options.d.ts +12 -16
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +8 -1
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
- package/dist/types/launch/broker.d.ts +1 -1
- package/dist/types/launch/client.d.ts +15 -4
- package/dist/types/launch/ensure.d.ts +8 -0
- package/dist/types/launch/paths.d.ts +1 -1
- package/dist/types/launch/protocol.d.ts +19 -2
- package/dist/types/lsp/client.d.ts +2 -0
- package/dist/types/lsp/mux/daemon.d.ts +15 -0
- package/dist/types/lsp/mux/protocol.d.ts +57 -0
- package/dist/types/lsp/mux/server.d.ts +18 -0
- package/dist/types/lsp/types.d.ts +22 -2
- package/dist/types/main.d.ts +2 -0
- package/dist/types/mnemopi/embed-client.d.ts +1 -1
- package/dist/types/mnemopi/state.d.ts +0 -23
- package/dist/types/modes/components/assistant-message.d.ts +2 -0
- package/dist/types/modes/components/btw-panel.d.ts +3 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/read-tool-group.d.ts +2 -0
- package/dist/types/modes/components/stripped-tool-calls-placeholder.d.ts +12 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/controllers/btw-controller.d.ts +2 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +5 -1
- package/dist/types/modes/types.d.ts +4 -1
- package/dist/types/modes/workflow.d.ts +2 -1
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/security/contracts/schemas.d.ts +405 -403
- package/dist/types/session/agent-session-types.d.ts +8 -1
- package/dist/types/session/agent-session.d.ts +26 -2
- package/dist/types/session/indexed-session-storage.d.ts +1 -0
- package/dist/types/session/launch-completion.d.ts +10 -0
- package/dist/types/session/session-advisors.d.ts +1 -1
- package/dist/types/session/session-context.d.ts +2 -1
- package/dist/types/session/session-entries.d.ts +15 -1
- package/dist/types/session/session-maintenance.d.ts +1 -0
- package/dist/types/session/session-manager.d.ts +23 -11
- package/dist/types/session/session-stats.d.ts +10 -0
- package/dist/types/session/session-storage.d.ts +15 -3
- package/dist/types/session/yield-queue.d.ts +6 -1
- package/dist/types/system-prompt.d.ts +4 -1
- package/dist/types/task/index.d.ts +2 -1
- package/dist/types/task/spawn-policy.d.ts +5 -0
- package/dist/types/thinking.d.ts +1 -7
- package/dist/types/tools/ast-grep.d.ts +1 -1
- package/dist/types/tools/browser/registry.d.ts +2 -1
- package/dist/types/tools/browser/relay/bridge.d.ts +35 -0
- package/dist/types/tools/browser/relay/daemon.d.ts +16 -0
- package/dist/types/tools/browser/relay/kind.d.ts +19 -0
- package/dist/types/tools/browser/relay/protocol.d.ts +97 -0
- package/dist/types/tools/browser/relay/server.d.ts +35 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -0
- package/dist/types/tools/computer/exposure.d.ts +9 -7
- package/dist/types/tools/computer/protocol.d.ts +70 -17
- package/dist/types/tools/computer/supervisor.d.ts +23 -10
- package/dist/types/tools/computer/worker-entry.d.ts +1 -0
- package/dist/types/tools/computer/worker.d.ts +42 -7
- package/dist/types/tools/computer-renderer.d.ts +7 -5
- package/dist/types/tools/computer.d.ts +25 -44
- package/dist/types/tools/context.d.ts +3 -0
- package/dist/types/tools/glob.d.ts +1 -1
- package/dist/types/tools/grep.d.ts +1 -1
- package/dist/types/tools/index.d.ts +9 -0
- package/dist/types/tools/render-utils.d.ts +2 -0
- package/dist/types/tools/{browser/run-cancellation.d.ts → run-scope.d.ts} +8 -8
- package/dist/types/tools/tool-timeouts.d.ts +5 -0
- package/dist/types/tools/xdev.d.ts +8 -0
- package/dist/types/utils/clipboard.d.ts +2 -2
- package/dist/types/web/kagi.d.ts +1 -0
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/providers/anthropic.d.ts +1 -0
- package/dist/types/web/search/providers/base.d.ts +2 -0
- package/dist/types/web/search/providers/brave.d.ts +1 -0
- package/dist/types/web/search/providers/browser-page.d.ts +1 -0
- package/dist/types/web/search/providers/codex.d.ts +1 -0
- package/dist/types/web/search/providers/exa.d.ts +1 -0
- package/dist/types/web/search/providers/firecrawl.d.ts +1 -0
- package/dist/types/web/search/providers/gemini.d.ts +1 -0
- package/dist/types/web/search/providers/jina.d.ts +1 -0
- package/dist/types/web/search/providers/kagi.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -0
- package/dist/types/web/search/providers/parallel.d.ts +1 -0
- package/dist/types/web/search/providers/perplexity.d.ts +1 -0
- package/dist/types/web/search/providers/searxng.d.ts +1 -0
- package/dist/types/web/search/providers/tavily.d.ts +1 -0
- package/dist/types/web/search/providers/tinyfish.d.ts +1 -0
- package/dist/types/web/search/providers/utils.d.ts +6 -9
- package/dist/types/web/search/providers/zai.d.ts +1 -0
- package/dist/types/web/search/types.d.ts +4 -0
- package/package.json +12 -12
- package/src/cli/args.ts +7 -87
- package/src/cli/browser-relay-cli.ts +119 -0
- package/src/cli/command-help.ts +103 -0
- package/src/cli/completion-gen.ts +5 -5
- package/src/cli/flag-tables.ts +9 -0
- package/src/cli/gc-cli.ts +641 -21
- package/src/cli/help-extra.ts +89 -0
- package/src/cli/setup-cli.ts +13 -21
- package/src/cli/thinking-levels.ts +7 -0
- package/src/cli/update-cli.ts +26 -7
- package/src/cli-commands.ts +170 -33
- package/src/cli.ts +17 -5
- package/src/commands/acp.ts +3 -1
- package/src/commands/agents.ts +3 -2
- package/src/commands/auth-broker.ts +3 -2
- package/src/commands/auth-gateway.ts +3 -2
- package/src/commands/bench.ts +2 -3
- package/src/commands/browser-relay.ts +53 -0
- package/src/commands/cleanse.ts +2 -2
- package/src/commands/commit.ts +3 -2
- package/src/commands/complete.ts +2 -1
- package/src/commands/completions.ts +3 -2
- package/src/commands/config.ts +3 -2
- package/src/commands/dry-balance.ts +2 -2
- package/src/commands/gallery.ts +3 -2
- package/src/commands/gc.ts +3 -2
- package/src/commands/grep.ts +3 -2
- package/src/commands/grievances.ts +3 -2
- package/src/commands/install.ts +2 -2
- package/src/commands/join.ts +3 -2
- package/src/commands/launch-help.ts +116 -0
- package/src/commands/launch.ts +7 -191
- package/src/commands/models.ts +3 -2
- package/src/commands/plugin.ts +3 -2
- package/src/commands/read.ts +3 -2
- package/src/commands/say.ts +3 -2
- package/src/commands/setup.ts +3 -2
- package/src/commands/shell.ts +3 -2
- package/src/commands/ssh.ts +3 -2
- package/src/commands/stats.ts +3 -2
- package/src/commands/tiny-models.ts +2 -2
- package/src/commands/token.ts +2 -2
- package/src/commands/ttsr.ts +2 -2
- package/src/commands/update.ts +3 -2
- package/src/commands/usage.ts +3 -2
- package/src/commands/web-search.ts +3 -2
- package/src/commands/worktree.ts +3 -2
- package/src/config/keybindings.ts +5 -0
- package/src/config/model-discovery.ts +44 -27
- package/src/config/model-registry.ts +19 -13
- package/src/config/models-config-schema-bundle.ts +9 -0
- package/src/config/resolve-config-value.ts +2 -1
- package/src/config/service-tier.ts +5 -0
- package/src/config/settings-schema.ts +72 -20
- package/src/config/settings.ts +1 -1
- package/src/cursor-bridge-tools.ts +1 -1
- package/src/cursor.ts +10 -14
- package/src/edit/diff.ts +17 -8
- package/src/edit/index.ts +20 -7
- package/src/edit/modes/replace.ts +93 -40
- package/src/edit/renderer.ts +1 -1
- package/src/edit/streaming.ts +14 -17
- package/src/eval/py/kernel.ts +2 -1
- package/src/eval/py/spawn-options.ts +24 -29
- package/src/export/html/index.ts +10 -3
- package/src/export/html/template.js +8 -26
- package/src/export/share.ts +4 -0
- package/src/extensibility/extensions/wrapper.ts +1 -0
- package/src/extensibility/legacy-pi-ai-shim.ts +22 -1
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -6
- package/src/extensibility/plugins/legacy-pi-compat.ts +124 -57
- package/src/extensibility/skills.ts +11 -0
- package/src/extensibility/utils.ts +10 -2
- package/src/launch/broker.ts +223 -7
- package/src/launch/client.ts +192 -21
- package/src/launch/ensure.ts +73 -0
- package/src/launch/paths.ts +1 -1
- package/src/launch/protocol.ts +54 -2
- package/src/lsp/client.ts +23 -2
- package/src/lsp/index.ts +8 -0
- package/src/lsp/mux/daemon.ts +348 -0
- package/src/lsp/mux/protocol.ts +96 -0
- package/src/lsp/mux/server.ts +797 -0
- package/src/lsp/types.ts +28 -2
- package/src/main.ts +20 -8
- package/src/mcp/config-writer.ts +1 -1
- package/src/mcp/oauth-flow.ts +11 -1
- package/src/mnemopi/embed-client.ts +49 -2
- package/src/mnemopi/state.ts +57 -23
- package/src/modes/components/assistant-message.ts +11 -0
- package/src/modes/components/btw-panel.ts +41 -4
- package/src/modes/components/chat-transcript-builder.ts +4 -0
- package/src/modes/components/custom-editor.ts +9 -0
- package/src/modes/components/read-tool-group.ts +10 -0
- package/src/modes/components/status-line/component.ts +1 -1
- package/src/modes/components/stripped-tool-calls-placeholder.ts +35 -0
- package/src/modes/components/tool-execution.ts +8 -0
- package/src/modes/components/tree-selector.ts +46 -48
- package/src/modes/controllers/btw-controller.ts +55 -7
- package/src/modes/controllers/command-controller.ts +31 -0
- package/src/modes/controllers/event-controller.ts +17 -0
- package/src/modes/controllers/input-controller.ts +63 -8
- package/src/modes/controllers/mcp-command-controller.ts +11 -5
- package/src/modes/controllers/selector-controller.ts +20 -0
- package/src/modes/interactive-mode.ts +18 -2
- package/src/modes/types.ts +9 -1
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/interactive-context-helpers.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +6 -10
- package/src/modes/workflow.ts +8 -2
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/session/launch-completion.md +1 -0
- package/src/prompts/system/plan-mode-active.md +2 -2
- package/src/prompts/system/system-prompt.md +26 -52
- package/src/prompts/system/workflow-notice.md +3 -3
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/browser.md +1 -0
- package/src/prompts/tools/computer.md +21 -21
- package/src/prompts/tools/glob.md +1 -1
- package/src/prompts/tools/grep.md +1 -1
- package/src/prompts/tools/replace.md +5 -4
- package/src/prompts/tools/task.md +4 -4
- package/src/sdk.ts +49 -6
- package/src/secrets/index.ts +1 -1
- package/src/security/contracts/schemas.ts +205 -183
- package/src/security/contracts/validation.ts +5 -1
- package/src/security/store.ts +2 -2
- package/src/session/agent-session-types.ts +9 -1
- package/src/session/agent-session.ts +204 -15
- package/src/session/indexed-session-storage.ts +9 -0
- package/src/session/launch-completion.ts +37 -0
- package/src/session/prewalk.ts +24 -2
- package/src/session/session-advisors.ts +2 -2
- package/src/session/session-context.ts +42 -12
- package/src/session/session-dump-format.ts +1 -1
- package/src/session/session-entries.ts +17 -1
- package/src/session/session-maintenance.ts +38 -4
- package/src/session/session-manager.ts +123 -67
- package/src/session/session-paths.ts +118 -55
- package/src/session/session-stats.ts +48 -3
- package/src/session/session-storage.ts +30 -22
- package/src/session/stream-guards.ts +1 -1
- package/src/session/yield-queue.ts +121 -16
- package/src/slash-commands/builtin-registry.ts +37 -24
- package/src/system-prompt.ts +8 -3
- package/src/task/index.ts +23 -8
- package/src/task/spawn-policy.ts +14 -0
- package/src/thinking.ts +2 -8
- package/src/tools/ast-grep.ts +10 -4
- package/src/tools/browser/cmux/cmux-tab.ts +97 -14
- package/src/tools/browser/cmux/rpc.ts +2 -8
- package/src/tools/browser/registry.ts +53 -2
- package/src/tools/browser/relay/bridge.ts +945 -0
- package/src/tools/browser/relay/daemon.ts +117 -0
- package/src/tools/browser/relay/extension-assets/background.js.txt +242 -0
- package/src/tools/browser/relay/extension-assets/manifest.json.txt +14 -0
- package/src/tools/browser/relay/extension-assets/options.html.txt +53 -0
- package/src/tools/browser/relay/extension-assets/options.js.txt +23 -0
- package/src/tools/browser/relay/kind.ts +41 -0
- package/src/tools/browser/relay/protocol.ts +54 -0
- package/src/tools/browser/relay/server.ts +141 -0
- package/src/tools/browser/render.ts +4 -1
- package/src/tools/browser/shared-daemon.ts +7 -58
- package/src/tools/browser/tab-supervisor.ts +5 -4
- package/src/tools/browser/tab-worker.ts +33 -12
- package/src/tools/browser.ts +26 -1
- package/src/tools/computer/exposure.ts +11 -35
- package/src/tools/computer/protocol.ts +51 -10
- package/src/tools/computer/supervisor.ts +227 -124
- package/src/tools/computer/worker-entry.ts +11 -6
- package/src/tools/computer/worker.ts +695 -81
- package/src/tools/computer-renderer.ts +104 -65
- package/src/tools/computer.ts +134 -428
- package/src/tools/context.ts +3 -0
- package/src/tools/glob.ts +9 -2
- package/src/tools/grep.ts +12 -6
- package/src/tools/hub/launch.ts +122 -6
- package/src/tools/index.ts +9 -0
- package/src/tools/inspect-image.ts +32 -6
- package/src/tools/render-utils.ts +2 -0
- package/src/tools/{browser/run-cancellation.ts → run-scope.ts} +11 -11
- package/src/tools/tool-timeouts.ts +1 -0
- package/src/tools/xdev.ts +29 -2
- package/src/utils/clipboard.ts +40 -14
- package/src/utils/command-args.ts +26 -28
- package/src/utils/tool-choice.ts +0 -13
- package/src/web/kagi.ts +2 -1
- package/src/web/search/index.ts +18 -2
- package/src/web/search/providers/anthropic.ts +4 -1
- package/src/web/search/providers/base.ts +2 -0
- package/src/web/search/providers/brave.ts +3 -1
- package/src/web/search/providers/browser-page.ts +6 -4
- package/src/web/search/providers/codex.ts +4 -1
- package/src/web/search/providers/duckduckgo.ts +2 -1
- package/src/web/search/providers/ecosia.ts +2 -1
- package/src/web/search/providers/exa.ts +4 -2
- package/src/web/search/providers/firecrawl.ts +3 -1
- package/src/web/search/providers/gemini.ts +8 -2
- package/src/web/search/providers/google.ts +2 -1
- package/src/web/search/providers/jina.ts +12 -2
- package/src/web/search/providers/kagi.ts +3 -0
- package/src/web/search/providers/kimi.ts +5 -1
- package/src/web/search/providers/mojeek.ts +2 -1
- package/src/web/search/providers/parallel.ts +5 -1
- package/src/web/search/providers/perplexity.ts +6 -3
- package/src/web/search/providers/public.ts +1 -1
- package/src/web/search/providers/searxng.ts +11 -5
- package/src/web/search/providers/startpage.ts +10 -4
- package/src/web/search/providers/synthetic.ts +11 -5
- package/src/web/search/providers/tavily.ts +3 -1
- package/src/web/search/providers/tinyfish.ts +3 -1
- package/src/web/search/providers/utils.ts +12 -10
- package/src/web/search/providers/xai.ts +2 -2
- package/src/web/search/providers/zai.ts +18 -3
- package/src/web/search/types.ts +6 -0
- package/dist/types/config/file-lock.d.ts +0 -29
- package/src/config/file-lock.ts +0 -164
|
@@ -39,6 +39,8 @@ export interface SessionHeader {
|
|
|
39
39
|
*/
|
|
40
40
|
additionalDirectories?: string[];
|
|
41
41
|
parentSession?: string;
|
|
42
|
+
/** Prior absolute JSONL locations recorded by successful session moves. */
|
|
43
|
+
previousSessionFiles?: string[];
|
|
42
44
|
/** Provider prompt-cache identity inherited by exact-route full forks. */
|
|
43
45
|
providerPromptCacheKey?: string;
|
|
44
46
|
}
|
|
@@ -119,6 +121,18 @@ export interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {
|
|
|
119
121
|
fromExtension?: boolean;
|
|
120
122
|
}
|
|
121
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Pure marker entry recorded by `/reset` (resetSessionContext). It carries no
|
|
126
|
+
* payload — its presence on the branch is a durable boundary the collapsed
|
|
127
|
+
* live transcript and the model-context rebuild start emission after, so a
|
|
128
|
+
* rebuild (theme change, focus attach, /shake, resume) does not resurrect the
|
|
129
|
+
* pre-reset conversation. The on-disk record and the plain `transcript:true`
|
|
130
|
+
* export path keep the full pre-reset history.
|
|
131
|
+
*/
|
|
132
|
+
export interface ResetBoundaryEntry extends SessionEntryBase {
|
|
133
|
+
type: "reset_boundary";
|
|
134
|
+
}
|
|
135
|
+
|
|
122
136
|
/**
|
|
123
137
|
* Custom entry for extensions to store extension-specific data in the session.
|
|
124
138
|
* Use customType to identify your extension's entries.
|
|
@@ -155,6 +169,7 @@ declare module "@oh-my-pi/pi-agent-core/compaction/entries" {
|
|
|
155
169
|
interface CustomCompactionSessionEntries {
|
|
156
170
|
titleChange: TitleChangeEntry;
|
|
157
171
|
credentialPin: CredentialPinEntry;
|
|
172
|
+
resetBoundary: ResetBoundaryEntry;
|
|
158
173
|
}
|
|
159
174
|
}
|
|
160
175
|
|
|
@@ -250,7 +265,8 @@ export type SessionEntry =
|
|
|
250
265
|
| TtsrInjectionEntry
|
|
251
266
|
| SessionInitEntry
|
|
252
267
|
| ModeChangeEntry
|
|
253
|
-
| CredentialPinEntry
|
|
268
|
+
| CredentialPinEntry
|
|
269
|
+
| ResetBoundaryEntry;
|
|
254
270
|
|
|
255
271
|
/** Raw logical file entry after loaders strip any fixed-width title slot. */
|
|
256
272
|
export type FileEntry = SessionHeader | SessionEntry;
|
|
@@ -26,8 +26,10 @@ import {
|
|
|
26
26
|
DEFAULT_SHAKE_CONFIG,
|
|
27
27
|
effectiveReserveTokens,
|
|
28
28
|
estimateTokens,
|
|
29
|
+
hasContextTokenUsage,
|
|
29
30
|
NativeCompactionError,
|
|
30
31
|
prepareCompaction,
|
|
32
|
+
RESCUE_SHAKE_CONFIG,
|
|
31
33
|
resolveBudgetReserveTokens,
|
|
32
34
|
resolveThresholdTokens,
|
|
33
35
|
type ShakeConfig,
|
|
@@ -74,7 +76,7 @@ import {
|
|
|
74
76
|
resolveRoleModelFull,
|
|
75
77
|
} from "./role-models";
|
|
76
78
|
import type { SessionContext } from "./session-context";
|
|
77
|
-
import { getLatestCompactionEntry } from "./session-context";
|
|
79
|
+
import { getLatestCompactionEntry, getOpenAiRemoteCompactionPayload } from "./session-context";
|
|
78
80
|
import type { CompactionEntry, SessionEntry } from "./session-entries";
|
|
79
81
|
import type { SessionManager } from "./session-manager";
|
|
80
82
|
import type { ShakeMode, ShakeResult } from "./shake-types";
|
|
@@ -235,6 +237,7 @@ export interface SessionMaintenanceHost {
|
|
|
235
237
|
syncTodoPhasesFromBranch(): void;
|
|
236
238
|
resetAdvisorRuntimes(): void;
|
|
237
239
|
rebaseAfterCompaction(): void;
|
|
240
|
+
recordAnchoredHistoryRewrite(tokensRemoved: number): void;
|
|
238
241
|
getContextBreakdown(options?: {
|
|
239
242
|
contextWindow?: number;
|
|
240
243
|
pendingMessages?: AgentMessage[];
|
|
@@ -461,11 +464,12 @@ export class SessionMaintenance {
|
|
|
461
464
|
}
|
|
462
465
|
|
|
463
466
|
const branchEntries = this.#host.sessionManager.getBranch();
|
|
467
|
+
const latestCompaction = getLatestCompactionEntry(branchEntries);
|
|
464
468
|
const config = this.#withPlanProtection({
|
|
465
469
|
...(opts.config ?? AGGRESSIVE_SHAKE_CONFIG),
|
|
466
470
|
// Skip entries summarized away by the latest compaction — shaking them
|
|
467
471
|
// only churns persisted history with no prompt/cache effect.
|
|
468
|
-
keepBoundaryId:
|
|
472
|
+
keepBoundaryId: latestCompaction?.firstKeptEntryId,
|
|
469
473
|
});
|
|
470
474
|
const regions = collectShakeRegions(branchEntries, config);
|
|
471
475
|
if (regions.length === 0) {
|
|
@@ -475,20 +479,50 @@ export class SessionMaintenance {
|
|
|
475
479
|
const artifactId = await this.#saveShakeArtifact(regions);
|
|
476
480
|
const replacements = regions.map((region, index) => this.#shakeElidePlaceholder(region, index, artifactId));
|
|
477
481
|
|
|
482
|
+
const hasRemoteReplacementHistory = getOpenAiRemoteCompactionPayload(latestCompaction) !== undefined;
|
|
483
|
+
const compactionIndex = latestCompaction ? branchEntries.lastIndexOf(latestCompaction) : -1;
|
|
484
|
+
let anchorIndex = -1;
|
|
485
|
+
for (let index = branchEntries.length - 1; index > compactionIndex; index--) {
|
|
486
|
+
const entry = branchEntries[index];
|
|
487
|
+
if (entry.type !== "message" || entry.message.role !== "assistant") continue;
|
|
488
|
+
const assistant = entry.message;
|
|
489
|
+
if (
|
|
490
|
+
assistant.stopReason !== "aborted" &&
|
|
491
|
+
assistant.stopReason !== "error" &&
|
|
492
|
+
assistant.usage &&
|
|
493
|
+
hasContextTokenUsage(assistant.usage)
|
|
494
|
+
) {
|
|
495
|
+
anchorIndex = index;
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
const entryIndexes = new Map(branchEntries.map((entry, index) => [entry, index]));
|
|
500
|
+
|
|
478
501
|
let toolResultsDropped = 0;
|
|
479
502
|
let blocksDropped = 0;
|
|
480
503
|
let originalTokens = 0;
|
|
481
504
|
let replacementTokens = 0;
|
|
505
|
+
let anchoredTokensRemoved = 0;
|
|
482
506
|
const items = regions.map((region, index) => {
|
|
483
507
|
if (region.kind === "toolResult") toolResultsDropped++;
|
|
484
508
|
else blocksDropped++;
|
|
485
509
|
originalTokens += region.tokens;
|
|
486
510
|
const replacement = replacements[index];
|
|
487
|
-
|
|
511
|
+
const replacementTokenCount = replacement.length > 0 ? countTokens(replacement) : 0;
|
|
512
|
+
replacementTokens += replacementTokenCount;
|
|
513
|
+
const entryIndex = entryIndexes.get(region.entry) ?? -1;
|
|
514
|
+
if (
|
|
515
|
+
entryIndex >= 0 &&
|
|
516
|
+
entryIndex < anchorIndex &&
|
|
517
|
+
(!hasRemoteReplacementHistory || entryIndex > compactionIndex)
|
|
518
|
+
) {
|
|
519
|
+
anchoredTokensRemoved += Math.max(0, region.tokens - replacementTokenCount);
|
|
520
|
+
}
|
|
488
521
|
return { region, replacement };
|
|
489
522
|
});
|
|
490
523
|
|
|
491
524
|
applyShakeRegions(items);
|
|
525
|
+
this.#host.recordAnchoredHistoryRewrite(anchoredTokensRemoved);
|
|
492
526
|
|
|
493
527
|
await this.#host.sessionManager.rewriteEntries();
|
|
494
528
|
const sessionContext = this.#host.buildDisplaySessionContext();
|
|
@@ -1859,7 +1893,7 @@ export class SessionMaintenance {
|
|
|
1859
1893
|
let elideSink = "placeholders";
|
|
1860
1894
|
if (!options.skipElide) {
|
|
1861
1895
|
try {
|
|
1862
|
-
const result = await this.#host.shake("elide", { signal });
|
|
1896
|
+
const result = await this.#host.shake("elide", { config: RESCUE_SHAKE_CONFIG, signal });
|
|
1863
1897
|
elided = result.toolResultsDropped + result.blocksDropped;
|
|
1864
1898
|
elidedTokens = result.tokensFreed;
|
|
1865
1899
|
if (result.artifactId) elideSink = "an artifact";
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
type ModeChangeEntry,
|
|
45
45
|
type ModelChangeEntry,
|
|
46
46
|
type NewSessionOptions,
|
|
47
|
+
type ResetBoundaryEntry,
|
|
47
48
|
type ServiceTierChangeEntry,
|
|
48
49
|
type SessionEntry,
|
|
49
50
|
type SessionHeader,
|
|
@@ -405,17 +406,22 @@ export class SessionPersistenceIndeterminateError extends AggregateError {
|
|
|
405
406
|
* tree by `(id, parentId)`, and the mutable leaf pointer selects which path is
|
|
406
407
|
* active for future appends and for LLM context construction.
|
|
407
408
|
*
|
|
408
|
-
* Durability is software-crash safe but not power-loss safe:
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
* that
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
409
|
+
* Durability is software-crash safe but not power-loss safe: completed entries
|
|
410
|
+
* (user/assistant/toolResult messages, tool_execution_start markers, custom
|
|
411
|
+
* entries) are handed to the OS synchronously in-body on append and never
|
|
412
|
+
* `fsync`'d. In-flight streaming text is intentionally not durable until
|
|
413
|
+
* `message_end` persists the finished message.
|
|
414
|
+
*
|
|
415
|
+
* While an in-place atomic rewrite is publishing, a concurrent completed append
|
|
416
|
+
* supersedes that publish with a synchronous full-body rewrite so the entry is
|
|
417
|
+
* software-crash durable before the append returns; the abandoned atomic's
|
|
418
|
+
* `commitGuard` then refuses to clobber the fresher body.
|
|
419
|
+
*
|
|
420
|
+
* During {@link moveTo}, appends write a full body to the live relocation path
|
|
421
|
+
* (source until rename, destination once the rename has landed) so a crash mid-
|
|
422
|
+
* move still preserves completed entries without recreating a vacated source.
|
|
423
|
+
* A trailing atomic rewrite still rewrites the header cwd after the path is
|
|
424
|
+
* repointed.
|
|
419
425
|
*/
|
|
420
426
|
export class SessionManager {
|
|
421
427
|
#cwd: string;
|
|
@@ -484,15 +490,12 @@ export class SessionManager {
|
|
|
484
490
|
/** Set by synchronous appends that land while an atomic replacement is active. */
|
|
485
491
|
#atomicRewriteDirty = false;
|
|
486
492
|
/**
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
* (
|
|
490
|
-
*
|
|
491
|
-
* otherwise touch the pre-rename path — opening a fresh writer or writing the
|
|
492
|
-
* full body — recreating the very orphan the move eliminates. Both defer
|
|
493
|
-
* while this is set; the move's trailing atomic rewrite persists them.
|
|
493
|
+
* Active {@link moveTo} relocation. Concurrent completed appends write a
|
|
494
|
+
* full body to the live path: source while it still exists, destination
|
|
495
|
+
* once rename has landed (source gone). Never recreates a vacated source.
|
|
496
|
+
* `null` outside an active relocation.
|
|
494
497
|
*/
|
|
495
|
-
#sessionFileRelocating =
|
|
498
|
+
#sessionFileRelocating: { source: string; dest: string } | null = null;
|
|
496
499
|
/** Atomic entry batch currently staged for a full-file commit. */
|
|
497
500
|
#atomicEntryBatch: AtomicEntryBatch | undefined;
|
|
498
501
|
|
|
@@ -763,30 +766,56 @@ export class SessionManager {
|
|
|
763
766
|
return this.#forceFileCreation || this.#fileIsCurrent || this.#historyContainsAssistantMessage();
|
|
764
767
|
}
|
|
765
768
|
|
|
769
|
+
/**
|
|
770
|
+
* Live path for concurrent completed appends during {@link moveTo}.
|
|
771
|
+
* Prefers destination once rename has landed (source gone); otherwise
|
|
772
|
+
* source. Never invents a path that does not already exist.
|
|
773
|
+
*/
|
|
774
|
+
#liveRelocationWritePath(): string | null {
|
|
775
|
+
const relocating = this.#sessionFileRelocating;
|
|
776
|
+
if (!relocating) return null;
|
|
777
|
+
if (this.#storage.existsSync(relocating.dest)) return relocating.dest;
|
|
778
|
+
if (this.#storage.existsSync(relocating.source)) return relocating.source;
|
|
779
|
+
// Rename in flight with neither path visible (rare cross-device edge):
|
|
780
|
+
// fall back to destination so we do not recreate a vacated source.
|
|
781
|
+
return relocating.dest;
|
|
782
|
+
}
|
|
783
|
+
|
|
766
784
|
/**
|
|
767
785
|
* Synchronously rewrite the whole file (header + entries) and keep no open
|
|
768
786
|
* writer; the next append re-opens one. `writeTextSync` returns with the
|
|
769
787
|
* bytes in the kernel page cache, so the file is software-crash durable.
|
|
788
|
+
*
|
|
789
|
+
* During {@link moveTo}, writes to the live relocation path (source pre-
|
|
790
|
+
* rename, destination post-rename) rather than always `#sessionFile`, so
|
|
791
|
+
* concurrent completed entries are durable without recreating a vacated source.
|
|
770
792
|
*/
|
|
771
793
|
#rewriteSynchronously(): void {
|
|
772
|
-
if (!this.#persist || !this.#
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
// orphan the move eliminates) or a path a queued backend publish may clobber
|
|
776
|
-
// post-rename, so defer to moveTo's trailing atomic rewrite. This narrows
|
|
777
|
-
// flushSync durability for entries in the rename window (see class doc).
|
|
778
|
-
if (this.#sessionFileRelocating) return;
|
|
794
|
+
if (!this.#persist || !this.#shouldHaveSessionFile()) return;
|
|
795
|
+
const targetPath = this.#liveRelocationWritePath() ?? this.#sessionFile;
|
|
796
|
+
if (!targetPath) return;
|
|
779
797
|
|
|
780
798
|
try {
|
|
781
799
|
const body = this.#fileBody();
|
|
782
800
|
this.#diskEpoch++;
|
|
783
801
|
this.#diskTail = Promise.resolve();
|
|
784
802
|
this.#closeWriterEventually();
|
|
785
|
-
this.#storage.writeTextSync(
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
this.#
|
|
803
|
+
this.#storage.writeTextSync(targetPath, body);
|
|
804
|
+
// Only mark the manager current when writing the active session path.
|
|
805
|
+
// Mid-move writes update the live relocation path; `#sessionFile` is
|
|
806
|
+
// still the pre-repoint source until moveTo repoints it.
|
|
807
|
+
if (!this.#sessionFileRelocating || targetPath === this.#sessionFile) {
|
|
808
|
+
this.#fileIsCurrent = true;
|
|
809
|
+
this.#materializeBreadcrumb();
|
|
810
|
+
this.#rewriteRequired = false;
|
|
811
|
+
this.#hasTitleSlot = true;
|
|
812
|
+
} else {
|
|
813
|
+
// Destination body is current on disk; in-memory still needs a
|
|
814
|
+
// header-cwd rewrite after repoint, but entries are durable.
|
|
815
|
+
this.#fileIsCurrent = false;
|
|
816
|
+
this.#rewriteRequired = true;
|
|
817
|
+
this.#hasTitleSlot = true;
|
|
818
|
+
}
|
|
790
819
|
} catch (err) {
|
|
791
820
|
this.#noteDiskFailure(err);
|
|
792
821
|
}
|
|
@@ -872,22 +901,21 @@ export class SessionManager {
|
|
|
872
901
|
return;
|
|
873
902
|
}
|
|
874
903
|
|
|
875
|
-
// Atomic replacement window:
|
|
876
|
-
//
|
|
877
|
-
//
|
|
878
|
-
//
|
|
879
|
-
//
|
|
880
|
-
//
|
|
881
|
-
//
|
|
882
|
-
//
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
) {
|
|
888
|
-
this.#fileIsCurrent = false;
|
|
889
|
-
this.#rewriteRequired = true;
|
|
904
|
+
// Atomic replacement / move window: do not open a fresh append writer that
|
|
905
|
+
// a Windows EPERM replace could detach from the current JSONL path.
|
|
906
|
+
// - moveTo: write a full body to the live relocation path (source pre-
|
|
907
|
+
// rename, destination post-rename) so completed entries are durable
|
|
908
|
+
// without recreating a vacated source.
|
|
909
|
+
// - in-place atomic fence: supersede the pending publish with a
|
|
910
|
+
// synchronous full-body rewrite; bumping `#diskEpoch` abandons the
|
|
911
|
+
// in-flight atomic via its `commitGuard`.
|
|
912
|
+
if (this.#sessionFileRelocating) {
|
|
913
|
+
this.#rewriteSynchronously();
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
if (this.#atomicRewriteFenceEpoch !== null && this.#atomicRewriteFenceEpoch === this.#diskEpoch) {
|
|
890
917
|
this.#atomicRewriteDirty = true;
|
|
918
|
+
this.#rewriteSynchronously();
|
|
891
919
|
return;
|
|
892
920
|
}
|
|
893
921
|
// Cold/divergent: not on disk yet, or in-memory entries diverged from the
|
|
@@ -897,15 +925,23 @@ export class SessionManager {
|
|
|
897
925
|
return;
|
|
898
926
|
}
|
|
899
927
|
|
|
900
|
-
// Hot path:
|
|
901
|
-
// chain.
|
|
902
|
-
//
|
|
928
|
+
// Hot path: write the entry directly on the writer, outside the async disk
|
|
929
|
+
// chain. Prefer appendSync so write failures latch `#diskFailure` before
|
|
930
|
+
// this call returns (not via a discarded rejected Promise after a later
|
|
931
|
+
// microtask). Callers stay non-throwing here — the core turn loop invokes
|
|
932
|
+
// appendMessage/appendCustomEntry without try/catch; flushSync/close and
|
|
933
|
+
// subsequent appends still throw the latched error. File writers apply
|
|
934
|
+
// each line to the OS page cache before return.
|
|
903
935
|
// A mid-close writer leaves `#writer` undefined, so `#appendWriter` simply
|
|
904
936
|
// opens a fresh append handle and the entry still lands.
|
|
905
937
|
try {
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
938
|
+
const writer = this.#appendWriter();
|
|
939
|
+
const line = this.#lineFor(entry);
|
|
940
|
+
if (writer.appendSync) {
|
|
941
|
+
writer.appendSync(line);
|
|
942
|
+
} else {
|
|
943
|
+
void writer.append(line).catch(err => this.#noteDiskFailure(err));
|
|
944
|
+
}
|
|
909
945
|
} catch (err) {
|
|
910
946
|
this.#noteDiskFailure(err);
|
|
911
947
|
}
|
|
@@ -921,12 +957,11 @@ export class SessionManager {
|
|
|
921
957
|
}
|
|
922
958
|
|
|
923
959
|
// Title changes use their own asynchronous append path rather than
|
|
924
|
-
// #appendToSessionFile.
|
|
925
|
-
//
|
|
960
|
+
// #appendToSessionFile. During move, write the full body (including the
|
|
961
|
+
// title entry) to the live relocation path so a crash mid-move still
|
|
962
|
+
// keeps the title change; the trailing rewrite still updates header cwd.
|
|
926
963
|
if (this.#sessionFileRelocating) {
|
|
927
|
-
this.#
|
|
928
|
-
this.#rewriteRequired = true;
|
|
929
|
-
this.#atomicRewriteDirty = true;
|
|
964
|
+
this.#rewriteSynchronously();
|
|
930
965
|
return;
|
|
931
966
|
}
|
|
932
967
|
|
|
@@ -1362,14 +1397,15 @@ export class SessionManager {
|
|
|
1362
1397
|
: computeDefaultSessionDir(resolvedCwd, this.#storage));
|
|
1363
1398
|
|
|
1364
1399
|
let sessionFileExisted = false;
|
|
1365
|
-
//
|
|
1366
|
-
//
|
|
1367
|
-
// not a `#diskEpoch` bump
|
|
1368
|
-
//
|
|
1369
|
-
//
|
|
1370
|
-
// below runs it, silently dropping an explicitly materialized session.
|
|
1400
|
+
// Track source+dest for concurrent completed appends during relocation
|
|
1401
|
+
// (see `#sessionFileRelocating`). Existence of either path decides the
|
|
1402
|
+
// live write target — not a `#diskEpoch` bump, which would cancel any
|
|
1403
|
+
// disk task already queued at the current epoch (e.g. a header-only
|
|
1404
|
+
// `ensureOnDisk()` materializing rewrite) before the drain below runs it.
|
|
1371
1405
|
if (this.#persist && this.#sessionFile) {
|
|
1372
|
-
|
|
1406
|
+
const source = this.#sessionFile;
|
|
1407
|
+
const dest = path.join(nextSessionDir, path.basename(source));
|
|
1408
|
+
this.#sessionFileRelocating = { source, dest };
|
|
1373
1409
|
}
|
|
1374
1410
|
|
|
1375
1411
|
try {
|
|
@@ -1430,11 +1466,17 @@ export class SessionManager {
|
|
|
1430
1466
|
throw err;
|
|
1431
1467
|
}
|
|
1432
1468
|
|
|
1469
|
+
if (sessionFileExisted && sessionPathChanged) {
|
|
1470
|
+
this.#header.previousSessionFiles = [
|
|
1471
|
+
...new Set([...(this.#header.previousSessionFiles ?? []), path.resolve(oldSessionFile)]),
|
|
1472
|
+
];
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1433
1475
|
this.#sessionFile = newSessionFile;
|
|
1434
1476
|
this.#artifactManager = null;
|
|
1435
1477
|
this.#artifactManagerSessionFile = null;
|
|
1436
|
-
// Path is repointed;
|
|
1437
|
-
this.#sessionFileRelocating =
|
|
1478
|
+
// Path is repointed; hot-path appends may use `#sessionFile` again.
|
|
1479
|
+
this.#sessionFileRelocating = null;
|
|
1438
1480
|
}
|
|
1439
1481
|
|
|
1440
1482
|
this.#cwd = resolvedCwd;
|
|
@@ -1459,7 +1501,7 @@ export class SessionManager {
|
|
|
1459
1501
|
|
|
1460
1502
|
if (this.#sessionFile) this.#rememberBreadcrumb(resolvedCwd, this.#sessionFile);
|
|
1461
1503
|
} finally {
|
|
1462
|
-
this.#sessionFileRelocating =
|
|
1504
|
+
this.#sessionFileRelocating = null;
|
|
1463
1505
|
}
|
|
1464
1506
|
}
|
|
1465
1507
|
|
|
@@ -2051,6 +2093,18 @@ export class SessionManager {
|
|
|
2051
2093
|
return entry.id;
|
|
2052
2094
|
}
|
|
2053
2095
|
|
|
2096
|
+
/**
|
|
2097
|
+
* Append the durable conversation boundary recorded by `/reset`. The
|
|
2098
|
+
* collapsed live transcript and the model-context rebuild start after the
|
|
2099
|
+
* latest one, while the full history stays on disk (the plain
|
|
2100
|
+
* `transcript:true` export walks it unchanged).
|
|
2101
|
+
*/
|
|
2102
|
+
appendResetBoundary(): string {
|
|
2103
|
+
const entry: ResetBoundaryEntry = { type: "reset_boundary", ...this.#freshEntryFields() };
|
|
2104
|
+
this.#recordEntry(entry);
|
|
2105
|
+
return entry.id;
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2054
2108
|
appendCustomEntry(customType: string, data?: unknown): string {
|
|
2055
2109
|
const entry: CustomEntry = { type: "custom", customType, data, ...this.#freshEntryFields() };
|
|
2056
2110
|
this.#recordEntry(entry);
|
|
@@ -2305,6 +2359,8 @@ export class SessionManager {
|
|
|
2305
2359
|
id: newSessionId,
|
|
2306
2360
|
timestamp,
|
|
2307
2361
|
cwd: this.#cwd,
|
|
2362
|
+
title: this.#sessionName,
|
|
2363
|
+
titleSource: this.#titleSource,
|
|
2308
2364
|
parentSession: this.#persist ? sourceSessionFile : undefined,
|
|
2309
2365
|
additionalDirectories: this.#additionalDirectories.length > 0 ? [...this.#additionalDirectories] : undefined,
|
|
2310
2366
|
};
|