@oh-my-pi/pi-coding-agent 15.9.67 → 15.10.1
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 +136 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/dry-balance-cli.d.ts +15 -1
- package/dist/types/cli/gallery-cli.d.ts +43 -0
- package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
- package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/types.d.ts +44 -0
- package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
- package/dist/types/cli/gallery-screenshot.d.ts +35 -0
- package/dist/types/commands/gallery.d.ts +47 -0
- package/dist/types/commit/analysis/conventional.d.ts +2 -2
- package/dist/types/commit/analysis/summary.d.ts +2 -2
- package/dist/types/commit/changelog/generate.d.ts +2 -2
- package/dist/types/commit/changelog/index.d.ts +2 -2
- package/dist/types/commit/map-reduce/index.d.ts +3 -3
- package/dist/types/commit/map-reduce/map-phase.d.ts +2 -2
- package/dist/types/commit/map-reduce/reduce-phase.d.ts +2 -2
- package/dist/types/commit/model-selection.d.ts +10 -4
- package/dist/types/config/api-key-resolver.d.ts +34 -0
- package/dist/types/config/keybindings.d.ts +6 -1
- package/dist/types/config/model-id-affixes.d.ts +2 -0
- package/dist/types/config/model-registry.d.ts +25 -2
- package/dist/types/config/settings-schema.d.ts +41 -6
- package/dist/types/dap/config.d.ts +14 -1
- package/dist/types/dap/types.d.ts +10 -0
- package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
- package/dist/types/lsp/types.d.ts +10 -0
- package/dist/types/lsp/utils.d.ts +3 -2
- package/dist/types/main.d.ts +3 -2
- package/dist/types/memory-backend/index.d.ts +2 -1
- package/dist/types/memory-backend/resolve.d.ts +1 -1
- package/dist/types/memory-backend/types.d.ts +1 -1
- package/dist/types/modes/components/chat-block.d.ts +64 -0
- package/dist/types/modes/components/custom-editor.d.ts +5 -1
- package/dist/types/modes/components/overlay-box.d.ts +17 -0
- package/dist/types/modes/components/plan-review-overlay.d.ts +59 -0
- package/dist/types/modes/components/plan-toc.d.ts +41 -0
- package/dist/types/modes/components/read-tool-group.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +18 -0
- package/dist/types/modes/components/transcript-container.d.ts +11 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +0 -1
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +0 -1
- package/dist/types/modes/controllers/input-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +22 -0
- package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
- package/dist/types/modes/index.d.ts +5 -4
- package/dist/types/modes/interactive-mode.d.ts +16 -6
- package/dist/types/modes/setup-version.d.ts +11 -0
- package/dist/types/modes/setup-wizard/index.d.ts +2 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +2 -1
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +19 -6
- package/dist/types/modes/utils/copy-targets.d.ts +21 -1
- package/dist/types/plan-mode/approved-plan.d.ts +27 -8
- package/dist/types/plan-mode/plan-protection.d.ts +4 -4
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +21 -0
- package/dist/types/session/messages.d.ts +12 -0
- package/dist/types/session/session-manager.d.ts +3 -1
- package/dist/types/slash-commands/types.d.ts +4 -6
- package/dist/types/task/executor.d.ts +14 -0
- package/dist/types/task/index.d.ts +1 -0
- package/dist/types/task/render.d.ts +3 -2
- package/dist/types/telemetry-export.d.ts +1 -1
- package/dist/types/tools/archive-reader.d.ts +5 -0
- package/dist/types/tools/ast-edit.d.ts +3 -0
- package/dist/types/tools/ast-grep.d.ts +3 -0
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tools/eval-render.d.ts +1 -8
- package/dist/types/tools/fetch.d.ts +15 -7
- package/dist/types/tools/find.d.ts +8 -4
- package/dist/types/tools/grouped-file-output.d.ts +95 -12
- package/dist/types/tools/memory-render.d.ts +4 -1
- package/dist/types/tools/plan-mode-guard.d.ts +8 -9
- package/dist/types/tools/render-utils.d.ts +13 -9
- package/dist/types/tools/renderers.d.ts +16 -2
- package/dist/types/tools/search.d.ts +5 -1
- package/dist/types/tools/sqlite-reader.d.ts +1 -0
- package/dist/types/tools/todo.d.ts +3 -2
- package/dist/types/tools/write.d.ts +5 -0
- package/dist/types/tui/output-block.d.ts +16 -4
- package/dist/types/tui/status-line.d.ts +3 -0
- package/dist/types/utils/enhanced-paste.d.ts +20 -0
- package/dist/types/web/scrapers/github.d.ts +22 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -1
- package/dist/types/web/search/providers/perplexity.d.ts +8 -1
- package/dist/types/web/search/types.d.ts +1 -1
- package/package.json +9 -9
- package/scripts/dev-launch +42 -0
- package/scripts/dev-launch-preload.ts +19 -0
- package/src/auto-thinking/classifier.ts +5 -1
- package/src/cli/args.ts +2 -2
- package/src/cli/dry-balance-cli.ts +52 -17
- package/src/cli/gallery-cli.ts +226 -0
- package/src/cli/gallery-fixtures/agentic.ts +292 -0
- package/src/cli/gallery-fixtures/codeintel.ts +188 -0
- package/src/cli/gallery-fixtures/edit.ts +194 -0
- package/src/cli/gallery-fixtures/fs.ts +153 -0
- package/src/cli/gallery-fixtures/index.ts +40 -0
- package/src/cli/gallery-fixtures/interaction.ts +49 -0
- package/src/cli/gallery-fixtures/memory.ts +81 -0
- package/src/cli/gallery-fixtures/misc.ts +250 -0
- package/src/cli/gallery-fixtures/search.ts +213 -0
- package/src/cli/gallery-fixtures/shell.ts +167 -0
- package/src/cli/gallery-fixtures/types.ts +41 -0
- package/src/cli/gallery-fixtures/web.ts +158 -0
- package/src/cli/gallery-screenshot.ts +279 -0
- package/src/cli-commands.ts +1 -0
- package/src/commands/gallery.ts +52 -0
- package/src/commands/launch.ts +1 -1
- package/src/commit/analysis/conventional.ts +2 -2
- package/src/commit/analysis/summary.ts +2 -2
- package/src/commit/changelog/generate.ts +2 -2
- package/src/commit/changelog/index.ts +2 -2
- package/src/commit/map-reduce/index.ts +3 -3
- package/src/commit/map-reduce/map-phase.ts +2 -2
- package/src/commit/map-reduce/reduce-phase.ts +2 -2
- package/src/commit/model-selection.ts +33 -9
- package/src/commit/pipeline.ts +4 -4
- package/src/config/api-key-resolver.ts +58 -0
- package/src/config/keybindings.ts +15 -6
- package/src/config/model-equivalence.ts +35 -12
- package/src/config/model-id-affixes.ts +39 -22
- package/src/config/model-registry.ts +41 -18
- package/src/config/settings-schema.ts +28 -5
- package/src/config/settings.ts +31 -2
- package/src/dap/client.ts +14 -16
- package/src/dap/config.ts +41 -2
- package/src/dap/defaults.json +1 -0
- package/src/dap/session.ts +1 -0
- package/src/dap/types.ts +10 -0
- package/src/debug/index.ts +40 -54
- package/src/edit/renderer.ts +111 -119
- package/src/eval/__tests__/agent-bridge.test.ts +75 -32
- package/src/eval/__tests__/llm-bridge.test.ts +90 -31
- package/src/eval/agent-bridge.ts +34 -7
- package/src/eval/llm-bridge.ts +8 -3
- package/src/extensibility/extensions/runner.ts +1 -0
- package/src/extensibility/plugins/doctor.ts +0 -1
- package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
- package/src/goals/tools/goal-tool.ts +37 -27
- package/src/internal-urls/docs-index.generated.ts +10 -10
- package/src/lsp/client.ts +104 -55
- package/src/lsp/types.ts +10 -0
- package/src/lsp/utils.ts +3 -2
- package/src/main.ts +53 -56
- package/src/memories/index.ts +12 -5
- package/src/memory-backend/index.ts +13 -1
- package/src/memory-backend/resolve.ts +3 -5
- package/src/memory-backend/types.ts +1 -1
- package/src/mnemopi/backend.ts +5 -1
- package/src/modes/acp/acp-agent.ts +33 -26
- package/src/modes/components/assistant-message.ts +2 -9
- package/src/modes/components/chat-block.ts +111 -0
- package/src/modes/components/copy-selector.ts +1 -44
- package/src/modes/components/custom-editor.ts +33 -1
- package/src/modes/components/custom-message.ts +1 -3
- package/src/modes/components/execution-shared.ts +1 -2
- package/src/modes/components/hook-message.ts +1 -3
- package/src/modes/components/overlay-box.ts +108 -0
- package/src/modes/components/plan-review-overlay.ts +799 -0
- package/src/modes/components/plan-toc.ts +138 -0
- package/src/modes/components/read-tool-group.ts +20 -4
- package/src/modes/components/skill-message.ts +0 -1
- package/src/modes/components/status-line.ts +3 -5
- package/src/modes/components/tips.txt +1 -0
- package/src/modes/components/todo-reminder.ts +0 -2
- package/src/modes/components/tool-execution.ts +115 -90
- package/src/modes/components/transcript-container.ts +84 -24
- package/src/modes/components/user-message.ts +1 -2
- package/src/modes/controllers/command-controller-shared.ts +7 -6
- package/src/modes/controllers/command-controller.ts +70 -57
- package/src/modes/controllers/event-controller.ts +41 -40
- package/src/modes/controllers/extension-ui-controller.ts +10 -73
- package/src/modes/controllers/input-controller.ts +135 -122
- package/src/modes/controllers/mcp-command-controller.ts +69 -60
- package/src/modes/controllers/selector-controller.ts +25 -27
- package/src/modes/controllers/streaming-reveal.ts +212 -0
- package/src/modes/controllers/tan-command-controller.ts +173 -0
- package/src/modes/index.ts +5 -4
- package/src/modes/interactive-mode.ts +171 -82
- package/src/modes/setup-version.ts +11 -0
- package/src/modes/setup-wizard/index.ts +3 -2
- package/src/modes/setup-wizard/scenes/web-search.ts +3 -2
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/theme/theme-schema.json +1 -1
- package/src/modes/theme/theme.ts +8 -4
- package/src/modes/types.ts +19 -8
- package/src/modes/utils/context-usage.ts +10 -6
- package/src/modes/utils/copy-targets.ts +133 -27
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +44 -46
- package/src/plan-mode/approved-plan.ts +66 -43
- package/src/plan-mode/plan-protection.ts +4 -4
- package/src/prompts/system/background-tan-dispatch.md +8 -0
- package/src/prompts/system/plan-mode-active.md +67 -58
- package/src/prompts/system/plan-mode-approved.md +1 -1
- package/src/sdk.ts +32 -60
- package/src/session/agent-session.ts +89 -13
- package/src/session/messages.ts +26 -0
- package/src/session/session-manager.ts +13 -5
- package/src/slash-commands/builtin-registry.ts +37 -10
- package/src/slash-commands/helpers/usage-report.ts +2 -0
- package/src/slash-commands/types.ts +4 -6
- package/src/task/executor.ts +25 -4
- package/src/task/index.ts +4 -0
- package/src/task/render.ts +212 -148
- package/src/telemetry-export.ts +25 -7
- package/src/tools/archive-reader.ts +64 -0
- package/src/tools/ask.ts +119 -164
- package/src/tools/ast-edit.ts +98 -71
- package/src/tools/ast-grep.ts +37 -43
- package/src/tools/bash.ts +50 -6
- package/src/tools/debug.ts +20 -8
- package/src/tools/eval-backends.ts +6 -17
- package/src/tools/eval-render.ts +21 -18
- package/src/tools/eval.ts +5 -4
- package/src/tools/fetch.ts +391 -91
- package/src/tools/find.ts +44 -30
- package/src/tools/gh-renderer.ts +81 -42
- package/src/tools/grouped-file-output.ts +272 -48
- package/src/tools/image-gen.ts +150 -103
- package/src/tools/inspect-image-renderer.ts +63 -41
- package/src/tools/inspect-image.ts +8 -1
- package/src/tools/job.ts +3 -4
- package/src/tools/memory-render.ts +4 -1
- package/src/tools/plan-mode-guard.ts +21 -39
- package/src/tools/read.ts +23 -16
- package/src/tools/render-utils.ts +38 -40
- package/src/tools/renderers.ts +16 -1
- package/src/tools/report-tool-issue.ts +1 -1
- package/src/tools/resolve.ts +14 -0
- package/src/tools/search-tool-bm25.ts +36 -23
- package/src/tools/search.ts +189 -95
- package/src/tools/sqlite-reader.ts +9 -12
- package/src/tools/todo.ts +138 -59
- package/src/tools/write.ts +100 -60
- package/src/tui/output-block.ts +60 -13
- package/src/tui/status-line.ts +5 -1
- package/src/utils/commit-message-generator.ts +9 -1
- package/src/utils/enhanced-paste.ts +202 -0
- package/src/utils/title-generator.ts +2 -1
- package/src/web/scrapers/github.ts +255 -3
- package/src/web/scrapers/youtube.ts +3 -2
- package/src/web/search/providers/anthropic.ts +25 -19
- package/src/web/search/providers/exa.ts +11 -3
- package/src/web/search/providers/kimi.ts +28 -17
- package/src/web/search/providers/parallel.ts +35 -24
- package/src/web/search/providers/perplexity.ts +199 -51
- package/src/web/search/providers/synthetic.ts +8 -6
- package/src/web/search/providers/tavily.ts +9 -8
- package/src/web/search/providers/zai.ts +8 -6
- package/src/web/search/render.ts +39 -54
- package/src/web/search/types.ts +5 -1
- package/dist/types/eval/__tests__/shared-executors.test.d.ts +0 -1
- package/src/eval/__tests__/shared-executors.test.ts +0 -609
|
@@ -128,7 +128,6 @@ import {
|
|
|
128
128
|
} from "../eval/py/executor";
|
|
129
129
|
import { defaultEvalSessionId } from "../eval/session-id";
|
|
130
130
|
import { type BashResult, executeBash as executeBashCommand } from "../exec/bash-executor";
|
|
131
|
-
import { exportSessionToHtml } from "../export/html";
|
|
132
131
|
import type { TtsrManager, TtsrMatchContext } from "../export/ttsr";
|
|
133
132
|
import type { LoadedCustomCommand } from "../extensibility/custom-commands";
|
|
134
133
|
import type { CustomTool, CustomToolContext } from "../extensibility/custom-tools/types";
|
|
@@ -472,6 +471,12 @@ export interface SessionStats {
|
|
|
472
471
|
cost: number;
|
|
473
472
|
}
|
|
474
473
|
|
|
474
|
+
export interface FreshSessionResult {
|
|
475
|
+
previousSessionId: string;
|
|
476
|
+
sessionId: string;
|
|
477
|
+
closedProviderSessions: number;
|
|
478
|
+
}
|
|
479
|
+
|
|
475
480
|
/** Internal marker for hook messages queued through the agent loop */
|
|
476
481
|
// ============================================================================
|
|
477
482
|
// Constants
|
|
@@ -923,6 +928,7 @@ export class AgentSession {
|
|
|
923
928
|
#agentId: string | undefined;
|
|
924
929
|
#agentRegistry: AgentRegistry | undefined;
|
|
925
930
|
#providerSessionId: string | undefined;
|
|
931
|
+
#freshProviderSessionId: string | undefined;
|
|
926
932
|
#isDisposed = false;
|
|
927
933
|
// Extension system
|
|
928
934
|
#extensionRunner: ExtensionRunner | undefined = undefined;
|
|
@@ -1276,6 +1282,14 @@ export class AgentSession {
|
|
|
1276
1282
|
return this.#modelRegistry;
|
|
1277
1283
|
}
|
|
1278
1284
|
|
|
1285
|
+
get asyncJobManager(): AsyncJobManager | undefined {
|
|
1286
|
+
return this.#asyncJobManager;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
getAgentId(): string | undefined {
|
|
1290
|
+
return this.#agentId;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1279
1293
|
/** Advance the tool-choice queue and return the next directive for the upcoming LLM call. */
|
|
1280
1294
|
nextToolChoice(): ToolChoice | undefined {
|
|
1281
1295
|
return this.#toolChoiceQueue.nextToolChoice();
|
|
@@ -1682,7 +1696,7 @@ export class AgentSession {
|
|
|
1682
1696
|
// Abort the stream immediately — do not gate on extension callbacks
|
|
1683
1697
|
this.#ttsrAbortPending = true;
|
|
1684
1698
|
this.#ensureTtsrResumePromise();
|
|
1685
|
-
this.agent.abort();
|
|
1699
|
+
this.agent.abort(this.#formatTtsrAbortReason(matches));
|
|
1686
1700
|
// Notify extensions (fire-and-forget, does not block abort)
|
|
1687
1701
|
this.#emitSessionEvent({ type: "ttsr_triggered", rules: matches }).catch(() => {});
|
|
1688
1702
|
// Schedule retry after a short delay
|
|
@@ -2163,6 +2177,12 @@ export class AgentSession {
|
|
|
2163
2177
|
}
|
|
2164
2178
|
}
|
|
2165
2179
|
|
|
2180
|
+
#formatTtsrAbortReason(rules: Rule[]): string {
|
|
2181
|
+
const label = rules.length === 1 ? "rule" : "rules";
|
|
2182
|
+
const ruleNames = rules.map(rule => rule.name).join(", ");
|
|
2183
|
+
return `TTSR matched ${label}: ${ruleNames}`;
|
|
2184
|
+
}
|
|
2185
|
+
|
|
2166
2186
|
/** Get TTSR injection payload and clear pending injections. */
|
|
2167
2187
|
#getTtsrInjectionContent(): { content: string; rules: Rule[] } | undefined {
|
|
2168
2188
|
if (this.#pendingTtsrInjections.length === 0) return undefined;
|
|
@@ -2186,13 +2206,20 @@ export class AgentSession {
|
|
|
2186
2206
|
* project, `~`-relative when it lives under home, else the raw path.
|
|
2187
2207
|
*/
|
|
2188
2208
|
#displayRulePath(rulePath: string): string {
|
|
2189
|
-
const cwdRel =
|
|
2209
|
+
const cwdRel =
|
|
2210
|
+
relativePathWithinRoot(this.sessionManager.getCwd(), rulePath) ??
|
|
2211
|
+
this.#displayPathWithinRoot(this.sessionManager.getCwd(), rulePath);
|
|
2190
2212
|
if (cwdRel) return cwdRel;
|
|
2191
2213
|
const homeRel = relativePathWithinRoot(os.homedir(), rulePath);
|
|
2192
2214
|
if (homeRel) return `~/${homeRel}`;
|
|
2193
2215
|
return rulePath;
|
|
2194
2216
|
}
|
|
2195
2217
|
|
|
2218
|
+
#displayPathWithinRoot(root: string, candidate: string): string | null {
|
|
2219
|
+
const relative = path.relative(path.resolve(root), path.resolve(candidate));
|
|
2220
|
+
return relative && !relative.startsWith("..") && !path.isAbsolute(relative) ? relative : null;
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2196
2223
|
#addPendingTtsrInjections(rules: Rule[]): void {
|
|
2197
2224
|
const seen = new Set(this.#pendingTtsrInjections.map(rule => rule.name));
|
|
2198
2225
|
for (const rule of rules) {
|
|
@@ -2947,6 +2974,10 @@ export class AgentSession {
|
|
|
2947
2974
|
this.#unsubscribeAgent = this.agent.subscribe(this.#handleAgentEvent);
|
|
2948
2975
|
}
|
|
2949
2976
|
|
|
2977
|
+
#activeProviderSessionId(sessionId?: string): string {
|
|
2978
|
+
return this.#freshProviderSessionId ?? this.#providerSessionId ?? sessionId ?? this.sessionManager.getSessionId();
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2950
2981
|
/**
|
|
2951
2982
|
* Set agent.sessionId from the session manager and install a dynamic
|
|
2952
2983
|
* metadata resolver so every Anthropic API request carries
|
|
@@ -2959,7 +2990,7 @@ export class AgentSession {
|
|
|
2959
2990
|
* `#syncAgentSessionId()` on every such event.
|
|
2960
2991
|
*/
|
|
2961
2992
|
#syncAgentSessionId(sessionId?: string): void {
|
|
2962
|
-
const sid = this.#
|
|
2993
|
+
const sid = this.#activeProviderSessionId(sessionId);
|
|
2963
2994
|
this.agent.sessionId = sid;
|
|
2964
2995
|
this.agent.setMetadataResolver((provider: string) =>
|
|
2965
2996
|
buildSessionMetadata(sid, provider, this.#modelRegistry.authStorage),
|
|
@@ -2967,14 +2998,14 @@ export class AgentSession {
|
|
|
2967
2998
|
}
|
|
2968
2999
|
|
|
2969
3000
|
#rekeyHindsightMemoryForCurrentSessionId(): void {
|
|
2970
|
-
if (
|
|
3001
|
+
if (this.settings.get("memory.backend") !== "hindsight") return;
|
|
2971
3002
|
const sid = this.agent.sessionId;
|
|
2972
3003
|
if (!sid) return;
|
|
2973
3004
|
this.getHindsightSessionState()?.setSessionId(sid);
|
|
2974
3005
|
}
|
|
2975
3006
|
|
|
2976
3007
|
#rekeyMnemopiMemoryForCurrentSessionId(): void {
|
|
2977
|
-
if (
|
|
3008
|
+
if (this.settings.get("memory.backend") !== "mnemopi") return;
|
|
2978
3009
|
const sid = this.agent.sessionId;
|
|
2979
3010
|
if (!sid) return;
|
|
2980
3011
|
this.getMnemopiSessionState()?.setSessionId(sid);
|
|
@@ -2982,14 +3013,14 @@ export class AgentSession {
|
|
|
2982
3013
|
|
|
2983
3014
|
/** New session file: reset auto-recall / retain-threshold counters for the new transcript. */
|
|
2984
3015
|
#resetHindsightConversationTrackingIfHindsight(): void {
|
|
2985
|
-
if (
|
|
3016
|
+
if (this.settings.get("memory.backend") !== "hindsight") return;
|
|
2986
3017
|
const state = this.getHindsightSessionState();
|
|
2987
3018
|
if (!state || state.aliasOf) return;
|
|
2988
3019
|
state.resetConversationTracking();
|
|
2989
3020
|
}
|
|
2990
3021
|
|
|
2991
3022
|
#resetMnemopiConversationTrackingIfMnemopi(): void {
|
|
2992
|
-
if (
|
|
3023
|
+
if (this.settings.get("memory.backend") !== "mnemopi") return;
|
|
2993
3024
|
const state = this.getMnemopiSessionState();
|
|
2994
3025
|
if (!state || state.aliasOf) return;
|
|
2995
3026
|
state.resetConversationTracking();
|
|
@@ -3089,6 +3120,23 @@ export class AgentSession {
|
|
|
3089
3120
|
this.#providerSessionState.clear();
|
|
3090
3121
|
}
|
|
3091
3122
|
|
|
3123
|
+
freshSession(): FreshSessionResult | undefined {
|
|
3124
|
+
if (this.isStreaming) return undefined;
|
|
3125
|
+
const previousSessionId = this.sessionId;
|
|
3126
|
+
const closedProviderSessions = this.#providerSessionState.size;
|
|
3127
|
+
this.#closeAllProviderSessions("fresh session");
|
|
3128
|
+
this.#freshProviderSessionId = Bun.randomUUIDv7();
|
|
3129
|
+
this.#syncAgentSessionId();
|
|
3130
|
+
this.#rekeyHindsightMemoryForCurrentSessionId();
|
|
3131
|
+
this.#rekeyMnemopiMemoryForCurrentSessionId();
|
|
3132
|
+
this.agent.appendOnlyContext?.invalidateForModelChange();
|
|
3133
|
+
return {
|
|
3134
|
+
previousSessionId,
|
|
3135
|
+
sessionId: this.sessionId,
|
|
3136
|
+
closedProviderSessions,
|
|
3137
|
+
};
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3092
3140
|
// =========================================================================
|
|
3093
3141
|
// Read-only State Access
|
|
3094
3142
|
// =========================================================================
|
|
@@ -3670,7 +3718,7 @@ export class AgentSession {
|
|
|
3670
3718
|
}
|
|
3671
3719
|
|
|
3672
3720
|
async #buildSystemPromptForAgentStart(promptText: string): Promise<string[]> {
|
|
3673
|
-
const backend = resolveMemoryBackend(this.settings);
|
|
3721
|
+
const backend = await resolveMemoryBackend(this.settings);
|
|
3674
3722
|
if (!backend.beforeAgentStartPrompt) return this.#baseSystemPrompt;
|
|
3675
3723
|
|
|
3676
3724
|
try {
|
|
@@ -3993,7 +4041,7 @@ export class AgentSession {
|
|
|
3993
4041
|
|
|
3994
4042
|
/** Current session ID */
|
|
3995
4043
|
get sessionId(): string {
|
|
3996
|
-
return this.#
|
|
4044
|
+
return this.#activeProviderSessionId();
|
|
3997
4045
|
}
|
|
3998
4046
|
getEvalSessionId(): string | null {
|
|
3999
4047
|
if (this.#parentEvalSessionId !== undefined) return this.#parentEvalSessionId;
|
|
@@ -5092,8 +5140,13 @@ export class AgentSession {
|
|
|
5092
5140
|
|
|
5093
5141
|
/**
|
|
5094
5142
|
* Abort current operation and wait for agent to become idle.
|
|
5143
|
+
*
|
|
5144
|
+
* `reason` (e.g. `USER_INTERRUPT_LABEL`) rides the agent's `AbortController`
|
|
5145
|
+
* and surfaces verbatim on the aborted assistant message's `errorMessage`, so
|
|
5146
|
+
* the transcript can distinguish a deliberate user interrupt from an opaque
|
|
5147
|
+
* abort. Omit it for internal/lifecycle aborts.
|
|
5095
5148
|
*/
|
|
5096
|
-
async abort(options?: { goalReason?: "interrupted" | "internal" }): Promise<void> {
|
|
5149
|
+
async abort(options?: { goalReason?: "interrupted" | "internal"; reason?: string }): Promise<void> {
|
|
5097
5150
|
this.abortRetry();
|
|
5098
5151
|
this.#promptGeneration++;
|
|
5099
5152
|
this.#scheduledHiddenNextTurnGeneration = undefined;
|
|
@@ -5102,7 +5155,7 @@ export class AgentSession {
|
|
|
5102
5155
|
this.abortBash();
|
|
5103
5156
|
this.abortEval();
|
|
5104
5157
|
const postPromptDrain = this.#cancelPostPromptTasks();
|
|
5105
|
-
this.agent.abort();
|
|
5158
|
+
this.agent.abort(options?.reason);
|
|
5106
5159
|
await postPromptDrain;
|
|
5107
5160
|
await this.agent.waitForIdle();
|
|
5108
5161
|
await this.#goalRuntime.onTaskAborted({ reason: options?.goalReason ?? "interrupted" });
|
|
@@ -5119,6 +5172,19 @@ export class AgentSession {
|
|
|
5119
5172
|
}
|
|
5120
5173
|
}
|
|
5121
5174
|
|
|
5175
|
+
/**
|
|
5176
|
+
* Abort active work, then immediately resume the agent so queued steer/follow-up
|
|
5177
|
+
* messages drain instead of waiting for another natural turn boundary.
|
|
5178
|
+
*/
|
|
5179
|
+
async interruptAndFlushQueuedMessages(options?: { reason?: string }): Promise<void> {
|
|
5180
|
+
if (!this.agent.hasQueuedMessages()) return;
|
|
5181
|
+
await this.abort({ reason: options?.reason });
|
|
5182
|
+
if (!this.agent.hasQueuedMessages()) return;
|
|
5183
|
+
if (this.isCompacting || this.isGeneratingHandoff) return;
|
|
5184
|
+
await this.#maybeRestoreRetryFallbackPrimary();
|
|
5185
|
+
await this.agent.continue();
|
|
5186
|
+
}
|
|
5187
|
+
|
|
5122
5188
|
/**
|
|
5123
5189
|
* Start a new session, optionally with initial messages and parent tracking.
|
|
5124
5190
|
* Clears all messages and starts a new session.
|
|
@@ -5163,6 +5229,7 @@ export class AgentSession {
|
|
|
5163
5229
|
}
|
|
5164
5230
|
await this.sessionManager.newSession(options);
|
|
5165
5231
|
this.setTodoPhases([]);
|
|
5232
|
+
this.#freshProviderSessionId = undefined;
|
|
5166
5233
|
this.#syncAgentSessionId();
|
|
5167
5234
|
this.#rekeyHindsightMemoryForCurrentSessionId();
|
|
5168
5235
|
this.#rekeyMnemopiMemoryForCurrentSessionId();
|
|
@@ -5260,6 +5327,7 @@ export class AgentSession {
|
|
|
5260
5327
|
}
|
|
5261
5328
|
|
|
5262
5329
|
// Update agent session ID
|
|
5330
|
+
this.#freshProviderSessionId = undefined;
|
|
5263
5331
|
this.#syncAgentSessionId();
|
|
5264
5332
|
this.#rekeyHindsightMemoryForCurrentSessionId();
|
|
5265
5333
|
this.#rekeyMnemopiMemoryForCurrentSessionId();
|
|
@@ -6096,7 +6164,7 @@ export class AgentSession {
|
|
|
6096
6164
|
messagesToSummarize: AgentMessage[];
|
|
6097
6165
|
turnPrefixMessages: AgentMessage[];
|
|
6098
6166
|
}): Promise<string | undefined> {
|
|
6099
|
-
const backend = resolveMemoryBackend(this.settings);
|
|
6167
|
+
const backend = await resolveMemoryBackend(this.settings);
|
|
6100
6168
|
if (!backend.preCompactionContext) return undefined;
|
|
6101
6169
|
const messages = preparation.messagesToSummarize.concat(preparation.turnPrefixMessages);
|
|
6102
6170
|
try {
|
|
@@ -6227,6 +6295,7 @@ export class AgentSession {
|
|
|
6227
6295
|
this.#cancelOwnAsyncJobs();
|
|
6228
6296
|
await this.sessionManager.newSession(previousSessionFile ? { parentSession: previousSessionFile } : undefined);
|
|
6229
6297
|
this.agent.reset();
|
|
6298
|
+
this.#freshProviderSessionId = undefined;
|
|
6230
6299
|
this.#syncAgentSessionId();
|
|
6231
6300
|
this.#rekeyHindsightMemoryForCurrentSessionId();
|
|
6232
6301
|
this.#rekeyMnemopiMemoryForCurrentSessionId();
|
|
@@ -8942,6 +9011,7 @@ export class AgentSession {
|
|
|
8942
9011
|
const previousTools = [...this.agent.state.tools];
|
|
8943
9012
|
const previousBaseSystemPrompt = this.#baseSystemPrompt;
|
|
8944
9013
|
const previousSystemPrompt = this.agent.state.systemPrompt;
|
|
9014
|
+
const previousFreshProviderSessionId = this.#freshProviderSessionId;
|
|
8945
9015
|
const previousFallbackSelectedMCPToolNames = previousSessionFile
|
|
8946
9016
|
? this.#getSessionDefaultSelectedMCPToolNames(previousSessionFile)
|
|
8947
9017
|
: undefined;
|
|
@@ -8953,6 +9023,9 @@ export class AgentSession {
|
|
|
8953
9023
|
|
|
8954
9024
|
try {
|
|
8955
9025
|
await this.sessionManager.setSessionFile(sessionPath);
|
|
9026
|
+
if (switchingToDifferentSession) {
|
|
9027
|
+
this.#freshProviderSessionId = undefined;
|
|
9028
|
+
}
|
|
8956
9029
|
this.#syncAgentSessionId();
|
|
8957
9030
|
this.#rekeyHindsightMemoryForCurrentSessionId();
|
|
8958
9031
|
this.#rekeyMnemopiMemoryForCurrentSessionId();
|
|
@@ -9062,6 +9135,7 @@ export class AgentSession {
|
|
|
9062
9135
|
return true;
|
|
9063
9136
|
} catch (error) {
|
|
9064
9137
|
this.sessionManager.restoreState(previousSessionState);
|
|
9138
|
+
this.#freshProviderSessionId = previousFreshProviderSessionId;
|
|
9065
9139
|
this.#syncAgentSessionId(previousSessionState.sessionId);
|
|
9066
9140
|
this.#rekeyHindsightMemoryForCurrentSessionId();
|
|
9067
9141
|
this.#rekeyMnemopiMemoryForCurrentSessionId();
|
|
@@ -9160,6 +9234,7 @@ export class AgentSession {
|
|
|
9160
9234
|
this.sessionManager.createBranchedSession(selectedEntry.parentId);
|
|
9161
9235
|
}
|
|
9162
9236
|
this.#syncTodoPhasesFromBranch();
|
|
9237
|
+
this.#freshProviderSessionId = undefined;
|
|
9163
9238
|
this.#syncAgentSessionId();
|
|
9164
9239
|
this.#rekeyHindsightMemoryForCurrentSessionId();
|
|
9165
9240
|
this.#rekeyMnemopiMemoryForCurrentSessionId();
|
|
@@ -9588,6 +9663,7 @@ export class AgentSession {
|
|
|
9588
9663
|
*/
|
|
9589
9664
|
async exportToHtml(outputPath?: string): Promise<string> {
|
|
9590
9665
|
const themeName = getCurrentThemeName();
|
|
9666
|
+
const { exportSessionToHtml } = await import("../export/html");
|
|
9591
9667
|
return exportSessionToHtml(this.sessionManager, this.state, { outputPath, themeName });
|
|
9592
9668
|
}
|
|
9593
9669
|
|
package/src/session/messages.ts
CHANGED
|
@@ -70,6 +70,32 @@ export function isSilentAbort(errorMessage: string | undefined): boolean {
|
|
|
70
70
|
return errorMessage === SILENT_ABORT_MARKER;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
/** Reason threaded through `AbortController.abort(reason)` when the user aborts
|
|
74
|
+
* the turn with Esc (see `AgentSession.abort`). The agent surfaces it verbatim
|
|
75
|
+
* on the aborted assistant message's `errorMessage`, so the transcript reads as
|
|
76
|
+
* a deliberate user interrupt instead of an opaque failure. */
|
|
77
|
+
export const USER_INTERRUPT_LABEL = "Interrupted by user";
|
|
78
|
+
|
|
79
|
+
/** Sentinel `errorMessage` the agent stamps on any abort that carried no custom
|
|
80
|
+
* reason (bare `abort()`). Renderers treat it as "no specific reason given". */
|
|
81
|
+
const GENERIC_ABORT_SENTINEL = "Request was aborted";
|
|
82
|
+
|
|
83
|
+
/** Resolve the operator-facing label for an aborted assistant turn. A custom
|
|
84
|
+
* abort reason (e.g. `USER_INTERRUPT_LABEL`) threaded onto `errorMessage` is
|
|
85
|
+
* shown verbatim; aborts with no threaded reason fall back to the retry-aware
|
|
86
|
+
* generic label. Centralizes the live-stream (`EventController`), replay
|
|
87
|
+
* (`ui-helpers`), and component (`AssistantMessageComponent`) render paths so
|
|
88
|
+
* they stay in lockstep. */
|
|
89
|
+
export function resolveAbortLabel(errorMessage: string | undefined, retryAttempt = 0): string {
|
|
90
|
+
if (errorMessage && errorMessage !== GENERIC_ABORT_SENTINEL && !isSilentAbort(errorMessage)) {
|
|
91
|
+
return errorMessage;
|
|
92
|
+
}
|
|
93
|
+
if (retryAttempt > 0) {
|
|
94
|
+
return `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? "s" : ""}`;
|
|
95
|
+
}
|
|
96
|
+
return "Operation aborted";
|
|
97
|
+
}
|
|
98
|
+
|
|
73
99
|
/** Extract the optional `__pendingDisplayTag` field from a CustomMessage's
|
|
74
100
|
* `details` blob. Safe over `unknown`; returns undefined when the field is
|
|
75
101
|
* absent or non-string. */
|
|
@@ -1967,6 +1967,7 @@ export class SessionManager {
|
|
|
1967
1967
|
#inMemoryArtifacts: Map<string, string> | null = null;
|
|
1968
1968
|
#inMemoryArtifactCounter = 0;
|
|
1969
1969
|
readonly #blobStore: BlobStore;
|
|
1970
|
+
#suppressBreadcrumb = false;
|
|
1970
1971
|
|
|
1971
1972
|
private constructor(
|
|
1972
1973
|
private cwd: string,
|
|
@@ -1981,6 +1982,11 @@ export class SessionManager {
|
|
|
1981
1982
|
// Note: call _initSession() or _initSessionFile() after construction
|
|
1982
1983
|
}
|
|
1983
1984
|
|
|
1985
|
+
#maybeWriteBreadcrumb(cwd: string, sessionFile: string): void {
|
|
1986
|
+
if (this.#suppressBreadcrumb) return;
|
|
1987
|
+
writeTerminalBreadcrumb(cwd, sessionFile);
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1984
1990
|
/** Puts a binary blob into the blob store and returns the blob reference */
|
|
1985
1991
|
async putBlob(data: Buffer, options?: BlobPutOptions): Promise<BlobPutResult> {
|
|
1986
1992
|
return this.#blobStore.put(data, options);
|
|
@@ -2027,7 +2033,7 @@ export class SessionManager {
|
|
|
2027
2033
|
this.#adoptedArtifactManager = null;
|
|
2028
2034
|
this.#buildIndex();
|
|
2029
2035
|
if (this.#sessionFile) {
|
|
2030
|
-
|
|
2036
|
+
this.#maybeWriteBreadcrumb(this.cwd, this.#sessionFile);
|
|
2031
2037
|
}
|
|
2032
2038
|
}
|
|
2033
2039
|
|
|
@@ -2047,7 +2053,7 @@ export class SessionManager {
|
|
|
2047
2053
|
this.#persistError = undefined;
|
|
2048
2054
|
this.#persistErrorReported = false;
|
|
2049
2055
|
this.#sessionFile = path.resolve(sessionFile);
|
|
2050
|
-
|
|
2056
|
+
this.#maybeWriteBreadcrumb(this.cwd, this.#sessionFile);
|
|
2051
2057
|
this.#fileEntries = await loadEntriesFromFile(this.#sessionFile, this.storage);
|
|
2052
2058
|
if (this.#fileEntries.length > 0) {
|
|
2053
2059
|
const header = this.#fileEntries.find(e => e.type === "session") as SessionHeader | undefined;
|
|
@@ -2064,7 +2070,7 @@ export class SessionManager {
|
|
|
2064
2070
|
if (headerCwd && headerCwd !== this.cwd) {
|
|
2065
2071
|
this.cwd = headerCwd;
|
|
2066
2072
|
this.sessionDir = path.resolve(this.#sessionFile, "..");
|
|
2067
|
-
|
|
2073
|
+
this.#maybeWriteBreadcrumb(this.cwd, this.#sessionFile);
|
|
2068
2074
|
}
|
|
2069
2075
|
|
|
2070
2076
|
this.#needsFullRewriteOnNextPersist = migrateToCurrentVersion(this.#fileEntries);
|
|
@@ -2245,7 +2251,7 @@ export class SessionManager {
|
|
|
2245
2251
|
|
|
2246
2252
|
// Update terminal breadcrumb
|
|
2247
2253
|
if (this.#sessionFile) {
|
|
2248
|
-
|
|
2254
|
+
this.#maybeWriteBreadcrumb(resolvedCwd, this.#sessionFile);
|
|
2249
2255
|
}
|
|
2250
2256
|
}
|
|
2251
2257
|
|
|
@@ -2280,7 +2286,7 @@ export class SessionManager {
|
|
|
2280
2286
|
if (this.persist) {
|
|
2281
2287
|
const fileTimestamp = timestamp.replace(/[:.]/g, "-");
|
|
2282
2288
|
this.#sessionFile = path.join(this.getSessionDir(), `${fileTimestamp}_${this.#sessionId}.jsonl`);
|
|
2283
|
-
|
|
2289
|
+
this.#maybeWriteBreadcrumb(this.cwd, this.#sessionFile);
|
|
2284
2290
|
}
|
|
2285
2291
|
return this.#sessionFile;
|
|
2286
2292
|
}
|
|
@@ -3429,9 +3435,11 @@ export class SessionManager {
|
|
|
3429
3435
|
cwd: string,
|
|
3430
3436
|
sessionDir?: string,
|
|
3431
3437
|
storage: SessionStorage = new FileSessionStorage(),
|
|
3438
|
+
options?: { suppressBreadcrumb?: boolean },
|
|
3432
3439
|
): Promise<SessionManager> {
|
|
3433
3440
|
const dir = sessionDir ?? SessionManager.getDefaultSessionDir(cwd, undefined, storage);
|
|
3434
3441
|
const manager = new SessionManager(cwd, dir, true, storage);
|
|
3442
|
+
manager.#suppressBreadcrumb = options?.suppressBreadcrumb === true;
|
|
3435
3443
|
const forkEntries = structuredClone(await loadEntriesFromFile(sourcePath, storage)) as FileEntry[];
|
|
3436
3444
|
migrateToCurrentVersion(forkEntries);
|
|
3437
3445
|
await resolveBlobRefsInEntries(forkEntries, manager.#blobStore);
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from "../extensibility/plugins/marketplace";
|
|
22
22
|
import { resolveMemoryBackend } from "../memory-backend";
|
|
23
23
|
import type { InteractiveModeContext } from "../modes/types";
|
|
24
|
+
import type { FreshSessionResult } from "../session/agent-session";
|
|
24
25
|
import { formatShakeSummary, type ShakeMode } from "../session/shake-types";
|
|
25
26
|
import { getChangelogPath, parseChangelog } from "../utils/changelog";
|
|
26
27
|
import { buildContextReportText } from "./helpers/context-report";
|
|
@@ -52,6 +53,11 @@ function refreshStatusLine(ctx: InteractiveModeContext): void {
|
|
|
52
53
|
ctx.ui.requestRender();
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
function formatFreshSessionResult(result: FreshSessionResult): string {
|
|
57
|
+
const stateLabel = result.closedProviderSessions === 1 ? "provider state" : "provider states";
|
|
58
|
+
return `Fresh provider session started (${result.closedProviderSessions} ${stateLabel} pruned).`;
|
|
59
|
+
}
|
|
60
|
+
|
|
55
61
|
const shutdownHandlerTui = (_command: ParsedSlashCommand, runtime: TuiSlashCommandRuntime): SlashCommandResult => {
|
|
56
62
|
runtime.ctx.editor.setText("");
|
|
57
63
|
void runtime.ctx.shutdown();
|
|
@@ -770,6 +776,25 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
770
776
|
await runtime.ctx.handleClearCommand();
|
|
771
777
|
},
|
|
772
778
|
},
|
|
779
|
+
{
|
|
780
|
+
name: "fresh",
|
|
781
|
+
description: "Reset provider stream state without changing the local transcript",
|
|
782
|
+
handle: async (_command, runtime) => {
|
|
783
|
+
const result = runtime.session.freshSession();
|
|
784
|
+
if (!result) {
|
|
785
|
+
await runtime.output(
|
|
786
|
+
"Wait for the current response to finish or abort it before refreshing provider state.",
|
|
787
|
+
);
|
|
788
|
+
return commandConsumed();
|
|
789
|
+
}
|
|
790
|
+
await runtime.output(formatFreshSessionResult(result));
|
|
791
|
+
return commandConsumed();
|
|
792
|
+
},
|
|
793
|
+
handleTui: async (_command, runtime) => {
|
|
794
|
+
runtime.ctx.editor.setText("");
|
|
795
|
+
await runtime.ctx.handleFreshCommand();
|
|
796
|
+
},
|
|
797
|
+
},
|
|
773
798
|
{
|
|
774
799
|
name: "drop",
|
|
775
800
|
description: "Delete the current session and start a new one",
|
|
@@ -868,6 +893,17 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
868
893
|
await runtime.ctx.handleBtwCommand(question);
|
|
869
894
|
},
|
|
870
895
|
},
|
|
896
|
+
{
|
|
897
|
+
name: "tan",
|
|
898
|
+
description: "Run a full background agent on tangential work",
|
|
899
|
+
inlineHint: "<work>",
|
|
900
|
+
allowArgs: true,
|
|
901
|
+
handleTui: async (command, runtime) => {
|
|
902
|
+
const work = command.text.slice(`/${command.name}`.length).trim();
|
|
903
|
+
runtime.ctx.editor.setText("");
|
|
904
|
+
await runtime.ctx.handleTanCommand(work);
|
|
905
|
+
},
|
|
906
|
+
},
|
|
871
907
|
{
|
|
872
908
|
name: "omfg",
|
|
873
909
|
description: "Forge a TTSR rule from a complaint to stop a recurring behavior",
|
|
@@ -890,15 +926,6 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
890
926
|
runtime.ctx.editor.setText("");
|
|
891
927
|
},
|
|
892
928
|
},
|
|
893
|
-
{
|
|
894
|
-
name: "background",
|
|
895
|
-
aliases: ["bg"],
|
|
896
|
-
description: "Detach UI and continue running in background",
|
|
897
|
-
handleTui: (_command, runtime) => {
|
|
898
|
-
runtime.ctx.editor.setText("");
|
|
899
|
-
runtime.handleBackgroundCommand();
|
|
900
|
-
},
|
|
901
|
-
},
|
|
902
929
|
{
|
|
903
930
|
name: "debug",
|
|
904
931
|
description: "Open debug tools selector",
|
|
@@ -934,7 +961,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
934
961
|
allowArgs: true,
|
|
935
962
|
handle: async (command, runtime) => {
|
|
936
963
|
const verb = (command.args.trim().split(/\s+/)[0] ?? "").toLowerCase() || "view";
|
|
937
|
-
const backend = resolveMemoryBackend(runtime.settings);
|
|
964
|
+
const backend = await resolveMemoryBackend(runtime.settings);
|
|
938
965
|
switch (verb) {
|
|
939
966
|
case "view": {
|
|
940
967
|
const payload = await backend.buildDeveloperInstructions(
|
|
@@ -26,6 +26,8 @@ function formatUsageReportAccount(report: UsageReport, limit: UsageLimit, index:
|
|
|
26
26
|
if (typeof email === "string" && email) return email;
|
|
27
27
|
const accountId = report.metadata?.accountId ?? limit.scope.accountId;
|
|
28
28
|
if (typeof accountId === "string" && accountId) return accountId;
|
|
29
|
+
const projectId = report.metadata?.projectId ?? limit.scope.projectId;
|
|
30
|
+
if (typeof projectId === "string" && projectId) return projectId;
|
|
29
31
|
return `account ${index + 1}`;
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -71,15 +71,13 @@ export interface SlashCommandRuntime {
|
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
73
|
* Runtime visible to TUI-only handlers (`handleTui`). Carries the interactive
|
|
74
|
-
* mode context
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* from `ctx`.
|
|
74
|
+
* mode context. Intentionally narrower than `SlashCommandRuntime` so existing
|
|
75
|
+
* callers can keep building it from just `{ ctx }`; when the TUI dispatcher
|
|
76
|
+
* needs to invoke a `handle` (no `handleTui` override), it synthesizes a
|
|
77
|
+
* `SlashCommandRuntime` from `ctx`.
|
|
79
78
|
*/
|
|
80
79
|
export interface TuiSlashCommandRuntime {
|
|
81
80
|
ctx: InteractiveModeContext;
|
|
82
|
-
handleBackgroundCommand: () => void;
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
/** Unified slash-command spec consumed by both TUI and ACP dispatchers. */
|
package/src/task/executor.ts
CHANGED
|
@@ -166,6 +166,13 @@ export interface ExecutorOptions {
|
|
|
166
166
|
outputSchema?: unknown;
|
|
167
167
|
/** Parent task recursion depth (0 = top-level, 1 = first child, etc.) */
|
|
168
168
|
taskDepth?: number;
|
|
169
|
+
/**
|
|
170
|
+
* Override the `task.maxRuntimeMs` wall-clock cap for this run. When provided
|
|
171
|
+
* it wins over the settings value; `0` disables the per-subagent wall-clock
|
|
172
|
+
* limit entirely. Used by the eval `agent()` bridge, whose parent cell
|
|
173
|
+
* watchdog is already suspended for the call's duration.
|
|
174
|
+
*/
|
|
175
|
+
maxRuntimeMs?: number;
|
|
169
176
|
enableLsp?: boolean;
|
|
170
177
|
signal?: AbortSignal;
|
|
171
178
|
onProgress?: (progress: AgentProgress) => void;
|
|
@@ -481,7 +488,7 @@ function getUsageTokens(usage: unknown): number {
|
|
|
481
488
|
/**
|
|
482
489
|
* Create proxy tools that reuse the parent's MCP connections.
|
|
483
490
|
*/
|
|
484
|
-
function createMCPProxyTools(mcpManager: MCPManager): CustomTool[] {
|
|
491
|
+
export function createMCPProxyTools(mcpManager: MCPManager): CustomTool[] {
|
|
485
492
|
return mcpManager.getTools().map(tool => {
|
|
486
493
|
const mcpTool = tool as { mcpToolName?: string; mcpServerName?: string };
|
|
487
494
|
return {
|
|
@@ -531,7 +538,10 @@ function createMCPProxyTools(mcpManager: MCPManager): CustomTool[] {
|
|
|
531
538
|
});
|
|
532
539
|
}
|
|
533
540
|
|
|
534
|
-
function createSubagentSettings(
|
|
541
|
+
export function createSubagentSettings(
|
|
542
|
+
baseSettings: Settings,
|
|
543
|
+
overrides?: Partial<Record<SettingPath, unknown>>,
|
|
544
|
+
): Settings {
|
|
535
545
|
const snapshot: Partial<Record<SettingPath, unknown>> = {};
|
|
536
546
|
for (const key of Object.keys(SETTINGS_SCHEMA) as SettingPath[]) {
|
|
537
547
|
snapshot[key] = baseSettings.get(key);
|
|
@@ -625,7 +635,10 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
625
635
|
agent.readSummarize === false ? { "read.summarize.enabled": false } : undefined,
|
|
626
636
|
);
|
|
627
637
|
const maxRecursionDepth = settings.get("task.maxRecursionDepth") ?? 2;
|
|
628
|
-
const maxRuntimeMs = Math.max(
|
|
638
|
+
const maxRuntimeMs = Math.max(
|
|
639
|
+
0,
|
|
640
|
+
Math.trunc(Number(options.maxRuntimeMs ?? settings.get("task.maxRuntimeMs") ?? 0) || 0),
|
|
641
|
+
);
|
|
629
642
|
const parentDepth = options.taskDepth ?? 0;
|
|
630
643
|
const childDepth = parentDepth + 1;
|
|
631
644
|
const atMaxDepth = maxRecursionDepth >= 0 && childDepth >= maxRecursionDepth;
|
|
@@ -1484,7 +1497,15 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
1484
1497
|
if (lastAssistant.stopReason === "aborted") {
|
|
1485
1498
|
aborted = abortReason === "signal" || runtimeLimitExceeded || abortReason === undefined;
|
|
1486
1499
|
if (aborted) {
|
|
1487
|
-
|
|
1500
|
+
// A real caller signal or the wall-clock timer carries a precise
|
|
1501
|
+
// reason (signal.reason / "runtime limit exceeded"). An internal
|
|
1502
|
+
// turn abort (abortReason === undefined) does NOT — prefer the
|
|
1503
|
+
// assistant message's own errorMessage ("Request was aborted" or a
|
|
1504
|
+
// specific stream error) over the misleading "Cancelled by caller".
|
|
1505
|
+
abortReasonText ??=
|
|
1506
|
+
abortReason === "signal" || runtimeLimitExceeded
|
|
1507
|
+
? resolveAbortReasonText()
|
|
1508
|
+
: lastAssistant.errorMessage?.trim() || resolveAbortReasonText();
|
|
1488
1509
|
}
|
|
1489
1510
|
exitCode = 1;
|
|
1490
1511
|
} else if (lastAssistant.stopReason === "error") {
|
package/src/task/index.ts
CHANGED
|
@@ -275,6 +275,10 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
275
275
|
readonly strict = true;
|
|
276
276
|
readonly loadMode = "discoverable";
|
|
277
277
|
readonly renderResult = renderResult;
|
|
278
|
+
// Suppress the streaming call preview once a (partial or final) result exists
|
|
279
|
+
// so the task renders as ONE block that transitions in place — not a pending
|
|
280
|
+
// call frame stacked above the result frame. Mirrors `taskToolRenderer`.
|
|
281
|
+
readonly mergeCallAndResult = true;
|
|
278
282
|
readonly #discoveredAgents: AgentDefinition[];
|
|
279
283
|
readonly #blockedAgent: string | undefined;
|
|
280
284
|
|