@oh-my-pi/pi-coding-agent 17.2.9 → 17.2.11
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 +83 -0
- package/dist/{CHANGELOG-8yy8h3bc.md → CHANGELOG-d9xenpn9.md} +83 -0
- package/dist/cli.js +10208 -12596
- package/dist/types/capability/mcp.d.ts +11 -0
- package/dist/types/capability/skill.d.ts +6 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/command-help.d.ts +3 -0
- package/dist/types/commands/share.d.ts +25 -0
- package/dist/types/commit/agentic/index.d.ts +3 -1
- package/dist/types/commit/execute.d.ts +32 -0
- package/dist/types/commit/index.d.ts +2 -1
- package/dist/types/commit/pipeline.d.ts +7 -1
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/model-resolver.d.ts +13 -0
- package/dist/types/config/settings-schema.d.ts +1 -34
- package/dist/types/discovery/agent-plugin-format.d.ts +143 -0
- package/dist/types/discovery/agent-plugins.d.ts +1 -0
- package/dist/types/discovery/contained-path.d.ts +34 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/extensibility/custom-commands/types.d.ts +5 -5
- package/dist/types/extensibility/custom-tools/types.d.ts +3 -3
- package/dist/types/extensibility/extensions/loader.d.ts +9 -2
- package/dist/types/extensibility/extensions/types.d.ts +45 -8
- package/dist/types/extensibility/hooks/types.d.ts +5 -5
- package/dist/types/extensibility/shared-events.d.ts +3 -2
- package/dist/types/extensibility/skills.d.ts +5 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/main.d.ts +1 -1
- package/dist/types/mcp/transports/header-policy.d.ts +45 -0
- package/dist/types/mcp/types.d.ts +15 -0
- package/dist/types/modes/acp/acp-agent.d.ts +1 -1
- package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -1
- package/dist/types/modes/acp/acp-event-mapper.d.ts +1 -1
- package/dist/types/modes/acp/acp-mode.d.ts +1 -1
- package/dist/types/modes/components/agent-hub-projection.d.ts +38 -0
- package/dist/types/modes/components/agent-hub-renderer.d.ts +41 -0
- package/dist/types/modes/components/agent-hub.d.ts +14 -5
- package/dist/types/modes/components/agent-transcript-viewer.d.ts +2 -0
- package/dist/types/modes/components/chat-transcript-builder.d.ts +2 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -2
- package/dist/types/modes/components/model-browser.d.ts +9 -1
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/interactive-mode.d.ts +8 -1
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +3 -2
- package/dist/types/registry/agent-registry.d.ts +47 -0
- package/dist/types/registry/persisted-agents.d.ts +3 -1
- package/dist/types/secrets/index.d.ts +23 -1
- package/dist/types/session/agent-session-events.d.ts +2 -2
- package/dist/types/session/agent-session.d.ts +4 -2
- package/dist/types/session/messages.d.ts +1 -0
- package/dist/types/session/prewalk.d.ts +3 -1
- package/dist/types/session/session-entries.d.ts +10 -0
- package/dist/types/session/session-loader.d.ts +11 -1
- package/dist/types/session/session-manager.d.ts +9 -1
- package/dist/types/session/session-tools.d.ts +18 -1
- package/dist/types/session/turn-recovery.d.ts +7 -2
- package/dist/types/slash-commands/acp-builtins.d.ts +1 -1
- package/dist/types/slash-commands/available-commands.d.ts +1 -1
- package/dist/types/task/executor.d.ts +6 -0
- package/dist/types/task/index.d.ts +4 -3
- package/dist/types/task/read-only-policy.d.ts +3 -0
- package/dist/types/task/structured-subagent.d.ts +2 -0
- package/dist/types/task/types.d.ts +4 -0
- package/dist/types/tools/bash.d.ts +3 -3
- package/dist/types/tools/browser/launch.d.ts +2 -1
- package/dist/types/tools/browser/tab-worker.d.ts +2 -2
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read.d.ts +1 -5
- package/dist/types/tools/run-scope.d.ts +27 -1
- package/dist/types/tools/shell-tokenize.d.ts +16 -0
- package/dist/types/tools/terminal-output.d.ts +1 -1
- package/dist/types/utils/turndown.d.ts +1 -1
- package/dist/types/vibe/runtime.d.ts +2 -3
- package/dist/types/web/scrapers/readthedocs.d.ts +0 -3
- package/dist/types/web/search/providers/browser-headers.d.ts +2 -3
- package/examples/custom-tools/README.md +1 -1
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/api-demo.ts +5 -6
- package/examples/extensions/chalk-logger.ts +1 -1
- package/examples/extensions/hello.ts +2 -2
- package/examples/extensions/reload-runtime.ts +1 -1
- package/examples/extensions/tools.ts +2 -2
- package/examples/extensions/with-deps/index.ts +1 -1
- package/examples/sdk/06-extensions.ts +1 -1
- package/package.json +15 -31
- package/scripts/bundle-dist.ts +1 -11
- package/scripts/legacy-pi-virtual-module.ts +4 -1
- package/src/advisor/runtime.ts +54 -0
- package/src/capability/mcp.ts +11 -0
- package/src/capability/skill.ts +6 -0
- package/src/cli/agents-cli.ts +1 -1
- package/src/cli/args.ts +24 -2
- package/src/cli/auth-broker-cli.ts +1 -1
- package/src/cli/auth-gateway-cli.ts +1 -1
- package/src/cli/bench-cli.ts +1 -1
- package/src/cli/claude-trace-cli.ts +1 -1
- package/src/cli/command-help.ts +4 -0
- package/src/cli/config-cli.ts +1 -1
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/file-processor.ts +1 -1
- package/src/cli/flag-tables.ts +4 -0
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli/grep-cli.ts +1 -1
- package/src/cli/grievances-cli.ts +1 -1
- package/src/cli/help-extra.ts +1 -1
- package/src/cli/models-cli.ts +1 -1
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/read-cli.ts +1 -1
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli/shell-cli.ts +1 -1
- package/src/cli/ssh-cli.ts +1 -1
- package/src/cli/stats-cli.ts +1 -1
- package/src/cli/tiny-models-cli.ts +1 -1
- package/src/cli/ttsr-cli.ts +1 -1
- package/src/cli/update-cli.ts +1 -1
- package/src/cli/usage-cli.ts +1 -1
- package/src/cli/web-search-cli.ts +1 -1
- package/src/cli/worktree-cli.ts +1 -1
- package/src/cli-commands.ts +5 -0
- package/src/commands/commit.ts +16 -3
- package/src/commands/say.ts +1 -1
- package/src/commands/share.ts +71 -0
- package/src/commands/token.ts +1 -1
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/agentic/index.ts +39 -21
- package/src/commit/cli.ts +1 -1
- package/src/commit/execute.ts +56 -0
- package/src/commit/index.ts +2 -1
- package/src/commit/pipeline.ts +20 -7
- package/src/config/model-discovery.ts +1 -1
- package/src/config/model-registry.ts +21 -1
- package/src/config/model-resolver.ts +54 -7
- package/src/config/settings-schema.ts +2 -33
- package/src/config/settings.ts +46 -0
- package/src/discovery/agent-plugin-format.ts +551 -0
- package/src/discovery/agent-plugins.ts +341 -0
- package/src/discovery/agents.ts +4 -2
- package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +5 -4
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +1 -1
- package/src/discovery/claude-plugins.ts +21 -5
- package/src/discovery/contained-path.ts +78 -0
- package/src/discovery/helpers.ts +23 -9
- package/src/discovery/index.ts +1 -0
- package/src/discovery/omp-plugins.ts +20 -7
- package/src/eval/py/runner.py +38 -1
- package/src/exec/non-interactive-env.ts +1 -0
- package/src/extensibility/custom-commands/loader.ts +4 -4
- package/src/extensibility/custom-commands/types.ts +5 -5
- package/src/extensibility/custom-tools/loader.ts +4 -4
- package/src/extensibility/custom-tools/types.ts +3 -3
- package/src/extensibility/extensions/loader.ts +85 -20
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +51 -8
- package/src/extensibility/hooks/loader.ts +4 -5
- package/src/extensibility/hooks/types.ts +5 -5
- package/src/extensibility/plugins/legacy-pi-compat.ts +53 -0
- package/src/extensibility/plugins/marketplace/manager.ts +2 -1
- package/src/extensibility/shared-events.ts +3 -2
- package/src/extensibility/skills.ts +9 -0
- package/src/index.ts +2 -2
- package/src/internal-urls/memory-protocol.ts +5 -1
- package/src/internal-urls/skill-protocol.ts +14 -0
- package/src/internal-urls/vault-protocol.ts +2 -2
- package/src/launch/client.ts +11 -1
- package/src/launch/protocol.ts +7 -2
- package/src/launch/terminal-output.ts +1 -1
- package/src/main.ts +88 -23
- package/src/markit/converters/docx.ts +1 -1
- package/src/markit/converters/epub.ts +1 -1
- package/src/markit/converters/pptx.ts +1 -1
- package/src/markit/converters/xlsx.ts +1 -1
- package/src/mcp/config.ts +3 -0
- package/src/mcp/manager.ts +12 -9
- package/src/mcp/transports/header-policy.ts +95 -0
- package/src/mcp/transports/http.ts +35 -52
- package/src/mcp/transports/sse.ts +20 -27
- package/src/mcp/types.ts +15 -0
- package/src/modes/acp/acp-agent.ts +20 -9
- package/src/modes/acp/acp-client-bridge.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +1 -1
- package/src/modes/acp/acp-mode.ts +1 -1
- package/src/modes/components/agent-dashboard.ts +2 -0
- package/src/modes/components/agent-hub-projection.ts +248 -0
- package/src/modes/components/agent-hub-renderer.ts +194 -0
- package/src/modes/components/agent-hub.ts +674 -207
- package/src/modes/components/agent-transcript-viewer.ts +3 -0
- package/src/modes/components/assistant-message.ts +1 -1
- package/src/modes/components/chat-transcript-builder.ts +3 -0
- package/src/modes/components/custom-editor.ts +0 -9
- package/src/modes/components/extensions/inspector-panel.ts +11 -6
- package/src/modes/components/footer.ts +1 -3
- package/src/modes/components/model-browser.ts +11 -3
- package/src/modes/components/model-hub.ts +4 -1
- package/src/modes/components/status-line/component.ts +1 -0
- package/src/modes/components/status-line/segments.ts +10 -7
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/tool-execution.ts +13 -16
- package/src/modes/components/tree-selector.ts +62 -3
- package/src/modes/controllers/command-controller.ts +4 -1
- package/src/modes/controllers/event-controller.ts +44 -20
- package/src/modes/controllers/extension-ui-controller.ts +2 -2
- package/src/modes/controllers/input-controller.ts +20 -2
- package/src/modes/controllers/mcp-command-controller.ts +81 -20
- package/src/modes/controllers/selector-controller.ts +41 -49
- package/src/modes/controllers/streaming-reveal.ts +1 -1
- package/src/modes/interactive-mode.ts +13 -2
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/runtime-init.ts +1 -1
- package/src/modes/theme/theme.ts +2 -2
- package/src/modes/utils/transcript-render-helpers.ts +4 -2
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/prompts/tools/computer.md +1 -1
- package/src/registry/agent-lifecycle.ts +14 -7
- package/src/registry/agent-registry.ts +65 -2
- package/src/registry/persisted-agents.ts +341 -16
- package/src/sdk.ts +6 -49
- package/src/secrets/index.ts +52 -1
- package/src/session/agent-session-events.ts +2 -2
- package/src/session/agent-session.ts +54 -16
- package/src/session/messages.ts +1 -0
- package/src/session/prewalk.ts +57 -17
- package/src/session/session-context.ts +3 -5
- package/src/session/session-entries.ts +10 -0
- package/src/session/session-handoff.ts +5 -1
- package/src/session/session-listing.ts +1 -1
- package/src/session/session-loader.ts +74 -8
- package/src/session/session-manager.ts +22 -2
- package/src/session/session-paths.ts +57 -9
- package/src/session/session-tools.ts +65 -4
- package/src/session/todo-tracker.ts +11 -1
- package/src/session/turn-recovery.ts +96 -74
- package/src/slash-commands/acp-builtins.ts +1 -1
- package/src/slash-commands/available-commands.ts +1 -1
- package/src/slash-commands/builtin-registry.ts +12 -8
- package/src/task/executor.ts +70 -20
- package/src/task/index.ts +30 -34
- package/src/task/isolation-runner.ts +24 -11
- package/src/task/persisted-revive.ts +12 -5
- package/src/task/read-only-policy.ts +27 -0
- package/src/task/structured-subagent.ts +14 -4
- package/src/task/types.ts +4 -0
- package/src/tools/auto-generated-guard.ts +1 -1
- package/src/tools/bash-interactive.ts +4 -4
- package/src/tools/bash-skill-urls.ts +15 -0
- package/src/tools/bash.ts +16 -17
- package/src/tools/browser/cmux/cmux-tab.ts +66 -18
- package/src/tools/browser/launch.ts +41 -12
- package/src/tools/browser/readable.ts +9 -9
- package/src/tools/browser/tab-supervisor.ts +12 -3
- package/src/tools/browser/tab-worker-entry.ts +1 -1
- package/src/tools/browser/tab-worker.ts +101 -12
- package/src/tools/debug.ts +1 -1
- package/src/tools/fetch.ts +1 -1
- package/src/tools/jtd-to-json-schema.ts +123 -21
- package/src/tools/path-utils.ts +9 -2
- package/src/tools/read.ts +21 -9
- package/src/tools/run-scope.ts +290 -4
- package/src/tools/shell-tokenize.ts +98 -0
- package/src/tools/terminal-output.ts +1 -1
- package/src/tools/todo.ts +1 -1
- package/src/utils/clipboard.ts +10 -2
- package/src/utils/external-editor.ts +4 -2
- package/src/utils/jj.ts +1 -1
- package/src/utils/turndown.ts +1 -2
- package/src/vibe/runtime.ts +5 -5
- package/src/web/scrapers/arxiv.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +1 -1
- package/src/web/scrapers/iacr.ts +1 -1
- package/src/web/scrapers/readthedocs.ts +2 -1
- package/src/web/scrapers/twitter.ts +2 -2
- package/src/web/scrapers/types.ts +1 -1
- package/src/web/scrapers/wikipedia.ts +1 -1
- package/src/web/search/providers/browser-headers.ts +12 -39
- package/src/web/search/providers/codex.ts +3 -26
- package/src/web/search/providers/ecosia.ts +1 -1
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/google.ts +1 -1
- package/src/web/search/providers/mojeek.ts +1 -1
- package/src/web/search/providers/startpage.ts +1 -1
- package/src/markit/converters/mammoth.d.ts +0 -24
|
@@ -82,6 +82,7 @@ import { modelsAreEqual } from "@oh-my-pi/pi-catalog/models";
|
|
|
82
82
|
import { MacOSPowerAssertion } from "@oh-my-pi/pi-natives";
|
|
83
83
|
import {
|
|
84
84
|
$env,
|
|
85
|
+
APP_NAME,
|
|
85
86
|
escapeXmlText,
|
|
86
87
|
formatDuration,
|
|
87
88
|
getAgentDbPath,
|
|
@@ -126,6 +127,7 @@ import type {
|
|
|
126
127
|
ToolExecutionEndEvent,
|
|
127
128
|
ToolExecutionStartEvent,
|
|
128
129
|
ToolExecutionUpdateEvent,
|
|
130
|
+
ToolInfo,
|
|
129
131
|
TreePreparation,
|
|
130
132
|
TurnEndEvent,
|
|
131
133
|
TurnStartEvent,
|
|
@@ -302,7 +304,7 @@ import {
|
|
|
302
304
|
USER_INTERRUPT_LABEL,
|
|
303
305
|
} from "./messages";
|
|
304
306
|
import { ModelControls, type ModelControlsHost } from "./model-controls";
|
|
305
|
-
import { PrewalkCoordinator, type PrewalkCoordinatorHost } from "./prewalk";
|
|
307
|
+
import { isPrewalkPlanNudge, PrewalkCoordinator, type PrewalkCoordinatorHost } from "./prewalk";
|
|
306
308
|
import {
|
|
307
309
|
isAdvisorCard,
|
|
308
310
|
isDisplayableQueuedMessage,
|
|
@@ -445,6 +447,7 @@ export class AgentSession {
|
|
|
445
447
|
// Event subscription state
|
|
446
448
|
#unsubscribeAgent?: () => void;
|
|
447
449
|
#cancelExitRecorder?: () => void;
|
|
450
|
+
#cancelFatalRecoveryHint?: () => void;
|
|
448
451
|
#exitRecorded = false;
|
|
449
452
|
#unsubscribeAppendOnly?: () => void;
|
|
450
453
|
#unsubscribeModelRoles?: () => void;
|
|
@@ -878,8 +881,8 @@ export class AgentSession {
|
|
|
878
881
|
/**
|
|
879
882
|
* Arm prewalk outside the normal startup path so an explicit slash command starts immediately.
|
|
880
883
|
*/
|
|
881
|
-
armPrewalk(target: Model, thinkingLevel?: ConfiguredThinkingLevel):
|
|
882
|
-
this.#prewalk.arm(target, thinkingLevel);
|
|
884
|
+
armPrewalk(target: Model, thinkingLevel?: ConfiguredThinkingLevel): boolean {
|
|
885
|
+
return this.#prewalk.arm(target, thinkingLevel);
|
|
883
886
|
}
|
|
884
887
|
|
|
885
888
|
/** Validate the active plan artifact and shape an `xd://propose` result for review-mode hosts. */
|
|
@@ -1376,6 +1379,14 @@ export class AgentSession {
|
|
|
1376
1379
|
this.#cancelExitRecorder = postmortem.register(`agent-session:${this.sessionManager.getSessionId()}`, reason => {
|
|
1377
1380
|
this.#recordSessionExit(reason);
|
|
1378
1381
|
});
|
|
1382
|
+
this.#cancelFatalRecoveryHint = postmortem.registerFatalRecoveryHint(() => {
|
|
1383
|
+
const sessionId = this.sessionManager.getSessionId();
|
|
1384
|
+
if (!sessionId || !this.sessionManager.getSessionFile()) return undefined;
|
|
1385
|
+
return {
|
|
1386
|
+
label: this.#agentId ?? (this.#agentKind === "main" ? "Main" : "Agent"),
|
|
1387
|
+
command: `${APP_NAME} --resume ${sessionId}`,
|
|
1388
|
+
};
|
|
1389
|
+
});
|
|
1379
1390
|
|
|
1380
1391
|
const advisorsHost: SessionAdvisorsHost = {
|
|
1381
1392
|
agent: this.agent,
|
|
@@ -2478,14 +2489,17 @@ export class AgentSession {
|
|
|
2478
2489
|
const persistMessageEnd = () => {
|
|
2479
2490
|
// Check if this is a hook/custom message
|
|
2480
2491
|
if (event.message.role === "hookMessage" || event.message.role === "custom") {
|
|
2481
|
-
//
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2492
|
+
// Prewalk's plan nudge is a one-run steering instruction. Persisting it would
|
|
2493
|
+
// resurrect the consumed prompt on resume, fork, or any context rebuild.
|
|
2494
|
+
if (!isPrewalkPlanNudge(event.message)) {
|
|
2495
|
+
this.sessionManager.appendCustomMessageEntry(
|
|
2496
|
+
event.message.customType,
|
|
2497
|
+
event.message.content,
|
|
2498
|
+
event.message.display,
|
|
2499
|
+
event.message.details,
|
|
2500
|
+
event.message.attribution ?? "agent",
|
|
2501
|
+
);
|
|
2502
|
+
}
|
|
2489
2503
|
if (event.message.role === "custom" && event.message.customType === "ttsr-injection") {
|
|
2490
2504
|
this.#ttsr.markInjectedFromDetails(event.message.details);
|
|
2491
2505
|
}
|
|
@@ -3006,11 +3020,23 @@ export class AgentSession {
|
|
|
3006
3020
|
}
|
|
3007
3021
|
this.#beginInFlight();
|
|
3008
3022
|
try {
|
|
3009
|
-
await this.#recovery.maybeRestoreRetryFallbackPrimary();
|
|
3023
|
+
const reverted = await this.#recovery.maybeRestoreRetryFallbackPrimary();
|
|
3010
3024
|
if (signal.aborted || this.#isDisposed) {
|
|
3011
3025
|
this.#skipAgentContinue("post-restore-unavailable", options);
|
|
3012
3026
|
return;
|
|
3013
3027
|
}
|
|
3028
|
+
// A cooldown-expiry revert can drop the active window below the
|
|
3029
|
+
// accumulated context. The user-prompt path re-checks context after
|
|
3030
|
+
// the revert via runPrePromptCompactionIfNeeded; the auto-continue
|
|
3031
|
+
// path must do the same so agent.continue() never sends a
|
|
3032
|
+
// predictably oversized request to the reverted (smaller) model.
|
|
3033
|
+
if (reverted) {
|
|
3034
|
+
await this.#maintenance.runPrePromptCompactionIfNeeded([]);
|
|
3035
|
+
if (signal.aborted || this.#isDisposed) {
|
|
3036
|
+
this.#skipAgentContinue("post-restore-unavailable", options);
|
|
3037
|
+
return;
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3014
3040
|
if (this.settings.get("retry.usageAwareFallback")) {
|
|
3015
3041
|
if (!(await this.#runQueuedUsageAwarePreflight(signal))) {
|
|
3016
3042
|
this.#skipAgentContinue("session-unavailable", options);
|
|
@@ -3429,7 +3455,7 @@ export class AgentSession {
|
|
|
3429
3455
|
success: event.success,
|
|
3430
3456
|
attempt: event.attempt,
|
|
3431
3457
|
finalError: event.finalError,
|
|
3432
|
-
|
|
3458
|
+
retryErrors: event.retryErrors,
|
|
3433
3459
|
});
|
|
3434
3460
|
} else if (event.type === "ttsr_triggered") {
|
|
3435
3461
|
await this.#extensionRunner.emit({ type: "ttsr_triggered", rules: event.rules });
|
|
@@ -3758,6 +3784,8 @@ export class AgentSession {
|
|
|
3758
3784
|
this.#recordSessionExit(options.reason ?? "dispose");
|
|
3759
3785
|
this.#cancelExitRecorder?.();
|
|
3760
3786
|
this.#cancelExitRecorder = undefined;
|
|
3787
|
+
this.#cancelFatalRecoveryHint?.();
|
|
3788
|
+
this.#cancelFatalRecoveryHint = undefined;
|
|
3761
3789
|
try {
|
|
3762
3790
|
await emitSessionShutdownEvent(this.#extensionRunner);
|
|
3763
3791
|
} catch (error) {
|
|
@@ -4169,6 +4197,11 @@ export class AgentSession {
|
|
|
4169
4197
|
return this.#tools.getAllToolNames();
|
|
4170
4198
|
}
|
|
4171
4199
|
|
|
4200
|
+
/** Full metadata for every registered tool, including source provenance (backs `getAllTools()`). */
|
|
4201
|
+
getAllToolInfos(): ToolInfo[] {
|
|
4202
|
+
return this.#tools.getAllToolInfos();
|
|
4203
|
+
}
|
|
4204
|
+
|
|
4172
4205
|
/** Installs and activates the ephemeral vibe tool set. */
|
|
4173
4206
|
activateVibeTools(baseToolNames: string[]): Promise<void> {
|
|
4174
4207
|
return this.#tools.activateVibeTools(baseToolNames);
|
|
@@ -5255,11 +5288,13 @@ export class AgentSession {
|
|
|
5255
5288
|
|
|
5256
5289
|
if (result?.systemPrompt !== undefined) {
|
|
5257
5290
|
baseXdevCatalogDelivered = false;
|
|
5258
|
-
this.
|
|
5291
|
+
this.#tools.setTurnSystemPromptOverride(result.systemPrompt);
|
|
5259
5292
|
} else {
|
|
5293
|
+
this.#tools.clearTurnSystemPromptOverride();
|
|
5260
5294
|
this.agent.setSystemPrompt(beforeAgentStartSystemPrompt);
|
|
5261
5295
|
}
|
|
5262
5296
|
} else {
|
|
5297
|
+
this.#tools.clearTurnSystemPromptOverride();
|
|
5263
5298
|
this.agent.setSystemPrompt(beforeAgentStartSystemPrompt);
|
|
5264
5299
|
}
|
|
5265
5300
|
|
|
@@ -5324,6 +5359,8 @@ export class AgentSession {
|
|
|
5324
5359
|
await this.#waitForPostPromptRecovery(generation);
|
|
5325
5360
|
}
|
|
5326
5361
|
} finally {
|
|
5362
|
+
// The per-turn before_agent_start override lives only for this turn.
|
|
5363
|
+
this.#tools.clearTurnSystemPromptOverride();
|
|
5327
5364
|
this.#usagePreflightReadyForNextModelCall = false;
|
|
5328
5365
|
this.#endInFlight();
|
|
5329
5366
|
}
|
|
@@ -6669,9 +6706,10 @@ export class AgentSession {
|
|
|
6669
6706
|
}
|
|
6670
6707
|
|
|
6671
6708
|
#extractRewindReport(messages: AgentMessage[]): string | undefined {
|
|
6672
|
-
|
|
6709
|
+
const checkpointState = this.#checkpointState;
|
|
6710
|
+
if (!checkpointState) return undefined;
|
|
6673
6711
|
if (this.#pendingRewindReport) return this.#pendingRewindReport;
|
|
6674
|
-
for (let i = messages.length - 1; i >=
|
|
6712
|
+
for (let i = messages.length - 1; i >= checkpointState.checkpointMessageCount; i--) {
|
|
6675
6713
|
const message = messages[i];
|
|
6676
6714
|
if (message?.role !== "toolResult" || message.isError) continue;
|
|
6677
6715
|
const semanticResult = semanticToolResult(message.toolName, message);
|
package/src/session/messages.ts
CHANGED
|
@@ -42,6 +42,7 @@ import { formatOutputNotice } from "../tools/output-meta";
|
|
|
42
42
|
export const SKILL_PROMPT_MESSAGE_TYPE = "skill-prompt";
|
|
43
43
|
export const LSP_LATE_DIAGNOSTIC_MESSAGE_TYPE = "lsp-late-diagnostic";
|
|
44
44
|
export const BACKGROUND_TAN_DISPATCH_MESSAGE_TYPE = "background-tan-dispatch";
|
|
45
|
+
export const PREWALK_PLAN_MESSAGE_TYPE = "prewalk-plan";
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
48
|
* Logs provider-error turns so their actual cause is available outside the
|
package/src/session/prewalk.ts
CHANGED
|
@@ -14,11 +14,16 @@ import { type ConfiguredThinkingLevel, prewalkWouldBeNoop } from "../thinking";
|
|
|
14
14
|
import type { PlanProposalHandler } from "../tools/resolve";
|
|
15
15
|
import { ToolError } from "../tools/tool-errors";
|
|
16
16
|
import type { PlanYolo, Prewalk } from "./agent-session-types";
|
|
17
|
+
import { PREWALK_PLAN_MESSAGE_TYPE } from "./messages";
|
|
17
18
|
import type { SessionManager } from "./session-manager";
|
|
18
19
|
|
|
19
|
-
const PREWALK_PLAN_MESSAGE_TYPE = "prewalk-plan";
|
|
20
20
|
const PREWALK_CONTINUE_MESSAGE_TYPE = "prewalk-continue";
|
|
21
21
|
const PREWALK_CHECKLIST_MESSAGE_TYPE = "prewalk-checklist";
|
|
22
|
+
|
|
23
|
+
/** Hidden plan steering is consumed within the live run and must not reappear after a context rebuild. */
|
|
24
|
+
export function isPrewalkPlanNudge(message: AgentMessage): boolean {
|
|
25
|
+
return message.role === "custom" && message.customType === PREWALK_PLAN_MESSAGE_TYPE;
|
|
26
|
+
}
|
|
22
27
|
const PREWALK_ACTION_TOOLS: Record<string, true> = {
|
|
23
28
|
edit: true,
|
|
24
29
|
write: true,
|
|
@@ -99,10 +104,40 @@ export class PrewalkCoordinator {
|
|
|
99
104
|
return this.#prewalk;
|
|
100
105
|
}
|
|
101
106
|
|
|
107
|
+
#isNoop(prewalk: Prewalk): boolean {
|
|
108
|
+
return prewalkWouldBeNoop(
|
|
109
|
+
this.#host.model(),
|
|
110
|
+
this.#host.configuredThinkingLevel(),
|
|
111
|
+
prewalk.target,
|
|
112
|
+
prewalk.thinkingLevel,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
#clearPrewalkState(): void {
|
|
117
|
+
this.#prewalk = undefined;
|
|
118
|
+
this.#planInjected = false;
|
|
119
|
+
this.#continuePending = false;
|
|
120
|
+
this.#todoSeen = false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
#disarmNoop(prewalk: Prewalk): void {
|
|
124
|
+
this.#clearPrewalkState();
|
|
125
|
+
this.#host.emitNotice(
|
|
126
|
+
"info",
|
|
127
|
+
`Prewalk: target ${prewalk.target.provider}/${prewalk.target.id} already matches the active model and thinking level; nothing to switch.`,
|
|
128
|
+
"prewalk",
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
102
132
|
/** Advances the one-way prewalk switch at a completed assistant-turn boundary. */
|
|
103
133
|
async advanceAtTurnEnd(liveMessages: AgentMessage[], context: AgentTurnEndContext | undefined): Promise<void> {
|
|
104
134
|
const prewalk = this.#prewalk;
|
|
105
135
|
if (!prewalk || context?.message.role !== "assistant") return;
|
|
136
|
+
if (this.#isNoop(prewalk)) {
|
|
137
|
+
this.#scrubPlanNudge(liveMessages);
|
|
138
|
+
this.#disarmNoop(prewalk);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
106
141
|
if (context.toolResults.some(result => result.toolName === "todo" && !result.isError)) this.#todoSeen = true;
|
|
107
142
|
|
|
108
143
|
const hasToolResults = context.toolResults.length > 0;
|
|
@@ -147,18 +182,12 @@ export class PrewalkCoordinator {
|
|
|
147
182
|
}
|
|
148
183
|
this.#scrubPlanNudge(liveMessages);
|
|
149
184
|
const target = prewalk.target;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
this.#prewalk = undefined;
|
|
153
|
-
this.#host.emitNotice(
|
|
154
|
-
"info",
|
|
155
|
-
`Prewalk: target ${target.provider}/${target.id} already matches the active model and thinking level; nothing to switch.`,
|
|
156
|
-
"prewalk",
|
|
157
|
-
);
|
|
185
|
+
if (this.#isNoop(prewalk)) {
|
|
186
|
+
this.#disarmNoop(prewalk);
|
|
158
187
|
return;
|
|
159
188
|
}
|
|
160
189
|
await this.#host.setModelTemporary(target, prewalk.thinkingLevel, { ephemeral: true });
|
|
161
|
-
this.#
|
|
190
|
+
this.#clearPrewalkState();
|
|
162
191
|
this.#host.emitNotice(
|
|
163
192
|
"info",
|
|
164
193
|
`Prewalk: switched to ${target.provider}/${target.id} after first ${action.toolName} call.`,
|
|
@@ -175,18 +204,29 @@ export class PrewalkCoordinator {
|
|
|
175
204
|
}
|
|
176
205
|
|
|
177
206
|
/** Arms a prewalk immediately for an explicit slash-command request. */
|
|
178
|
-
arm(target: Model, thinkingLevel?: ConfiguredThinkingLevel):
|
|
179
|
-
|
|
207
|
+
arm(target: Model, thinkingLevel?: ConfiguredThinkingLevel): boolean {
|
|
208
|
+
const active = this.#prewalk;
|
|
209
|
+
if (active) {
|
|
180
210
|
this.#host.emitNotice(
|
|
181
211
|
"info",
|
|
182
|
-
`Prewalk: already armed for ${
|
|
212
|
+
`Prewalk: already armed for ${active.target.provider}/${active.target.id}, waiting for the first edit/write.`,
|
|
183
213
|
"prewalk",
|
|
184
214
|
);
|
|
185
|
-
return
|
|
215
|
+
return (
|
|
216
|
+
active.target.provider === target.provider &&
|
|
217
|
+
active.target.id === target.id &&
|
|
218
|
+
active.thinkingLevel === thinkingLevel
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
const candidate = { target, thinkingLevel };
|
|
222
|
+
if (this.#isNoop(candidate)) {
|
|
223
|
+
this.#disarmNoop(candidate);
|
|
224
|
+
return false;
|
|
186
225
|
}
|
|
187
|
-
this.#prewalk =
|
|
226
|
+
this.#prewalk = candidate;
|
|
188
227
|
this.#planInjected = true;
|
|
189
228
|
this.#continuePending = true;
|
|
229
|
+
this.#todoSeen = false;
|
|
190
230
|
this.#host.agent.steer({
|
|
191
231
|
role: "custom",
|
|
192
232
|
customType: PREWALK_PLAN_MESSAGE_TYPE,
|
|
@@ -200,6 +240,7 @@ export class PrewalkCoordinator {
|
|
|
200
240
|
`Prewalk: armed for ${target.provider}/${target.id} — will switch at the first edit/write once the todo list exists.`,
|
|
201
241
|
"prewalk",
|
|
202
242
|
);
|
|
243
|
+
return true;
|
|
203
244
|
}
|
|
204
245
|
|
|
205
246
|
/** Lazily enables plan-yolo's plan phase before the first prompt is built. */
|
|
@@ -220,8 +261,7 @@ export class PrewalkCoordinator {
|
|
|
220
261
|
|
|
221
262
|
#scrubPlanNudge(liveMessages: AgentMessage[]): void {
|
|
222
263
|
if (!this.#planInjected) return;
|
|
223
|
-
const isPlanNudge =
|
|
224
|
-
message.role === "custom" && message.customType === PREWALK_PLAN_MESSAGE_TYPE;
|
|
264
|
+
const isPlanNudge = isPrewalkPlanNudge;
|
|
225
265
|
for (let index = liveMessages.length - 1; index >= 0; index--) {
|
|
226
266
|
if (!isPlanNudge(liveMessages[index])) continue;
|
|
227
267
|
invalidateMessageCache(liveMessages[index]);
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
INTERRUPTED_THINKING_MESSAGE_TYPE,
|
|
9
9
|
isCustomMessageContent,
|
|
10
10
|
normalizeCustomMessagePayload,
|
|
11
|
+
PREWALK_PLAN_MESSAGE_TYPE,
|
|
11
12
|
} from "./messages";
|
|
12
13
|
import { type CompactionEntry, EPHEMERAL_MODEL_CHANGE_ROLE, type SessionEntry } from "./session-entries";
|
|
13
14
|
|
|
@@ -332,15 +333,12 @@ export function buildSessionContext(
|
|
|
332
333
|
const appendMessage = (entry: SessionEntry) => {
|
|
333
334
|
handleEntryResetTracking(entry);
|
|
334
335
|
if (entry.type === "message") {
|
|
335
|
-
if (
|
|
336
|
-
!options?.transcript &&
|
|
337
|
-
entry.message.role === "assistant" &&
|
|
338
|
-
entry.message.retryRecovery?.status === "recovered"
|
|
339
|
-
) {
|
|
336
|
+
if (!options?.transcript && entry.message.role === "assistant" && entry.message.retryRecovery) {
|
|
340
337
|
return;
|
|
341
338
|
}
|
|
342
339
|
pushMessage(entry.message);
|
|
343
340
|
} else if (entry.type === "custom_message") {
|
|
341
|
+
if (!options?.transcript && entry.customType === PREWALK_PLAN_MESSAGE_TYPE) return;
|
|
344
342
|
if (!isCustomMessageContent(entry.content)) return;
|
|
345
343
|
const normalized = normalizeCustomMessagePayload(entry);
|
|
346
344
|
const attribution = entry.attribution === undefined ? undefined : normalized.attribution;
|
|
@@ -84,6 +84,8 @@ export interface ModelChangeEntry extends SessionEntryBase {
|
|
|
84
84
|
model: string;
|
|
85
85
|
/** Role: "default", "smol", "slow", etc. Undefined treated as "default" */
|
|
86
86
|
role?: string;
|
|
87
|
+
/** True when this transition selected a retry-fallback model rather than the configured model. */
|
|
88
|
+
resolvedModelIsFallback?: boolean;
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
export interface ServiceTierChangeEntry extends SessionEntryBase {
|
|
@@ -207,6 +209,14 @@ export interface SessionInitEntry extends SessionEntryBase {
|
|
|
207
209
|
task: string;
|
|
208
210
|
/** Tools available to the agent */
|
|
209
211
|
tools: string[];
|
|
212
|
+
/** Agent definition name (for example `scout` or `reviewer`). */
|
|
213
|
+
agent?: string;
|
|
214
|
+
/** Semantic model role declared by the agent, retained even after concrete model resolution. */
|
|
215
|
+
modelRole?: string;
|
|
216
|
+
/** Initially resolved provider/model selector for historical display. */
|
|
217
|
+
resolvedModel?: string;
|
|
218
|
+
/** Whether the agent definition is read-only, allowing an exact zero-LoC attribution. */
|
|
219
|
+
readOnly?: boolean;
|
|
210
220
|
/** Output schema if structured output was requested. */
|
|
211
221
|
outputSchema?: unknown;
|
|
212
222
|
/** Enforcement policy recorded with the output schema for faithful revival. */
|
|
@@ -309,7 +309,11 @@ export class SessionHandoff {
|
|
|
309
309
|
|
|
310
310
|
return { document: handoffText, savedPath };
|
|
311
311
|
} catch (error) {
|
|
312
|
-
|
|
312
|
+
// Only a genuine abort (user Esc or the source turn cancelling) is a
|
|
313
|
+
// cancellation. A provider that throws a name==="AbortError" error without the
|
|
314
|
+
// handoff signal being aborted (stall/idle timeout, nested resolution failure)
|
|
315
|
+
// is a real failure and must surface verbatim, not be masked as "cancelled".
|
|
316
|
+
if (handoffSignal.aborted) {
|
|
313
317
|
throw new Error("Handoff cancelled");
|
|
314
318
|
}
|
|
315
319
|
throw error;
|
|
@@ -2,7 +2,7 @@ import * as os from "node:os";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import type { Message } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import { getAgentDir as getDefaultAgentDir, logger, parseJsonlLenient, toError } from "@oh-my-pi/pi-utils";
|
|
5
|
-
import { LRUCache } from "
|
|
5
|
+
import { LRUCache } from "@oh-my-pi/pi-utils/lru";
|
|
6
6
|
import { computeDefaultSessionDir } from "./session-paths";
|
|
7
7
|
import { FileSessionStorage, type SessionStorage, type SessionStorageStat } from "./session-storage";
|
|
8
8
|
|
|
@@ -21,6 +21,19 @@ import {
|
|
|
21
21
|
} from "./session-title-slot";
|
|
22
22
|
|
|
23
23
|
const STREAM_LOAD_THRESHOLD_BYTES = 8 * 1024 * 1024;
|
|
24
|
+
const STREAM_YIELD_BYTES = 1 * 1024 * 1024;
|
|
25
|
+
const STREAM_YIELD_ENTRIES = 8_192;
|
|
26
|
+
|
|
27
|
+
export interface VisitEntriesFromFileStreamOptions {
|
|
28
|
+
/** Stop after the visitor returns `false`. */
|
|
29
|
+
shouldContinue?: () => boolean;
|
|
30
|
+
/** Stop after this many valid or malformed JSONL records have been consumed. */
|
|
31
|
+
maxRecords?: number;
|
|
32
|
+
/** Yield to the macrotask queue after this many bytes have been consumed. */
|
|
33
|
+
yieldEveryBytes?: number;
|
|
34
|
+
/** Yield to the macrotask queue after this many entries have been visited. */
|
|
35
|
+
yieldEveryEntries?: number;
|
|
36
|
+
}
|
|
24
37
|
|
|
25
38
|
function splitTitleSlot(content: string): { body: string; slot: SessionTitleUpdate | undefined } {
|
|
26
39
|
const slot = titleUpdateFromSlot(parseTitleSlotFromContent(content));
|
|
@@ -59,11 +72,19 @@ export function parseSessionContent(content: string): {
|
|
|
59
72
|
/** Parse session JSONL and visit each entry without retaining prior entries. */
|
|
60
73
|
export async function visitEntriesFromFileStream(
|
|
61
74
|
filePath: string,
|
|
62
|
-
visit: (entry: FileEntry) => void,
|
|
75
|
+
visit: (entry: FileEntry) => void | boolean,
|
|
76
|
+
options: VisitEntriesFromFileStreamOptions = {},
|
|
63
77
|
): Promise<SessionTitleUpdate | undefined> {
|
|
64
78
|
let titleSlot: SessionTitleUpdate | undefined;
|
|
65
79
|
let sawFirstLine = false;
|
|
80
|
+
let bytesSinceYield = 0;
|
|
81
|
+
let entriesSinceYield = 0;
|
|
82
|
+
let recordsSeen = 0;
|
|
83
|
+
const maxRecords = Math.max(0, options.maxRecords ?? Number.POSITIVE_INFINITY);
|
|
84
|
+
let stopped = false;
|
|
66
85
|
let visitorThrew = false;
|
|
86
|
+
const yieldEveryBytes = Math.max(0, options.yieldEveryBytes ?? STREAM_YIELD_BYTES);
|
|
87
|
+
const yieldEveryEntries = Math.max(0, options.yieldEveryEntries ?? STREAM_YIELD_ENTRIES);
|
|
67
88
|
// Byte buffer (NOT a decoded string): multibyte UTF-8 sequences that straddle
|
|
68
89
|
// a stream-chunk boundary stay intact, and Bun.JSONL.parseChunk accepts typed
|
|
69
90
|
// arrays directly. Only the unconsumed remainder is held (≤ one record + a
|
|
@@ -72,22 +93,62 @@ export async function visitEntriesFromFileStream(
|
|
|
72
93
|
let buffer: Uint8Array = new Uint8Array();
|
|
73
94
|
const decoder = new TextDecoder();
|
|
74
95
|
|
|
75
|
-
const
|
|
76
|
-
|
|
96
|
+
const yieldToMacrotask = async (): Promise<void> => {
|
|
97
|
+
if (yieldEveryBytes === 0 && yieldEveryEntries === 0) return;
|
|
98
|
+
const bytesReady = yieldEveryBytes === 0 || bytesSinceYield < yieldEveryBytes;
|
|
99
|
+
const entriesReady = yieldEveryEntries === 0 || entriesSinceYield < yieldEveryEntries;
|
|
100
|
+
if (bytesReady && entriesReady) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
bytesSinceYield = 0;
|
|
104
|
+
entriesSinceYield = 0;
|
|
105
|
+
await Bun.sleep(0);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const drain = async (): Promise<void> => {
|
|
109
|
+
while (buffer.length > 0 && !stopped) {
|
|
110
|
+
if (recordsSeen >= maxRecords) {
|
|
111
|
+
stopped = true;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
77
114
|
const { values, error, read, done } = Bun.JSONL.parseChunk(buffer);
|
|
78
115
|
for (const value of values) {
|
|
116
|
+
if (recordsSeen >= maxRecords) {
|
|
117
|
+
stopped = true;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
if (options.shouldContinue && !options.shouldContinue()) {
|
|
121
|
+
stopped = true;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
79
124
|
try {
|
|
80
|
-
visit(value as FileEntry)
|
|
125
|
+
if (visit(value as FileEntry) === false) {
|
|
126
|
+
stopped = true;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
recordsSeen++;
|
|
130
|
+
entriesSinceYield++;
|
|
131
|
+
if (recordsSeen >= maxRecords) {
|
|
132
|
+
stopped = true;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
81
135
|
} catch (err) {
|
|
82
136
|
visitorThrew = true;
|
|
83
137
|
throw err;
|
|
84
138
|
}
|
|
139
|
+
await yieldToMacrotask();
|
|
85
140
|
}
|
|
141
|
+
if (stopped) break;
|
|
86
142
|
if (error) {
|
|
87
143
|
// Malformed record: skip past the next newline and continue.
|
|
88
144
|
const nextNewline = buffer.indexOf(0x0a, read);
|
|
89
145
|
if (nextNewline === -1) break; // rest of the bad line not yet received
|
|
146
|
+
recordsSeen++;
|
|
90
147
|
buffer = buffer.subarray(nextNewline + 1);
|
|
148
|
+
if (recordsSeen >= maxRecords) {
|
|
149
|
+
stopped = true;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
91
152
|
continue;
|
|
92
153
|
}
|
|
93
154
|
if (read === 0) break; // incomplete record awaiting more data
|
|
@@ -101,6 +162,8 @@ export async function visitEntriesFromFileStream(
|
|
|
101
162
|
|
|
102
163
|
try {
|
|
103
164
|
for await (const chunk of Bun.file(filePath).stream()) {
|
|
165
|
+
if (stopped) break;
|
|
166
|
+
bytesSinceYield += chunk.byteLength;
|
|
104
167
|
buffer = buffer.length === 0 ? chunk : Buffer.concat([buffer, chunk]);
|
|
105
168
|
// The optional fixed-width title slot is a physical first line that is
|
|
106
169
|
// NOT JSON; peel it before the parser would (correctly) reject it. The
|
|
@@ -121,14 +184,15 @@ export async function visitEntriesFromFileStream(
|
|
|
121
184
|
}
|
|
122
185
|
}
|
|
123
186
|
}
|
|
124
|
-
drain();
|
|
187
|
+
await drain();
|
|
188
|
+
await yieldToMacrotask();
|
|
125
189
|
}
|
|
126
190
|
// A trailing record without a final newline: terminate it so the parser
|
|
127
191
|
// can complete it (readline yielded it; parseChunk needs the delimiter).
|
|
128
|
-
if (buffer.length > 0 && buffer[buffer.length - 1] !== 0x0a) {
|
|
192
|
+
if (!stopped && buffer.length > 0 && buffer[buffer.length - 1] !== 0x0a) {
|
|
129
193
|
buffer = Buffer.concat([buffer, new Uint8Array([0x0a])]);
|
|
194
|
+
await drain();
|
|
130
195
|
}
|
|
131
|
-
drain();
|
|
132
196
|
} catch (err) {
|
|
133
197
|
if (visitorThrew) throw err;
|
|
134
198
|
if (isEnoent(err)) return undefined;
|
|
@@ -144,7 +208,9 @@ export async function loadEntriesFromFileStream(filePath: string): Promise<{
|
|
|
144
208
|
titleSlot: SessionTitleUpdate | undefined;
|
|
145
209
|
}> {
|
|
146
210
|
const entries: FileEntry[] = [];
|
|
147
|
-
const titleSlot = await visitEntriesFromFileStream(filePath, entry =>
|
|
211
|
+
const titleSlot = await visitEntriesFromFileStream(filePath, entry => {
|
|
212
|
+
entries.push(entry);
|
|
213
|
+
});
|
|
148
214
|
return { entries: foldTitleSlot(entries, titleSlot), titleSlot };
|
|
149
215
|
}
|
|
150
216
|
|
|
@@ -2047,9 +2047,16 @@ export class SessionManager {
|
|
|
2047
2047
|
* Append a model change as a child of the current leaf, then advance the leaf.
|
|
2048
2048
|
* @param model Model in "provider/modelId" format
|
|
2049
2049
|
* @param role Optional role (default: "default")
|
|
2050
|
+
* @param resolvedModelIsFallback Whether this transition selected a retry-fallback model
|
|
2050
2051
|
*/
|
|
2051
|
-
appendModelChange(model: string, role?: string): string {
|
|
2052
|
-
const entry: ModelChangeEntry = {
|
|
2052
|
+
appendModelChange(model: string, role?: string, resolvedModelIsFallback = false): string {
|
|
2053
|
+
const entry: ModelChangeEntry = {
|
|
2054
|
+
type: "model_change",
|
|
2055
|
+
...this.#freshEntryFields(),
|
|
2056
|
+
model,
|
|
2057
|
+
role,
|
|
2058
|
+
resolvedModelIsFallback,
|
|
2059
|
+
};
|
|
2053
2060
|
this.#recordEntry(entry);
|
|
2054
2061
|
return entry.id;
|
|
2055
2062
|
}
|
|
@@ -2058,6 +2065,10 @@ export class SessionManager {
|
|
|
2058
2065
|
systemPrompt: string;
|
|
2059
2066
|
task: string;
|
|
2060
2067
|
tools: string[];
|
|
2068
|
+
agent?: string;
|
|
2069
|
+
modelRole?: string;
|
|
2070
|
+
resolvedModel?: string;
|
|
2071
|
+
readOnly?: boolean;
|
|
2061
2072
|
outputSchema?: unknown;
|
|
2062
2073
|
outputSchemaMode?: StructuredSubagentSchemaMode;
|
|
2063
2074
|
restrictToolNames?: boolean;
|
|
@@ -2547,6 +2558,9 @@ export class SessionManager {
|
|
|
2547
2558
|
systemPrompt: string;
|
|
2548
2559
|
task: string;
|
|
2549
2560
|
tools: string[];
|
|
2561
|
+
agent?: string;
|
|
2562
|
+
modelRole?: string;
|
|
2563
|
+
resolvedModel?: string;
|
|
2550
2564
|
outputSchema?: unknown;
|
|
2551
2565
|
outputSchemaMode?: StructuredSubagentSchemaMode;
|
|
2552
2566
|
restrictToolNames?: boolean;
|
|
@@ -2567,6 +2581,9 @@ export class SessionManager {
|
|
|
2567
2581
|
systemPrompt: string;
|
|
2568
2582
|
task: string;
|
|
2569
2583
|
tools: string[];
|
|
2584
|
+
agent?: string;
|
|
2585
|
+
modelRole?: string;
|
|
2586
|
+
resolvedModel?: string;
|
|
2570
2587
|
outputSchema?: unknown;
|
|
2571
2588
|
outputSchemaMode?: StructuredSubagentSchemaMode;
|
|
2572
2589
|
restrictToolNames?: boolean;
|
|
@@ -2580,6 +2597,9 @@ export class SessionManager {
|
|
|
2580
2597
|
systemPrompt: entry.systemPrompt,
|
|
2581
2598
|
task: entry.task,
|
|
2582
2599
|
tools: entry.tools,
|
|
2600
|
+
agent: entry.agent,
|
|
2601
|
+
modelRole: entry.modelRole,
|
|
2602
|
+
resolvedModel: entry.resolvedModel,
|
|
2583
2603
|
outputSchema: entry.outputSchema,
|
|
2584
2604
|
outputSchemaMode: entry.outputSchemaMode,
|
|
2585
2605
|
restrictToolNames: entry.restrictToolNames,
|