@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
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import * as fs from "node:fs/promises";
|
|
2
|
-
import { isEnoent } from "@oh-my-pi/pi-utils";
|
|
3
|
-
import { resolveLocalUrlToPath } from "../internal-urls";
|
|
4
|
-
import { normalizeLocalScheme } from "../tools/path-utils";
|
|
5
1
|
import { ToolError } from "../tools/tool-errors";
|
|
6
2
|
|
|
7
3
|
/** Shape forwarded from the plan-mode resolve handler to InteractiveMode's
|
|
8
4
|
* approval popup. Populated by the standing handler that the resolve tool
|
|
9
|
-
* dispatches to when the agent submits `resolve { action: "apply" }`.
|
|
5
|
+
* dispatches to when the agent submits `resolve { action: "apply" }`.
|
|
6
|
+
* `planFilePath` is the agent-chosen `local://<slug>-plan.md` artifact — it is
|
|
7
|
+
* never renamed on approval, so links to it stay valid for the session. */
|
|
10
8
|
export interface PlanApprovalDetails {
|
|
11
9
|
planFilePath: string;
|
|
12
|
-
finalPlanFilePath: string;
|
|
13
10
|
title: string;
|
|
14
11
|
planExists: boolean;
|
|
15
12
|
}
|
|
@@ -110,54 +107,80 @@ export function humanizePlanTitle(title: string): string {
|
|
|
110
107
|
return spaced.charAt(0).toUpperCase() + spaced.slice(1);
|
|
111
108
|
}
|
|
112
109
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
110
|
+
/** The `local://` URL a plan slug maps to. The agent writes the plan here and
|
|
111
|
+
* passes the slug to `resolve`; the file is never renamed, so this URL — and
|
|
112
|
+
* any hyperlink to it — stays valid for the life of the session. */
|
|
113
|
+
export function planFileUrlForSlug(slug: string): string {
|
|
114
|
+
return `local://${slug}-plan.md`;
|
|
118
115
|
}
|
|
119
116
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
/** Derive a `<slug>` from an agent-supplied `extra.title`, or `undefined` when
|
|
118
|
+
* the title is missing/non-string/unsanitizable. A trailing `-plan` is stripped
|
|
119
|
+
* so a supplied "auth-plan" maps to `auth-plan.md`, not `auth-plan-plan.md`. */
|
|
120
|
+
function planSlugFromSupplied(suppliedTitle: unknown): string | undefined {
|
|
121
|
+
if (typeof suppliedTitle !== "string" || !suppliedTitle.trim()) return undefined;
|
|
122
|
+
try {
|
|
123
|
+
const { title } = normalizePlanTitle(suppliedTitle);
|
|
124
|
+
const slug = title.replace(/-plan$/i, "");
|
|
125
|
+
return slug || title;
|
|
126
|
+
} catch {
|
|
127
|
+
return undefined;
|
|
123
128
|
}
|
|
124
129
|
}
|
|
125
130
|
|
|
126
|
-
export
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
131
|
+
export interface ResolveApprovedPlanInput {
|
|
132
|
+
/** The agent's `extra.title` from the `resolve` call, if any. */
|
|
133
|
+
suppliedTitle?: unknown;
|
|
134
|
+
/** The plan path recorded in plan-mode state (the entry default or a prior plan). */
|
|
135
|
+
statePlanFilePath: string;
|
|
136
|
+
/** Read a plan `local://` URL, returning null when the file does not exist. */
|
|
137
|
+
readPlan: (planUrl: string) => Promise<string | null>;
|
|
138
|
+
/** Optional fallback: list candidate plan `local://` URLs (newest first) so a
|
|
139
|
+
* plan whose name can't be reconstructed (e.g. a dropped `extra.title`) is
|
|
140
|
+
* still found. */
|
|
141
|
+
listPlanFiles?: () => Promise<string[]>;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface ResolvedApprovedPlan {
|
|
145
|
+
planFilePath: string;
|
|
146
|
+
planContent: string;
|
|
147
|
+
title: string;
|
|
148
|
+
}
|
|
130
149
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
150
|
+
/** Locate the plan file the agent wrote and finalize its title — without
|
|
151
|
+
* renaming anything. Tries, in order: the slug derived from `extra.title`
|
|
152
|
+
* (`local://<slug>-plan.md`), the plan path from plan-mode state, then a scan
|
|
153
|
+
* of recent plan files. Throws a `ToolError` guiding the agent when none exist. */
|
|
154
|
+
export async function resolveApprovedPlan(input: ResolveApprovedPlanInput): Promise<ResolvedApprovedPlan> {
|
|
155
|
+
const ordered: string[] = [];
|
|
156
|
+
const consider = (url: string | undefined): void => {
|
|
157
|
+
if (url && !ordered.includes(url)) ordered.push(url);
|
|
134
158
|
};
|
|
135
|
-
const resolvedSource = resolveLocalUrlToPath(normalizeLocalScheme(planFilePath), resolveOptions);
|
|
136
|
-
const resolvedDestination = resolveLocalUrlToPath(normalizeLocalScheme(finalPlanFilePath), resolveOptions);
|
|
137
159
|
|
|
138
|
-
|
|
139
|
-
|
|
160
|
+
const slug = planSlugFromSupplied(input.suppliedTitle);
|
|
161
|
+
consider(slug ? planFileUrlForSlug(slug) : undefined);
|
|
162
|
+
consider(input.statePlanFilePath);
|
|
163
|
+
|
|
164
|
+
for (const url of ordered) {
|
|
165
|
+
const content = await input.readPlan(url);
|
|
166
|
+
if (content !== null) return finalizeApprovedPlan(url, content, input.suppliedTitle);
|
|
140
167
|
}
|
|
141
168
|
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
throw new Error(`Plan destination exists but is not a file: ${finalPlanFilePath}`);
|
|
150
|
-
} catch (error) {
|
|
151
|
-
if (!isEnoent(error)) {
|
|
152
|
-
throw error;
|
|
169
|
+
if (input.listPlanFiles) {
|
|
170
|
+
for (const url of await input.listPlanFiles()) {
|
|
171
|
+
if (ordered.includes(url)) continue;
|
|
172
|
+
const content = await input.readPlan(url);
|
|
173
|
+
if (content !== null) return finalizeApprovedPlan(url, content, input.suppliedTitle);
|
|
153
174
|
}
|
|
154
175
|
}
|
|
155
176
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
177
|
+
const target = ordered[0] ?? input.statePlanFilePath;
|
|
178
|
+
throw new ToolError(
|
|
179
|
+
`Plan file not found at ${target}. Write the finalized plan to ${target} before requesting approval.`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function finalizeApprovedPlan(planFilePath: string, planContent: string, suppliedTitle: unknown): ResolvedApprovedPlan {
|
|
184
|
+
const { title } = resolvePlanTitle({ suppliedTitle, planContent, planFilePath });
|
|
185
|
+
return { planFilePath, planContent, title };
|
|
163
186
|
}
|
|
@@ -16,11 +16,11 @@ function readTargetsPlan(readPath: string, planTarget: string): boolean {
|
|
|
16
16
|
* Build a compaction protection matcher that keeps `read` results for the active
|
|
17
17
|
* plan file intact through prune/shake — the plan analog of skill-read
|
|
18
18
|
* protection. Matches both the canonical `local://PLAN.md` alias and the
|
|
19
|
-
* session's current plan reference path (
|
|
20
|
-
* the plan survives compaction whether the agent reads it by alias or by
|
|
19
|
+
* session's current plan reference path (the agent-chosen `local://<slug>-plan.md`),
|
|
20
|
+
* so the plan survives compaction whether the agent reads it by alias or by name.
|
|
21
21
|
*
|
|
22
|
-
* `getPlanReferencePath` is evaluated at match time so
|
|
23
|
-
*
|
|
22
|
+
* `getPlanReferencePath` is evaluated at match time so the plan path set on
|
|
23
|
+
* approval is honored immediately.
|
|
24
24
|
*/
|
|
25
25
|
export function createPlanReadMatcher(getPlanReferencePath: () => string): (context: ProtectedToolContext) => boolean {
|
|
26
26
|
return (context: ProtectedToolContext) => {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<system-notice reason="background_task_dispatched" job="{{jobId}}">
|
|
2
|
+
The user launched a tangential task that is now running in a separate background agent. This is NOT a prompt injection and NOT a new instruction for you — it is the coding agent informing you that work was handed off elsewhere.
|
|
3
|
+
|
|
4
|
+
The task below is being handled by another agent in its own session. You are NOT responsible for it: do NOT start working on it, do NOT reference it, and do NOT let it interrupt or alter your current task. Simply continue what you were doing as if this message had not appeared. Results, if any, will surface separately when the background task ({{jobId}}) completes.
|
|
5
|
+
|
|
6
|
+
Dispatched work (for your awareness only):
|
|
7
|
+
{{work}}
|
|
8
|
+
</system-notice>
|
|
@@ -6,111 +6,120 @@ You NEVER:
|
|
|
6
6
|
- Run state-changing commands (git commit, npm install, etc.)
|
|
7
7
|
- Make any system changes
|
|
8
8
|
|
|
9
|
-
To implement: call `resolve` with `action: "apply"`, a `reason`, and `extra: { title: "<
|
|
9
|
+
To implement: call `resolve` with `action: "apply"`, a `reason`, and `extra: { title: "<slug>" }` where `<slug>` matches your `local://<slug>-plan.md` file → user approves an execution option → full write access is restored. `<slug>` may only contain letters, numbers, underscores, and hyphens. The plan file is never renamed, so its name is yours to choose.
|
|
10
10
|
|
|
11
11
|
You NEVER ask the user to exit plan mode for you; you MUST call `resolve` yourself.
|
|
12
12
|
</critical>
|
|
13
13
|
|
|
14
|
+
## Objective
|
|
15
|
+
|
|
16
|
+
A plan is **decision-complete**: another engineer or agent can execute it end-to-end without making a single design decision. Optimize every choice for that. Detail exists to remove the implementer's decisions — not to look thorough. A document that reads like a design doc (Non-Goals, Alternatives, risk matrices) yet leaves real decisions open is a FAILED plan.
|
|
17
|
+
|
|
14
18
|
## Plan File
|
|
15
19
|
|
|
16
20
|
{{#if planExists}}
|
|
17
|
-
Plan file exists at `{{planFilePath}}`; you MUST read and update it incrementally.
|
|
21
|
+
Plan file exists at `{{planFilePath}}`; you MUST read and update it incrementally. If this request is a different task, write a fresh `local://<slug>-plan.md` instead and leave the old plan in place.
|
|
18
22
|
{{else}}
|
|
19
|
-
You MUST
|
|
23
|
+
Choose a short kebab-case `<slug>` that names this task (letters, numbers, hyphens) and write the plan to `local://<slug>-plan.md` — e.g. `local://auth-token-refresh-plan.md`. You MUST pass that same `<slug>` as `title` when you call `resolve`.
|
|
20
24
|
{{/if}}
|
|
21
25
|
|
|
22
|
-
You MUST use `{{editToolName}}` for incremental updates; use `{{writeToolName}}` only for create/full replace.
|
|
26
|
+
You MUST use `{{editToolName}}` for incremental updates; use `{{writeToolName}}` only for create/full replace. You MUST update the plan as you learn — you NEVER batch all writing to the end.
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
The approval selector includes:
|
|
26
|
-
- **Approve and execute**: starts execution in fresh context (session cleared).
|
|
27
|
-
- **Approve and compact context**: distills the plan-mode discussion into a summary, then starts execution in this session.
|
|
28
|
-
- **Approve and keep context**: starts execution in this session, preserving exploration history.
|
|
28
|
+
## Resolving Unknowns
|
|
29
29
|
|
|
30
|
-
You MUST
|
|
31
|
-
|
|
30
|
+
You MUST eliminate unknowns by discovering facts, not by asking. Before asking the user anything, perform at least one targeted exploration pass.
|
|
31
|
+
|
|
32
|
+
Two kinds of unknowns, treated differently:
|
|
33
|
+
- **Discoverable facts** — repo/system truth: file locations, current behavior, existing patterns, types, configs. You MUST explore first (`find`, `search`, `read`, parallel explore subagents). You NEVER ask what the codebase can answer (e.g. "where is this defined?"). Ask only when several plausible candidates remain or a required identifier is genuinely absent — and then present the candidates with a recommendation.
|
|
34
|
+
- **Preferences and tradeoffs** — intent, UX, scope boundaries, performance-vs-simplicity: not derivable from code. You MUST surface these early via `{{askToolName}}` with 2–4 mutually exclusive options and a recommended default. If left unanswered, proceed with the default and record it under Assumptions.
|
|
35
|
+
|
|
36
|
+
Every question MUST materially change the plan, confirm a load-bearing assumption, or choose between real tradeoffs. You MUST batch questions. You NEVER ask filler questions or offer obviously-wrong options.
|
|
32
37
|
|
|
33
38
|
{{#if reentry}}
|
|
34
39
|
## Re-entry
|
|
35
40
|
|
|
36
41
|
<procedure>
|
|
37
|
-
1. Read existing plan
|
|
38
|
-
2. Evaluate request against it
|
|
42
|
+
1. Read the existing plan.
|
|
43
|
+
2. Evaluate the new request against it.
|
|
39
44
|
3. Decide:
|
|
40
|
-
- **Different task** →
|
|
41
|
-
- **Same task, continuing** →
|
|
42
|
-
4. Call `resolve` with `action: "apply"` and `extra: { title }` when complete
|
|
45
|
+
- **Different task** → overwrite the plan.
|
|
46
|
+
- **Same task, continuing** → update and delete outdated sections.
|
|
47
|
+
4. Call `resolve` with `action: "apply"` and `extra: { title }` when complete.
|
|
43
48
|
</procedure>
|
|
44
49
|
{{/if}}
|
|
45
50
|
|
|
46
51
|
{{#if iterative}}
|
|
47
|
-
## Iterative
|
|
52
|
+
## Workflow — Iterative
|
|
48
53
|
|
|
49
54
|
<procedure>
|
|
50
55
|
### 1. Explore
|
|
51
|
-
You MUST use `find`, `search`, `read` to
|
|
56
|
+
You MUST use `find`, `search`, `read` to ground yourself in the actual code. Hunt for existing functions, utilities, and conventions to reuse before proposing anything new.
|
|
52
57
|
|
|
53
58
|
### 2. Interview
|
|
54
|
-
You MUST use `{{askToolName}}` to
|
|
55
|
-
- Ambiguous requirements
|
|
56
|
-
- Technical decisions and tradeoffs
|
|
57
|
-
- Preferences: UI/UX, performance, edge cases
|
|
59
|
+
You MUST use `{{askToolName}}` to resolve preferences and tradeoffs (see Resolving Unknowns). Batch questions; never ask what exploration answers.
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
### 3. Update Incrementally
|
|
62
|
-
You MUST use `{{editToolName}}` to update plan file as you learn; NEVER wait until end.
|
|
61
|
+
### 3. Update incrementally
|
|
62
|
+
You MUST use `{{editToolName}}` to revise the plan file as you learn.
|
|
63
63
|
|
|
64
64
|
### 4. Calibrate
|
|
65
|
-
- Large unspecified task → multiple interview rounds
|
|
66
|
-
-
|
|
65
|
+
- Large, unspecified task → multiple interview rounds.
|
|
66
|
+
- Small, well-specified task → few or no questions.
|
|
67
67
|
</procedure>
|
|
68
|
-
|
|
69
|
-
<caution>
|
|
70
|
-
### Plan Structure
|
|
71
|
-
|
|
72
|
-
You MUST use clear markdown headers; include:
|
|
73
|
-
- Recommended approach (not alternatives)
|
|
74
|
-
- Paths of critical files to modify
|
|
75
|
-
- Verification: how to test end-to-end
|
|
76
|
-
|
|
77
|
-
The plan MUST be scannable yet detailed enough to execute.
|
|
78
|
-
</caution>
|
|
79
|
-
|
|
80
68
|
{{else}}
|
|
81
|
-
##
|
|
69
|
+
## Workflow — Parallel
|
|
82
70
|
|
|
83
71
|
<procedure>
|
|
84
|
-
### Phase 1
|
|
85
|
-
You MUST focus on the request and
|
|
72
|
+
### Phase 1 — Understand
|
|
73
|
+
You MUST focus on the request and the code behind it. You SHOULD launch parallel `explore` subagents (via `task`) when scope spans multiple areas — give each a distinct focus (existing implementations, related components, test patterns). Actively hunt for reusable functions, utilities, and conventions; avoid proposing new code when a suitable implementation already exists.
|
|
86
74
|
|
|
87
|
-
### Phase 2
|
|
88
|
-
You MUST draft an approach
|
|
75
|
+
### Phase 2 — Design
|
|
76
|
+
You MUST draft an approach from your exploration, weigh trade-offs briefly, then commit to one. For large or cross-cutting changes you MAY spawn a planning/critique subagent to pressure-test the approach before you commit.
|
|
89
77
|
|
|
90
|
-
### Phase 3
|
|
91
|
-
You MUST read critical files. You MUST verify plan matches original request. You SHOULD use `{{askToolName}}` to
|
|
78
|
+
### Phase 3 — Review
|
|
79
|
+
You MUST read the critical files you intend to touch to confirm the approach holds against the real code. You MUST verify the plan still matches the original request. You SHOULD use `{{askToolName}}` to close remaining preference questions.
|
|
92
80
|
|
|
93
|
-
### Phase 4
|
|
94
|
-
You MUST
|
|
95
|
-
- Recommended approach only
|
|
96
|
-
- Paths of critical files to modify
|
|
97
|
-
- Verification section
|
|
81
|
+
### Phase 4 — Write the plan
|
|
82
|
+
You MUST write the plan file (see **Plan File** above) per **The Plan** below.
|
|
98
83
|
</procedure>
|
|
84
|
+
{{/if}}
|
|
85
|
+
|
|
86
|
+
## The Plan
|
|
87
|
+
|
|
88
|
+
The plan MUST be self-contained: approval may clear or compact this conversation, so the file alone must carry everything needed to execute.
|
|
99
89
|
|
|
100
90
|
<caution>
|
|
101
|
-
|
|
91
|
+
Write 3–5 short, scannable markdown sections. The usual shape:
|
|
92
|
+
- **Context** — why this change: the problem or need, what prompted it, the intended outcome. 2–4 sentences.
|
|
93
|
+
- **Approach** — the recommended approach only. Group bullets by subsystem or behavior, NOT file-by-file. Name existing functions/utilities to reuse, with their paths. Describe a repeated pattern once with a few representative paths — you NEVER enumerate every file or line.
|
|
94
|
+
- **Critical files** — the ≤5 files that disambiguate non-obvious changes, each with a one-line reason. Skip files whose change is already obvious from the Approach.
|
|
95
|
+
- **Verification** — how to test end-to-end: exact commands, tests to run or add, manual steps.
|
|
96
|
+
- **Assumptions** — only the decisions you made that the user might want to override.
|
|
97
|
+
|
|
98
|
+
Prefer the minimum detail needed for safe implementation, not exhaustive coverage. Compress related changes into high-signal bullets; omit branch-by-branch logic, restated invariants, and lists of unaffected behavior. Behavior-level descriptions beat symbol-by-symbol removal lists.
|
|
102
99
|
</caution>
|
|
103
|
-
{{/if}}
|
|
104
100
|
|
|
105
101
|
<directives>
|
|
106
|
-
- You
|
|
102
|
+
- You NEVER include sections that decide nothing: Non-Goals, Out of Scope, Alternatives Considered, Risks/Mitigations boilerplate, Future Work. Omit them entirely.
|
|
103
|
+
- You NEVER invent schema, validation, precedence, or fallback policy the request did not establish, unless it is required to prevent a concrete implementation mistake.
|
|
104
|
+
- You NEVER present alternatives in the final plan — choose. Record a discarded option only when it is a live tradeoff the user should confirm, and put it under Assumptions.
|
|
107
105
|
</directives>
|
|
108
106
|
|
|
107
|
+
<caution>
|
|
108
|
+
The approval selector offers:
|
|
109
|
+
- **Approve and execute** — execution starts in fresh context (session cleared).
|
|
110
|
+
- **Approve and compact context** — distills this discussion into a summary, then executes in this session.
|
|
111
|
+
- **Approve and keep context** — executes in this session, preserving exploration history.
|
|
112
|
+
|
|
113
|
+
All three rely on the plan file being self-contained.
|
|
114
|
+
</caution>
|
|
115
|
+
|
|
109
116
|
<critical>
|
|
117
|
+
You MUST use `{{askToolName}}` only to clarify requirements or choose between approaches.
|
|
118
|
+
|
|
110
119
|
Your turn ends ONLY by:
|
|
111
120
|
1. Using `{{askToolName}}` to gather information, OR
|
|
112
|
-
2. Calling `resolve` with `action: "apply"`, `reason`, and `extra: { title: "<
|
|
121
|
+
2. Calling `resolve` with `action: "apply"`, `reason`, and `extra: { title: "<slug>" }` (the slug of your `local://<slug>-plan.md`) when ready — this triggers user approval, then implementation with full tool access.
|
|
113
122
|
|
|
114
|
-
You NEVER ask plan approval via text or `{{askToolName}}`; you MUST use `resolve`.
|
|
115
|
-
You MUST keep going until complete.
|
|
123
|
+
You NEVER ask for plan approval via text or `{{askToolName}}`; you MUST use `resolve`.
|
|
124
|
+
You MUST keep going until the plan is decision-complete.
|
|
116
125
|
</critical>
|
package/src/sdk.ts
CHANGED
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
} from "@oh-my-pi/pi-agent-core";
|
|
11
11
|
import {
|
|
12
12
|
type CredentialDisabledEvent,
|
|
13
|
-
isUsageLimitError,
|
|
14
13
|
type Message,
|
|
15
14
|
type Model,
|
|
16
15
|
type SimpleStreamOptions,
|
|
@@ -24,7 +23,6 @@ import type { Component } from "@oh-my-pi/pi-tui";
|
|
|
24
23
|
import {
|
|
25
24
|
$env,
|
|
26
25
|
$flag,
|
|
27
|
-
extractRetryHint,
|
|
28
26
|
getAgentDbPath,
|
|
29
27
|
getAgentDir,
|
|
30
28
|
getAuthBrokerSnapshotCachePath,
|
|
@@ -36,10 +34,10 @@ import {
|
|
|
36
34
|
} from "@oh-my-pi/pi-utils";
|
|
37
35
|
import chalk from "chalk";
|
|
38
36
|
import { type AsyncJob, AsyncJobManager, isBackgroundJobSupportEnabled } from "./async";
|
|
39
|
-
import { createAutoresearchExtension } from "./autoresearch";
|
|
40
37
|
import { loadCapability } from "./capability";
|
|
41
38
|
import { type Rule, ruleCapability, setActiveRules } from "./capability/rule";
|
|
42
39
|
import { bucketRules } from "./capability/rule-buckets";
|
|
40
|
+
import { createApiKeyResolver } from "./config/api-key-resolver";
|
|
43
41
|
import { shouldEnableAppendOnlyContext } from "./config/append-only-context-mode";
|
|
44
42
|
import { ModelRegistry } from "./config/model-registry";
|
|
45
43
|
import {
|
|
@@ -57,7 +55,6 @@ import { resolveConfigValue } from "./config/resolve-config-value";
|
|
|
57
55
|
import { initializeWithSettings } from "./discovery";
|
|
58
56
|
import { disposeAllKernelSessions, disposeKernelSessionsByOwner } from "./eval/py/executor";
|
|
59
57
|
import { defaultEvalSessionId } from "./eval/session-id";
|
|
60
|
-
import { TtsrManager } from "./export/ttsr";
|
|
61
58
|
import {
|
|
62
59
|
type CustomCommandsLoadResult,
|
|
63
60
|
type LoadedCustomCommand,
|
|
@@ -90,7 +87,7 @@ import { LocalProtocolHandler, type LocalProtocolOptions } from "./internal-urls
|
|
|
90
87
|
import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "./lsp/startup-events";
|
|
91
88
|
import { discoverAndLoadMCPTools, MCPManager, type MCPToolsLoadResult } from "./mcp";
|
|
92
89
|
import { resolveMemoryBackend } from "./memory-backend";
|
|
93
|
-
import {
|
|
90
|
+
import type { MnemopiSessionState } from "./mnemopi/state";
|
|
94
91
|
import asyncResultTemplate from "./prompts/tools/async-result.md" with { type: "text" };
|
|
95
92
|
import { AgentRegistry, MAIN_AGENT_ID } from "./registry/agent-registry";
|
|
96
93
|
import {
|
|
@@ -282,6 +279,8 @@ export interface CreateAgentSessionOptions {
|
|
|
282
279
|
/** Optional provider-facing session identifier for prompt caches and sticky auth selection.
|
|
283
280
|
* Keeps persisted session files isolated while reusing provider-side caches. */
|
|
284
281
|
providerSessionId?: string;
|
|
282
|
+
/** Optional provider-facing prompt cache key, distinct from request lineage. */
|
|
283
|
+
providerPromptCacheKey?: string;
|
|
285
284
|
|
|
286
285
|
/** Custom tools to register (in addition to built-in tools). Accepts both CustomTool and ToolDefinition. */
|
|
287
286
|
customTools?: (CustomTool | ToolDefinition)[];
|
|
@@ -1150,6 +1149,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1150
1149
|
|
|
1151
1150
|
// Discover rules and bucket them in one pass to avoid repeated scans over large rule sets.
|
|
1152
1151
|
const { ttsrManager, rulebookRules, alwaysApplyRules } = await logger.time("discoverTtsrRules", async () => {
|
|
1152
|
+
const { TtsrManager } = await import("./export/ttsr");
|
|
1153
1153
|
const ttsrSettings = settings.getGroup("ttsr");
|
|
1154
1154
|
const ttsrManager = new TtsrManager(ttsrSettings);
|
|
1155
1155
|
const rulesResult =
|
|
@@ -1295,7 +1295,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1295
1295
|
session ? session.trackEvalExecution(execution, abortController) : execution,
|
|
1296
1296
|
getSessionId: () => sessionManager.getSessionId?.() ?? null,
|
|
1297
1297
|
getHindsightSessionState: () => session?.getHindsightSessionState(),
|
|
1298
|
-
getMnemopiSessionState: () => getMnemopiSessionState(
|
|
1298
|
+
getMnemopiSessionState: () => session?.getMnemopiSessionState(),
|
|
1299
1299
|
getAgentId: () => resolvedAgentId,
|
|
1300
1300
|
getToolByName: name => session?.getToolByName(name),
|
|
1301
1301
|
agentRegistry,
|
|
@@ -1472,7 +1472,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1472
1472
|
}
|
|
1473
1473
|
|
|
1474
1474
|
const inlineExtensions: ExtensionFactory[] = options.extensions ? [...options.extensions] : [];
|
|
1475
|
-
inlineExtensions.push(createAutoresearchExtension);
|
|
1475
|
+
inlineExtensions.push((await import("./autoresearch")).createAutoresearchExtension);
|
|
1476
1476
|
if (customTools.length > 0) {
|
|
1477
1477
|
inlineExtensions.push(createCustomToolsExtension(customTools));
|
|
1478
1478
|
}
|
|
@@ -1607,9 +1607,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1607
1607
|
// `ExtensionToolWrapper` installed below is the only place the per-tool approval gate runs.
|
|
1608
1608
|
// A conditional runner means the approval system silently disappears for users with no
|
|
1609
1609
|
// extensions, contradicting non-yolo `tools.approvalMode` settings without feedback.
|
|
1610
|
-
// (
|
|
1611
|
-
// is unreachable;
|
|
1612
|
-
//
|
|
1610
|
+
// (The builtin autoresearch extension is unconditionally loaded above, so this scenario
|
|
1611
|
+
// is unreachable; unconditional runner construction keeps that invariant explicit and
|
|
1612
|
+
// prevents future optional extensions from silently re-opening the hole.)
|
|
1613
1613
|
const extensionRunner: ExtensionRunner = new ExtensionRunner(
|
|
1614
1614
|
extensionsResult.extensions,
|
|
1615
1615
|
extensionsResult.runtime,
|
|
@@ -1723,7 +1723,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1723
1723
|
|
|
1724
1724
|
const repeatToolDescriptions = settings.get("repeatToolDescriptions");
|
|
1725
1725
|
const eagerTasks = settings.get("task.eager");
|
|
1726
|
-
const intentField = settings.get("tools.intentTracing")
|
|
1726
|
+
const intentField = $flag("PI_INTENT_TRACING", settings.get("tools.intentTracing")) ? INTENT_FIELD : undefined;
|
|
1727
1727
|
const rebuildSystemPrompt = async (
|
|
1728
1728
|
toolNames: string[],
|
|
1729
1729
|
tools: Map<string, AgentTool>,
|
|
@@ -1749,7 +1749,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1749
1749
|
const promptTools = buildSystemPromptToolMetadata(tools, {
|
|
1750
1750
|
search_tool_bm25: { description: renderSearchToolBm25Description(discoverableToolsForDesc) },
|
|
1751
1751
|
});
|
|
1752
|
-
const memoryBackend = resolveMemoryBackend(settings);
|
|
1752
|
+
const memoryBackend = await resolveMemoryBackend(settings);
|
|
1753
1753
|
const memoryInstructions = await memoryBackend.buildDeveloperInstructions(agentDir, settings, session);
|
|
1754
1754
|
|
|
1755
1755
|
// Build combined append prompt: memory instructions + MCP server instructions
|
|
@@ -2002,6 +2002,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2002
2002
|
onPayload,
|
|
2003
2003
|
onResponse,
|
|
2004
2004
|
sessionId: providerSessionId,
|
|
2005
|
+
promptCacheKey: options.providerPromptCacheKey,
|
|
2005
2006
|
transformContext,
|
|
2006
2007
|
steeringMode: settings.get("steeringMode") ?? "one-at-a-time",
|
|
2007
2008
|
followUpMode: settings.get("followUpMode") ?? "one-at-a-time",
|
|
@@ -2018,9 +2019,15 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2018
2019
|
kimiApiFormat: settings.get("providers.kimiApiFormat") ?? "anthropic",
|
|
2019
2020
|
preferWebsockets: preferOpenAICodexWebsockets,
|
|
2020
2021
|
getToolContext: tc => toolContextStore.getContext(tc),
|
|
2021
|
-
getApiKey: async provider => {
|
|
2022
|
+
getApiKey: async (provider, ctx) => {
|
|
2022
2023
|
// Read agent.sessionId at call time so credential selection stays aligned
|
|
2023
2024
|
// with metadataResolver after /new, fork, resume, or branch switches.
|
|
2025
|
+
// Retry steps (ctx carries an auth error) drive the central a/b/c
|
|
2026
|
+
// policy — force-refresh the same account, then rotate to a sibling —
|
|
2027
|
+
// and may legitimately yield no key when every account is exhausted.
|
|
2028
|
+
if (ctx?.error !== undefined) {
|
|
2029
|
+
return createApiKeyResolver(modelRegistry, provider, { sessionId: agent.sessionId })(ctx);
|
|
2030
|
+
}
|
|
2024
2031
|
const key = await modelRegistry.getApiKeyForProvider(provider, agent.sessionId);
|
|
2025
2032
|
if (!key) {
|
|
2026
2033
|
throw new Error(`No API key found for provider "${provider}"`);
|
|
@@ -2034,40 +2041,6 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2034
2041
|
return streamSimple(streamModel, context, {
|
|
2035
2042
|
...streamOptions,
|
|
2036
2043
|
openrouterVariant: streamOptions?.openrouterVariant ?? openrouterVariant,
|
|
2037
|
-
onAuthError: async (provider, oldKey, error) => {
|
|
2038
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2039
|
-
// streamSimple invokes this for both 401 auth failures AND
|
|
2040
|
-
// rotatable usage-limit errors (Codex usage_limit_reached,
|
|
2041
|
-
// Anthropic usage_limit_reached, etc.). The two need
|
|
2042
|
-
// different storage actions: a real 401 means the credential
|
|
2043
|
-
// is bad and should be marked suspect; a usage limit just
|
|
2044
|
-
// means this account is parked until reset and should be
|
|
2045
|
-
// temporarily blocked so a sibling can pick the request up.
|
|
2046
|
-
if (isUsageLimitError(message)) {
|
|
2047
|
-
const retryAfterMs = extractRetryHint(undefined, message);
|
|
2048
|
-
const switched = await modelRegistry.authStorage.markUsageLimitReached(provider, agent.sessionId, {
|
|
2049
|
-
retryAfterMs,
|
|
2050
|
-
signal: streamOptions?.signal,
|
|
2051
|
-
});
|
|
2052
|
-
logger.debug("Retrying provider request after usage-limit block", {
|
|
2053
|
-
provider,
|
|
2054
|
-
switched,
|
|
2055
|
-
retryAfterMs,
|
|
2056
|
-
error: message,
|
|
2057
|
-
});
|
|
2058
|
-
if (!switched) return undefined;
|
|
2059
|
-
return modelRegistry.getApiKeyForProvider(provider, agent.sessionId);
|
|
2060
|
-
}
|
|
2061
|
-
await modelRegistry.authStorage.invalidateCredentialMatching(provider, oldKey, {
|
|
2062
|
-
signal: streamOptions?.signal,
|
|
2063
|
-
sessionId: agent.sessionId,
|
|
2064
|
-
});
|
|
2065
|
-
logger.debug("Retrying provider request after credential invalidation", {
|
|
2066
|
-
provider,
|
|
2067
|
-
error: message,
|
|
2068
|
-
});
|
|
2069
|
-
return modelRegistry.getApiKeyForProvider(provider, agent.sessionId);
|
|
2070
|
-
},
|
|
2071
2044
|
});
|
|
2072
2045
|
},
|
|
2073
2046
|
cursorExecHandlers,
|
|
@@ -2267,19 +2240,18 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2267
2240
|
}
|
|
2268
2241
|
}
|
|
2269
2242
|
|
|
2270
|
-
logger.time("startMemoryStartupTask", () =>
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
);
|
|
2243
|
+
logger.time("startMemoryStartupTask", async () => {
|
|
2244
|
+
const memoryBackend = await resolveMemoryBackend(settings);
|
|
2245
|
+
await memoryBackend.start({
|
|
2246
|
+
session,
|
|
2247
|
+
settings,
|
|
2248
|
+
modelRegistry,
|
|
2249
|
+
agentDir,
|
|
2250
|
+
taskDepth,
|
|
2251
|
+
parentHindsightSessionState: options.parentHindsightSessionState,
|
|
2252
|
+
parentMnemopiSessionState: options.parentMnemopiSessionState,
|
|
2253
|
+
});
|
|
2254
|
+
});
|
|
2283
2255
|
|
|
2284
2256
|
// Wire MCP manager callbacks to session for reactive tool updates.
|
|
2285
2257
|
// Skip when reusing a parent's manager — the parent owns the callbacks.
|