@oh-my-pi/pi-coding-agent 16.1.3 → 16.1.4
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 +14 -0
- package/dist/cli.js +2378 -2378
- package/dist/types/modes/components/cache-invalidation-marker.d.ts +23 -10
- package/dist/types/modes/components/status-line/component.d.ts +2 -3
- package/dist/types/sdk.d.ts +12 -0
- package/dist/types/session/agent-session.d.ts +2 -0
- package/dist/types/session/tool-choice-queue.d.ts +2 -0
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tui/hyperlink.d.ts +3 -2
- package/package.json +12 -12
- package/src/cli/bench-cli.ts +33 -2
- package/src/cli/dry-balance-cli.ts +4 -2
- package/src/extensibility/plugins/manager.ts +82 -22
- package/src/modes/components/cache-invalidation-marker.ts +31 -15
- package/src/modes/components/custom-editor.test.ts +4 -3
- package/src/modes/components/status-line/component.ts +64 -18
- package/src/sdk.ts +33 -0
- package/src/session/agent-session.ts +5 -0
- package/src/session/tool-choice-queue.ts +6 -0
- package/src/tools/index.ts +2 -0
- package/src/tools/resolve.ts +1 -0
- package/src/tui/hyperlink.ts +6 -3
package/src/sdk.ts
CHANGED
|
@@ -687,6 +687,37 @@ export async function loadSessionExtensions(
|
|
|
687
687
|
return result;
|
|
688
688
|
}
|
|
689
689
|
|
|
690
|
+
/**
|
|
691
|
+
* Load discovered/configured extensions and register their providers into
|
|
692
|
+
* `modelRegistry`, then discover the dynamic provider catalogs. One-shot CLIs
|
|
693
|
+
* (`omp bench`, dry-balance) build a bare {@link ModelRegistry} that only knows
|
|
694
|
+
* built-in catalog providers; without this, providers contributed by an
|
|
695
|
+
* extension (e.g. a custom OpenAI-compatible provider under
|
|
696
|
+
* `~/.omp/agent/extensions/`) never reach model resolution. Mirrors the
|
|
697
|
+
* session / `omp models` path: drain the queued provider registrations, then
|
|
698
|
+
* `refreshRuntimeProviders` so dynamically-discovered models exist before
|
|
699
|
+
* selectors are resolved.
|
|
700
|
+
*/
|
|
701
|
+
export async function loadCliExtensionProviders(
|
|
702
|
+
modelRegistry: ModelRegistry,
|
|
703
|
+
settings: Settings,
|
|
704
|
+
cwd: string,
|
|
705
|
+
options: Pick<CreateAgentSessionOptions, "disableExtensionDiscovery" | "additionalExtensionPaths"> = {},
|
|
706
|
+
): Promise<void> {
|
|
707
|
+
const eventBus = new EventBus();
|
|
708
|
+
const extensionsResult = await loadSessionExtensions(options, cwd, settings, eventBus);
|
|
709
|
+
const activeSources = extensionsResult.extensions.map(extension => extension.path);
|
|
710
|
+
modelRegistry.syncExtensionSources(activeSources);
|
|
711
|
+
for (const sourceId of new Set(activeSources)) {
|
|
712
|
+
modelRegistry.clearSourceRegistrations(sourceId);
|
|
713
|
+
}
|
|
714
|
+
for (const { name, config, sourceId } of extensionsResult.runtime.pendingProviderRegistrations) {
|
|
715
|
+
modelRegistry.registerProvider(name, config, sourceId);
|
|
716
|
+
}
|
|
717
|
+
extensionsResult.runtime.pendingProviderRegistrations = [];
|
|
718
|
+
await modelRegistry.refreshRuntimeProviders();
|
|
719
|
+
}
|
|
720
|
+
|
|
690
721
|
/**
|
|
691
722
|
* Discover skills from cwd and agentDir.
|
|
692
723
|
*/
|
|
@@ -1518,6 +1549,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1518
1549
|
timestamp: Date.now(),
|
|
1519
1550
|
}),
|
|
1520
1551
|
peekQueueInvoker: () => session.peekQueueInvoker(),
|
|
1552
|
+
peekPendingInvoker: () => session.peekPendingInvoker(),
|
|
1553
|
+
clearPendingInvokers: () => session.clearPendingInvokers(),
|
|
1521
1554
|
peekStandingResolveHandler: () => session.peekStandingResolveHandler(),
|
|
1522
1555
|
setStandingResolveHandler: handler => session.setStandingResolveHandler(handler),
|
|
1523
1556
|
allocateOutputArtifact: async toolType => {
|
|
@@ -2181,6 +2181,11 @@ export class AgentSession {
|
|
|
2181
2181
|
return this.#toolChoiceQueue.peekPendingInvoker();
|
|
2182
2182
|
}
|
|
2183
2183
|
|
|
2184
|
+
/** Clear stale non-forcing pending preview invokers after `resolve` proves none can run. */
|
|
2185
|
+
clearPendingInvokers(): void {
|
|
2186
|
+
this.#toolChoiceQueue.clearPendingInvokers();
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2184
2189
|
/**
|
|
2185
2190
|
* Force the next model call to target a specific active tool, then terminate
|
|
2186
2191
|
* the agent loop. Pushes a two-step sequence [forced, "none"] so the model
|
|
@@ -231,6 +231,12 @@ export class ToolChoiceQueue {
|
|
|
231
231
|
this.#pendingInvokers = this.#pendingInvokers.filter(p => p.id !== id);
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
+
/** Drop every pending preview invoker without touching hard tool-choice directives. */
|
|
235
|
+
clearPendingInvokers(): void {
|
|
236
|
+
if (this.#pendingInvokers.length === 0) return;
|
|
237
|
+
this.#pendingInvokers = [];
|
|
238
|
+
}
|
|
239
|
+
|
|
234
240
|
/** True when at least one non-forcing pending preview is registered. */
|
|
235
241
|
get hasPendingInvoker(): boolean {
|
|
236
242
|
return this.#pendingInvokers.length > 0;
|
package/src/tools/index.ts
CHANGED
|
@@ -316,6 +316,8 @@ export interface ToolSession {
|
|
|
316
316
|
* tool dispatches to it so a staged preview resolves WITHOUT forcing tool_choice — the
|
|
317
317
|
* agent-loop's SoftToolRequirement lifecycle owns reminder injection and escalation. */
|
|
318
318
|
peekPendingInvoker?(): ((input: unknown) => Promise<unknown> | unknown) | undefined;
|
|
319
|
+
/** Clear stale pending preview markers when `resolve` cannot dispatch them. */
|
|
320
|
+
clearPendingInvokers?(): void;
|
|
319
321
|
/** Peek the long-lived "standing" resolve handler registered by a mode (e.g. plan mode).
|
|
320
322
|
* Consulted by the `resolve` tool as a fallback when no queue invoker is in flight,
|
|
321
323
|
* letting modes accept `resolve` invocations without forcing the tool choice every turn. */
|
package/src/tools/resolve.ts
CHANGED
|
@@ -212,6 +212,7 @@ export class ResolveTool implements AgentTool<typeof resolveSchema, ResolveToolD
|
|
|
212
212
|
this.session.peekPendingInvoker?.() ??
|
|
213
213
|
this.session.peekStandingResolveHandler?.();
|
|
214
214
|
if (!invoker) {
|
|
215
|
+
this.session.clearPendingInvokers?.();
|
|
215
216
|
// `discard` is a request to cancel/abort a staged action. When nothing is
|
|
216
217
|
// pending, the desired end-state (no staged change) already holds, so honor
|
|
217
218
|
// it as a successful cancellation instead of surfacing a hard error to the
|
package/src/tui/hyperlink.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import * as url from "node:url";
|
|
9
9
|
import { TERMINAL } from "@oh-my-pi/pi-tui";
|
|
10
|
-
import { settings } from "../config/settings";
|
|
10
|
+
import { isSettingsInitialized, settings } from "../config/settings";
|
|
11
11
|
import {
|
|
12
12
|
LocalProtocolHandler,
|
|
13
13
|
memoryRootsFromRegistry,
|
|
@@ -45,8 +45,10 @@ function buildFileUri(filePath: string, opts?: { line?: number; col?: number }):
|
|
|
45
45
|
* - `"off"`: never
|
|
46
46
|
* - `"auto"`: when `process.stdout.isTTY`, `NO_COLOR` is unset, and the detected terminal reports hyperlink support
|
|
47
47
|
* - `"always"`: unconditionally (useful for viewers that support OSC 8 without advertising it)
|
|
48
|
+
* Before settings initialization, returns false so early render paths stay plain text.
|
|
48
49
|
*/
|
|
49
50
|
export function isHyperlinkEnabled(): boolean {
|
|
51
|
+
if (!isSettingsInitialized()) return false;
|
|
50
52
|
const mode = settings.get("tui.hyperlinks");
|
|
51
53
|
if (mode === "off") return false;
|
|
52
54
|
if (mode === "always") return true;
|
|
@@ -104,10 +106,11 @@ export function urlHyperlink(url: string, displayText: string): string {
|
|
|
104
106
|
* Wrap `displayText` in an OSC 8 hyperlink pointing at an HTTP(S) URL,
|
|
105
107
|
* bypassing terminal capability auto-detection. Used for auth prompts where
|
|
106
108
|
* an inert "click" label blocks login on terminals whose capabilities are
|
|
107
|
-
* not advertised. Still returns plain text
|
|
108
|
-
* opted out via `tui.hyperlinks=off`.
|
|
109
|
+
* not advertised. Still returns plain text before settings initialization or
|
|
110
|
+
* when the user has explicitly opted out via `tui.hyperlinks=off`.
|
|
109
111
|
*/
|
|
110
112
|
export function urlHyperlinkAlways(url: string, displayText: string): string {
|
|
113
|
+
if (!isSettingsInitialized()) return displayText;
|
|
111
114
|
if (settings.get("tui.hyperlinks") === "off") return displayText;
|
|
112
115
|
const normalized = url.match(/^www\./i) ? `https://${url}` : url;
|
|
113
116
|
try {
|