@oh-my-pi/pi-coding-agent 17.3.3 → 17.3.5
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 +81 -0
- package/dist/{CHANGELOG-s5t1xdmy.md → CHANGELOG-tt9k4jpr.md} +81 -0
- package/dist/cli.js +3724 -3705
- package/dist/docs-index.generated.txt +1 -1
- package/dist/types/config/model-discovery.d.ts +2 -0
- package/dist/types/config/model-registry.d.ts +6 -1
- package/dist/types/config/settings-schema.d.ts +10 -0
- package/dist/types/debug/report-bundle.d.ts +7 -2
- package/dist/types/extensibility/extensions/loader.d.ts +2 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -3
- package/dist/types/extensibility/extensions/types.d.ts +2 -0
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +4 -0
- package/dist/types/launch/presence.d.ts +11 -0
- package/dist/types/lsp/client.d.ts +22 -0
- package/dist/types/lsp/workspace-diagnostics.d.ts +2 -0
- package/dist/types/markit/converters/pdf/index.d.ts +2 -1
- package/dist/types/mcp/config.d.ts +3 -1
- package/dist/types/modes/components/tool-execution.d.ts +3 -1
- package/dist/types/registry/agent-lifecycle.d.ts +11 -0
- package/dist/types/registry/agent-registry.d.ts +4 -0
- package/dist/types/session/agent-session-types.d.ts +0 -2
- package/dist/types/session/agent-session.d.ts +20 -0
- package/dist/types/session/date-cwd-reminder.d.ts +22 -0
- package/dist/types/session/irc-bridge.d.ts +2 -0
- package/dist/types/session/messages.d.ts +4 -0
- package/dist/types/session/session-loader.d.ts +18 -11
- package/dist/types/session/session-maintenance.d.ts +6 -2
- package/dist/types/session/session-manager.d.ts +19 -3
- package/dist/types/session/session-tools.d.ts +0 -1
- package/dist/types/session/turn-recovery.d.ts +7 -7
- package/dist/types/tools/browser/attach.d.ts +16 -0
- package/dist/types/tools/browser/launch.d.ts +2 -2
- package/dist/types/tools/browser.d.ts +1 -1
- package/dist/types/tools/builtin-names.d.ts +1 -1
- package/dist/types/tools/hub/jobs.d.ts +6 -0
- package/dist/types/tools/hub/types.d.ts +6 -0
- package/dist/types/tools/read-pdf.d.ts +15 -0
- package/dist/types/utils/external-editor.d.ts +7 -0
- package/dist/types/utils/markit.d.ts +3 -4
- package/dist/types/vibe/runtime.d.ts +3 -3
- package/package.json +13 -16
- package/scripts/build-binary.ts +0 -2
- package/scripts/bundle-dist.ts +0 -1
- package/src/auto-thinking/classifier.ts +37 -23
- package/src/cli/models-cli.ts +1 -1
- package/src/cli/read-cli.ts +2 -0
- package/src/commit/analysis/conventional.ts +15 -9
- package/src/commit/analysis/summary.ts +15 -9
- package/src/commit/changelog/generate.ts +15 -9
- package/src/commit/map-reduce/map-phase.ts +3 -19
- package/src/commit/map-reduce/reduce-phase.ts +15 -9
- package/src/config/model-discovery.ts +3 -3
- package/src/config/model-registry.ts +29 -16
- package/src/config/settings-schema.ts +13 -0
- package/src/debug/report-bundle.ts +25 -59
- package/src/discovery/claude-plugins.ts +2 -1
- package/src/discovery/claude.ts +4 -2
- package/src/discovery/helpers.ts +5 -0
- package/src/edit/renderer.ts +48 -19
- package/src/extensibility/extensions/loader.ts +9 -5
- package/src/extensibility/extensions/runner.ts +124 -21
- package/src/extensibility/extensions/types.ts +2 -0
- package/src/extensibility/extensions/wrapper.ts +16 -10
- package/src/extensibility/legacy-pi-ai-shim.ts +4 -0
- package/src/extensibility/plugins/marketplace/manager.ts +15 -18
- package/src/irc/bus.ts +1 -1
- package/src/launch/broker.ts +8 -1
- package/src/launch/presence.ts +77 -1
- package/src/lsp/client.ts +35 -3
- package/src/lsp/clients/biome-client.ts +47 -93
- package/src/lsp/servers.ts +17 -11
- package/src/lsp/tool.ts +2 -4
- package/src/lsp/workspace-diagnostics.ts +24 -2
- package/src/markit/NOTICE +8 -8
- package/src/markit/converters/pdf/index.ts +14 -126
- package/src/mcp/client.ts +8 -9
- package/src/mcp/config.ts +50 -6
- package/src/memories/index.ts +29 -25
- package/src/mnemopi/backend.ts +13 -11
- package/src/modes/components/ask-dialog.ts +25 -5
- package/src/modes/components/tool-execution.ts +10 -6
- package/src/modes/components/welcome.ts +4 -1
- package/src/modes/controllers/extension-ui-controller.ts +52 -32
- package/src/modes/controllers/selector-controller.ts +6 -0
- package/src/modes/controllers/tan-command-controller.ts +1 -0
- package/src/modes/interactive-mode.ts +49 -10
- package/src/modes/rpc/rpc-client.ts +7 -0
- package/src/modes/theme/defaults/birch.json +2 -2
- package/src/modes/utils/hotkeys-markdown.ts +1 -1
- package/src/prompts/system/checkpoint-active-notice.md +5 -0
- package/src/prompts/system/date-cwd-reminder.md +3 -0
- package/src/prompts/system/project-prompt.md +0 -1
- package/src/prompts/system/rewind-report.md +1 -3
- package/src/prompts/tools/browser.md +1 -0
- package/src/prompts/tools/rewind.md +1 -13
- package/src/registry/agent-lifecycle.ts +34 -0
- package/src/registry/agent-registry.ts +27 -2
- package/src/registry/persisted-agents.ts +40 -20
- package/src/sdk.ts +32 -2
- package/src/session/agent-session-types.ts +0 -2
- package/src/session/agent-session.ts +178 -46
- package/src/session/date-cwd-reminder.ts +77 -0
- package/src/session/irc-bridge.ts +5 -0
- package/src/session/messages.ts +5 -1
- package/src/session/session-loader.ts +106 -64
- package/src/session/session-maintenance.ts +189 -115
- package/src/session/session-manager.ts +142 -35
- package/src/session/session-persistence.ts +4 -4
- package/src/session/session-storage.ts +18 -5
- package/src/session/session-tools.ts +5 -10
- package/src/session/turn-recovery.ts +102 -20
- package/src/session/unexpected-stop-classifier.ts +33 -21
- package/src/system-prompt.ts +0 -5
- package/src/task/executor.ts +4 -15
- package/src/task/persisted-revive.ts +3 -6
- package/src/tools/ask.ts +10 -3
- package/src/tools/browser/attach.ts +80 -25
- package/src/tools/browser/launch.ts +44 -15
- package/src/tools/browser/relay/daemon.ts +3 -7
- package/src/tools/browser/render.ts +1 -1
- package/src/tools/browser/shared-daemon.ts +3 -7
- package/src/tools/browser.ts +5 -5
- package/src/tools/builtin-names.ts +7 -3
- package/src/tools/checkpoint.ts +1 -7
- package/src/tools/hub/index.ts +1 -1
- package/src/tools/hub/jobs.ts +20 -3
- package/src/tools/hub/types.ts +6 -0
- package/src/tools/read-pdf.ts +135 -0
- package/src/tools/read.ts +63 -37
- package/src/tools/render-utils.ts +53 -21
- package/src/tools/think.ts +15 -3
- package/src/tts/speech-enhancer.ts +19 -14
- package/src/utils/commit-message-generator.ts +14 -12
- package/src/utils/external-editor.ts +24 -5
- package/src/utils/markit.ts +6 -44
- package/src/utils/title-generator.ts +23 -19
- package/src/vibe/runtime.ts +32 -17
- package/dist/types/markit/converters/pdf/columns.d.ts +0 -35
- package/dist/types/markit/converters/pdf/extract.d.ts +0 -10
- package/dist/types/markit/converters/pdf/grid.d.ts +0 -25
- package/dist/types/markit/converters/pdf/headers.d.ts +0 -24
- package/dist/types/markit/converters/pdf/render.d.ts +0 -24
- package/dist/types/markit/converters/pdf/types.d.ts +0 -75
- package/dist/types/tools/read-pdf-images.d.ts +0 -12
- package/dist/types/utils/mupdf-wasm-embed.d.ts +0 -1
- package/scripts/embed-mupdf-wasm.ts +0 -67
- package/src/markit/converters/pdf/columns.ts +0 -103
- package/src/markit/converters/pdf/extract.ts +0 -598
- package/src/markit/converters/pdf/grid.ts +0 -780
- package/src/markit/converters/pdf/headers.ts +0 -106
- package/src/markit/converters/pdf/render.ts +0 -501
- package/src/markit/converters/pdf/types.ts +0 -84
- package/src/tools/read-pdf-images.ts +0 -250
- package/src/utils/mupdf-wasm-embed.ts +0 -12
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ToolSession } from "../sdk.js";
|
|
2
|
+
import type { ScreenshotResult } from "./browser/tab-protocol.js";
|
|
3
|
+
/** A legacy PDF image-member path interpreted as a page screenshot request. */
|
|
4
|
+
export interface PdfImageReadTarget {
|
|
5
|
+
/** PDF path before the member delimiter. */
|
|
6
|
+
pdfPath: string;
|
|
7
|
+
/** Original member text after the delimiter. */
|
|
8
|
+
member: string;
|
|
9
|
+
/** One-indexed page inferred from names such as `p2-img0.png`; defaults to page 1. */
|
|
10
|
+
page: number;
|
|
11
|
+
}
|
|
12
|
+
/** Parse a former PDF image-member path as a Chromium page screenshot request. */
|
|
13
|
+
export declare function splitPdfImageReadPath(readPath: string): PdfImageReadTarget | null;
|
|
14
|
+
/** Render one PDF page through the browser tool's shared headless Chromium. */
|
|
15
|
+
export declare function renderPdfPageScreenshot(session: ToolSession, absolutePdfPath: string, page: number, signal?: AbortSignal): Promise<ScreenshotResult>;
|
|
@@ -18,6 +18,13 @@ export interface OpenInEditorOptions {
|
|
|
18
18
|
/** Keep the file's trailing newline instead of trimming it from the returned text. */
|
|
19
19
|
trimTrailingNewline?: boolean;
|
|
20
20
|
}
|
|
21
|
+
/** Subprocess argv and Windows quoting mode used to launch an external editor. */
|
|
22
|
+
export interface EditorSpawnCommand {
|
|
23
|
+
cmd: string[];
|
|
24
|
+
windowsVerbatimArguments: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Resolves shell argv without letting the host runtime re-quote the editor command. */
|
|
27
|
+
export declare function resolveEditorSpawnCommand(editorCmd: string, tmpFile: string, platform?: NodeJS.Platform): EditorSpawnCommand;
|
|
21
28
|
/**
|
|
22
29
|
* Opens `content` in the user's external editor and returns the edited text.
|
|
23
30
|
* Returns `null` if the editor exits with a non-zero code.
|
|
@@ -18,10 +18,9 @@ export interface MarkitConversionResult {
|
|
|
18
18
|
}
|
|
19
19
|
export interface MarkitFileConversionOptions {
|
|
20
20
|
/**
|
|
21
|
-
* Directory
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* placeholder comment instead.
|
|
21
|
+
* Directory converters may use for extracted image or diagram files. Since
|
|
22
|
+
* those files are conversion side effects, conversions using this option
|
|
23
|
+
* bypass the markdown cache.
|
|
25
24
|
*/
|
|
26
25
|
imageDir?: string;
|
|
27
26
|
}
|
|
@@ -102,15 +102,15 @@ export declare class VibeSessionRegistry {
|
|
|
102
102
|
/** Reset the global registry. Test-only. */
|
|
103
103
|
static resetGlobalForTests(): void;
|
|
104
104
|
/**
|
|
105
|
-
* Insert a bare worker record without the spawn
|
|
106
|
-
* lets
|
|
107
|
-
* fake roster + AgentRegistry session without driving a real turn.
|
|
105
|
+
* Insert a bare worker record without the spawn machinery. Test-only —
|
|
106
|
+
* lets focused runtime tests attach an optional synthetic in-flight job.
|
|
108
107
|
*/
|
|
109
108
|
registerRecordForTests(record: {
|
|
110
109
|
id: string;
|
|
111
110
|
cli?: VibeCli;
|
|
112
111
|
ownerId: string;
|
|
113
112
|
state?: VibeSessionState;
|
|
113
|
+
jobId?: string;
|
|
114
114
|
}): void;
|
|
115
115
|
/** Override the teardown grace period for deterministic lifecycle tests. */
|
|
116
116
|
setTeardownGraceForTesting(timeoutMs: number): void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "17.3.
|
|
4
|
+
"version": "17.3.5",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -41,8 +41,6 @@
|
|
|
41
41
|
"format-prompts": "bun scripts/format-prompts.ts",
|
|
42
42
|
"gen:tool-views": "bun --cwd=../collab-web run gen:tool-views",
|
|
43
43
|
"gen:bundle": "bun scripts/bundle-dist.ts",
|
|
44
|
-
"gen:mupdf": "bun scripts/embed-mupdf-wasm.ts --generate",
|
|
45
|
-
"gen:mupdf:reset": "bun scripts/embed-mupdf-wasm.ts --reset",
|
|
46
44
|
"gen:native": "bun --cwd=../natives run gen:native",
|
|
47
45
|
"gen:native:reset": "bun --cwd=../natives run gen:native:reset",
|
|
48
46
|
"prepack": "bun run gen:tool-views && bun run gen:bundle",
|
|
@@ -50,18 +48,18 @@
|
|
|
50
48
|
},
|
|
51
49
|
"dependencies": {
|
|
52
50
|
"@babel/parser": "^7.29.7",
|
|
53
|
-
"@oh-my-pi/hashline": "17.3.
|
|
54
|
-
"@oh-my-pi/omp-stats": "17.3.
|
|
55
|
-
"@oh-my-pi/omptype": "17.3.
|
|
56
|
-
"@oh-my-pi/pi-agent-core": "17.3.
|
|
57
|
-
"@oh-my-pi/pi-ai": "17.3.
|
|
58
|
-
"@oh-my-pi/pi-catalog": "17.3.
|
|
59
|
-
"@oh-my-pi/pi-mnemopi": "17.3.
|
|
60
|
-
"@oh-my-pi/pi-natives": "17.3.
|
|
61
|
-
"@oh-my-pi/pi-tui": "17.3.
|
|
62
|
-
"@oh-my-pi/pi-utils": "17.3.
|
|
63
|
-
"@oh-my-pi/pi-wire": "17.3.
|
|
64
|
-
"@oh-my-pi/snapcompact": "17.3.
|
|
51
|
+
"@oh-my-pi/hashline": "17.3.5",
|
|
52
|
+
"@oh-my-pi/omp-stats": "17.3.5",
|
|
53
|
+
"@oh-my-pi/omptype": "17.3.5",
|
|
54
|
+
"@oh-my-pi/pi-agent-core": "17.3.5",
|
|
55
|
+
"@oh-my-pi/pi-ai": "17.3.5",
|
|
56
|
+
"@oh-my-pi/pi-catalog": "17.3.5",
|
|
57
|
+
"@oh-my-pi/pi-mnemopi": "17.3.5",
|
|
58
|
+
"@oh-my-pi/pi-natives": "17.3.5",
|
|
59
|
+
"@oh-my-pi/pi-tui": "17.3.5",
|
|
60
|
+
"@oh-my-pi/pi-utils": "17.3.5",
|
|
61
|
+
"@oh-my-pi/pi-wire": "17.3.5",
|
|
62
|
+
"@oh-my-pi/snapcompact": "17.3.5",
|
|
65
63
|
"@opentelemetry/api": "^1.9.1",
|
|
66
64
|
"@opentelemetry/api-logs": "^0.220.0",
|
|
67
65
|
"@opentelemetry/context-async-hooks": "^2.9.0",
|
|
@@ -73,7 +71,6 @@
|
|
|
73
71
|
"@opentelemetry/sdk-metrics": "^2.9.0",
|
|
74
72
|
"@opentelemetry/sdk-trace-base": "^2.9.0",
|
|
75
73
|
"@opentelemetry/sdk-trace-node": "^2.9.0",
|
|
76
|
-
"mupdf": "^1.28.0",
|
|
77
74
|
"puppeteer-core": "25.3.0"
|
|
78
75
|
},
|
|
79
76
|
"optionalDependencies": {
|
package/scripts/build-binary.ts
CHANGED
|
@@ -88,7 +88,6 @@ async function main(): Promise<void> {
|
|
|
88
88
|
["bun", "--cwd=../natives", "run", "gen:native"],
|
|
89
89
|
crossBuild ? { ...Bun.env, TARGET_PLATFORM: crossBuild.platform, TARGET_ARCH: crossBuild.arch } : Bun.env,
|
|
90
90
|
);
|
|
91
|
-
await runCommand(["bun", "run", "gen:mupdf"]);
|
|
92
91
|
try {
|
|
93
92
|
await compileCodingAgent({
|
|
94
93
|
repoRoot,
|
|
@@ -104,7 +103,6 @@ async function main(): Promise<void> {
|
|
|
104
103
|
await runCommand(["codesign", "--force", "--sign", "-", outputPath]);
|
|
105
104
|
}
|
|
106
105
|
} finally {
|
|
107
|
-
await runCommand(["bun", "run", "gen:mupdf:reset"]);
|
|
108
106
|
await runCommand(["bun", "--cwd=../natives", "run", "gen:native:reset"]);
|
|
109
107
|
}
|
|
110
108
|
} finally {
|
package/scripts/bundle-dist.ts
CHANGED
|
@@ -15,7 +15,6 @@ const legacyHtmlExportAssetPattern = /^(?:template-[^.]+\.(?:css|html|js)|tool-v
|
|
|
15
15
|
// `omp-legacy-pi-modules` exists only in compiled binaries via the build plugin;
|
|
16
16
|
// the npm bundle never executes that `isCompiledBinary()` branch.
|
|
17
17
|
const ALWAYS_EXTERNAL = [
|
|
18
|
-
"mupdf",
|
|
19
18
|
"@oh-my-pi/pi-natives",
|
|
20
19
|
"@huggingface/transformers",
|
|
21
20
|
"fastembed",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* Throws on any failure (no model, no key, unparseable output, abort/timeout);
|
|
15
15
|
* the caller falls back to a concrete level and continues the turn.
|
|
16
16
|
*/
|
|
17
|
-
import { type AssistantMessage, completeSimple, Effort, type Model } from "@oh-my-pi/pi-ai";
|
|
17
|
+
import { type AssistantMessage, completeSimple, Effort, type Model, retryTransientCompletion } from "@oh-my-pi/pi-ai";
|
|
18
18
|
import { getSupportedEfforts } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
19
19
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
20
20
|
|
|
@@ -60,14 +60,24 @@ function difficultySystemPromptFor(ceiling: Effort): string {
|
|
|
60
60
|
|
|
61
61
|
/** Local classifiers occasionally need more room for chat-template boilerplate. */
|
|
62
62
|
const LOCAL_ANSWER_MAX_TOKENS = 16;
|
|
63
|
+
/** On-device reasoning classifiers need room for the bucket keyword after the `<think>` preamble. */
|
|
64
|
+
const LOCAL_REASONING_MAX_TOKENS = 1024;
|
|
63
65
|
/**
|
|
64
|
-
* Online classifier budget. Sized
|
|
65
|
-
* `disableReasoning`
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
66
|
+
* Online classifier budget. Sized against two independent constraints:
|
|
67
|
+
* - Backends that ignore `disableReasoning` still emit a thinking preamble
|
|
68
|
+
* (e.g. Qwen3 via llama.cpp catalogued `reasoning: false` but still thinking;
|
|
69
|
+
* Anthropic via LiteLLM/Vertex, whose `openai-completions` route downgrades a
|
|
70
|
+
* disabled request to the lowest reasoning effort instead of turning thinking
|
|
71
|
+
* off). The classifier keyword must have room to land after that preamble
|
|
72
|
+
* (issue #4355).
|
|
73
|
+
* - Anthropic-dialect proxies reject `max_tokens <= thinking.budget_tokens`. The
|
|
74
|
+
* pinned lowest effort maps to at least Anthropic's 1024-token minimum budget,
|
|
75
|
+
* so the cap MUST comfortably exceed 1024 or every classifier call 400s with
|
|
76
|
+
* `max_tokens must be greater than thinking.budget_tokens` (issue #8610).
|
|
77
|
+
* `maxTokens` is a hard cap — non-thinking completions still return in a handful
|
|
78
|
+
* of tokens.
|
|
69
79
|
*/
|
|
70
|
-
const
|
|
80
|
+
const ONLINE_REASONING_SAFE_MAX_TOKENS = 4096;
|
|
71
81
|
|
|
72
82
|
export interface ClassifyDifficultyDeps {
|
|
73
83
|
settings: Settings;
|
|
@@ -113,21 +123,25 @@ async function classifyOnline(input: string, deps: ClassifyDifficultyDeps, ceili
|
|
|
113
123
|
}
|
|
114
124
|
// Resolve metadata after getApiKey so the session-sticky credential is recorded first.
|
|
115
125
|
const metadata = deps.metadataResolver?.(model.provider);
|
|
116
|
-
const maxTokens =
|
|
117
|
-
|
|
118
|
-
const response = await
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
const maxTokens = ONLINE_REASONING_SAFE_MAX_TOKENS;
|
|
127
|
+
|
|
128
|
+
const response = await retryTransientCompletion(
|
|
129
|
+
() =>
|
|
130
|
+
completeSimple(
|
|
131
|
+
model,
|
|
132
|
+
{
|
|
133
|
+
systemPrompt: [difficultySystemPromptFor(ceiling)],
|
|
134
|
+
messages: [{ role: "user", content: input, timestamp: Date.now() }],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
apiKey: deps.registry.resolver(model, deps.sessionId),
|
|
138
|
+
maxTokens,
|
|
139
|
+
disableReasoning: true,
|
|
140
|
+
metadata,
|
|
141
|
+
signal: deps.signal,
|
|
142
|
+
},
|
|
143
|
+
),
|
|
144
|
+
{ signal: deps.signal },
|
|
131
145
|
);
|
|
132
146
|
|
|
133
147
|
if (response.stopReason === "error") {
|
|
@@ -147,7 +161,7 @@ async function classifyLocal(input: string, modelKey: string, deps: ClassifyDiff
|
|
|
147
161
|
throw new Error(`auto-thinking: unsupported local classifier model: ${modelKey}`);
|
|
148
162
|
}
|
|
149
163
|
const maxTokens = isTinyMemoryReasoningModelKey(modelKey)
|
|
150
|
-
? Math.max(LOCAL_ANSWER_MAX_TOKENS,
|
|
164
|
+
? Math.max(LOCAL_ANSWER_MAX_TOKENS, LOCAL_REASONING_MAX_TOKENS)
|
|
151
165
|
: LOCAL_ANSWER_MAX_TOKENS;
|
|
152
166
|
const builtPrompt = prompt.render(difficultyLocalPrompt, { prompt: input });
|
|
153
167
|
const text = await tinyModelClient.complete(modelKey, builtPrompt, {
|
package/src/cli/models-cli.ts
CHANGED
|
@@ -304,7 +304,7 @@ export async function runModelsListing(options: RunModelsListingOptions): Promis
|
|
|
304
304
|
cwd,
|
|
305
305
|
eventBus,
|
|
306
306
|
disableExtensionDiscovery ? undefined : disabledExtensionIds,
|
|
307
|
-
{ ambient: !disableExtensionDiscovery },
|
|
307
|
+
{ ambient: !disableExtensionDiscovery, includeAmbientHooks: false },
|
|
308
308
|
);
|
|
309
309
|
const extensionRunner =
|
|
310
310
|
extensionsResult.extensions.length > 0
|
package/src/cli/read-cli.ts
CHANGED
|
@@ -10,6 +10,7 @@ import chalk from "@oh-my-pi/pi-utils/chalk";
|
|
|
10
10
|
import { Settings } from "../config/settings";
|
|
11
11
|
import { extractUriScheme } from "../internal-urls/parse";
|
|
12
12
|
import { InternalUrlRouter } from "../internal-urls/router";
|
|
13
|
+
import { closeDaemonClients } from "../launch/client";
|
|
13
14
|
import { discoverAndLoadMCPTools } from "../mcp/loader";
|
|
14
15
|
import { MCPManager } from "../mcp/manager";
|
|
15
16
|
import { discoverAuthStorage } from "../session/auth-broker-config";
|
|
@@ -93,6 +94,7 @@ export async function runReadCommand(cmd: ReadCommandArgs): Promise<void> {
|
|
|
93
94
|
if (MCPManager.instance() === mcpManager) MCPManager.setInstance(undefined);
|
|
94
95
|
}
|
|
95
96
|
authStorage?.close();
|
|
97
|
+
await closeDaemonClients();
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
if (failed) process.exit(1);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { Api, ApiKey, Model } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import { completeSimple } from "@oh-my-pi/pi-ai";
|
|
3
|
+
import { completeSimple, retryTransientCompletion } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
5
5
|
import analysisSystemPrompt from "../../commit/prompts/analysis-system.md" with { type: "text" };
|
|
6
6
|
import analysisUserPrompt from "../../commit/prompts/analysis-user.md" with { type: "text" };
|
|
@@ -50,15 +50,21 @@ export async function generateConventionalAnalysis({
|
|
|
50
50
|
diff,
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
const response = await
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
const response = await retryTransientCompletion(() =>
|
|
54
|
+
completeSimple(
|
|
55
|
+
model,
|
|
56
|
+
{
|
|
57
|
+
systemPrompt: [prompt.render(analysisSystemPrompt)],
|
|
58
|
+
messages: [{ role: "user", content: userContent, timestamp: Date.now() }],
|
|
59
|
+
tools: [ConventionalAnalysisTool],
|
|
60
|
+
},
|
|
61
|
+
{ apiKey, maxTokens: 2400, reasoning: toReasoningEffort(thinkingLevel) },
|
|
62
|
+
),
|
|
61
63
|
);
|
|
62
64
|
|
|
65
|
+
if (response.stopReason === "error") {
|
|
66
|
+
throw new Error(response.errorMessage ?? "provider error");
|
|
67
|
+
}
|
|
68
|
+
|
|
63
69
|
return parseConventionalAnalysisResponse(response, ConventionalAnalysisTool);
|
|
64
70
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type } from "@oh-my-pi/omptype";
|
|
2
2
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
3
3
|
import type { Api, ApiKey, AssistantMessage, Model } from "@oh-my-pi/pi-ai";
|
|
4
|
-
import { completeSimple, validateToolCall } from "@oh-my-pi/pi-ai";
|
|
4
|
+
import { completeSimple, retryTransientCompletion, validateToolCall } from "@oh-my-pi/pi-ai";
|
|
5
5
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
6
6
|
import summarySystemPrompt from "../../commit/prompts/summary-system.md" with { type: "text" };
|
|
7
7
|
import summaryUserPrompt from "../../commit/prompts/summary-user.md" with { type: "text" };
|
|
@@ -52,16 +52,22 @@ export async function generateSummary({
|
|
|
52
52
|
stat,
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
const response = await
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
const response = await retryTransientCompletion(() =>
|
|
56
|
+
completeSimple(
|
|
57
|
+
model,
|
|
58
|
+
{
|
|
59
|
+
systemPrompt: [systemPrompt],
|
|
60
|
+
messages: [{ role: "user", content: userPrompt, timestamp: Date.now() }],
|
|
61
|
+
tools: [SummaryTool],
|
|
62
|
+
},
|
|
63
|
+
{ apiKey, maxTokens: 200, reasoning: toReasoningEffort(thinkingLevel) },
|
|
64
|
+
),
|
|
63
65
|
);
|
|
64
66
|
|
|
67
|
+
if (response.stopReason === "error") {
|
|
68
|
+
throw new Error(response.errorMessage ?? "provider error");
|
|
69
|
+
}
|
|
70
|
+
|
|
65
71
|
return parseSummaryFromResponse(response, commitType, scope);
|
|
66
72
|
}
|
|
67
73
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type } from "@oh-my-pi/omptype";
|
|
2
2
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
3
3
|
import type { Api, ApiKey, AssistantMessage, Model } from "@oh-my-pi/pi-ai";
|
|
4
|
-
import { completeSimple, validateToolCall } from "@oh-my-pi/pi-ai";
|
|
4
|
+
import { completeSimple, retryTransientCompletion, validateToolCall } from "@oh-my-pi/pi-ai";
|
|
5
5
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
6
6
|
import changelogSystemPrompt from "../../commit/prompts/changelog-system.md" with { type: "text" };
|
|
7
7
|
import changelogUserPrompt from "../../commit/prompts/changelog-user.md" with { type: "text" };
|
|
@@ -55,16 +55,22 @@ export async function generateChangelogEntries({
|
|
|
55
55
|
stat,
|
|
56
56
|
diff,
|
|
57
57
|
});
|
|
58
|
-
const response = await
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
const response = await retryTransientCompletion(() =>
|
|
59
|
+
completeSimple(
|
|
60
|
+
model,
|
|
61
|
+
{
|
|
62
|
+
systemPrompt: [prompt.render(changelogSystemPrompt)],
|
|
63
|
+
messages: [{ role: "user", content: userContent, timestamp: Date.now() }],
|
|
64
|
+
tools: [changelogTool],
|
|
65
|
+
},
|
|
66
|
+
{ apiKey, maxTokens: 1200, reasoning: toReasoningEffort(thinkingLevel) },
|
|
67
|
+
),
|
|
66
68
|
);
|
|
67
69
|
|
|
70
|
+
if (response.stopReason === "error") {
|
|
71
|
+
throw new Error(response.errorMessage ?? "provider error");
|
|
72
|
+
}
|
|
73
|
+
|
|
68
74
|
const parsed = parseChangelogResponse(response);
|
|
69
75
|
return { entries: dedupeEntries(parsed.entries) };
|
|
70
76
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { Api, ApiKey, AssistantMessage, Message, Model } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import { completeSimple } from "@oh-my-pi/pi-ai";
|
|
3
|
+
import { completeSimple, retryTransientCompletion } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
5
5
|
import fileObserverSystemPrompt from "../../commit/prompts/file-observer-system.md" with { type: "text" };
|
|
6
6
|
import fileObserverUserPrompt from "../../commit/prompts/file-observer-user.md" with { type: "text" };
|
|
@@ -66,7 +66,7 @@ export async function runMapPhase({
|
|
|
66
66
|
messages: [{ role: "user", content: userContent, timestamp: Date.now() }] as Message[],
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
const response = await
|
|
69
|
+
const response = await retryTransientCompletion(
|
|
70
70
|
() =>
|
|
71
71
|
completeSimple(model, request, {
|
|
72
72
|
apiKey,
|
|
@@ -74,8 +74,7 @@ export async function runMapPhase({
|
|
|
74
74
|
reasoning: toReasoningEffort(thinkingLevel),
|
|
75
75
|
signal: AbortSignal.timeout(timeoutMs),
|
|
76
76
|
}),
|
|
77
|
-
maxRetries,
|
|
78
|
-
retryBackoffMs,
|
|
77
|
+
{ maxAttempts: maxRetries, baseDelayMs: retryBackoffMs },
|
|
79
78
|
);
|
|
80
79
|
|
|
81
80
|
const observations = parseObservations(response);
|
|
@@ -176,18 +175,3 @@ async function runWithConcurrency<T, R>(
|
|
|
176
175
|
await Promise.all(runners);
|
|
177
176
|
return results;
|
|
178
177
|
}
|
|
179
|
-
|
|
180
|
-
async function withRetry<T>(fn: () => Promise<T>, attempts: number, backoffMs: number): Promise<T> {
|
|
181
|
-
let lastError: unknown;
|
|
182
|
-
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
183
|
-
try {
|
|
184
|
-
return await fn();
|
|
185
|
-
} catch (error) {
|
|
186
|
-
lastError = error;
|
|
187
|
-
if (attempt < attempts - 1) {
|
|
188
|
-
await Bun.sleep(backoffMs * (attempt + 1));
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
throw lastError;
|
|
193
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { Api, ApiKey, Model } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import { completeSimple } from "@oh-my-pi/pi-ai";
|
|
3
|
+
import { completeSimple, retryTransientCompletion } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
5
5
|
import reduceSystemPrompt from "../../commit/prompts/reduce-system.md" with { type: "text" };
|
|
6
6
|
import reduceUserPrompt from "../../commit/prompts/reduce-user.md" with { type: "text" };
|
|
@@ -35,15 +35,21 @@ export async function runReducePhase({
|
|
|
35
35
|
stat,
|
|
36
36
|
scope_candidates: scopeCandidates,
|
|
37
37
|
});
|
|
38
|
-
const response = await
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
const response = await retryTransientCompletion(() =>
|
|
39
|
+
completeSimple(
|
|
40
|
+
model,
|
|
41
|
+
{
|
|
42
|
+
systemPrompt: [prompt.render(reduceSystemPrompt)],
|
|
43
|
+
messages: [{ role: "user", content: userContent, timestamp: Date.now() }],
|
|
44
|
+
tools: [ReduceTool],
|
|
45
|
+
},
|
|
46
|
+
{ apiKey, maxTokens: 2400, reasoning: toReasoningEffort(thinkingLevel) },
|
|
47
|
+
),
|
|
46
48
|
);
|
|
47
49
|
|
|
50
|
+
if (response.stopReason === "error") {
|
|
51
|
+
throw new Error(response.errorMessage ?? "provider error");
|
|
52
|
+
}
|
|
53
|
+
|
|
48
54
|
return parseConventionalAnalysisResponse(response, ReduceTool);
|
|
49
55
|
}
|
|
@@ -645,7 +645,7 @@ export async function discoverLlamaCppModels(
|
|
|
645
645
|
name: id,
|
|
646
646
|
api: providerConfig.api,
|
|
647
647
|
provider: providerConfig.provider,
|
|
648
|
-
baseUrl,
|
|
648
|
+
baseUrl: ensureLlamaCppV1BaseUrl(baseUrl),
|
|
649
649
|
reasoning: false,
|
|
650
650
|
input: item.input ?? serverMetadata?.input ?? ["text"],
|
|
651
651
|
imageInputDecoder: "stb",
|
|
@@ -1018,7 +1018,7 @@ export async function discoverProxyModels(
|
|
|
1018
1018
|
return discovered;
|
|
1019
1019
|
}
|
|
1020
1020
|
|
|
1021
|
-
function normalizeLlamaCppBaseUrl(baseUrl?: string): string {
|
|
1021
|
+
export function normalizeLlamaCppBaseUrl(baseUrl?: string): string {
|
|
1022
1022
|
const defaultBaseUrl = "http://127.0.0.1:8080";
|
|
1023
1023
|
const raw = baseUrl || defaultBaseUrl;
|
|
1024
1024
|
try {
|
|
@@ -1033,7 +1033,7 @@ function normalizeLlamaCppBaseUrl(baseUrl?: string): string {
|
|
|
1033
1033
|
// ensureLlamaCppV1BaseUrl appends the OpenAI-compatible `/v1` prefix a
|
|
1034
1034
|
// chat-completions request needs; native discovery keeps the bare root, which
|
|
1035
1035
|
// serves `/models` and `/props` but not `/chat/completions`.
|
|
1036
|
-
function ensureLlamaCppV1BaseUrl(baseUrl: string): string {
|
|
1036
|
+
export function ensureLlamaCppV1BaseUrl(baseUrl: string): string {
|
|
1037
1037
|
return baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`;
|
|
1038
1038
|
}
|
|
1039
1039
|
|
|
@@ -61,9 +61,11 @@ import {
|
|
|
61
61
|
type DiscoveryProviderConfig,
|
|
62
62
|
discoverLlamaCppModelRuntimeMetadata,
|
|
63
63
|
discoverModelsByProviderType,
|
|
64
|
+
ensureLlamaCppV1BaseUrl,
|
|
64
65
|
getImplicitOllamaBaseUrl,
|
|
65
66
|
getOllamaContextLengthOverride,
|
|
66
67
|
normalizeLiteLLMDiscoveryBaseUrl,
|
|
68
|
+
normalizeLlamaCppBaseUrl,
|
|
67
69
|
} from "./model-discovery";
|
|
68
70
|
import {
|
|
69
71
|
AUTHORITATIVE_RUNTIME_CATALOG_PROVIDERS,
|
|
@@ -577,7 +579,7 @@ export class ModelRegistry {
|
|
|
577
579
|
const withConfigModels = this.#mergeCustomModels(resolvedDefaults, select(this.#customModelOverlays));
|
|
578
580
|
const combined = this.#mergeCustomModels(withConfigModels, select(this.#runtimeModelOverlays));
|
|
579
581
|
const withModelOverrides = this.#applyModelOverrides(collapseBuiltModelVariants(combined), this.#modelOverrides);
|
|
580
|
-
return this.#
|
|
582
|
+
return this.#applyLlamaCppModelFixups(this.#applyRuntimeProviderOverrides(withModelOverrides));
|
|
581
583
|
}
|
|
582
584
|
|
|
583
585
|
#composeStaticModels(providerFilter?: ReadonlySet<string>): Model<Api>[] {
|
|
@@ -1064,9 +1066,7 @@ export class ModelRegistry {
|
|
|
1064
1066
|
const withConfigModels = this.#mergeCustomModels(resolved, this.#customModelOverlays);
|
|
1065
1067
|
const combined = this.#mergeCustomModels(withConfigModels, this.#runtimeModelOverlays);
|
|
1066
1068
|
const withModelOverrides = this.#applyModelOverrides(collapseBuiltModelVariants(combined), this.#modelOverrides);
|
|
1067
|
-
this.#unprojectedModels = this.#
|
|
1068
|
-
this.#applyRuntimeProviderOverrides(withModelOverrides),
|
|
1069
|
-
);
|
|
1069
|
+
this.#unprojectedModels = this.#applyLlamaCppModelFixups(this.#applyRuntimeProviderOverrides(withModelOverrides));
|
|
1070
1070
|
this.#models = this.#applyRuntimeModelModifiers(this.#unprojectedModels);
|
|
1071
1071
|
}
|
|
1072
1072
|
|
|
@@ -1446,20 +1446,28 @@ export class ModelRegistry {
|
|
|
1446
1446
|
});
|
|
1447
1447
|
}
|
|
1448
1448
|
|
|
1449
|
-
// #
|
|
1450
|
-
//
|
|
1451
|
-
//
|
|
1452
|
-
//
|
|
1453
|
-
//
|
|
1454
|
-
|
|
1455
|
-
// cached row would otherwise leave the old spec in place.
|
|
1456
|
-
#applyLlamaCppQwenThinkingToModels(models: Model<Api>[]): Model<Api>[] {
|
|
1449
|
+
// #applyLlamaCppModelFixups is the outermost transform for llama.cpp-provider
|
|
1450
|
+
// models, after discovery merges, cache fallbacks, and provider/transport
|
|
1451
|
+
// overrides have run. It applies Qwen-specific fixes (api, reasoning, compat)
|
|
1452
|
+
// and ensures all non-transport models have the `/v1` prefix in their baseUrl,
|
|
1453
|
+
// even when a configured override or stale cache row would strip it.
|
|
1454
|
+
#applyLlamaCppModelFixups(models: Model<Api>[]): Model<Api>[] {
|
|
1457
1455
|
const llamaCppProviders = new Set<string>();
|
|
1458
1456
|
for (const provider of this.#discoverableProviders) {
|
|
1459
1457
|
if (provider.discovery.type === "llama.cpp") llamaCppProviders.add(provider.provider);
|
|
1460
1458
|
}
|
|
1461
1459
|
if (llamaCppProviders.size === 0) return models;
|
|
1462
|
-
return models.map(model =>
|
|
1460
|
+
return models.map(model => {
|
|
1461
|
+
if (!llamaCppProviders.has(model.provider)) return model;
|
|
1462
|
+
const withFixups = applyLlamaCppQwenThinking(model);
|
|
1463
|
+
if (!withFixups.transport && !withFixups.baseUrl.endsWith("/v1")) {
|
|
1464
|
+
return buildModel({
|
|
1465
|
+
...withFixups,
|
|
1466
|
+
baseUrl: ensureLlamaCppV1BaseUrl(normalizeLlamaCppBaseUrl(withFixups.baseUrl)),
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
return withFixups;
|
|
1470
|
+
});
|
|
1463
1471
|
}
|
|
1464
1472
|
|
|
1465
1473
|
#mergeProviderOverride(baseOverride: ProviderOverride | undefined, override: ProviderOverride): ProviderOverride {
|
|
@@ -1667,17 +1675,22 @@ export class ModelRegistry {
|
|
|
1667
1675
|
*
|
|
1668
1676
|
* Side-effect-free and synchronous: a command-backed key (`!cmd`) counts as
|
|
1669
1677
|
* configured by its presence alone — the program is NOT executed — and OAuth
|
|
1670
|
-
* tokens are NOT refreshed (`authStorage.
|
|
1678
|
+
* tokens are NOT refreshed (`authStorage.hasResolvableAuth`). This is what keeps the
|
|
1671
1679
|
* model-switch pre-flight off the event loop's hot path; the real key
|
|
1672
1680
|
* (command execution + OAuth refresh) is resolved lazily per request via
|
|
1673
1681
|
* {@link ModelRegistry.resolver}.
|
|
1682
|
+
*
|
|
1683
|
+
* Cross-provider env aliases count here (`xai-oauth` can borrow `XAI_API_KEY`)
|
|
1684
|
+
* so an explicit `xai-oauth/…` selector does not fail with "No API key".
|
|
1685
|
+
* Default-model availability still uses {@link AuthStorage.hasAuth}, which
|
|
1686
|
+
* ignores that alias so SuperGrok is not auto-selected from a paid key.
|
|
1674
1687
|
*/
|
|
1675
1688
|
hasConfiguredAuth(model: Model<Api>): boolean {
|
|
1676
1689
|
const keyConfig = this.#customProviderApiKeys.get(model.provider);
|
|
1677
1690
|
return (
|
|
1678
1691
|
isCommandConfigValue(keyConfig) ||
|
|
1679
1692
|
this.#keylessProviders.has(model.provider) ||
|
|
1680
|
-
this.authStorage.
|
|
1693
|
+
this.authStorage.hasResolvableAuth(model.provider)
|
|
1681
1694
|
);
|
|
1682
1695
|
}
|
|
1683
1696
|
|
|
@@ -2097,7 +2110,7 @@ export class ModelRegistry {
|
|
|
2097
2110
|
transportOverride,
|
|
2098
2111
|
);
|
|
2099
2112
|
this.#runtimeProviderOverrides.set(providerName, nextRuntimeOverride);
|
|
2100
|
-
this.#unprojectedModels = this.#
|
|
2113
|
+
this.#unprojectedModels = this.#applyLlamaCppModelFixups(
|
|
2101
2114
|
this.#unprojectedModels.map(model => {
|
|
2102
2115
|
if (model.provider !== providerName) return model;
|
|
2103
2116
|
return this.#applyProviderTransportOverrideToModel(model, transportOverride);
|
|
@@ -152,6 +152,7 @@ export const TAB_GROUPS: Record<SettingTab, readonly string[]> = {
|
|
|
152
152
|
"Output Limits",
|
|
153
153
|
"Execution",
|
|
154
154
|
"Discovery & MCP",
|
|
155
|
+
"Extensions",
|
|
155
156
|
"Developer",
|
|
156
157
|
],
|
|
157
158
|
tasks: ["Modes", "Subagents", "Isolation", "Commands & Skills"],
|
|
@@ -5494,6 +5495,18 @@ export const SETTINGS_SCHEMA = {
|
|
|
5494
5495
|
|
|
5495
5496
|
"commit.changelogMaxDiffChars": { type: "number", default: 120000 },
|
|
5496
5497
|
|
|
5498
|
+
"extensionHandlers.toolCallTimeoutMs": {
|
|
5499
|
+
type: "number",
|
|
5500
|
+
default: 30_000,
|
|
5501
|
+
ui: {
|
|
5502
|
+
tab: "tools",
|
|
5503
|
+
group: "Extensions",
|
|
5504
|
+
label: "Tool Call Handler Timeout (ms)",
|
|
5505
|
+
description:
|
|
5506
|
+
"Positive finite active-work timeout for extension tool_call handlers; invalid values use 30000ms, and time awaiting OMP-owned dialogs does not count",
|
|
5507
|
+
},
|
|
5508
|
+
},
|
|
5509
|
+
|
|
5497
5510
|
"dev.autoqa": {
|
|
5498
5511
|
type: "boolean",
|
|
5499
5512
|
default: true,
|