@oh-my-pi/pi-coding-agent 15.9.3 → 15.9.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 +39 -1
- package/dist/types/cli/classify-install-target.d.ts +5 -1
- package/dist/types/config/settings-schema.d.ts +13 -4
- package/dist/types/modes/components/assistant-message.d.ts +11 -0
- package/dist/types/modes/components/custom-editor.d.ts +3 -1
- package/dist/types/modes/components/error-banner.d.ts +11 -0
- package/dist/types/modes/components/tool-execution.d.ts +15 -0
- package/dist/types/modes/components/transcript-container.d.ts +1 -0
- package/dist/types/modes/components/user-message.d.ts +1 -1
- package/dist/types/modes/image-references.d.ts +17 -0
- package/dist/types/modes/interactive-mode.d.ts +7 -0
- package/dist/types/modes/types.d.ts +7 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
- package/dist/types/session/blob-store.d.ts +12 -11
- package/dist/types/session/session-manager.d.ts +5 -3
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/tiny/title-client.d.ts +16 -1
- package/dist/types/tool-discovery/mode.d.ts +8 -0
- package/dist/types/tools/archive-reader.d.ts +5 -1
- package/dist/types/tui/hyperlink.d.ts +12 -0
- package/dist/types/web/search/render.d.ts +1 -2
- package/package.json +9 -9
- package/src/cli/classify-install-target.ts +31 -5
- package/src/cli/plugin-cli.ts +45 -0
- package/src/cli/web-search-cli.ts +0 -1
- package/src/config/model-registry.ts +54 -4
- package/src/config/settings-schema.ts +14 -4
- package/src/eval/__tests__/agent-bridge.test.ts +72 -0
- package/src/eval/py/tool-bridge.ts +43 -5
- package/src/extensibility/custom-commands/bundled/ci-green/index.ts +31 -2
- package/src/internal-urls/docs-index.generated.ts +3 -3
- package/src/main.ts +7 -1
- package/src/modes/components/assistant-message.ts +22 -0
- package/src/modes/components/custom-editor.ts +14 -2
- package/src/modes/components/error-banner.ts +33 -0
- package/src/modes/components/tool-execution.ts +44 -0
- package/src/modes/components/transcript-container.ts +93 -32
- package/src/modes/components/user-message.ts +9 -2
- package/src/modes/controllers/event-controller.ts +42 -3
- package/src/modes/controllers/input-controller.ts +33 -1
- package/src/modes/image-references.ts +111 -0
- package/src/modes/interactive-mode.ts +48 -13
- package/src/modes/types.ts +10 -1
- package/src/modes/utils/ui-helpers.ts +23 -2
- package/src/prompts/ci-green-request.md +5 -3
- package/src/prompts/system/project-prompt.md +1 -0
- package/src/sdk.ts +17 -9
- package/src/session/agent-session.ts +37 -12
- package/src/session/blob-store.ts +96 -9
- package/src/session/session-manager.ts +19 -10
- package/src/system-prompt.ts +4 -0
- package/src/tiny/title-client.ts +7 -1
- package/src/tool-discovery/mode.ts +24 -0
- package/src/tools/archive-reader.ts +339 -31
- package/src/tools/fetch.ts +29 -9
- package/src/tools/gh.ts +65 -11
- package/src/tools/index.ts +6 -8
- package/src/tools/read.ts +58 -12
- package/src/tools/search-tool-bm25.ts +4 -6
- package/src/tools/search.ts +60 -11
- package/src/tui/hyperlink.ts +42 -7
- package/src/web/search/index.ts +2 -2
- package/src/web/search/render.ts +20 -52
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [15.9.5] - 2026-06-05
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- Added a persistent error banner pinned above the editor when an assistant turn ends on a provider error (e.g. Anthropic's "Output blocked by content filtering policy"). The transcript `Error: …` line scrolls away as the conversation grows, so terminal turns that ended on a stream error could pass unnoticed; the banner stays in the fixed region above the input and is cleared when the next turn starts.
|
|
9
|
+
|
|
10
|
+
- Added bold, underlined, clickable `[Image #N]` placeholders in the draft editor and sent user-message bubbles, backed by extension-bearing blob-store sidecar files so terminal `file://` links open in image viewers.
|
|
11
|
+
- Added the active model identifier (`provider/id`) to the system prompt's `<workstation>` block so the agent knows which model it is running as. Gated by the new `includeModelInPrompt` setting (default on); the base prompt is rebuilt on a mid-session model switch so the surfaced identifier stays current.
|
|
12
|
+
- Added `OLLAMA_HOST` support for implicit local Ollama discovery when `OLLAMA_BASE_URL` is unset, so OMP picks up the same host setting used by Ollama.
|
|
13
|
+
- Added `OLLAMA_CONTEXT_LENGTH` as a positive-integer context-window override for implicit local Ollama discovery, so users can correct OMP context budgeting without writing per-model overrides.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Changed `tools.discoveryMode` to default to `auto`, which keeps discovery off for small tool sets and automatically switches to MCP-only tool discovery when more than 40 tools are registered.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Fixed user-message rendering to materialize image links from embedded image blocks when rebuilding chat output, so image placeholders remain clickable after replayed or restored messages
|
|
22
|
+
- Fixed queued/steering user messages carrying a pasted image rendering out of order — sometimes dropping the user bubble *below* the very tool output it was sent to steer. `EventController.#handleMessageStart` awaited async image-link materialization between the user `message_start` and `addMessageToChat`; since `AgentSession.#emit` dispatches TUI listeners fire-and-forget, that mid-handler yield let the next synchronously-handled events (assistant `message_start`, tool execution start/end) append their components first, scrambling transcript order and live-region block boundaries. The bubble is now appended synchronously, with clickable image links still materialized via the synchronous blob-store fallback.
|
|
23
|
+
- Fixed tool execution cards to finalize promptly when a turn is abandoned or completed so stale streaming previews and frozen spinner frames no longer keep transcript rows in the live region
|
|
24
|
+
- Fixed `read` and `search` TUI rendering to emit OSC 8 hyperlinks for HTTP URLs, `local://` resources backed by files, and filesystem search targets, including line-specific links for search match rows.
|
|
25
|
+
- Fixed aborted streaming assistant messages staying frozen before their red "Operation aborted" label when status rows were appended underneath on ED3-risk terminals.
|
|
26
|
+
- Fixed `omp` / `omp -c` stacking a fresh welcome screen and transcript on top of the previous run's leftover terminal scrollback. The cold-launch transcript render was the only session-load path that did not pass `clearTerminalHistory`, so the TUI's scrollback-preserving initial paint left the prior run's welcome + conversation above the new one; the cold launch now clears native scrollback before painting, matching every in-process session switch.
|
|
27
|
+
- Fixed a long streamed assistant reply dropping its earlier lines on ED3-risk terminals (Ghostty/kitty/iTerm2) once it grew past the viewport — the head scrolled off the top and never reached scrollback, so the reply rendered as a ~viewport-tall circular buffer of only its latest lines. `AssistantMessageComponent` now reports itself as an append-only transcript block and `TranscriptContainer` surfaces the resulting commit-safe boundary, so the renderer commits the scrolled-off head to native scrollback instead of discarding it (volatile tool previews stay deferred as before).
|
|
28
|
+
|
|
29
|
+
### Security
|
|
30
|
+
|
|
31
|
+
- Blocked OSC 8 hyperlink wrapping for URI targets containing terminal control bytes to avoid rendering malformed control-sequence links
|
|
32
|
+
|
|
33
|
+
## [15.9.4] - 2026-06-05
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- Fixed chat transcript updates after submitting input so frozen scrollback is only thawed when native scrollback replay succeeds, preventing misplaced or duplicated rows when the viewport is not at the tail
|
|
37
|
+
- Fixed `read` of `.zip` archives to list the central directory without inflating every member, so large or corrupt zip payloads no longer freeze directory reads; member contents are inflated only when a specific entry is read.
|
|
38
|
+
- Fixed the Python `eval` kernel being hard-killed (and its persistent session state lost) when a cell blocked in `parallel()` / `agent()` was interrupted. Each `agent()`/`tool.*` call blocks a kernel worker thread in a synchronous `urllib` request to the host bridge, and `parallel()`'s `ThreadPoolExecutor` exit joins those threads — so the kernel cannot unwind a `KeyboardInterrupt` until every in-flight bridge call returns. A wide subagent fan-out's teardown routinely outlasted the kernel's 5s SIGINT-escalation window, so the kernel was force-killed (surfacing `[kernel] Python kernel shutdown`) while the subagents were still winding down. The host bridge now resolves an in-flight call the instant the cell's signal aborts, so the kernel unwinds cleanly and keeps its state; the already-signaled subagent continues tearing down in the background.
|
|
39
|
+
- Fixed `github` tool `run_watch` op ignoring the explicit `repo` argument and silently watching the cwd-inferred repository in nested/umbrella workspaces. `executeRunWatch` passed `undefined` for the user-supplied `repo` to `resolveGitHubRepo`, so a call like `{op: "run_watch", repo: "owner/cxf", branch: "main"}` fell back to `gh repo view` in cwd and streamed `watching <sha> on <cwd-repo>` against the wrong repository. The explicit `repo` now takes precedence over the cwd inference, and the no-`branch`/no-`run` path refuses to derive the watched commit from `git HEAD` unless the cwd actually points at the resolved repo — otherwise it raises a `ToolError` telling the caller to pass `branch` or `run` instead of silently rebinding to an unrelated commit ([#1949](https://github.com/can1357/oh-my-pi/issues/1949)).
|
|
40
|
+
- Fixed `omp plugin install <local-path>` failing with `Invalid package name: .` (and similar) for cwd-relative (`.`, `./pkg`), absolute (`/abs`, `C:\…`, `\\unc`), and tilde-prefixed (`~/pkg`) specs. `classifyInstallTarget` now returns a `local` arm in addition to `marketplace`/`npm`, and `plugin install` routes those specs to `PluginManager.link()` — the same code path as `omp plugin link`. ([#1945](https://github.com/can1357/oh-my-pi/issues/1945))
|
|
41
|
+
- Fixed the `web_search` result renderer capping the synthesized answer at 12 lines even when expanded, while the Sources list expanded in full — so a long answer stayed truncated ("… N more lines") after `Ctrl+O`, making the expand toggle look like a no-op and dwarfing the answer next to its sources. The answer now renders the full text (markdown-formatted) when expanded and a short markdown preview when collapsed, matching the sources' collapse/expand behavior. The answer is also rendered through the Markdown component instead of dimmed raw lines, so headings, bold, lists, and code in the answer display formatted.
|
|
42
|
+
|
|
5
43
|
## [15.9.3] - 2026-06-05
|
|
6
44
|
|
|
7
45
|
### Fixed
|
|
@@ -9361,4 +9399,4 @@ Initial public release.
|
|
|
9361
9399
|
- Git branch display in footer
|
|
9362
9400
|
- Message queueing during streaming responses
|
|
9363
9401
|
- OAuth integration for Gmail and Google Calendar access
|
|
9364
|
-
- HTML export with syntax highlighting and collapsible sections
|
|
9402
|
+
- HTML export with syntax highlighting and collapsible sections
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type ClassifiedInstallTarget = {
|
|
2
|
+
type: "local";
|
|
3
|
+
path: string;
|
|
4
|
+
} | {
|
|
2
5
|
type: "marketplace";
|
|
3
6
|
name: string;
|
|
4
7
|
marketplace: string;
|
|
@@ -6,3 +9,4 @@ export declare function classifyInstallTarget(spec: string, knownMarketplaces: S
|
|
|
6
9
|
type: "npm";
|
|
7
10
|
spec: string;
|
|
8
11
|
};
|
|
12
|
+
export declare function classifyInstallTarget(spec: string, knownMarketplaces: Set<string>): ClassifiedInstallTarget;
|
|
@@ -659,7 +659,7 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
659
659
|
readonly ui: {
|
|
660
660
|
readonly tab: "appearance";
|
|
661
661
|
readonly label: "Terminal Hyperlinks";
|
|
662
|
-
readonly description: "Wrap
|
|
662
|
+
readonly description: "Wrap paths and URLs in OSC 8 hyperlinks for terminal-native click-to-open (auto: detect support; off: never; always: unconditional)";
|
|
663
663
|
};
|
|
664
664
|
};
|
|
665
665
|
readonly "display.tabWidth": {
|
|
@@ -745,6 +745,15 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
745
745
|
readonly description: "Render full tool descriptions in the system prompt instead of a tool name list";
|
|
746
746
|
};
|
|
747
747
|
};
|
|
748
|
+
readonly includeModelInPrompt: {
|
|
749
|
+
readonly type: "boolean";
|
|
750
|
+
readonly default: true;
|
|
751
|
+
readonly ui: {
|
|
752
|
+
readonly tab: "model";
|
|
753
|
+
readonly label: "Include Model In Prompt";
|
|
754
|
+
readonly description: "Surface the active model identifier in the system prompt so the agent knows which model it is";
|
|
755
|
+
};
|
|
756
|
+
};
|
|
748
757
|
readonly temperature: {
|
|
749
758
|
readonly type: "number";
|
|
750
759
|
readonly default: -1;
|
|
@@ -2828,12 +2837,12 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
2828
2837
|
};
|
|
2829
2838
|
readonly "tools.discoveryMode": {
|
|
2830
2839
|
readonly type: "enum";
|
|
2831
|
-
readonly values: readonly ["off", "mcp-only", "all"];
|
|
2832
|
-
readonly default: "
|
|
2840
|
+
readonly values: readonly ["auto", "off", "mcp-only", "all"];
|
|
2841
|
+
readonly default: "auto";
|
|
2833
2842
|
readonly ui: {
|
|
2834
2843
|
readonly tab: "tools";
|
|
2835
2844
|
readonly label: "Tool Discovery";
|
|
2836
|
-
readonly description: "Hide tools behind a search tool to save tokens. 'mcp-only' hides MCP tools; 'all' hides all non-essential built-ins too.";
|
|
2845
|
+
readonly description: "Hide tools behind a search tool to save tokens. 'auto' hides MCP tools once the tool set has more than 40 tools; 'mcp-only' always hides MCP tools; 'all' hides all non-essential built-ins too.";
|
|
2837
2846
|
};
|
|
2838
2847
|
};
|
|
2839
2848
|
readonly "tools.essentialOverride": {
|
|
@@ -13,6 +13,17 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
13
13
|
constructor(message?: AssistantMessage, hideThinkingBlock?: boolean, onImageUpdate?: (() => void) | undefined, thinkingRenderers?: readonly AssistantThinkingRenderer[], imageBudget?: ImageBudget | undefined);
|
|
14
14
|
invalidate(): void;
|
|
15
15
|
setHideThinkingBlock(hide: boolean): void;
|
|
16
|
+
isTranscriptBlockFinalized(): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Assistant text/thinking streams in append-only: earlier rendered rows never
|
|
19
|
+
* re-layout, new content only grows the block at the bottom. The transcript
|
|
20
|
+
* reports this so the renderer may commit scrolled-off head rows of a long
|
|
21
|
+
* streamed reply to native scrollback instead of dropping them (see
|
|
22
|
+
* `NativeScrollbackLiveRegion#getNativeScrollbackCommitSafeEnd`). Volatile
|
|
23
|
+
* blocks (tool previews that collapse) intentionally do not implement this.
|
|
24
|
+
*/
|
|
25
|
+
isTranscriptBlockAppendOnly(): boolean;
|
|
26
|
+
markTranscriptBlockFinalized(): void;
|
|
16
27
|
setToolResultImages(toolCallId: string, images: ImageContent[]): void;
|
|
17
28
|
setUsageInfo(usage: Usage): void;
|
|
18
29
|
updateContent(message: AssistantMessage): void;
|
|
@@ -6,8 +6,10 @@ type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.cl
|
|
|
6
6
|
*/
|
|
7
7
|
export declare class CustomEditor extends Editor {
|
|
8
8
|
#private;
|
|
9
|
+
imageLinks?: readonly (string | undefined)[];
|
|
9
10
|
/** Gradient-highlight the "ultrathink" / "orchestrate" / "workflow" keywords as the user types
|
|
10
|
-
* them, skipping any occurrence inside code spans, fenced blocks, or XML sections.
|
|
11
|
+
* them, skipping any occurrence inside code spans, fenced blocks, or XML sections. Also make
|
|
12
|
+
* pasted image placeholders visually distinct and hyperlink them once their blob file exists. */
|
|
11
13
|
decorateText: (text: string) => string;
|
|
12
14
|
onEscape?: () => void;
|
|
13
15
|
onClear?: () => void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Container } from "@oh-my-pi/pi-tui";
|
|
2
|
+
/**
|
|
3
|
+
* A persistent error banner pinned above the editor. Unlike the transcript
|
|
4
|
+
* "Error: …" line (which scrolls away as the conversation grows), this stays in
|
|
5
|
+
* the fixed region directly above the input so a turn that ended on a provider
|
|
6
|
+
* error — e.g. Anthropic's "Output blocked by content filtering policy" — cannot
|
|
7
|
+
* be missed. It is cleared when the next turn starts.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ErrorBannerComponent extends Container {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
@@ -52,6 +52,21 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
52
52
|
details?: any;
|
|
53
53
|
isError?: boolean;
|
|
54
54
|
}, isPartial?: boolean, _toolCallId?: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* Whether this block has reached a terminal state for transcript freezing.
|
|
57
|
+
* Reports `false` while it can still visually change so the
|
|
58
|
+
* {@link TranscriptContainer} keeps it inside the repaintable live region:
|
|
59
|
+
* a foreground tool awaiting its result, or one streaming partial output.
|
|
60
|
+
* A final (non-partial) result, a background-async tool the agent has moved
|
|
61
|
+
* past, or an explicit {@link seal} flips it to `true`.
|
|
62
|
+
*/
|
|
63
|
+
isTranscriptBlockFinalized(): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Mark the tool terminal even though no result arrived (the turn aborted or
|
|
66
|
+
* abandoned it) and stop animating, so it can freeze and stops pinning the
|
|
67
|
+
* transcript live region.
|
|
68
|
+
*/
|
|
69
|
+
seal(): void;
|
|
55
70
|
/**
|
|
56
71
|
* Stop spinner animation and cleanup resources.
|
|
57
72
|
*/
|
|
@@ -26,6 +26,7 @@ export declare class TranscriptContainer extends Container implements NativeScro
|
|
|
26
26
|
invalidate(): void;
|
|
27
27
|
clear(): void;
|
|
28
28
|
getNativeScrollbackLiveRegionStart(): number | undefined;
|
|
29
|
+
getNativeScrollbackCommitSafeEnd(): number | undefined;
|
|
29
30
|
/**
|
|
30
31
|
* Retire all frozen snapshots so the next render reflects each block's current
|
|
31
32
|
* state. Call at reconciliation checkpoints (prompt submit) where the whole
|
|
@@ -3,6 +3,6 @@ import { Container } from "@oh-my-pi/pi-tui";
|
|
|
3
3
|
* Component that renders a user message
|
|
4
4
|
*/
|
|
5
5
|
export declare class UserMessageComponent extends Container {
|
|
6
|
-
constructor(text: string, synthetic?: boolean);
|
|
6
|
+
constructor(text: string, synthetic?: boolean, imageLinks?: readonly (string | undefined)[]);
|
|
7
7
|
render(width: number): string[];
|
|
8
8
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import { type BlobPutResult } from "../session/blob-store";
|
|
3
|
+
type ImageBlobWriter = (data: Buffer, options?: {
|
|
4
|
+
extension?: string;
|
|
5
|
+
}) => Promise<BlobPutResult>;
|
|
6
|
+
type ImageBlobWriterSync = (data: Buffer, options?: {
|
|
7
|
+
extension?: string;
|
|
8
|
+
}) => BlobPutResult;
|
|
9
|
+
export interface ImageReferenceRenderers {
|
|
10
|
+
renderText: (text: string) => string;
|
|
11
|
+
renderReference: (label: string, index: number) => string;
|
|
12
|
+
}
|
|
13
|
+
export declare function renderImageReferences(text: string, renderers: ImageReferenceRenderers): string;
|
|
14
|
+
export declare function imageReferenceHyperlink(label: string, index: number, imageLinks: readonly (string | undefined)[] | undefined, renderLabel: (text: string) => string): string;
|
|
15
|
+
export declare function materializeImageReferenceLinks(images: readonly ImageContent[] | undefined, putBlob: ImageBlobWriter): Promise<(string | undefined)[] | undefined>;
|
|
16
|
+
export declare function materializeImageReferenceLinksSync(images: readonly ImageContent[] | undefined, putBlob: ImageBlobWriterSync): (string | undefined)[] | undefined;
|
|
17
|
+
export {};
|
|
@@ -56,6 +56,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
56
56
|
todoContainer: Container;
|
|
57
57
|
btwContainer: Container;
|
|
58
58
|
omfgContainer: Container;
|
|
59
|
+
errorBannerContainer: Container;
|
|
59
60
|
editor: CustomEditor;
|
|
60
61
|
editorContainer: Container;
|
|
61
62
|
hookWidgetContainerAbove: Container;
|
|
@@ -77,6 +78,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
77
78
|
todoPhases: TodoPhase[];
|
|
78
79
|
hideThinkingBlock: boolean;
|
|
79
80
|
pendingImages: ImageContent[];
|
|
81
|
+
pendingImageLinks: (string | undefined)[];
|
|
80
82
|
compactionQueuedMessages: CompactionQueuedMessage[];
|
|
81
83
|
pendingTools: Map<string, ToolExecutionHandle>;
|
|
82
84
|
pendingBashComponents: BashExecutionComponent[];
|
|
@@ -136,6 +138,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
136
138
|
startPendingSubmission(input: {
|
|
137
139
|
text: string;
|
|
138
140
|
images?: ImageContent[];
|
|
141
|
+
imageLinks?: (string | undefined)[];
|
|
139
142
|
customType?: string;
|
|
140
143
|
display?: boolean;
|
|
141
144
|
}): SubmittedUserInput;
|
|
@@ -162,6 +165,8 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
162
165
|
dim?: boolean;
|
|
163
166
|
}): void;
|
|
164
167
|
showError(message: string): void;
|
|
168
|
+
showPinnedError(message: string): void;
|
|
169
|
+
clearPinnedError(): void;
|
|
165
170
|
showWarning(message: string): void;
|
|
166
171
|
ensureLoadingAnimation(): void;
|
|
167
172
|
setWorkingMessage(message?: string): void;
|
|
@@ -177,6 +182,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
177
182
|
isKnownSlashCommand(text: string): boolean;
|
|
178
183
|
addMessageToChat(message: AgentMessage, options?: {
|
|
179
184
|
populateHistory?: boolean;
|
|
185
|
+
imageLinks?: readonly (string | undefined)[];
|
|
180
186
|
}): Component[];
|
|
181
187
|
renderSessionContext(sessionContext: SessionContext, options?: {
|
|
182
188
|
updateFooter?: boolean;
|
|
@@ -184,6 +190,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
184
190
|
}): void;
|
|
185
191
|
renderInitialMessages(prebuiltContext?: SessionContext, options?: {
|
|
186
192
|
preserveExistingChat?: boolean;
|
|
193
|
+
clearTerminalHistory?: boolean;
|
|
187
194
|
}): void;
|
|
188
195
|
getUserMessageText(message: Message): string;
|
|
189
196
|
findLastAssistantMessage(): AssistantMessage | undefined;
|
|
@@ -32,6 +32,7 @@ export type CompactionQueuedMessage = {
|
|
|
32
32
|
export type SubmittedUserInput = {
|
|
33
33
|
text: string;
|
|
34
34
|
images?: ImageContent[];
|
|
35
|
+
imageLinks?: (string | undefined)[];
|
|
35
36
|
customType?: string;
|
|
36
37
|
display?: boolean;
|
|
37
38
|
cancelled: boolean;
|
|
@@ -60,6 +61,7 @@ export interface InteractiveModeContext {
|
|
|
60
61
|
todoContainer: Container;
|
|
61
62
|
btwContainer: Container;
|
|
62
63
|
omfgContainer: Container;
|
|
64
|
+
errorBannerContainer: Container;
|
|
63
65
|
editor: CustomEditor;
|
|
64
66
|
editorContainer: Container;
|
|
65
67
|
hookWidgetContainerAbove: Container;
|
|
@@ -87,6 +89,7 @@ export interface InteractiveModeContext {
|
|
|
87
89
|
planModePlanFilePath?: string;
|
|
88
90
|
hideThinkingBlock: boolean;
|
|
89
91
|
pendingImages: ImageContent[];
|
|
92
|
+
pendingImageLinks: (string | undefined)[];
|
|
90
93
|
compactionQueuedMessages: CompactionQueuedMessage[];
|
|
91
94
|
pendingTools: Map<string, ToolExecutionHandle>;
|
|
92
95
|
pendingBashComponents: BashExecutionComponent[];
|
|
@@ -130,6 +133,8 @@ export interface InteractiveModeContext {
|
|
|
130
133
|
dim?: boolean;
|
|
131
134
|
}): void;
|
|
132
135
|
showError(message: string): void;
|
|
136
|
+
showPinnedError(message: string): void;
|
|
137
|
+
clearPinnedError(): void;
|
|
133
138
|
showWarning(message: string): void;
|
|
134
139
|
showNewVersionNotification(newVersion: string): void;
|
|
135
140
|
clearEditor(): void;
|
|
@@ -146,6 +151,7 @@ export interface InteractiveModeContext {
|
|
|
146
151
|
startPendingSubmission(input: {
|
|
147
152
|
text: string;
|
|
148
153
|
images?: ImageContent[];
|
|
154
|
+
imageLinks?: (string | undefined)[];
|
|
149
155
|
customType?: string;
|
|
150
156
|
display?: boolean;
|
|
151
157
|
}): SubmittedUserInput;
|
|
@@ -170,6 +176,7 @@ export interface InteractiveModeContext {
|
|
|
170
176
|
isKnownSlashCommand(text: string): boolean;
|
|
171
177
|
addMessageToChat(message: AgentMessage, options?: {
|
|
172
178
|
populateHistory?: boolean;
|
|
179
|
+
imageLinks?: readonly (string | undefined)[];
|
|
173
180
|
}): Component[];
|
|
174
181
|
renderSessionContext(sessionContext: SessionContext, options?: {
|
|
175
182
|
updateFooter?: boolean;
|
|
@@ -24,6 +24,7 @@ export declare class UiHelpers {
|
|
|
24
24
|
}): void;
|
|
25
25
|
addMessageToChat(message: AgentMessage, options?: {
|
|
26
26
|
populateHistory?: boolean;
|
|
27
|
+
imageLinks?: readonly (string | undefined)[];
|
|
27
28
|
}): Component[];
|
|
28
29
|
/**
|
|
29
30
|
* Render session context to chat. Used for initial load and rebuild after compaction.
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
export interface BlobPutOptions {
|
|
2
|
+
/** Optional file extension for a sidecar hardlink/copy that OS openers can type-detect. */
|
|
3
|
+
extension?: string;
|
|
4
|
+
}
|
|
1
5
|
export interface BlobPutResult {
|
|
2
6
|
hash: string;
|
|
7
|
+
/** Canonical content-addressed path, always `<dir>/<sha256-hex>`. */
|
|
3
8
|
path: string;
|
|
9
|
+
/** Path with the requested extension when supplied, otherwise the canonical path. */
|
|
10
|
+
displayPath: string;
|
|
4
11
|
get ref(): string;
|
|
5
12
|
}
|
|
6
|
-
|
|
7
|
-
* Content-addressed blob store for externalizing large binary data (images) from session JSONL files.
|
|
8
|
-
*
|
|
9
|
-
* Files are stored at `<dir>/<sha256-hex>` with no extension. The SHA-256 hash is computed
|
|
10
|
-
* over the raw binary data (not base64). Content-addressing makes writes idempotent and
|
|
11
|
-
* provides automatic deduplication across sessions.
|
|
12
|
-
*/
|
|
13
|
+
export declare function blobExtensionForImageMimeType(mimeType: string | undefined): string | undefined;
|
|
13
14
|
export declare class BlobStore {
|
|
14
15
|
readonly dir: string;
|
|
15
16
|
constructor(dir: string);
|
|
@@ -17,13 +18,13 @@ export declare class BlobStore {
|
|
|
17
18
|
* Write binary data to the blob store.
|
|
18
19
|
* @returns SHA-256 hex hash of the data
|
|
19
20
|
*/
|
|
20
|
-
put(data: Buffer): Promise<BlobPutResult>;
|
|
21
|
+
put(data: Buffer, options?: BlobPutOptions): Promise<BlobPutResult>;
|
|
21
22
|
/**
|
|
22
23
|
* Synchronous variant of {@link put}. Use on persistence hot paths where the caller
|
|
23
24
|
* cannot afford the microtask hops of the async version (e.g. OOM-safe session writes).
|
|
24
25
|
* Returns once the bytes are in the kernel page cache.
|
|
25
26
|
*/
|
|
26
|
-
putSync(data: Buffer): BlobPutResult;
|
|
27
|
+
putSync(data: Buffer, options?: BlobPutOptions): BlobPutResult;
|
|
27
28
|
/** Read blob by hash, returns Buffer or null if not found. */
|
|
28
29
|
get(hash: string): Promise<Buffer | null>;
|
|
29
30
|
/** Check if a blob exists. */
|
|
@@ -46,9 +47,9 @@ export declare function externalizeImageDataUrlSync(blobStore: BlobStore, dataUr
|
|
|
46
47
|
* Externalize an image's base64 data to the blob store, returning a blob reference.
|
|
47
48
|
* If the data is already a blob reference, returns it unchanged.
|
|
48
49
|
*/
|
|
49
|
-
export declare function externalizeImageData(blobStore: BlobStore, base64Data: string): Promise<string>;
|
|
50
|
+
export declare function externalizeImageData(blobStore: BlobStore, base64Data: string, mimeType?: string): Promise<string>;
|
|
50
51
|
/** Synchronous variant of {@link externalizeImageData}. */
|
|
51
|
-
export declare function externalizeImageDataSync(blobStore: BlobStore, base64Data: string): string;
|
|
52
|
+
export declare function externalizeImageDataSync(blobStore: BlobStore, base64Data: string, mimeType?: string): string;
|
|
52
53
|
/**
|
|
53
54
|
* Resolve an externalized provider image data URL back to its original string.
|
|
54
55
|
* If the data is not a blob reference, returns it unchanged.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { ImageContent, Message, MessageAttribution, ServiceTier, TextContent } from "@oh-my-pi/pi-ai";
|
|
3
3
|
import { ArtifactManager } from "./artifacts";
|
|
4
|
-
import { type BlobPutResult } from "./blob-store";
|
|
4
|
+
import { type BlobPutOptions, type BlobPutResult } from "./blob-store";
|
|
5
5
|
import { type BashExecutionMessage, type CustomMessage, type FileMentionMessage, type HookMessage, type PythonExecutionMessage } from "./messages";
|
|
6
6
|
import type { SessionStorage } from "./session-storage";
|
|
7
7
|
export declare const CURRENT_SESSION_VERSION = 3;
|
|
@@ -208,7 +208,7 @@ export interface SessionInfo {
|
|
|
208
208
|
*/
|
|
209
209
|
status?: SessionStatus;
|
|
210
210
|
}
|
|
211
|
-
export type ReadonlySessionManager = Pick<SessionManager, "getCwd" | "getSessionDir" | "getSessionId" | "getSessionFile" | "getSessionName" | "getArtifactsDir" | "getArtifactManager" | "allocateArtifactPath" | "saveArtifact" | "getArtifactPath" | "getLeafId" | "getLeafEntry" | "getEntry" | "getLabel" | "getBranch" | "getHeader" | "getEntries" | "getTree" | "getUsageStatistics" | "putBlob">;
|
|
211
|
+
export type ReadonlySessionManager = Pick<SessionManager, "getCwd" | "getSessionDir" | "getSessionId" | "getSessionFile" | "getSessionName" | "getArtifactsDir" | "getArtifactManager" | "allocateArtifactPath" | "saveArtifact" | "getArtifactPath" | "getLeafId" | "getLeafEntry" | "getEntry" | "getLabel" | "getBranch" | "getHeader" | "getEntries" | "getTree" | "getUsageStatistics" | "putBlob" | "putBlobSync">;
|
|
212
212
|
/** Exported for testing */
|
|
213
213
|
export declare function migrateSessionEntries(entries: FileEntry[]): void;
|
|
214
214
|
/** Exported for compaction.test.ts */
|
|
@@ -294,7 +294,9 @@ export declare class SessionManager {
|
|
|
294
294
|
private readonly storage;
|
|
295
295
|
private constructor();
|
|
296
296
|
/** Puts a binary blob into the blob store and returns the blob reference */
|
|
297
|
-
putBlob(data: Buffer): Promise<BlobPutResult>;
|
|
297
|
+
putBlob(data: Buffer, options?: BlobPutOptions): Promise<BlobPutResult>;
|
|
298
|
+
/** Synchronous variant of {@link putBlob} for rebuild-only render paths. */
|
|
299
|
+
putBlobSync(data: Buffer, options?: BlobPutOptions): BlobPutResult;
|
|
298
300
|
captureState(): SessionManagerStateSnapshot;
|
|
299
301
|
restoreState(snapshot: SessionManagerStateSnapshot): void;
|
|
300
302
|
/** Switch to a different session file (used for resume and branching) */
|
|
@@ -84,6 +84,8 @@ export interface BuildSystemPromptOptions {
|
|
|
84
84
|
workspaceTree?: WorkspaceTree | Promise<WorkspaceTree>;
|
|
85
85
|
/** Whether the local memory://root summary is active. */
|
|
86
86
|
memoryRootEnabled?: boolean;
|
|
87
|
+
/** Active model identifier (e.g. "anthropic/claude-opus-4") surfaced to the agent. */
|
|
88
|
+
model?: string;
|
|
87
89
|
}
|
|
88
90
|
/** Result of building provider-facing system prompt messages. */
|
|
89
91
|
export interface BuildSystemPromptResult {
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import type { Subprocess } from "bun";
|
|
2
|
-
import type { TinyTitleProgressEvent, TinyTitleWorkerOutbound } from "./title-protocol";
|
|
2
|
+
import type { TinyTitleProgressEvent, TinyTitleWorkerInbound, TinyTitleWorkerOutbound } from "./title-protocol";
|
|
3
|
+
/**
|
|
4
|
+
* Abstraction over the tiny-model subprocess. Modelled as a worker interface
|
|
5
|
+
* so existing callers (titles, memory completions, downloads) compose the
|
|
6
|
+
* same way; the runtime implementation is a Bun child process so
|
|
7
|
+
* `onnxruntime-node`'s NAPI finalizer never runs inside the main agent
|
|
8
|
+
* address space — that destructor segfaults Bun on Windows during shutdown
|
|
9
|
+
* (issue #1606).
|
|
10
|
+
*/
|
|
11
|
+
interface WorkerHandle {
|
|
12
|
+
send(message: TinyTitleWorkerInbound): void;
|
|
13
|
+
onMessage(handler: (message: TinyTitleWorkerOutbound) => void): () => void;
|
|
14
|
+
onError(handler: (error: Error) => void): () => void;
|
|
15
|
+
terminate(): Promise<void>;
|
|
16
|
+
}
|
|
3
17
|
export interface TinyTitleDownloadOptions {
|
|
4
18
|
signal?: AbortSignal;
|
|
5
19
|
onProgress?: (event: TinyTitleProgressEvent) => void;
|
|
@@ -39,6 +53,7 @@ interface SpawnedSubprocess {
|
|
|
39
53
|
export declare function createTinyTitleSubprocess(): SpawnedSubprocess;
|
|
40
54
|
export declare class TinyTitleClient {
|
|
41
55
|
#private;
|
|
56
|
+
constructor(spawnWorker?: () => WorkerHandle);
|
|
42
57
|
onProgress(listener: (event: TinyTitleProgressEvent) => void): () => void;
|
|
43
58
|
generate(modelKey: string, message: string, signal?: AbortSignal): Promise<string | null>;
|
|
44
59
|
complete(modelKey: string, prompt: string, options?: {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Settings } from "../config/settings";
|
|
2
|
+
import type { SettingValue } from "../config/settings-schema";
|
|
3
|
+
export declare const TOOL_DISCOVERY_AUTO_THRESHOLD = 40;
|
|
4
|
+
export declare const TOOL_DISCOVERY_SEARCH_TOOL_NAME = "search_tool_bm25";
|
|
5
|
+
export type ToolDiscoveryModeSetting = SettingValue<"tools.discoveryMode">;
|
|
6
|
+
export type EffectiveToolDiscoveryMode = Exclude<ToolDiscoveryModeSetting, "auto">;
|
|
7
|
+
export declare function countToolsForAutoDiscovery(toolNames: Iterable<string>): number;
|
|
8
|
+
export declare function resolveEffectiveToolDiscoveryMode(settings: Settings, toolCount: number): EffectiveToolDiscoveryMode;
|
|
@@ -21,7 +21,11 @@ interface TarStorage {
|
|
|
21
21
|
}
|
|
22
22
|
interface ZipStorage {
|
|
23
23
|
type: "zip";
|
|
24
|
-
|
|
24
|
+
archivePath: string;
|
|
25
|
+
compressedSize: number;
|
|
26
|
+
compression: number;
|
|
27
|
+
flags: number;
|
|
28
|
+
localHeaderOffset: number;
|
|
25
29
|
}
|
|
26
30
|
type EntryStorage = TarStorage | ZipStorage;
|
|
27
31
|
interface ArchiveIndexEntry extends ArchiveNode {
|
|
@@ -7,6 +7,18 @@
|
|
|
7
7
|
* - `"always"`: unconditionally (useful for viewers that support OSC 8 without advertising it)
|
|
8
8
|
*/
|
|
9
9
|
export declare function isHyperlinkEnabled(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Wrap `displayText` in an OSC 8 hyperlink pointing at `uri`.
|
|
12
|
+
*
|
|
13
|
+
* Returns `displayText` unchanged when hyperlinks are disabled, `uri` contains
|
|
14
|
+
* terminal control bytes, or `displayText` already contains an OSC 8 sequence.
|
|
15
|
+
*/
|
|
16
|
+
export declare function uriHyperlink(uri: string, displayText: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Wrap `displayText` in an OSC 8 hyperlink pointing at an HTTP(S) URL.
|
|
19
|
+
* `www.example.com` inputs are linked as `https://www.example.com`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function urlHyperlink(url: string, displayText: string): string;
|
|
10
22
|
/**
|
|
11
23
|
* Wrap `displayText` in an OSC 8 hyperlink pointing at the given absolute file path.
|
|
12
24
|
*
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
7
7
|
import type { RenderResultOptions } from "../../extensibility/custom-tools/types";
|
|
8
|
-
import type
|
|
8
|
+
import { type Theme } from "../../modes/theme/theme";
|
|
9
9
|
import type { SearchResponse } from "./types";
|
|
10
10
|
export interface SearchRenderDetails {
|
|
11
11
|
response: SearchResponse;
|
|
@@ -20,7 +20,6 @@ export declare function renderSearchResult(result: {
|
|
|
20
20
|
details?: SearchRenderDetails;
|
|
21
21
|
}, options: RenderResultOptions, theme: Theme, args?: {
|
|
22
22
|
query?: string;
|
|
23
|
-
allowLongAnswer?: boolean;
|
|
24
23
|
maxAnswerLines?: number;
|
|
25
24
|
}): Component;
|
|
26
25
|
/** Render web search call (query preview) */
|
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": "15.9.
|
|
4
|
+
"version": "15.9.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",
|
|
@@ -47,14 +47,14 @@
|
|
|
47
47
|
"@agentclientprotocol/sdk": "0.22.1",
|
|
48
48
|
"@babel/parser": "^7.29.7",
|
|
49
49
|
"@mozilla/readability": "^0.6.0",
|
|
50
|
-
"@oh-my-pi/hashline": "15.9.
|
|
51
|
-
"@oh-my-pi/omp-stats": "15.9.
|
|
52
|
-
"@oh-my-pi/pi-agent-core": "15.9.
|
|
53
|
-
"@oh-my-pi/pi-ai": "15.9.
|
|
54
|
-
"@oh-my-pi/pi-mnemopi": "15.9.
|
|
55
|
-
"@oh-my-pi/pi-natives": "15.9.
|
|
56
|
-
"@oh-my-pi/pi-tui": "15.9.
|
|
57
|
-
"@oh-my-pi/pi-utils": "15.9.
|
|
50
|
+
"@oh-my-pi/hashline": "15.9.5",
|
|
51
|
+
"@oh-my-pi/omp-stats": "15.9.5",
|
|
52
|
+
"@oh-my-pi/pi-agent-core": "15.9.5",
|
|
53
|
+
"@oh-my-pi/pi-ai": "15.9.5",
|
|
54
|
+
"@oh-my-pi/pi-mnemopi": "15.9.5",
|
|
55
|
+
"@oh-my-pi/pi-natives": "15.9.5",
|
|
56
|
+
"@oh-my-pi/pi-tui": "15.9.5",
|
|
57
|
+
"@oh-my-pi/pi-utils": "15.9.5",
|
|
58
58
|
"@opentelemetry/api": "^1.9.1",
|
|
59
59
|
"@opentelemetry/context-async-hooks": "^2.7.1",
|
|
60
60
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Classify an install spec as a marketplace plugin reference or
|
|
2
|
+
* Classify an install spec as a local path, marketplace plugin reference, or
|
|
3
|
+
* plain npm package.
|
|
3
4
|
*
|
|
4
5
|
* Rules (applied in order):
|
|
6
|
+
* 0. Looks like a filesystem path (`.`, `..`, `./…`, `..\…`, `/…`, `~/…`,
|
|
7
|
+
* `C:\…`, `\\unc`) -> local. Routed through `PluginManager.link()` so the
|
|
8
|
+
* `omp plugin install <path>` and `omp plugin link <path>` flows agree.
|
|
5
9
|
* 1. Starts with `@` (scoped npm) -> always npm.
|
|
6
10
|
* 2. Contains `@` after the first character -> split on the LAST `@`.
|
|
7
11
|
* If the right-hand side is a known marketplace name, it's a marketplace ref.
|
|
@@ -25,10 +29,32 @@ const NPM_DIST_TAGS = new Set([
|
|
|
25
29
|
// Semver-like: starts with digit, or contains version range prefixes
|
|
26
30
|
const LOOKS_LIKE_VERSION = /^[\d~^>=<]/;
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Detect specs that name a filesystem path rather than a package: bare `.` /
|
|
34
|
+
* `..`, cwd-relative (`./`, `../`, `.\`, `..\`), absolute (`/`, `C:\`, `C:/`,
|
|
35
|
+
* UNC `\\`), and tilde-prefixed (`~`, `~/`, `~\`). Tilde paths still rely on
|
|
36
|
+
* the shell or the caller for expansion — we only classify them so they reach
|
|
37
|
+
* the link path instead of npm-name validation.
|
|
38
|
+
*/
|
|
39
|
+
function isLocalPathSpec(spec: string): boolean {
|
|
40
|
+
if (spec === "." || spec === ".." || spec === "~") return true;
|
|
41
|
+
if (spec.startsWith("./") || spec.startsWith("../")) return true;
|
|
42
|
+
if (spec.startsWith(".\\") || spec.startsWith("..\\")) return true;
|
|
43
|
+
if (spec.startsWith("~/") || spec.startsWith("~\\")) return true;
|
|
44
|
+
if (spec.startsWith("/")) return true;
|
|
45
|
+
if (spec.startsWith("\\\\")) return true;
|
|
46
|
+
if (/^[A-Za-z]:[\\/]/.test(spec)) return true;
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type ClassifiedInstallTarget =
|
|
51
|
+
| { type: "local"; path: string }
|
|
52
|
+
| { type: "marketplace"; name: string; marketplace: string }
|
|
53
|
+
| { type: "npm"; spec: string };
|
|
54
|
+
|
|
55
|
+
export function classifyInstallTarget(spec: string, knownMarketplaces: Set<string>): ClassifiedInstallTarget {
|
|
56
|
+
// Rule 0: filesystem path — bypass npm/marketplace validation entirely.
|
|
57
|
+
if (isLocalPathSpec(spec)) return { type: "local", path: spec };
|
|
32
58
|
// Rule 1: scoped npm package — @ at position 0 is never a marketplace separator.
|
|
33
59
|
if (spec.startsWith("@")) return { type: "npm", spec };
|
|
34
60
|
// Rule 2: @ somewhere after the first character.
|