pi2dsh 0.13.2 → 0.13.3
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/README.md +22 -19
- package/README.zh.md +18 -15
- package/dist/{analyzer-CJFwQlSG.mjs → analyzer-DBtUYKI1.mjs} +2 -2
- package/dist/{analyzer-CJFwQlSG.mjs.map → analyzer-DBtUYKI1.mjs.map} +1 -1
- package/dist/anthropic-messages-CaYTgvLF.mjs +6436 -0
- package/dist/anthropic-messages-CaYTgvLF.mjs.map +1 -0
- package/dist/azure-openai-responses-HKWkzl2m.mjs +208 -0
- package/dist/azure-openai-responses-HKWkzl2m.mjs.map +1 -0
- package/dist/cli.mjs +3 -2
- package/dist/cli.mjs.map +1 -1
- package/dist/compat/pi-ai.d.mts +3 -2636
- package/dist/compat/pi-ai.mjs +3 -2
- package/dist/compat/pi-coding-agent.d.mts +2 -2
- package/dist/compat/pi-coding-agent.mjs +2 -2
- package/dist/{mcp-config-_idn-pzI.mjs → compatibility-Bz6ZXA7F.mjs} +8 -185
- package/dist/compatibility-Bz6ZXA7F.mjs.map +1 -0
- package/dist/completionchunk-Dhk56lZl.mjs +5212 -0
- package/dist/completionchunk-Dhk56lZl.mjs.map +1 -0
- package/dist/{credentials-oauth-Txs6oew8.mjs → credentials-oauth-CAohSLcB.mjs} +3 -3
- package/dist/{credentials-oauth-Txs6oew8.mjs.map → credentials-oauth-CAohSLcB.mjs.map} +1 -1
- package/dist/credentials-oauth.mjs +1 -1
- package/dist/deferred-tools-BD4g5QUx.mjs +32 -0
- package/dist/deferred-tools-BD4g5QUx.mjs.map +1 -0
- package/dist/diagnostics-BqYkodgB.mjs +35 -0
- package/dist/diagnostics-BqYkodgB.mjs.map +1 -0
- package/dist/dist-QBBA-dL_.mjs +1246 -0
- package/dist/dist-QBBA-dL_.mjs.map +1 -0
- package/dist/error-body-DKA3lknR.mjs +104 -0
- package/dist/error-body-DKA3lknR.mjs.map +1 -0
- package/dist/event-stream-QxN1yvIF.mjs +64 -0
- package/dist/event-stream-QxN1yvIF.mjs.map +1 -0
- package/dist/from-BCscBQ9P.mjs +3856 -0
- package/dist/from-BCscBQ9P.mjs.map +1 -0
- package/dist/github-copilot-headers-CZo2QHrt.mjs +25 -0
- package/dist/github-copilot-headers-CZo2QHrt.mjs.map +1 -0
- package/dist/google-generative-ai-2gCFYp-t.mjs +356 -0
- package/dist/google-generative-ai-2gCFYp-t.mjs.map +1 -0
- package/dist/google-shared-75IdVyrx.mjs +29041 -0
- package/dist/google-shared-75IdVyrx.mjs.map +1 -0
- package/dist/google-vertex-Bhyo4z2i.mjs +400 -0
- package/dist/google-vertex-Bhyo4z2i.mjs.map +1 -0
- package/dist/hash-Dbggamac.mjs +19 -0
- package/dist/hash-Dbggamac.mjs.map +1 -0
- package/dist/headers-CPzZhJQn.mjs +17 -0
- package/dist/headers-CPzZhJQn.mjs.map +1 -0
- package/dist/host.d.mts +12 -2
- package/dist/host.d.mts.map +1 -1
- package/dist/host.mjs +43 -5
- package/dist/host.mjs.map +1 -1
- package/dist/index.d.mts +5 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +40 -16
- package/dist/index.mjs.map +1 -1
- package/dist/json-parse-CZ0U0sj_.mjs +384 -0
- package/dist/json-parse-CZ0U0sj_.mjs.map +1 -0
- package/dist/mcp-config-jmzbgdHa.mjs +181 -0
- package/dist/mcp-config-jmzbgdHa.mjs.map +1 -0
- package/dist/mistral-conversations-DJyeTo8C.mjs +36921 -0
- package/dist/mistral-conversations-DJyeTo8C.mjs.map +1 -0
- package/dist/multipart-parser-SRcGkVuX.mjs +301 -0
- package/dist/multipart-parser-SRcGkVuX.mjs.map +1 -0
- package/dist/{pi-ai-D7PqVeWs.mjs → openai-DkzRh5_G.mjs} +78 -5063
- package/dist/openai-DkzRh5_G.mjs.map +1 -0
- package/dist/openai-codex-responses-DedxQjNG.mjs +1220 -0
- package/dist/openai-codex-responses-DedxQjNG.mjs.map +1 -0
- package/dist/openai-completions-DrjrWRdX.mjs +945 -0
- package/dist/openai-completions-DrjrWRdX.mjs.map +1 -0
- package/dist/openai-prompt-cache-BDWtZRKh.mjs +11 -0
- package/dist/openai-prompt-cache-BDWtZRKh.mjs.map +1 -0
- package/dist/openai-responses-BRdGpBX6.mjs +251 -0
- package/dist/openai-responses-BRdGpBX6.mjs.map +1 -0
- package/dist/openai-responses-shared-BmnSvdKL.mjs +570 -0
- package/dist/openai-responses-shared-BmnSvdKL.mjs.map +1 -0
- package/dist/otel-CBhmS-NR.mjs +24935 -0
- package/dist/otel-CBhmS-NR.mjs.map +1 -0
- package/dist/pi-ai-CfokFhIL.d.mts +2673 -0
- package/dist/pi-ai-CfokFhIL.d.mts.map +1 -0
- package/dist/pi-ai-Dh7HUxbt.mjs +3239 -0
- package/dist/pi-ai-Dh7HUxbt.mjs.map +1 -0
- package/dist/{pi-coding-agent-B0PT23gE.d.mts → pi-coding-agent-69yY0ke-.d.mts} +4 -2
- package/dist/{pi-coding-agent-B0PT23gE.d.mts.map → pi-coding-agent-69yY0ke-.d.mts.map} +1 -1
- package/dist/{pi-coding-agent-BVZu0dHG.mjs → pi-coding-agent-Cvez0jkF.mjs} +0 -0
- package/dist/{pi-coding-agent-BVZu0dHG.mjs.map → pi-coding-agent-Cvez0jkF.mjs.map} +1 -1
- package/dist/pi-messages-D61G2tgs.mjs +307 -0
- package/dist/pi-messages-D61G2tgs.mjs.map +1 -0
- package/dist/provider-env-C72pF4vP.mjs +40 -0
- package/dist/provider-env-C72pF4vP.mjs.map +1 -0
- package/dist/provider-retry-Cw6YJ4cr.mjs +80 -0
- package/dist/provider-retry-Cw6YJ4cr.mjs.map +1 -0
- package/dist/rolldown-runtime-CTfmNlz1.mjs +44 -0
- package/dist/{runtime-DEjs_Qlf.mjs → runtime-Dd2KhoX-.mjs} +659 -125
- package/dist/runtime-Dd2KhoX-.mjs.map +1 -0
- package/dist/runtime.d.mts +135 -26
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/simple-options-B_GO8FDE.mjs +456 -0
- package/dist/simple-options-B_GO8FDE.mjs.map +1 -0
- package/dist/src-DlTagfW5.mjs +1186 -0
- package/dist/src-DlTagfW5.mjs.map +1 -0
- package/dist/{types-7IWJPPvS.d.mts → types-B9VBF8le.d.mts} +2 -9
- package/dist/{types-7IWJPPvS.d.mts.map → types-B9VBF8le.d.mts.map} +1 -1
- package/package.json +2 -2
- package/dist/compat/pi-ai.d.mts.map +0 -1
- package/dist/mcp-config-_idn-pzI.mjs.map +0 -1
- package/dist/pi-ai-D7PqVeWs.mjs.map +0 -1
- package/dist/runtime-DEjs_Qlf.mjs.map +0 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import { P as generateBranchSummary, Tn as PiCapabilityError, b as Theme, d as ExtensionRunner, w as __setSubagentSessionFactory, wn as CapabilityLedger } from "./pi-coding-agent-BVZu0dHG.mjs";
|
|
2
|
+
import { En as PiCapabilityError, F as generateBranchSummary, Tn as CapabilityLedger, b as Theme, d as ExtensionRunner, w as __runWithSubagentSessionFactory } from "./pi-coding-agent-Cvez0jkF.mjs";
|
|
4
3
|
import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
|
|
5
|
-
import {
|
|
4
|
+
import { $ as isContextOverflow, Q as AssistantMessageEventStream, S as getSupportedThinkingLevels, c as builtinProviders, o as __runWithPiAiRuntime, r as __createPiAiRuntimeRegistry } from "./pi-ai-Dh7HUxbt.mjs";
|
|
5
|
+
import { W as getKeybindings } from "./pi-tui-DruSeKmd.mjs";
|
|
6
|
+
import { a as FileCredentialStore, c as providerSupportsOAuth, i as oauthCredentialRef, l as resolvePiProviderAuth, o as joinSignals, s as loginPiProvider, u as storedOAuthCredential } from "./credentials-oauth-CAohSLcB.mjs";
|
|
6
7
|
import { createRequire } from "node:module";
|
|
7
8
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
8
9
|
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
@@ -13,6 +14,7 @@ import { EventEmitter } from "node:events";
|
|
|
13
14
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
14
15
|
import { createJiti } from "jiti";
|
|
15
16
|
import { CONTEXT_WINDOW_EXCEEDED_CODE, EMPTY_RESPONSE_CODE, LlmError, QUOTA_EXCEEDED_CODE, createUserMessage, isContextWindowExceededError, isQuotaExceededError } from "@deepseek-ai/dsh-llm";
|
|
17
|
+
import { scopeOf } from "@deepseek-ai/dsh-scope";
|
|
16
18
|
import { renderPrompt } from "@deepseek-ai/dsh-system-prompt";
|
|
17
19
|
import { randomUUID } from "node:crypto";
|
|
18
20
|
import { foldSurface } from "@deepseek-ai/dsh-session";
|
|
@@ -2274,7 +2276,12 @@ function piProviderDshAdapter(providerId, provider, host) {
|
|
|
2274
2276
|
async *stream(options) {
|
|
2275
2277
|
const auth = (await host.resolveAuth())?.auth;
|
|
2276
2278
|
const modelId = String(options.model ?? "");
|
|
2277
|
-
|
|
2279
|
+
let model = providerModels(provider).find((entry) => entry.id === modelId);
|
|
2280
|
+
if (model === void 0 && host.ensureModel !== void 0) {
|
|
2281
|
+
await host.ensureModel(modelId);
|
|
2282
|
+
model = providerModels(provider).find((entry) => entry.id === modelId);
|
|
2283
|
+
}
|
|
2284
|
+
model ??= {
|
|
2278
2285
|
id: modelId,
|
|
2279
2286
|
provider: providerId
|
|
2280
2287
|
};
|
|
@@ -2297,6 +2304,7 @@ function piProviderDshAdapter(providerId, provider, host) {
|
|
|
2297
2304
|
...host.beforeProviderRequest === void 0 ? {} : { onPayload: (payload) => host.beforeProviderRequest(payload, {
|
|
2298
2305
|
provider: providerId,
|
|
2299
2306
|
model,
|
|
2307
|
+
...typeof options.sessionId === "string" ? { sessionId: options.sessionId } : {},
|
|
2300
2308
|
...options.signal instanceof AbortSignal ? { signal: options.signal } : {}
|
|
2301
2309
|
}) },
|
|
2302
2310
|
...effort === void 0 || effort === "off" ? {} : { reasoning: effort }
|
|
@@ -2654,6 +2662,220 @@ function registerPiProviderRoute(options) {
|
|
|
2654
2662
|
}
|
|
2655
2663
|
}
|
|
2656
2664
|
//#endregion
|
|
2665
|
+
//#region src/tui-surfaces.ts
|
|
2666
|
+
function service(ctx, name) {
|
|
2667
|
+
try {
|
|
2668
|
+
return ctx.get(name, false);
|
|
2669
|
+
} catch {
|
|
2670
|
+
return;
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
function surfaceToken(value) {
|
|
2674
|
+
const normalized = value.toLowerCase().replace(/[^a-z0-9_-]+/gu, "-").replace(/^-+|-+$/gu, "");
|
|
2675
|
+
if (normalized.length === 0) return "entry";
|
|
2676
|
+
return /^[a-z]/u.test(normalized) ? normalized : `k-${normalized}`;
|
|
2677
|
+
}
|
|
2678
|
+
function sceneIdFor(packageName) {
|
|
2679
|
+
return `pi2dsh-${surfaceToken(packageName)}-custom`;
|
|
2680
|
+
}
|
|
2681
|
+
function statusKeyFor(packageName, key) {
|
|
2682
|
+
return `pi2dsh:${surfaceToken(packageName)}:${surfaceToken(key)}`;
|
|
2683
|
+
}
|
|
2684
|
+
function rawTerminalInput(input, key, event) {
|
|
2685
|
+
const keypress = event?.keypress;
|
|
2686
|
+
if (typeof keypress?.sequence === "string" && keypress.sequence.length > 0) return keypress.sequence;
|
|
2687
|
+
if (key.return === true) return "\r";
|
|
2688
|
+
if (key.escape === true) return "\x1B";
|
|
2689
|
+
if (key.tab === true) return " ";
|
|
2690
|
+
if (key.backspace === true) return "";
|
|
2691
|
+
if (key.upArrow === true) return "\x1B[A";
|
|
2692
|
+
if (key.downArrow === true) return "\x1B[B";
|
|
2693
|
+
if (key.rightArrow === true) return "\x1B[C";
|
|
2694
|
+
if (key.leftArrow === true) return "\x1B[D";
|
|
2695
|
+
if (key.ctrl === true && input.length === 1) {
|
|
2696
|
+
const code = input.toLowerCase().charCodeAt(0);
|
|
2697
|
+
if (code >= 97 && code <= 122) return String.fromCharCode(code - 96);
|
|
2698
|
+
}
|
|
2699
|
+
return input;
|
|
2700
|
+
}
|
|
2701
|
+
function preferredWidth(options) {
|
|
2702
|
+
const width = (typeof options?.overlayOptions === "function" ? options.overlayOptions() : options?.overlayOptions)?.width;
|
|
2703
|
+
return typeof width === "number" && Number.isFinite(width) && width > 0 ? Math.floor(width) : void 0;
|
|
2704
|
+
}
|
|
2705
|
+
/**
|
|
2706
|
+
* One package-scoped Pi custom-surface host backed by one dsh-TUI scene.
|
|
2707
|
+
* The MCP adapter is a consumer, not a special case: every component using
|
|
2708
|
+
* the public Pi component protocol follows the same path.
|
|
2709
|
+
*/
|
|
2710
|
+
var TuiSurfaceAdapter = class {
|
|
2711
|
+
packageName;
|
|
2712
|
+
instanceKey;
|
|
2713
|
+
sceneId;
|
|
2714
|
+
scenes;
|
|
2715
|
+
status;
|
|
2716
|
+
statusDisposers = /* @__PURE__ */ new Map();
|
|
2717
|
+
listeners = /* @__PURE__ */ new Set();
|
|
2718
|
+
unregisterScene;
|
|
2719
|
+
revision = 0;
|
|
2720
|
+
active;
|
|
2721
|
+
disposed = false;
|
|
2722
|
+
constructor(ctx, packageName, instanceKey) {
|
|
2723
|
+
this.packageName = packageName;
|
|
2724
|
+
this.instanceKey = instanceKey;
|
|
2725
|
+
const scenes = service(ctx, "tuiScenes");
|
|
2726
|
+
if (scenes === void 0) throw new Error("pi2dsh: dsh-TUI scene service is unavailable");
|
|
2727
|
+
this.scenes = scenes;
|
|
2728
|
+
this.status = service(ctx, "tuiStatus");
|
|
2729
|
+
this.sceneId = sceneIdFor(instanceKey === void 0 ? packageName : `${packageName}-${instanceKey}`);
|
|
2730
|
+
this.unregisterScene = scenes.register({
|
|
2731
|
+
id: this.sceneId,
|
|
2732
|
+
title: `${packageName} custom panel`,
|
|
2733
|
+
component: (props) => this.scene(props)
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2736
|
+
get available() {
|
|
2737
|
+
return !this.disposed;
|
|
2738
|
+
}
|
|
2739
|
+
subscribe(listener) {
|
|
2740
|
+
this.listeners.add(listener);
|
|
2741
|
+
return () => this.listeners.delete(listener);
|
|
2742
|
+
}
|
|
2743
|
+
snapshot() {
|
|
2744
|
+
return this.revision;
|
|
2745
|
+
}
|
|
2746
|
+
setStatus(key, text) {
|
|
2747
|
+
if (this.disposed || this.status === void 0) return;
|
|
2748
|
+
const dshKey = statusKeyFor(this.instanceKey === void 0 ? this.packageName : `${this.packageName}-${this.instanceKey}`, key);
|
|
2749
|
+
this.statusDisposers.get(dshKey)?.();
|
|
2750
|
+
this.statusDisposers.delete(dshKey);
|
|
2751
|
+
if (text === void 0) return;
|
|
2752
|
+
const dispose = this.status.set(dshKey, String(text));
|
|
2753
|
+
if (typeof dispose === "function") this.statusDisposers.set(dshKey, dispose);
|
|
2754
|
+
}
|
|
2755
|
+
custom(factory, theme, keybindings, options) {
|
|
2756
|
+
if (this.disposed) return Promise.resolve(void 0);
|
|
2757
|
+
this.finish(void 0);
|
|
2758
|
+
return new Promise((resolve, reject) => {
|
|
2759
|
+
const run = {
|
|
2760
|
+
options,
|
|
2761
|
+
resolve,
|
|
2762
|
+
reject
|
|
2763
|
+
};
|
|
2764
|
+
this.active = run;
|
|
2765
|
+
const driver = { requestRender: () => this.invalidate() };
|
|
2766
|
+
const done = (value) => this.finishFor(run, value);
|
|
2767
|
+
Promise.resolve().then(() => factory(driver, theme, keybindings, done)).then((component) => {
|
|
2768
|
+
if (this.active !== run) {
|
|
2769
|
+
component.dispose?.();
|
|
2770
|
+
return;
|
|
2771
|
+
}
|
|
2772
|
+
if (typeof component?.render !== "function") {
|
|
2773
|
+
this.failFor(run, /* @__PURE__ */ new TypeError("Pi custom component must implement render(width)"));
|
|
2774
|
+
return;
|
|
2775
|
+
}
|
|
2776
|
+
run.component = component;
|
|
2777
|
+
this.invalidate();
|
|
2778
|
+
if (!this.scenes.open(this.sceneId)) this.finishFor(run, void 0);
|
|
2779
|
+
}, (error) => this.failFor(run, error));
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
render(width) {
|
|
2783
|
+
const active = this.active;
|
|
2784
|
+
if (active?.component === void 0) return [];
|
|
2785
|
+
const available = Math.max(12, Math.floor(width) - 2);
|
|
2786
|
+
const requested = preferredWidth(active.options);
|
|
2787
|
+
return active.component.render(requested === void 0 ? available : Math.min(available, requested));
|
|
2788
|
+
}
|
|
2789
|
+
handleInput(data) {
|
|
2790
|
+
const component = this.active?.component;
|
|
2791
|
+
if (component === void 0) return;
|
|
2792
|
+
component.handleInput?.(data);
|
|
2793
|
+
component.invalidate?.();
|
|
2794
|
+
this.invalidate();
|
|
2795
|
+
}
|
|
2796
|
+
dispose() {
|
|
2797
|
+
if (this.disposed) return;
|
|
2798
|
+
this.disposed = true;
|
|
2799
|
+
this.finish(void 0);
|
|
2800
|
+
for (const dispose of this.statusDisposers.values()) dispose();
|
|
2801
|
+
this.statusDisposers.clear();
|
|
2802
|
+
this.unregisterScene();
|
|
2803
|
+
this.listeners.clear();
|
|
2804
|
+
}
|
|
2805
|
+
invalidate() {
|
|
2806
|
+
this.revision += 1;
|
|
2807
|
+
for (const listener of this.listeners) listener();
|
|
2808
|
+
}
|
|
2809
|
+
finish(value) {
|
|
2810
|
+
const active = this.active;
|
|
2811
|
+
if (active !== void 0) this.finishFor(active, value);
|
|
2812
|
+
}
|
|
2813
|
+
finishFor(run, value, closeScene = true) {
|
|
2814
|
+
if (this.active !== run) return;
|
|
2815
|
+
this.active = void 0;
|
|
2816
|
+
run.component?.dispose?.();
|
|
2817
|
+
if (closeScene) this.scenes.close();
|
|
2818
|
+
this.invalidate();
|
|
2819
|
+
run.resolve(value);
|
|
2820
|
+
}
|
|
2821
|
+
failFor(run, error) {
|
|
2822
|
+
if (this.active !== run) return;
|
|
2823
|
+
this.active = void 0;
|
|
2824
|
+
run.component?.dispose?.();
|
|
2825
|
+
this.scenes.close();
|
|
2826
|
+
this.invalidate();
|
|
2827
|
+
run.reject(error);
|
|
2828
|
+
}
|
|
2829
|
+
scene(props) {
|
|
2830
|
+
const { React, ui } = props;
|
|
2831
|
+
React.useSyncExternalStore((listener) => this.subscribe(listener), () => this.snapshot(), () => this.snapshot());
|
|
2832
|
+
React.useEffect(() => () => {
|
|
2833
|
+
const active = this.active;
|
|
2834
|
+
if (active !== void 0) this.finishFor(active, void 0, false);
|
|
2835
|
+
}, []);
|
|
2836
|
+
ui.useInput((input, key, event) => this.handleInput(rawTerminalInput(input, key, event)));
|
|
2837
|
+
const { columns } = ui.useTerminalSize();
|
|
2838
|
+
const lines = this.render(columns);
|
|
2839
|
+
const Line = ui.Ansi ?? ui.Text;
|
|
2840
|
+
return React.createElement(ui.Box, {
|
|
2841
|
+
flexDirection: "column",
|
|
2842
|
+
width: "100%",
|
|
2843
|
+
paddingX: 1
|
|
2844
|
+
}, ...lines.map((line, index) => React.createElement(Line, { key: index }, line)));
|
|
2845
|
+
}
|
|
2846
|
+
};
|
|
2847
|
+
/**
|
|
2848
|
+
* Attach lazily to dsh-TUI. Cordis reloads this child fiber whenever the
|
|
2849
|
+
* service implementation changes, so a TUI update cannot leave a stale scene
|
|
2850
|
+
* proxy in the bridge.
|
|
2851
|
+
*/
|
|
2852
|
+
function mountTuiSurfaceAdapter(ctx, packageName, publish, instanceKey) {
|
|
2853
|
+
const attach = (surfaceCtx) => {
|
|
2854
|
+
const adapter = new TuiSurfaceAdapter(surfaceCtx, packageName, instanceKey);
|
|
2855
|
+
publish(adapter);
|
|
2856
|
+
surfaceCtx.effect?.(() => () => {
|
|
2857
|
+
adapter.dispose();
|
|
2858
|
+
publish(void 0);
|
|
2859
|
+
});
|
|
2860
|
+
};
|
|
2861
|
+
if (service(ctx, "tuiScenes") !== void 0) {
|
|
2862
|
+
attach(ctx);
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2865
|
+
if (typeof ctx.inject === "function") {
|
|
2866
|
+
ctx.inject(["tuiScenes"], attach);
|
|
2867
|
+
return;
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
/**
|
|
2871
|
+
* dsh-TUI handles `/mcp` locally before it asks DSH's command registry. Until
|
|
2872
|
+
* it exposes a reserved-command seam, keep its native status command and make
|
|
2873
|
+
* an installed Pi MCP manager reachable as `/pi-mcp`.
|
|
2874
|
+
*/
|
|
2875
|
+
function commandNameForDshTui(name, tuiAvailable) {
|
|
2876
|
+
return tuiAvailable && name === "mcp" ? "pi-mcp" : name;
|
|
2877
|
+
}
|
|
2878
|
+
//#endregion
|
|
2657
2879
|
//#region src/runtime.ts
|
|
2658
2880
|
/** Fallback thread ids when a child session reports none. */
|
|
2659
2881
|
let sidePanelSerial = 0;
|
|
@@ -3042,9 +3264,8 @@ function contextFor(ctx, state, agent, signal, command = false, sessionOverride)
|
|
|
3042
3264
|
...prefill === void 0 ? {} : { detail: `Current text:\n${String(prefill)}` }
|
|
3043
3265
|
}),
|
|
3044
3266
|
setStatus: (key, text) => {
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
surfaces.setStatus(sessionIdOf(state, agent), state.packageName, String(key), text);
|
|
3267
|
+
state.shared.browserSurfaces?.setStatus(sessionIdOf(state, agent), state.packageName, String(key), text);
|
|
3268
|
+
state.tuiSurfaces?.setStatus(String(key), text);
|
|
3048
3269
|
},
|
|
3049
3270
|
setWidget: (key, content) => {
|
|
3050
3271
|
const surfaces = state.shared.browserSurfaces;
|
|
@@ -3063,7 +3284,11 @@ function contextFor(ctx, state, agent, signal, command = false, sessionOverride)
|
|
|
3063
3284
|
setFooter: (factory) => putSurface(ctx, state, agent, "footer", factory),
|
|
3064
3285
|
setHeader: (factory) => putSurface(ctx, state, agent, "header", factory),
|
|
3065
3286
|
setTitle: (title) => putSurface(ctx, state, agent, "title", title),
|
|
3066
|
-
custom: async () =>
|
|
3287
|
+
custom: async (factory, options) => {
|
|
3288
|
+
const surfaces = state.tuiSurfaces;
|
|
3289
|
+
if (surfaces === void 0 || typeof factory !== "function") return void 0;
|
|
3290
|
+
return surfaces.custom(factory, state.theme, getKeybindings(), options);
|
|
3291
|
+
},
|
|
3067
3292
|
pasteToEditor(text) {
|
|
3068
3293
|
const surfaces = state.shared.browserSurfaces;
|
|
3069
3294
|
const sessionId = sessionIdOf(state, agent);
|
|
@@ -3258,9 +3483,11 @@ function contextFor(ctx, state, agent, signal, command = false, sessionOverride)
|
|
|
3258
3483
|
}
|
|
3259
3484
|
},
|
|
3260
3485
|
ui,
|
|
3261
|
-
mode
|
|
3486
|
+
get mode() {
|
|
3487
|
+
return state.tuiSurfaces?.available === true ? "tui" : "rpc";
|
|
3488
|
+
},
|
|
3262
3489
|
get hasUI() {
|
|
3263
|
-
return humanAnswererAvailable(userQuestions, agent);
|
|
3490
|
+
return state.tuiSurfaces?.available === true || humanAnswererAvailable(userQuestions, agent);
|
|
3264
3491
|
},
|
|
3265
3492
|
cwd: contextCwd,
|
|
3266
3493
|
sessionManager: session === void 0 ? state.bridge.readonlySessionManager({
|
|
@@ -3461,8 +3688,8 @@ function contextFor(ctx, state, agent, signal, command = false, sessionOverride)
|
|
|
3461
3688
|
return { cancelled: false };
|
|
3462
3689
|
},
|
|
3463
3690
|
reload: async () => {
|
|
3464
|
-
const remounts = state.shared
|
|
3465
|
-
if (remounts
|
|
3691
|
+
const remounts = packageRemountsOf(ctx, state.shared);
|
|
3692
|
+
if (remounts.size === 0) return;
|
|
3466
3693
|
for (const [name, remount] of remounts) try {
|
|
3467
3694
|
await remount();
|
|
3468
3695
|
} catch (error) {
|
|
@@ -3481,10 +3708,19 @@ function contextFor(ctx, state, agent, signal, command = false, sessionOverride)
|
|
|
3481
3708
|
async function dispatch(state, eventName, event, eventContext) {
|
|
3482
3709
|
const results = [];
|
|
3483
3710
|
const agent = eventContext.__agent;
|
|
3484
|
-
for (const handler of state.handlers.get(eventName) ?? []) results.push(await state
|
|
3711
|
+
for (const handler of state.handlers.get(eventName) ?? []) results.push(await runInPiRuntime(state, agent, () => handler(event, eventContext)));
|
|
3485
3712
|
return results;
|
|
3486
3713
|
}
|
|
3487
3714
|
/**
|
|
3715
|
+
* Bind every compatibility singleton to this exact Agent runtime for the
|
|
3716
|
+
* duration of extension-owned work. AsyncLocalStorage follows promises and
|
|
3717
|
+
* detached work spawned inside the callback, so two live Agents cannot
|
|
3718
|
+
* overwrite each other's model bridge or child-session factory.
|
|
3719
|
+
*/
|
|
3720
|
+
function runInPiRuntime(state, agent, callback) {
|
|
3721
|
+
return state.agentScope.run(agent, () => __runWithSubagentSessionFactory(state.subagentSessionFactory, () => __runWithPiAiRuntime(state.llmBridge, state.piAiRegistry, callback)));
|
|
3722
|
+
}
|
|
3723
|
+
/**
|
|
3488
3724
|
* Pi's request-body event is a waterfall over the body the provider transport
|
|
3489
3725
|
* will actually send. Only package-registered Pi transports expose that body
|
|
3490
3726
|
* through SimpleStreamOptions.onPayload; native DSH adapters build it behind
|
|
@@ -3499,7 +3735,7 @@ async function dispatchBeforeProviderRequest(ctx, state, payload, request) {
|
|
|
3499
3735
|
provider: request.provider
|
|
3500
3736
|
};
|
|
3501
3737
|
for (const handler of state.handlers.get("before_provider_request") ?? []) try {
|
|
3502
|
-
const result = await state
|
|
3738
|
+
const result = await runInPiRuntime(state, agent, () => handler({
|
|
3503
3739
|
type: "before_provider_request",
|
|
3504
3740
|
payload: current
|
|
3505
3741
|
}, eventContext));
|
|
@@ -3509,6 +3745,14 @@ async function dispatchBeforeProviderRequest(ctx, state, payload, request) {
|
|
|
3509
3745
|
}
|
|
3510
3746
|
return current;
|
|
3511
3747
|
}
|
|
3748
|
+
/** Run Pi's provider-body waterfall through every package runtime of one Agent. */
|
|
3749
|
+
async function dispatchHostProviderRequest(ctx, shared, fallback, payload, request) {
|
|
3750
|
+
const scoped = request.sessionId === void 0 ? void 0 : shared.runtimeStatesBySession.get(request.sessionId);
|
|
3751
|
+
const states = scoped === void 0 || scoped.size === 0 ? [fallback] : [...scoped];
|
|
3752
|
+
let current = payload;
|
|
3753
|
+
for (const state of states) current = await dispatchBeforeProviderRequest(ctx, state, current, request);
|
|
3754
|
+
return current;
|
|
3755
|
+
}
|
|
3512
3756
|
/**
|
|
3513
3757
|
* What triggered a compaction, in Pi's vocabulary.
|
|
3514
3758
|
*
|
|
@@ -3611,41 +3855,167 @@ async function messageFromSessionEvent(ctx, event) {
|
|
|
3611
3855
|
function sourceReason(value) {
|
|
3612
3856
|
return value === "resume" ? "resume" : value === "fork" ? "fork" : "startup";
|
|
3613
3857
|
}
|
|
3858
|
+
/**
|
|
3859
|
+
* Claim Pi's once-per-session `session_start` event.
|
|
3860
|
+
*
|
|
3861
|
+
* dsh-TUI can execute a slash command before DSH starts the first model turn,
|
|
3862
|
+
* so `agent/session-start` has not necessarily been announced yet. Pi, by
|
|
3863
|
+
* contrast, announces `session_start` before the user can execute a command.
|
|
3864
|
+
* The command bridge uses this same claim before invoking a Pi command; when
|
|
3865
|
+
* DSH later announces the real agent lifecycle, the durable session id keeps
|
|
3866
|
+
* the second path from restarting the extension.
|
|
3867
|
+
*/
|
|
3868
|
+
function claimPiSessionStart(state, agent) {
|
|
3869
|
+
const id = agentSession(agent)?.id;
|
|
3870
|
+
if (typeof id === "string") {
|
|
3871
|
+
if (state.startedSessions.has(id)) return false;
|
|
3872
|
+
state.startedSessions.add(id);
|
|
3873
|
+
return true;
|
|
3874
|
+
}
|
|
3875
|
+
if (typeof agent === "object" && agent !== null) {
|
|
3876
|
+
if (state.startedSessionlessAgents.has(agent)) return false;
|
|
3877
|
+
state.startedSessionlessAgents.add(agent);
|
|
3878
|
+
return true;
|
|
3879
|
+
}
|
|
3880
|
+
return false;
|
|
3881
|
+
}
|
|
3882
|
+
async function ensurePiSessionStarted(ctx, state, agent, signal) {
|
|
3883
|
+
await startPiSession(ctx, state, agent, "startup", signal);
|
|
3884
|
+
}
|
|
3885
|
+
function inFlightPiSessionStart(state, agent) {
|
|
3886
|
+
const id = agentSession(agent)?.id;
|
|
3887
|
+
if (typeof id === "string") return state.sessionStartTasks.get(id);
|
|
3888
|
+
if (typeof agent === "object" && agent !== null) return state.sessionlessStartTasks.get(agent);
|
|
3889
|
+
}
|
|
3890
|
+
function rememberPiSessionStart(state, agent, task) {
|
|
3891
|
+
const id = agentSession(agent)?.id;
|
|
3892
|
+
if (typeof id === "string") state.sessionStartTasks.set(id, task);
|
|
3893
|
+
else if (typeof agent === "object" && agent !== null) state.sessionlessStartTasks.set(agent, task);
|
|
3894
|
+
}
|
|
3895
|
+
function forgetPiSessionStart(state, agent, task) {
|
|
3896
|
+
const id = agentSession(agent)?.id;
|
|
3897
|
+
if (typeof id === "string") {
|
|
3898
|
+
if (state.sessionStartTasks.get(id) === task) state.sessionStartTasks.delete(id);
|
|
3899
|
+
} else if (typeof agent === "object" && agent !== null && state.sessionlessStartTasks.get(agent) === task) state.sessionlessStartTasks.delete(agent);
|
|
3900
|
+
}
|
|
3901
|
+
function releasePiSessionClaim(state, agent) {
|
|
3902
|
+
const id = agentSession(agent)?.id;
|
|
3903
|
+
if (typeof id === "string") {
|
|
3904
|
+
state.startedSessions.delete(id);
|
|
3905
|
+
state.sessionStartTasks.delete(id);
|
|
3906
|
+
} else if (typeof agent === "object" && agent !== null) {
|
|
3907
|
+
state.startedSessionlessAgents.delete(agent);
|
|
3908
|
+
state.sessionlessStartTasks.delete(agent);
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
function replacementReason(reason) {
|
|
3912
|
+
if (reason === "resume") return "resume";
|
|
3913
|
+
if (reason === "fork") return "fork";
|
|
3914
|
+
return "new";
|
|
3915
|
+
}
|
|
3916
|
+
function trackRuntimeSession(state, agent) {
|
|
3917
|
+
const id = agentSession(agent)?.id;
|
|
3918
|
+
if (typeof id !== "string") return;
|
|
3919
|
+
let states = state.shared.runtimeStatesBySession.get(id);
|
|
3920
|
+
if (states === void 0) {
|
|
3921
|
+
states = /* @__PURE__ */ new Set();
|
|
3922
|
+
state.shared.runtimeStatesBySession.set(id, states);
|
|
3923
|
+
}
|
|
3924
|
+
states.add(state);
|
|
3925
|
+
}
|
|
3926
|
+
function untrackRuntimeSession(state, agent) {
|
|
3927
|
+
const id = agentSession(agent)?.id;
|
|
3928
|
+
if (typeof id !== "string") return;
|
|
3929
|
+
const states = state.shared.runtimeStatesBySession.get(id);
|
|
3930
|
+
states?.delete(state);
|
|
3931
|
+
if (states?.size === 0) state.shared.runtimeStatesBySession.delete(id);
|
|
3932
|
+
}
|
|
3933
|
+
/** Dispatch or join the one in-flight Pi session_start for this session. */
|
|
3934
|
+
async function startPiSession(ctx, state, agent, reason, signal) {
|
|
3935
|
+
if (!acceptsAgent(state, agent)) return;
|
|
3936
|
+
const existing = inFlightPiSessionStart(state, agent);
|
|
3937
|
+
if (existing !== void 0) {
|
|
3938
|
+
await existing;
|
|
3939
|
+
return;
|
|
3940
|
+
}
|
|
3941
|
+
const task = runInPiRuntime(state, agent, async () => {
|
|
3942
|
+
const previous = state.hostAgent;
|
|
3943
|
+
const replacing = typeof previous === "object" && previous !== null && previous !== agent;
|
|
3944
|
+
const transitionReason = replacing ? replacementReason(reason) : reason;
|
|
3945
|
+
if (replacing && !state.piShutdownAgents.has(previous)) {
|
|
3946
|
+
state.piShutdownAgents.add(previous);
|
|
3947
|
+
releasePiSessionClaim(state, previous);
|
|
3948
|
+
await runInPiRuntime(state, previous, () => dispatch(state, "session_shutdown", {
|
|
3949
|
+
type: "session_shutdown",
|
|
3950
|
+
reason: replacementReason(reason)
|
|
3951
|
+
}, contextFor(ctx, state, previous, signal)));
|
|
3952
|
+
}
|
|
3953
|
+
if (typeof agent === "object" && agent !== null) {
|
|
3954
|
+
state.hostAgent = agent;
|
|
3955
|
+
state.piShutdownAgents.delete(agent);
|
|
3956
|
+
}
|
|
3957
|
+
if (!claimPiSessionStart(state, agent)) return;
|
|
3958
|
+
try {
|
|
3959
|
+
await dispatch(state, "session_start", {
|
|
3960
|
+
type: "session_start",
|
|
3961
|
+
reason: transitionReason
|
|
3962
|
+
}, contextFor(ctx, state, agent, signal));
|
|
3963
|
+
} catch (error) {
|
|
3964
|
+
releasePiSessionClaim(state, agent);
|
|
3965
|
+
throw error;
|
|
3966
|
+
}
|
|
3967
|
+
});
|
|
3968
|
+
rememberPiSessionStart(state, agent, task);
|
|
3969
|
+
try {
|
|
3970
|
+
await task;
|
|
3971
|
+
} finally {
|
|
3972
|
+
forgetPiSessionStart(state, agent, task);
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3614
3975
|
function subscribeLifecycle(ctx, state) {
|
|
3615
3976
|
const cordis = ctx;
|
|
3616
3977
|
const warn = (event, error) => logger(ctx).warn(`[pi2dsh] ${event} handler failed: ${String(error)}`);
|
|
3617
3978
|
cordis.on("agent/session-start", (payload) => {
|
|
3618
3979
|
const agent = payload.agent;
|
|
3619
|
-
if (
|
|
3620
|
-
state.activeAgents.add(agent);
|
|
3621
|
-
return;
|
|
3622
|
-
}
|
|
3980
|
+
if (!acceptsAgent(state, agent)) return;
|
|
3623
3981
|
state.activeAgents.add(agent);
|
|
3982
|
+
trackRuntimeSession(state, agent);
|
|
3624
3983
|
const session = agentSession(agent);
|
|
3625
3984
|
if (session !== void 0) state.bridge.load(session.id);
|
|
3626
|
-
if (state.pendingActiveTools !== void 0) state
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
}
|
|
3985
|
+
if (state.pendingActiveTools !== void 0) runInPiRuntime(state, agent, () => setActiveTools(ctx, state, state.pendingActiveTools));
|
|
3986
|
+
if (!state.extensionsReady) {
|
|
3987
|
+
state.pendingSessionStarts.set(agent, sourceReason(payload.source));
|
|
3988
|
+
return;
|
|
3989
|
+
}
|
|
3990
|
+
startPiSession(ctx, state, agent, sourceReason(payload.source), void 0).catch((error) => warn("session_start", error));
|
|
3631
3991
|
});
|
|
3632
3992
|
cordis.on("agent/disposed", (payload) => {
|
|
3633
3993
|
const agent = payload.agent;
|
|
3994
|
+
if (!acceptsAgent(state, agent)) return;
|
|
3995
|
+
const ownsHostSession = state.hostAgent === agent;
|
|
3634
3996
|
state.activeAgents.delete(agent);
|
|
3997
|
+
untrackRuntimeSession(state, agent);
|
|
3998
|
+
state.pendingSessionStarts.delete(agent);
|
|
3635
3999
|
if (typeof agent === "object" && agent !== null) {
|
|
3636
4000
|
state.toolRestrictions.get(agent)?.();
|
|
3637
4001
|
state.toolRestrictions.delete(agent);
|
|
3638
4002
|
}
|
|
3639
4003
|
if (typeof agent === "object" && agent !== null && !state.disposedAgents.has(agent)) {
|
|
3640
4004
|
state.disposedAgents.add(agent);
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
4005
|
+
releasePiSessionClaim(state, agent);
|
|
4006
|
+
if (ownsHostSession && !state.piShutdownAgents.has(agent)) {
|
|
4007
|
+
state.piShutdownAgents.add(agent);
|
|
4008
|
+
state.hostAgent = void 0;
|
|
4009
|
+
dispatch(state, "session_shutdown", {
|
|
4010
|
+
type: "session_shutdown",
|
|
4011
|
+
reason: "quit"
|
|
4012
|
+
}, contextFor(ctx, state, agent, void 0)).catch((error) => warn("session_shutdown", error));
|
|
4013
|
+
}
|
|
3645
4014
|
}
|
|
3646
4015
|
});
|
|
3647
4016
|
cordis.on("session/event", (session, event) => {
|
|
3648
|
-
|
|
4017
|
+
const ownedSession = agentSession(state.ownerAgent);
|
|
4018
|
+
if (ownedSession !== void 0 ? session !== ownedSession : isSubagentOrigin(session)) return;
|
|
3649
4019
|
const agent = [...state.activeAgents].find((candidate) => candidate.session === session);
|
|
3650
4020
|
const eventContext = contextFor(ctx, state, agent, void 0);
|
|
3651
4021
|
const type = event.type;
|
|
@@ -3796,7 +4166,7 @@ function subscribeLifecycle(ctx, state) {
|
|
|
3796
4166
|
cordis.on("agent/request", async (payload, next) => {
|
|
3797
4167
|
const config = await next();
|
|
3798
4168
|
const agent = payload.agent;
|
|
3799
|
-
if (agent === void 0) return config;
|
|
4169
|
+
if (agent === void 0 || !acceptsAgent(state, agent)) return config;
|
|
3800
4170
|
const override = state.modelOverrides.get(agent);
|
|
3801
4171
|
const thinking = state.thinkingLevels.get(agent);
|
|
3802
4172
|
if (override === void 0 && thinking === void 0) return config;
|
|
@@ -3808,23 +4178,71 @@ function subscribeLifecycle(ctx, state) {
|
|
|
3808
4178
|
};
|
|
3809
4179
|
});
|
|
3810
4180
|
cordis.effect(() => async () => {
|
|
3811
|
-
|
|
4181
|
+
const agent = state.hostAgent;
|
|
4182
|
+
if (typeof agent === "object" && agent !== null && !state.piShutdownAgents.has(agent)) {
|
|
4183
|
+
state.piShutdownAgents.add(agent);
|
|
3812
4184
|
state.disposedAgents.add(agent);
|
|
3813
4185
|
await dispatch(state, "session_shutdown", {
|
|
3814
4186
|
type: "session_shutdown",
|
|
3815
4187
|
reason: "quit"
|
|
3816
4188
|
}, contextFor(ctx, state, agent, void 0));
|
|
3817
4189
|
}
|
|
4190
|
+
state.hostAgent = void 0;
|
|
4191
|
+
for (const active of state.activeAgents) untrackRuntimeSession(state, active);
|
|
3818
4192
|
state.activeAgents.clear();
|
|
4193
|
+
state.startedSessions.clear();
|
|
4194
|
+
state.sessionStartTasks.clear();
|
|
4195
|
+
state.pendingSessionStarts.clear();
|
|
3819
4196
|
for (const dispose of state.toolDisposers.values()) dispose();
|
|
3820
4197
|
state.toolDisposers.clear();
|
|
4198
|
+
for (const provider of [...state.ownedProviderRoutes]) releaseSharedProviderRoute(state, provider);
|
|
3821
4199
|
state.eventBus.removeAllListeners();
|
|
3822
4200
|
}, "pi2dsh session shutdown");
|
|
3823
4201
|
}
|
|
4202
|
+
async function flushPendingSessionStarts(ctx, state) {
|
|
4203
|
+
state.extensionsReady = true;
|
|
4204
|
+
const pending = [...state.pendingSessionStarts];
|
|
4205
|
+
state.pendingSessionStarts.clear();
|
|
4206
|
+
for (const [agent, reason] of pending) await startPiSession(ctx, state, agent, reason, void 0);
|
|
4207
|
+
}
|
|
4208
|
+
/**
|
|
4209
|
+
* Start freshly reloaded extension handlers in every live Pi host session.
|
|
4210
|
+
*
|
|
4211
|
+
* `ctx.reload()` creates a new extension instance. The durable session has
|
|
4212
|
+
* already been claimed by the previous instance, so the ordinary once-per-
|
|
4213
|
+
* session guard must deliberately NOT suppress this replay: from the new
|
|
4214
|
+
* instance's point of view this is its first `session_start`. The command's
|
|
4215
|
+
* AsyncLocalStorage agent is included because a lean composition can execute
|
|
4216
|
+
* a Pi command without publishing DSH's optional agent/session-start event.
|
|
4217
|
+
*/
|
|
4218
|
+
async function restartReloadedPiSessions(ctx, state) {
|
|
4219
|
+
state.extensionsReady = true;
|
|
4220
|
+
const pending = new Map(state.pendingSessionStarts);
|
|
4221
|
+
state.pendingSessionStarts.clear();
|
|
4222
|
+
const commandAgent = currentAgent(state);
|
|
4223
|
+
const candidates = [...state.activeAgents, ...commandAgent === void 0 ? [] : [commandAgent]];
|
|
4224
|
+
const seenSessions = /* @__PURE__ */ new Set();
|
|
4225
|
+
const seenSessionless = /* @__PURE__ */ new Set();
|
|
4226
|
+
for (const agent of candidates) {
|
|
4227
|
+
if (!acceptsAgent(state, agent)) continue;
|
|
4228
|
+
const sessionId = agentSession(agent)?.id;
|
|
4229
|
+
if (typeof sessionId === "string") {
|
|
4230
|
+
if (seenSessions.has(sessionId)) continue;
|
|
4231
|
+
seenSessions.add(sessionId);
|
|
4232
|
+
} else {
|
|
4233
|
+
if (seenSessionless.has(agent)) continue;
|
|
4234
|
+
seenSessionless.add(agent);
|
|
4235
|
+
}
|
|
4236
|
+
await runInPiRuntime(state, agent, () => dispatch(state, "session_start", {
|
|
4237
|
+
type: "session_start",
|
|
4238
|
+
reason: pending.get(agent) ?? "resume"
|
|
4239
|
+
}, contextFor(ctx, state, agent, void 0)));
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
3824
4242
|
function subscribeInterceptors(ctx, state) {
|
|
3825
4243
|
const cordis = ctx;
|
|
3826
4244
|
cordis.on("tools/pre-execute", async (exec, next) => {
|
|
3827
|
-
if (
|
|
4245
|
+
if (!acceptsAgent(state, exec.agent)) return next();
|
|
3828
4246
|
const input = cloneJson(exec.arguments);
|
|
3829
4247
|
const event = {
|
|
3830
4248
|
type: "tool_call",
|
|
@@ -3862,7 +4280,7 @@ function subscribeInterceptors(ctx, state) {
|
|
|
3862
4280
|
return next();
|
|
3863
4281
|
});
|
|
3864
4282
|
cordis.on("tools/post-execute", async (exec, result, next) => {
|
|
3865
|
-
if (
|
|
4283
|
+
if (!acceptsAgent(state, exec.agent)) return next();
|
|
3866
4284
|
const downstream = await next();
|
|
3867
4285
|
await dispatch(state, "tool_execution_end", {
|
|
3868
4286
|
type: "tool_execution_end",
|
|
@@ -3904,7 +4322,7 @@ function subscribeInterceptors(ctx, state) {
|
|
|
3904
4322
|
});
|
|
3905
4323
|
cordis.on("agent/inbox/claimed", (payload) => {
|
|
3906
4324
|
const agent = payload.agent;
|
|
3907
|
-
if (agent === void 0 ||
|
|
4325
|
+
if (agent === void 0 || !acceptsAgent(state, agent)) return;
|
|
3908
4326
|
const claimed = state.claimedForStep.get(agent) ?? [];
|
|
3909
4327
|
claimed.push({
|
|
3910
4328
|
message: payload.message,
|
|
@@ -3914,7 +4332,7 @@ function subscribeInterceptors(ctx, state) {
|
|
|
3914
4332
|
});
|
|
3915
4333
|
cordis.on("agent/pre-step", async (payload, next) => {
|
|
3916
4334
|
const agent = payload.agent;
|
|
3917
|
-
if (
|
|
4335
|
+
if (!acceptsAgent(state, agent)) return next();
|
|
3918
4336
|
const tally = state.terminateBatch.get(agent);
|
|
3919
4337
|
state.terminateBatch.delete(agent);
|
|
3920
4338
|
if (tally !== void 0 && tally.calls > 0 && tally.calls === tally.terminating) {
|
|
@@ -3946,7 +4364,8 @@ function subscribeInterceptors(ctx, state) {
|
|
|
3946
4364
|
const original = renderPrompt(downstream);
|
|
3947
4365
|
state.currentSystemPrompt = original;
|
|
3948
4366
|
const agent = assembleContext.agent ?? assembleContext.scope;
|
|
3949
|
-
if (agent !== void 0 && !
|
|
4367
|
+
if (agent !== void 0 && !acceptsAgent(state, agent)) return downstream;
|
|
4368
|
+
if (agent !== void 0 && acceptsAgent(state, agent)) {
|
|
3950
4369
|
await runBeforeAgentStart(ctx, state, agent, assembleContext.signal, original);
|
|
3951
4370
|
const override = state.turnSystemPromptOverrides.get(agent);
|
|
3952
4371
|
if (override === void 0) return downstream;
|
|
@@ -4154,6 +4573,9 @@ function sharedHostStateOf(ctx) {
|
|
|
4154
4573
|
shared = {
|
|
4155
4574
|
companionRoutes: /* @__PURE__ */ new Map(),
|
|
4156
4575
|
providerRouteDisposers: /* @__PURE__ */ new Map(),
|
|
4576
|
+
providerModelDiscoveries: /* @__PURE__ */ new Map(),
|
|
4577
|
+
providerRouteOwners: /* @__PURE__ */ new Map(),
|
|
4578
|
+
runtimeStatesBySession: /* @__PURE__ */ new Map(),
|
|
4157
4579
|
publishedOAuthKeys: /* @__PURE__ */ new Map(),
|
|
4158
4580
|
providers: /* @__PURE__ */ new Map()
|
|
4159
4581
|
};
|
|
@@ -4161,6 +4583,17 @@ function sharedHostStateOf(ctx) {
|
|
|
4161
4583
|
}
|
|
4162
4584
|
return shared;
|
|
4163
4585
|
}
|
|
4586
|
+
function packageRemountsOf(ctx, shared) {
|
|
4587
|
+
const scoped = scopeOf(ctx);
|
|
4588
|
+
const owner = typeof scoped === "object" && scoped !== null ? scoped : ctx;
|
|
4589
|
+
const byOwner = shared.packageRemounts ??= /* @__PURE__ */ new WeakMap();
|
|
4590
|
+
let remounts = byOwner.get(owner);
|
|
4591
|
+
if (remounts === void 0) {
|
|
4592
|
+
remounts = /* @__PURE__ */ new Map();
|
|
4593
|
+
byOwner.set(owner, remounts);
|
|
4594
|
+
}
|
|
4595
|
+
return remounts;
|
|
4596
|
+
}
|
|
4164
4597
|
/**
|
|
4165
4598
|
* Image-admission companion routes: for every text-only route in the DSH
|
|
4166
4599
|
* llm directory, a `<route>-vision` route that admits images at the host's
|
|
@@ -4285,11 +4718,15 @@ async function materializeAttachmentImage(ctx, attachment) {
|
|
|
4285
4718
|
}
|
|
4286
4719
|
}
|
|
4287
4720
|
function ensureLoginCommand(ctx, state) {
|
|
4288
|
-
|
|
4289
|
-
|
|
4721
|
+
const scoped = scopeOf(ctx);
|
|
4722
|
+
const owner = typeof scoped === "object" && scoped !== null ? scoped : ctx;
|
|
4723
|
+
const registered = state.shared.loginRegistered ??= /* @__PURE__ */ new WeakSet();
|
|
4724
|
+
if (registered.has(owner)) return;
|
|
4725
|
+
registered.add(owner);
|
|
4290
4726
|
try {
|
|
4291
4727
|
registerLoginCommand(ctx, state);
|
|
4292
4728
|
} catch (error) {
|
|
4729
|
+
registered.delete(owner);
|
|
4293
4730
|
logger(ctx).warn(`[pi2dsh] /login is already registered by an earlier package in this host; this package's providers use that command (${error instanceof Error ? error.message : String(error)})`);
|
|
4294
4731
|
}
|
|
4295
4732
|
}
|
|
@@ -4432,7 +4869,7 @@ function keepOAuthCredentialFresh(ctx, state) {
|
|
|
4432
4869
|
state.shared.oauthRefreshHooked = true;
|
|
4433
4870
|
ctx.on("llm/stream", ((options, next) => {
|
|
4434
4871
|
const provider = typeof options.provider === "string" ? options.provider : void 0;
|
|
4435
|
-
const config = provider === void 0 ? void 0 : state.providers.get(provider);
|
|
4872
|
+
const config = provider === void 0 ? void 0 : state.shared.providers.get(provider);
|
|
4436
4873
|
if (provider === void 0 || config === void 0 || !providerSupportsOAuth(config)) return next();
|
|
4437
4874
|
const publish = () => publishOAuthCredential(ctx, state, provider, config).catch((error) => logger(ctx).warn(`[pi2dsh] could not refresh the stored credential for ${JSON.stringify(provider)}: ${error instanceof Error ? error.message : String(error)}`));
|
|
4438
4875
|
return (async function* () {
|
|
@@ -4461,37 +4898,47 @@ function keepOAuthCredentialFresh(ctx, state) {
|
|
|
4461
4898
|
async function discoverProviderModels(ctx, state, name, value) {
|
|
4462
4899
|
const refreshModels = value.refreshModels;
|
|
4463
4900
|
if (typeof refreshModels !== "function") return void 0;
|
|
4901
|
+
const existing = state.shared.providerModelDiscoveries.get(name);
|
|
4902
|
+
if (existing !== void 0) return await existing;
|
|
4903
|
+
const task = (async () => {
|
|
4904
|
+
try {
|
|
4905
|
+
const apiKey = ((await resolvePiProviderAuth({
|
|
4906
|
+
providerId: name,
|
|
4907
|
+
providerConfig: value,
|
|
4908
|
+
store: oauthStoreOf(state)
|
|
4909
|
+
}).catch(() => void 0))?.auth)?.apiKey;
|
|
4910
|
+
await Promise.resolve(refreshModels.call(value, {
|
|
4911
|
+
stored: void 0,
|
|
4912
|
+
...apiKey === void 0 ? {} : { credential: {
|
|
4913
|
+
type: "api_key",
|
|
4914
|
+
key: apiKey
|
|
4915
|
+
} },
|
|
4916
|
+
store: {
|
|
4917
|
+
read: async () => void 0,
|
|
4918
|
+
write: async () => {},
|
|
4919
|
+
delete: async () => {}
|
|
4920
|
+
},
|
|
4921
|
+
allowNetwork: true,
|
|
4922
|
+
signal: new AbortController().signal,
|
|
4923
|
+
publish: async (publication) => {
|
|
4924
|
+
publication.update?.();
|
|
4925
|
+
return true;
|
|
4926
|
+
}
|
|
4927
|
+
}));
|
|
4928
|
+
} catch (error) {
|
|
4929
|
+
logger(ctx).warn(`[pi2dsh] model catalog refresh for Pi provider ${JSON.stringify(name)} failed (its registry entries stay static): ${error instanceof Error ? error.message : String(error)}`);
|
|
4930
|
+
return;
|
|
4931
|
+
}
|
|
4932
|
+
state.modelCatalog?.refresh();
|
|
4933
|
+
state.providerRouteDisposers.get(name)?.reannounce?.();
|
|
4934
|
+
return await llmOf(ctx)?.listModels(name).then((models) => models.length).catch(() => void 0);
|
|
4935
|
+
})();
|
|
4936
|
+
state.shared.providerModelDiscoveries.set(name, task);
|
|
4464
4937
|
try {
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
store: oauthStoreOf(state)
|
|
4469
|
-
}).catch(() => void 0))?.auth)?.apiKey;
|
|
4470
|
-
await Promise.resolve(refreshModels.call(value, {
|
|
4471
|
-
stored: void 0,
|
|
4472
|
-
...apiKey === void 0 ? {} : { credential: {
|
|
4473
|
-
type: "api_key",
|
|
4474
|
-
key: apiKey
|
|
4475
|
-
} },
|
|
4476
|
-
store: {
|
|
4477
|
-
read: async () => void 0,
|
|
4478
|
-
write: async () => {},
|
|
4479
|
-
delete: async () => {}
|
|
4480
|
-
},
|
|
4481
|
-
allowNetwork: true,
|
|
4482
|
-
signal: new AbortController().signal,
|
|
4483
|
-
publish: async (publication) => {
|
|
4484
|
-
publication.update?.();
|
|
4485
|
-
return true;
|
|
4486
|
-
}
|
|
4487
|
-
}));
|
|
4488
|
-
} catch (error) {
|
|
4489
|
-
logger(ctx).warn(`[pi2dsh] model catalog refresh for Pi provider ${JSON.stringify(name)} failed (its registry entries stay static): ${error instanceof Error ? error.message : String(error)}`);
|
|
4490
|
-
return;
|
|
4938
|
+
return await task;
|
|
4939
|
+
} finally {
|
|
4940
|
+
if (state.shared.providerModelDiscoveries.get(name) === task) state.shared.providerModelDiscoveries.delete(name);
|
|
4491
4941
|
}
|
|
4492
|
-
state.modelCatalog?.refresh();
|
|
4493
|
-
state.providerRouteDisposers.get(name)?.reannounce?.();
|
|
4494
|
-
return await llmOf(ctx)?.listModels(name).then((models) => models.length).catch(() => void 0);
|
|
4495
4942
|
}
|
|
4496
4943
|
function registerLoginCommand(ctx, state) {
|
|
4497
4944
|
registerCommand(ctx, state, {
|
|
@@ -4576,6 +5023,8 @@ function registerTool(ctx, state, tool) {
|
|
|
4576
5023
|
isConcurrencySafe: () => tool.executionMode === "parallel",
|
|
4577
5024
|
async execute(args, exec) {
|
|
4578
5025
|
const live = state.tools.get(tool.name) ?? tool;
|
|
5026
|
+
const agent = exec.agent;
|
|
5027
|
+
await ensurePiSessionStarted(ctx, state, agent, exec.signal);
|
|
4579
5028
|
const mutated = state.argMutations.get(exec);
|
|
4580
5029
|
if (mutated !== void 0) state.argMutations.delete(exec);
|
|
4581
5030
|
const effective = mutated ?? args;
|
|
@@ -4586,8 +5035,7 @@ function registerTool(ctx, state, tool) {
|
|
|
4586
5035
|
name: live.name,
|
|
4587
5036
|
arguments: live.prepareArguments?.(cloneJson(effective)) ?? effective
|
|
4588
5037
|
});
|
|
4589
|
-
const
|
|
4590
|
-
const result = await normalizeToolResultForDsh(ctx, await state.agentScope.run(agent, () => live.execute(String(exec.callId), prepared, exec.signal, (update) => {
|
|
5038
|
+
const result = await normalizeToolResultForDsh(ctx, await runInPiRuntime(state, agent, () => live.execute(String(exec.callId), prepared, exec.signal, (update) => {
|
|
4591
5039
|
dispatch(state, "tool_execution_update", {
|
|
4592
5040
|
type: "tool_execution_update",
|
|
4593
5041
|
toolCallId: String(exec.callId),
|
|
@@ -4621,6 +5069,11 @@ function currentAgent(state) {
|
|
|
4621
5069
|
if (scoped !== void 0) return scoped;
|
|
4622
5070
|
if (state.activeAgents.size === 1) return state.activeAgents.values().next().value;
|
|
4623
5071
|
}
|
|
5072
|
+
/** Exact-Agent ownership for scoped mounts; legacy root mounts retain their old host-session rule. */
|
|
5073
|
+
function acceptsAgent(state, agent) {
|
|
5074
|
+
if (state.ownerAgent !== void 0) return agent === state.ownerAgent;
|
|
5075
|
+
return !isSubagentOrigin(agent);
|
|
5076
|
+
}
|
|
4624
5077
|
function toolRuntime(ctx, agent) {
|
|
4625
5078
|
return (agent?.ctx)?.tools ?? ctx.tools;
|
|
4626
5079
|
}
|
|
@@ -4845,10 +5298,16 @@ async function executePiCommand(service, cwd, command, args, options) {
|
|
|
4845
5298
|
operation.cleanup();
|
|
4846
5299
|
}
|
|
4847
5300
|
}
|
|
4848
|
-
function
|
|
5301
|
+
function normalizedPiCommandName(piName) {
|
|
4849
5302
|
const normalized = piName.toLowerCase().replace(/[^a-z0-9_-]+/gu, "-").replace(/^[^a-z]+/u, "");
|
|
4850
|
-
|
|
4851
|
-
|
|
5303
|
+
return normalized.length > 0 ? normalized : "pi-command";
|
|
5304
|
+
}
|
|
5305
|
+
function dshCommandName(ctx, state, piName) {
|
|
5306
|
+
const name = commandNameForDshTui(normalizedPiCommandName(piName), state.tuiSurfaces?.available === true || optionalService(ctx, "tuiScenes") !== void 0);
|
|
5307
|
+
if (name !== piName) {
|
|
5308
|
+
const reason = name === "pi-mcp" ? "because dsh-TUI reserves /mcp for its native MCP status view" : "to satisfy DSH command naming";
|
|
5309
|
+
logger(ctx).warn(`[pi2dsh] Pi command /${piName} registered as /${name} ${reason}`);
|
|
5310
|
+
}
|
|
4852
5311
|
return name;
|
|
4853
5312
|
}
|
|
4854
5313
|
function registerCommand(ctx, state, command) {
|
|
@@ -4862,7 +5321,13 @@ function registerCommand(ctx, state, command) {
|
|
|
4862
5321
|
logger(ctx).warn(`[pi2dsh] command /${command.name} was not registered because this DSH composition has no ctx.commands`);
|
|
4863
5322
|
return;
|
|
4864
5323
|
}
|
|
4865
|
-
const baseName = dshCommandName(ctx, command.name);
|
|
5324
|
+
const baseName = dshCommandName(ctx, state, command.name);
|
|
5325
|
+
const existingOwner = state.dshCommandOwners.get(baseName);
|
|
5326
|
+
if (existingOwner !== void 0 && existingOwner !== command.name && normalizedPiCommandName(command.name) === baseName && normalizedPiCommandName(existingOwner) !== baseName) {
|
|
5327
|
+
state.commandDisposers.get(existingOwner)?.();
|
|
5328
|
+
state.commandDisposers.delete(existingOwner);
|
|
5329
|
+
state.dshCommandOwners.delete(baseName);
|
|
5330
|
+
}
|
|
4866
5331
|
const definitionFor = (dshName) => ({
|
|
4867
5332
|
name: dshName,
|
|
4868
5333
|
description: command.description || `Migrated Pi command /${command.name}`,
|
|
@@ -4871,7 +5336,10 @@ function registerCommand(ctx, state, command) {
|
|
|
4871
5336
|
const agent = invocation.agent;
|
|
4872
5337
|
const commandContext = contextFor(ctx, state, agent, invocation.signal, true);
|
|
4873
5338
|
const live = state.commands.get(command.name) ?? command;
|
|
4874
|
-
await state
|
|
5339
|
+
await runInPiRuntime(state, agent, async () => {
|
|
5340
|
+
await ensurePiSessionStarted(ctx, state, agent, invocation.signal);
|
|
5341
|
+
await live.handler(String(invocation.rawInput ?? "").trimStart(), commandContext);
|
|
5342
|
+
});
|
|
4875
5343
|
const notices = commandContext.__notices;
|
|
4876
5344
|
return {
|
|
4877
5345
|
kind: "success",
|
|
@@ -4884,6 +5352,7 @@ function registerCommand(ctx, state, command) {
|
|
|
4884
5352
|
const dshName = ordinal === 1 ? baseName : `${baseName}-${ordinal}`;
|
|
4885
5353
|
try {
|
|
4886
5354
|
state.commandDisposers.set(command.name, commands.register(definitionFor(dshName)));
|
|
5355
|
+
state.dshCommandOwners.set(dshName, command.name);
|
|
4887
5356
|
if (ordinal > 1) logger(ctx).warn(`[pi2dsh] command /${command.name} collides with an earlier registration in this host; mounted as /${dshName} (Pi numbers colliding commands the same way)`);
|
|
4888
5357
|
return;
|
|
4889
5358
|
} catch (error) {
|
|
@@ -4942,6 +5411,56 @@ function requireSession(state, operation) {
|
|
|
4942
5411
|
if (session === void 0) throw new Error(`pi2dsh: ${operation} requires one active DSH agent with a durable session`);
|
|
4943
5412
|
return session;
|
|
4944
5413
|
}
|
|
5414
|
+
function releaseSharedProviderRoute(state, name) {
|
|
5415
|
+
if (!state.ownedProviderRoutes.delete(name)) return;
|
|
5416
|
+
const owners = state.shared.providerRouteOwners.get(name);
|
|
5417
|
+
owners?.delete(state);
|
|
5418
|
+
if (owners !== void 0 && owners.size > 0) return;
|
|
5419
|
+
state.shared.providerRouteOwners.delete(name);
|
|
5420
|
+
const route = state.shared.providerRouteDisposers.get(name);
|
|
5421
|
+
state.shared.providerRouteDisposers.delete(name);
|
|
5422
|
+
route?.();
|
|
5423
|
+
}
|
|
5424
|
+
function registerSharedProviderRoute(ctx, state, name, value) {
|
|
5425
|
+
const shared = state.shared;
|
|
5426
|
+
const existing = shared.providerRouteDisposers.get(name);
|
|
5427
|
+
if (existing !== void 0) {
|
|
5428
|
+
let owners = shared.providerRouteOwners.get(name);
|
|
5429
|
+
if (owners === void 0) {
|
|
5430
|
+
owners = /* @__PURE__ */ new Set();
|
|
5431
|
+
shared.providerRouteOwners.set(name, owners);
|
|
5432
|
+
}
|
|
5433
|
+
owners.add(state);
|
|
5434
|
+
state.ownedProviderRoutes.add(name);
|
|
5435
|
+
return existing;
|
|
5436
|
+
}
|
|
5437
|
+
const canonical = shared.providers.get(name) ?? value;
|
|
5438
|
+
shared.providers.set(name, canonical);
|
|
5439
|
+
const route = registerPiProviderRoute({
|
|
5440
|
+
llm: llmOf(ctx),
|
|
5441
|
+
ctx,
|
|
5442
|
+
providerId: name,
|
|
5443
|
+
provider: canonical,
|
|
5444
|
+
host: {
|
|
5445
|
+
resolveAuth: async () => resolvePiProviderAuth({
|
|
5446
|
+
providerId: name,
|
|
5447
|
+
providerConfig: canonical,
|
|
5448
|
+
store: oauthStoreOf(state)
|
|
5449
|
+
}),
|
|
5450
|
+
ensureModel: async () => {
|
|
5451
|
+
await discoverProviderModels(ctx, state, name, canonical);
|
|
5452
|
+
},
|
|
5453
|
+
warn: (message) => logger(ctx).warn(message),
|
|
5454
|
+
beforeProviderRequest: (payload, request) => dispatchHostProviderRequest(ctx, shared, state, payload, request),
|
|
5455
|
+
resolveAttachments: () => optionalService(ctx, "attachments")
|
|
5456
|
+
}
|
|
5457
|
+
});
|
|
5458
|
+
if (route === void 0) return void 0;
|
|
5459
|
+
shared.providerRouteDisposers.set(name, route);
|
|
5460
|
+
shared.providerRouteOwners.set(name, /* @__PURE__ */ new Set([state]));
|
|
5461
|
+
state.ownedProviderRoutes.add(name);
|
|
5462
|
+
return route;
|
|
5463
|
+
}
|
|
4945
5464
|
function createPiApi(ctx, state) {
|
|
4946
5465
|
return {
|
|
4947
5466
|
on(event, handler) {
|
|
@@ -4971,28 +5490,12 @@ function createPiApi(ctx, state) {
|
|
|
4971
5490
|
const name = typeof providerOrName === "string" ? providerOrName : String(providerOrName?.id ?? providerOrName?.name ?? "unnamed");
|
|
4972
5491
|
const value = typeof providerOrName === "string" ? config ?? {} : providerOrName;
|
|
4973
5492
|
state.providers.set(name, value);
|
|
5493
|
+
if (!state.shared.providers.has(name)) state.shared.providers.set(name, value);
|
|
4974
5494
|
if (providerSupportsOAuth(value)) {
|
|
4975
5495
|
ensureLoginCommand(ctx, state);
|
|
4976
5496
|
logger(ctx).info(`[pi2dsh] Pi provider ${JSON.stringify(name)} supports OAuth — log in with /login ${name}`);
|
|
4977
5497
|
}
|
|
4978
|
-
|
|
4979
|
-
llm: llmOf(ctx),
|
|
4980
|
-
ctx,
|
|
4981
|
-
providerId: name,
|
|
4982
|
-
provider: value,
|
|
4983
|
-
host: {
|
|
4984
|
-
resolveAuth: async () => resolvePiProviderAuth({
|
|
4985
|
-
providerId: name,
|
|
4986
|
-
providerConfig: value,
|
|
4987
|
-
store: oauthStoreOf(state)
|
|
4988
|
-
}),
|
|
4989
|
-
warn: (message) => logger(ctx).warn(message),
|
|
4990
|
-
beforeProviderRequest: (payload, request) => dispatchBeforeProviderRequest(ctx, state, payload, request),
|
|
4991
|
-
resolveAttachments: () => optionalService(ctx, "attachments")
|
|
4992
|
-
}
|
|
4993
|
-
});
|
|
4994
|
-
if (routeDisposer !== void 0) {
|
|
4995
|
-
state.providerRouteDisposers.set(name, routeDisposer);
|
|
5498
|
+
if (registerSharedProviderRoute(ctx, state, name, value) !== void 0) {
|
|
4996
5499
|
state.modelCatalog?.refresh();
|
|
4997
5500
|
if (providerCarriesTransport(value)) logger(ctx).info(`[pi2dsh] Pi provider ${JSON.stringify(name)} registered as a native DSH llm route`);
|
|
4998
5501
|
} else if (!providerSupportsOAuth(value)) logger(ctx).info(`[pi2dsh] recorded Pi provider ${JSON.stringify(name)}; model calls stay on DSH llm adapters`);
|
|
@@ -5000,11 +5503,7 @@ function createPiApi(ctx, state) {
|
|
|
5000
5503
|
},
|
|
5001
5504
|
unregisterProvider(name) {
|
|
5002
5505
|
state.providers.delete(name);
|
|
5003
|
-
|
|
5004
|
-
if (routeDisposer !== void 0) {
|
|
5005
|
-
state.providerRouteDisposers.delete(name);
|
|
5006
|
-
routeDisposer();
|
|
5007
|
-
}
|
|
5506
|
+
releaseSharedProviderRoute(state, name);
|
|
5008
5507
|
},
|
|
5009
5508
|
registerMessageRenderer(customType, renderer) {
|
|
5010
5509
|
state.messageRenderers.set(customType, renderer);
|
|
@@ -5200,15 +5699,10 @@ async function loadExtensions(rootDir, manifest, api, onExtensionError, onCapabi
|
|
|
5200
5699
|
resolveShim("pi-ai")
|
|
5201
5700
|
]);
|
|
5202
5701
|
const aliases = {};
|
|
5702
|
+
const require = createRequire(import.meta.url);
|
|
5203
5703
|
for (const family of ["@earendil-works", "@mariozechner"]) {
|
|
5204
5704
|
aliases[`${family}/pi-coding-agent`] = codingAgentShim;
|
|
5205
5705
|
aliases[`${family}/pi-tui`] = tuiShim;
|
|
5206
|
-
aliases[`${family}/pi-ai`] = aiShim;
|
|
5207
|
-
aliases[`${family}/pi-ai/compat`] = aiShim;
|
|
5208
|
-
aliases[`${family}/pi-ai/oauth`] = aiShim;
|
|
5209
|
-
aliases[`${family}/pi-ai/providers/all`] = aiShim;
|
|
5210
|
-
aliases[`${family}/pi-ai/bedrock-provider`] = aiShim;
|
|
5211
|
-
aliases[`${family}/pi-ai/bun-oauth`] = aiShim;
|
|
5212
5706
|
for (const api of [
|
|
5213
5707
|
"anthropic-messages",
|
|
5214
5708
|
"openai-completions",
|
|
@@ -5220,9 +5714,19 @@ async function loadExtensions(rootDir, manifest, api, onExtensionError, onCapabi
|
|
|
5220
5714
|
"mistral-conversations",
|
|
5221
5715
|
"bedrock-converse-stream",
|
|
5222
5716
|
"pi-messages"
|
|
5223
|
-
])
|
|
5717
|
+
]) {
|
|
5718
|
+
try {
|
|
5719
|
+
aliases[`${family}/pi-ai/api/${api}.lazy`] = fileURLToPath(import.meta.resolve(`@earendil-works/pi-ai/api/${api}.lazy`));
|
|
5720
|
+
} catch {}
|
|
5721
|
+
aliases[`${family}/pi-ai/api/${api}`] = aiShim;
|
|
5722
|
+
}
|
|
5723
|
+
aliases[`${family}/pi-ai/compat`] = aiShim;
|
|
5724
|
+
aliases[`${family}/pi-ai/oauth`] = aiShim;
|
|
5725
|
+
aliases[`${family}/pi-ai/providers/all`] = aiShim;
|
|
5726
|
+
aliases[`${family}/pi-ai/bedrock-provider`] = aiShim;
|
|
5727
|
+
aliases[`${family}/pi-ai/bun-oauth`] = aiShim;
|
|
5728
|
+
aliases[`${family}/pi-ai`] = aiShim;
|
|
5224
5729
|
}
|
|
5225
|
-
const require = createRequire(import.meta.url);
|
|
5226
5730
|
for (const entry of [
|
|
5227
5731
|
"typebox",
|
|
5228
5732
|
"typebox/value",
|
|
@@ -5272,9 +5776,12 @@ async function applyPiPackage(ctx, options) {
|
|
|
5272
5776
|
}
|
|
5273
5777
|
}));
|
|
5274
5778
|
const shared = sharedHostStateOf(ctx);
|
|
5779
|
+
const scopedOwner = options.ownerAgent ?? scopeOf(ctx);
|
|
5780
|
+
const ownerAgent = typeof scopedOwner === "object" && scopedOwner !== null ? scopedOwner : void 0;
|
|
5275
5781
|
const state = {
|
|
5276
5782
|
shared,
|
|
5277
5783
|
packageName: options.manifest.package.name,
|
|
5784
|
+
ownerAgent,
|
|
5278
5785
|
handlers: /* @__PURE__ */ new Map(),
|
|
5279
5786
|
tools: runtimeTools,
|
|
5280
5787
|
runner: new ExtensionRunner(piToolRecords),
|
|
@@ -5282,21 +5789,33 @@ async function applyPiPackage(ctx, options) {
|
|
|
5282
5789
|
toolRestrictions: /* @__PURE__ */ new WeakMap(),
|
|
5283
5790
|
commands: /* @__PURE__ */ new Map(),
|
|
5284
5791
|
commandDisposers: /* @__PURE__ */ new Map(),
|
|
5792
|
+
dshCommandOwners: /* @__PURE__ */ new Map(),
|
|
5285
5793
|
companionRoutes: shared.companionRoutes,
|
|
5286
5794
|
flags: /* @__PURE__ */ new Map(),
|
|
5287
5795
|
notifications: [],
|
|
5288
5796
|
activeAgents: /* @__PURE__ */ new Set(),
|
|
5797
|
+
hostAgent: void 0,
|
|
5798
|
+
piShutdownAgents: /* @__PURE__ */ new WeakSet(),
|
|
5289
5799
|
disposedAgents: /* @__PURE__ */ new WeakSet(),
|
|
5800
|
+
startedSessions: /* @__PURE__ */ new Set(),
|
|
5801
|
+
sessionStartTasks: /* @__PURE__ */ new Map(),
|
|
5802
|
+
startedSessionlessAgents: /* @__PURE__ */ new WeakSet(),
|
|
5803
|
+
sessionlessStartTasks: /* @__PURE__ */ new WeakMap(),
|
|
5804
|
+
extensionsReady: false,
|
|
5805
|
+
pendingSessionStarts: /* @__PURE__ */ new Map(),
|
|
5290
5806
|
currentSystemPrompt: "",
|
|
5291
5807
|
messageSource: `pi2dsh:${options.manifest.package.name}`,
|
|
5292
5808
|
eventBus: new EventEmitter(),
|
|
5293
5809
|
agentScope: new AsyncLocalStorage(),
|
|
5810
|
+
llmBridge: void 0,
|
|
5811
|
+
piAiRegistry: __createPiAiRuntimeRegistry(),
|
|
5812
|
+
subagentSessionFactory: void 0,
|
|
5294
5813
|
bridge: new PiSessionBridge(),
|
|
5295
5814
|
theme: new Theme(),
|
|
5296
5815
|
shortcuts: /* @__PURE__ */ new Map(),
|
|
5297
5816
|
messageRenderers: /* @__PURE__ */ new Map(),
|
|
5298
5817
|
entryRenderers: /* @__PURE__ */ new Map(),
|
|
5299
|
-
providers:
|
|
5818
|
+
providers: /* @__PURE__ */ new Map(),
|
|
5300
5819
|
autocompleteProviders: [],
|
|
5301
5820
|
editorBuffers: /* @__PURE__ */ new WeakMap(),
|
|
5302
5821
|
toolsExpanded: false,
|
|
@@ -5314,15 +5833,24 @@ async function applyPiPackage(ctx, options) {
|
|
|
5314
5833
|
streamingTexts: /* @__PURE__ */ new Map(),
|
|
5315
5834
|
lastLoggedModels: /* @__PURE__ */ new WeakMap(),
|
|
5316
5835
|
providerRouteDisposers: shared.providerRouteDisposers,
|
|
5317
|
-
|
|
5836
|
+
ownedProviderRoutes: /* @__PURE__ */ new Set(),
|
|
5837
|
+
publishedOAuthKeys: shared.publishedOAuthKeys,
|
|
5838
|
+
tuiSurfaces: void 0
|
|
5318
5839
|
};
|
|
5840
|
+
mountTuiSurfaceAdapter(ctx, state.packageName, (adapter) => {
|
|
5841
|
+
state.tuiSurfaces = adapter;
|
|
5842
|
+
}, typeof ownerAgent?.id === "string" ? ownerAgent.id : void 0);
|
|
5319
5843
|
subscribeLifecycle(ctx, state);
|
|
5320
5844
|
subscribeInterceptors(ctx, state);
|
|
5321
|
-
for (const provider of builtinProviders())
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5845
|
+
for (const provider of builtinProviders()) {
|
|
5846
|
+
const config = {
|
|
5847
|
+
name: provider.name,
|
|
5848
|
+
baseUrl: provider.baseUrl,
|
|
5849
|
+
oauth: provider.auth.oauth
|
|
5850
|
+
};
|
|
5851
|
+
state.providers.set(provider.id, config);
|
|
5852
|
+
if (!shared.providers.has(provider.id)) shared.providers.set(provider.id, config);
|
|
5853
|
+
}
|
|
5326
5854
|
ensureLoginCommand(ctx, state);
|
|
5327
5855
|
for (const [name, config] of [...state.providers]) try {
|
|
5328
5856
|
await ensureLoggedInProviderRoute(ctx, state, name, config);
|
|
@@ -5333,12 +5861,13 @@ async function applyPiPackage(ctx, options) {
|
|
|
5333
5861
|
if (ctx.get("skills") === void 0) logger(ctx).warn("[pi2dsh] migrated skills were not mounted because this DSH composition has no ctx.skills");
|
|
5334
5862
|
else {
|
|
5335
5863
|
const { apply: applyFilesystemSkills } = await import("@deepseek-ai/dsh-skill-filesystem");
|
|
5336
|
-
|
|
5864
|
+
const config = {
|
|
5337
5865
|
providerName: `pi2dsh-${options.manifest.package.name.replace(/[^a-zA-Z0-9_-]+/gu, "-").replace(/^-+|-+$/gu, "")}`,
|
|
5338
5866
|
includeDefaultRoots: false,
|
|
5339
5867
|
customSkillDirs: options.manifest.skillDirs.map((path) => join(rootDir, path)),
|
|
5340
5868
|
watch: false
|
|
5341
|
-
}
|
|
5869
|
+
};
|
|
5870
|
+
await ctx.plugin(Object.assign((skillCtx) => applyFilesystemSkills(skillCtx, config), { inject: ["skills"] }));
|
|
5342
5871
|
}
|
|
5343
5872
|
}
|
|
5344
5873
|
const llm = llmOf(ctx);
|
|
@@ -5352,12 +5881,11 @@ async function applyPiPackage(ctx, options) {
|
|
|
5352
5881
|
});
|
|
5353
5882
|
}
|
|
5354
5883
|
await state.modelCatalog.refresh();
|
|
5355
|
-
|
|
5884
|
+
state.llmBridge = (model, context, callOptions) => streamViaDshLlm(llm, {
|
|
5356
5885
|
model,
|
|
5357
5886
|
context,
|
|
5358
5887
|
options: callOptions
|
|
5359
|
-
})
|
|
5360
|
-
ctx.effect(() => () => __setPiAiLlmBridge(void 0));
|
|
5888
|
+
});
|
|
5361
5889
|
}
|
|
5362
5890
|
const browserSurfaces = state.shared.browserSurfaces ??= new BrowserSurfaces();
|
|
5363
5891
|
if (state.shared.browserSurfacesRouted !== true) state.shared.browserSurfacesRouted = registerBrowserSurfaceRoute(ctx, browserSurfaces);
|
|
@@ -5416,7 +5944,7 @@ async function applyPiPackage(ctx, options) {
|
|
|
5416
5944
|
}
|
|
5417
5945
|
return rendered;
|
|
5418
5946
|
}));
|
|
5419
|
-
|
|
5947
|
+
state.subagentSessionFactory = async (subagentOptions) => {
|
|
5420
5948
|
const created = await createBridgedAgentSession(subagentHost(), subagentOptions);
|
|
5421
5949
|
const parent = agentSession(currentAgent(state));
|
|
5422
5950
|
const parentId = parent === void 0 ? "" : String(parent.id ?? "");
|
|
@@ -5430,7 +5958,7 @@ async function applyPiPackage(ctx, options) {
|
|
|
5430
5958
|
ctx.effect(() => dispose);
|
|
5431
5959
|
}
|
|
5432
5960
|
return created;
|
|
5433
|
-
}
|
|
5961
|
+
};
|
|
5434
5962
|
const subagentHost = () => ({
|
|
5435
5963
|
cordis: ctx,
|
|
5436
5964
|
cwd: () => cwdOf(currentAgent(state)),
|
|
@@ -5451,7 +5979,6 @@ async function applyPiPackage(ctx, options) {
|
|
|
5451
5979
|
messageSource: state.messageSource,
|
|
5452
5980
|
packageName: state.packageName
|
|
5453
5981
|
});
|
|
5454
|
-
ctx.effect(() => () => __setSubagentSessionFactory(void 0));
|
|
5455
5982
|
await registerPromptCommands(ctx, state, rootDir, options.manifest);
|
|
5456
5983
|
const onExtensionError = (failure) => logger(ctx).warn(`[pi2dsh] extension entry failed and was skipped (matching Pi's per-extension error isolation): ${failure}`);
|
|
5457
5984
|
const onCapabilityGap = (gap) => capabilityLedgerOf(ctx, state).reportUnusable({
|
|
@@ -5466,14 +5993,21 @@ async function applyPiPackage(ctx, options) {
|
|
|
5466
5993
|
guidance: "",
|
|
5467
5994
|
packageName: state.packageName
|
|
5468
5995
|
});
|
|
5469
|
-
const mountExtensions = () => loadExtensions(rootDir, options.manifest, createPiApi(ctx, state), onExtensionError, onCapabilityGap, onHostInfraReference);
|
|
5996
|
+
const mountExtensions = () => runInPiRuntime(state, currentAgent(state), () => loadExtensions(rootDir, options.manifest, createPiApi(ctx, state), onExtensionError, onCapabilityGap, onHostInfraReference));
|
|
5470
5997
|
await mountExtensions();
|
|
5471
|
-
|
|
5998
|
+
await flushPendingSessionStarts(ctx, state);
|
|
5999
|
+
const remounts = packageRemountsOf(ctx, shared);
|
|
5472
6000
|
remounts.set(state.packageName, async () => {
|
|
6001
|
+
state.extensionsReady = false;
|
|
5473
6002
|
state.handlers.clear();
|
|
5474
6003
|
state.eventBus.removeAllListeners();
|
|
5475
|
-
|
|
5476
|
-
|
|
6004
|
+
try {
|
|
6005
|
+
await registerPromptCommands(ctx, state, rootDir, options.manifest);
|
|
6006
|
+
await mountExtensions();
|
|
6007
|
+
await restartReloadedPiSessions(ctx, state);
|
|
6008
|
+
} finally {
|
|
6009
|
+
state.extensionsReady = true;
|
|
6010
|
+
}
|
|
5477
6011
|
});
|
|
5478
6012
|
ctx.effect(() => () => {
|
|
5479
6013
|
remounts.delete(state.packageName);
|
|
@@ -5497,4 +6031,4 @@ const runtimeInternals = {
|
|
|
5497
6031
|
//#endregion
|
|
5498
6032
|
export { runtimeInternals as i, normalizeToolSchema as n, registerVisionCompanions as r, applyPiPackage as t };
|
|
5499
6033
|
|
|
5500
|
-
//# sourceMappingURL=runtime-
|
|
6034
|
+
//# sourceMappingURL=runtime-Dd2KhoX-.mjs.map
|