pi2dsh 0.3.0 → 0.3.2
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 +31 -11
- package/README.zh.md +31 -11
- package/dist/all-Rt4K68QA.mjs +28512 -0
- package/dist/all-Rt4K68QA.mjs.map +1 -0
- package/dist/anthropic-messages-Beym0_aC.mjs +6438 -0
- package/dist/anthropic-messages-Beym0_aC.mjs.map +1 -0
- package/dist/azure-openai-responses-cHqZTgLD.mjs +209 -0
- package/dist/azure-openai-responses-cHqZTgLD.mjs.map +1 -0
- package/dist/{build-DsGYAgiT.mjs → build-BG7p2Lbr.mjs} +2 -2
- package/dist/{build-DsGYAgiT.mjs.map → build-BG7p2Lbr.mjs.map} +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/compat/pi-ai.d.mts +25 -3
- package/dist/compat/pi-ai.d.mts.map +1 -1
- package/dist/compat/pi-ai.mjs +3 -2919
- package/dist/compat/pi-coding-agent.d.mts +12 -1
- package/dist/compat/pi-coding-agent.d.mts.map +1 -1
- package/dist/compat/pi-coding-agent.mjs +2 -2
- package/dist/credentials-oauth.d.mts +27 -0
- package/dist/credentials-oauth.d.mts.map +1 -0
- package/dist/credentials-oauth.mjs +91 -0
- package/dist/credentials-oauth.mjs.map +1 -0
- package/dist/deferred-tools-BD4g5QUx.mjs +32 -0
- package/dist/deferred-tools-BD4g5QUx.mjs.map +1 -0
- package/dist/diagnostics-CJye1UFh.mjs +99 -0
- package/dist/diagnostics-CJye1UFh.mjs.map +1 -0
- package/dist/dist-IQKOgQyt.mjs +10035 -0
- package/dist/dist-IQKOgQyt.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/github-copilot-headers-CZo2QHrt.mjs +25 -0
- package/dist/github-copilot-headers-CZo2QHrt.mjs.map +1 -0
- package/dist/google-generative-ai-B7OZs5lu.mjs +358 -0
- package/dist/google-generative-ai-B7OZs5lu.mjs.map +1 -0
- package/dist/google-shared-CRsAUItF.mjs +29042 -0
- package/dist/google-shared-CRsAUItF.mjs.map +1 -0
- package/dist/google-vertex-DmdaHQtB.mjs +402 -0
- package/dist/google-vertex-DmdaHQtB.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.map +1 -1
- package/dist/host.mjs +15 -3
- package/dist/host.mjs.map +1 -1
- package/dist/images-models-DJtHo9Rp.mjs +1068 -0
- package/dist/images-models-DJtHo9Rp.mjs.map +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/json-parse-CFyFZSLJ.mjs +384 -0
- package/dist/json-parse-CFyFZSLJ.mjs.map +1 -0
- package/dist/{mcp-config-gqg7GJEE.mjs → mcp-config-D2B3kv-Z.mjs} +34 -16
- package/dist/mcp-config-D2B3kv-Z.mjs.map +1 -0
- package/dist/mistral-conversations-HHZCcFv_.mjs +42007 -0
- package/dist/mistral-conversations-HHZCcFv_.mjs.map +1 -0
- package/dist/multipart-parser-CIa5BbwO.mjs +301 -0
- package/dist/multipart-parser-CIa5BbwO.mjs.map +1 -0
- package/dist/oauth-bridge-C6fL1qSv.mjs +375 -0
- package/dist/oauth-bridge-C6fL1qSv.mjs.map +1 -0
- package/dist/openai-DkzRh5_G.mjs +6732 -0
- package/dist/openai-DkzRh5_G.mjs.map +1 -0
- package/dist/openai-codex-responses-vmovNu-q.mjs +1169 -0
- package/dist/openai-codex-responses-vmovNu-q.mjs.map +1 -0
- package/dist/openai-completions-fXHhRolF.mjs +947 -0
- package/dist/openai-completions-fXHhRolF.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-DKdCYf3h.mjs +247 -0
- package/dist/openai-responses-DKdCYf3h.mjs.map +1 -0
- package/dist/openai-responses-shared-D0Jq7yVP.mjs +572 -0
- package/dist/openai-responses-shared-D0Jq7yVP.mjs.map +1 -0
- package/dist/openrouter-images-fG3Aj6M4.mjs +127 -0
- package/dist/openrouter-images-fG3Aj6M4.mjs.map +1 -0
- package/dist/otel-BQSQRBLF.mjs +24935 -0
- package/dist/otel-BQSQRBLF.mjs.map +1 -0
- package/dist/pi-ai-DhYGgq4Y.mjs +2984 -0
- package/dist/pi-ai-DhYGgq4Y.mjs.map +1 -0
- package/dist/{pi-coding-agent-Z1hTs61i.mjs → pi-coding-agent-fPHwKP4d.mjs} +27 -3
- package/dist/{pi-coding-agent-Z1hTs61i.mjs.map → pi-coding-agent-fPHwKP4d.mjs.map} +1 -1
- package/dist/pi-messages-CV-Ts8An.mjs +306 -0
- package/dist/pi-messages-CV-Ts8An.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-oLd2EInK.mjs → runtime-B9R7bDWT.mjs} +838 -345
- package/dist/runtime-B9R7bDWT.mjs.map +1 -0
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/sanitize-unicode-wLA11KvZ.mjs +29 -0
- package/dist/sanitize-unicode-wLA11KvZ.mjs.map +1 -0
- package/dist/src-C3WBfOks.mjs +5031 -0
- package/dist/src-C3WBfOks.mjs.map +1 -0
- package/dist/transform-messages-DGq9mvhA.mjs +379 -0
- package/dist/transform-messages-DGq9mvhA.mjs.map +1 -0
- package/dist/uuid-DtFT7tOE.mjs +65 -0
- package/dist/uuid-DtFT7tOE.mjs.map +1 -0
- package/package.json +11 -1
- package/dist/compat/pi-ai.mjs.map +0 -1
- package/dist/mcp-config-gqg7GJEE.mjs.map +0 -1
- package/dist/rolldown-runtime-D-uZhY3_.mjs +0 -16
- package/dist/runtime-oLd2EInK.mjs.map +0 -1
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
|
|
2
2
|
import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
|
|
3
|
-
import { E as __setSubagentSessionFactory, S as Theme, f as ExtensionRunner } from "./pi-coding-agent-
|
|
3
|
+
import { E as __setSubagentSessionFactory, S as Theme, f as ExtensionRunner } from "./pi-coding-agent-fPHwKP4d.mjs";
|
|
4
|
+
import { a as resolvePiProviderAuth, n as loginPiProvider, r as providerSupportsOAuth, t as FileCredentialStore } from "./oauth-bridge-C6fL1qSv.mjs";
|
|
5
|
+
import { L as AssistantMessageEventStream, S as realBuiltinProvider, i as builtinProviders, n as __setPiAiLlmBridge } from "./pi-ai-DhYGgq4Y.mjs";
|
|
4
6
|
import { createRequire } from "node:module";
|
|
5
|
-
import { access,
|
|
6
|
-
import {
|
|
7
|
+
import { access, readFile } from "node:fs/promises";
|
|
8
|
+
import { join } from "node:path";
|
|
7
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
8
11
|
import { EventEmitter } from "node:events";
|
|
9
12
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
13
|
import { createJiti } from "jiti";
|
|
11
14
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
12
15
|
import { renderPrompt } from "@deepseek-ai/dsh-system-prompt";
|
|
13
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
14
16
|
import { randomUUID } from "node:crypto";
|
|
15
17
|
//#region src/session-bridge.ts
|
|
16
18
|
function sidecarDir() {
|
|
@@ -433,11 +435,13 @@ var PiBridgedAgentSession = class {
|
|
|
433
435
|
}
|
|
434
436
|
abort() {
|
|
435
437
|
this.#aborted = true;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
438
|
+
try {
|
|
439
|
+
const cancel = this.#handle.agent.cancel;
|
|
440
|
+
cancel?.({
|
|
441
|
+
kind: "hook",
|
|
442
|
+
reason: "pi2dsh subagent abort()"
|
|
443
|
+
});
|
|
444
|
+
} catch {}
|
|
441
445
|
}
|
|
442
446
|
setSessionName(name) {
|
|
443
447
|
this.#sessionName = String(name);
|
|
@@ -477,14 +481,34 @@ async function createBridgedAgentSession(host, options) {
|
|
|
477
481
|
const sessionId = `pi2dsh-sub-${Date.now().toString(36)}-${subagentSerial}`;
|
|
478
482
|
let handle;
|
|
479
483
|
try {
|
|
484
|
+
const requestedModel = options.model;
|
|
485
|
+
const loader = options.resourceLoader;
|
|
486
|
+
const overrideText = typeof options.systemPrompt === "string" && options.systemPrompt.length > 0 ? options.systemPrompt : typeof loader?.getSystemPrompt === "function" ? loader.getSystemPrompt() : void 0;
|
|
487
|
+
const appendTexts = (typeof loader?.getAppendSystemPrompt === "function" ? loader.getAppendSystemPrompt() : []).filter((text) => typeof text === "string" && text.length > 0);
|
|
488
|
+
const systemPrompt = overrideText !== void 0 && overrideText.length > 0 ? [overrideText, ...appendTexts].join("\n\n") : void 0;
|
|
480
489
|
handle = await agents.create({
|
|
481
490
|
sessionId,
|
|
482
491
|
meta: {
|
|
483
492
|
cwd: typeof options.cwd === "string" ? options.cwd : host.cwd(),
|
|
484
493
|
origin: "subagent",
|
|
485
494
|
...host.parentSessionId() !== void 0 ? { parentSession: host.parentSessionId() } : {}
|
|
486
|
-
}
|
|
495
|
+
},
|
|
496
|
+
...typeof requestedModel?.id === "string" && requestedModel.id.length > 0 ? { agentOptions: {
|
|
497
|
+
model: requestedModel.id,
|
|
498
|
+
...typeof requestedModel.provider === "string" && requestedModel.provider.length > 0 ? { provider: requestedModel.provider } : {}
|
|
499
|
+
} } : {}
|
|
487
500
|
});
|
|
501
|
+
if (systemPrompt !== void 0) {
|
|
502
|
+
const agentCtx = handle.agent.ctx;
|
|
503
|
+
const prompt = typeof agentCtx?.get === "function" ? agentCtx.get("systemPrompt") : void 0;
|
|
504
|
+
if (prompt === void 0) throw new Error("pi2dsh: createAgentSession() got a system prompt but the DSH composition has no systemPrompt service to carry it");
|
|
505
|
+
prompt.section({
|
|
506
|
+
name: "pi2dsh:subagent-system-prompt",
|
|
507
|
+
order: -1e6,
|
|
508
|
+
text: systemPrompt,
|
|
509
|
+
complete: true
|
|
510
|
+
});
|
|
511
|
+
}
|
|
488
512
|
} catch (error) {
|
|
489
513
|
throw new Error(`pi2dsh: subagent creation needs the DSH host loop (model runtime) to provide the agent factory; this composition cannot run one (${error instanceof Error ? error.message : String(error)})`);
|
|
490
514
|
}
|
|
@@ -492,356 +516,661 @@ async function createBridgedAgentSession(host, options) {
|
|
|
492
516
|
return { session: new PiBridgedAgentSession(host, handle, tools) };
|
|
493
517
|
}
|
|
494
518
|
//#endregion
|
|
495
|
-
//#region src/
|
|
496
|
-
function
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
519
|
+
//#region src/model-bridge.ts
|
|
520
|
+
function llmOf(ctx) {
|
|
521
|
+
try {
|
|
522
|
+
const service = ctx.get("llm");
|
|
523
|
+
if (typeof service?.stream !== "function") return void 0;
|
|
524
|
+
return service;
|
|
525
|
+
} catch {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
501
528
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
return
|
|
529
|
+
function piModelFromInfo(info) {
|
|
530
|
+
const modalities = Array.isArray(info.inputModalities) ? info.inputModalities : void 0;
|
|
531
|
+
return {
|
|
532
|
+
id: String(info.id ?? ""),
|
|
533
|
+
name: String(info.name ?? info.id ?? ""),
|
|
534
|
+
provider: String(info.provider ?? ""),
|
|
535
|
+
api: "dsh-llm",
|
|
536
|
+
input: modalities === void 0 ? ["text"] : modalities.filter((m) => m === "text" || m === "image"),
|
|
537
|
+
reasoning: info.reasoning !== void 0
|
|
538
|
+
};
|
|
505
539
|
}
|
|
506
540
|
/**
|
|
507
|
-
*
|
|
508
|
-
*
|
|
541
|
+
* Cached projection of DSH's advisory model catalog as Pi Model objects.
|
|
542
|
+
* `refresh()` re-reads providers and models; the runtime subscribes it to
|
|
543
|
+
* `llm/adapters-updated`. Reads are synchronous (Pi's getAll contract).
|
|
509
544
|
*/
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
545
|
+
var ModelCatalog = class {
|
|
546
|
+
#llm;
|
|
547
|
+
#models = [];
|
|
548
|
+
#resolved = /* @__PURE__ */ new Map();
|
|
549
|
+
#refreshing;
|
|
550
|
+
constructor(llm) {
|
|
551
|
+
this.#llm = llm;
|
|
514
552
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
518
|
-
const onAbort = () => {
|
|
519
|
-
if (settled) return;
|
|
520
|
-
settled = true;
|
|
521
|
-
cleanup();
|
|
522
|
-
reject(abortReason(signal));
|
|
523
|
-
};
|
|
524
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
525
|
-
operation.then((value) => {
|
|
526
|
-
if (settled) return;
|
|
527
|
-
settled = true;
|
|
528
|
-
cleanup();
|
|
529
|
-
resolve(value);
|
|
530
|
-
}, (error) => {
|
|
531
|
-
if (settled) return;
|
|
532
|
-
settled = true;
|
|
533
|
-
cleanup();
|
|
534
|
-
reject(error);
|
|
535
|
-
});
|
|
536
|
-
if (signal.aborted) onAbort();
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
//#endregion
|
|
540
|
-
//#region src/compat/vendor/pi-ai-credential-store.ts
|
|
541
|
-
/**
|
|
542
|
-
* Default in-memory credential store. Apps inject persistent stores.
|
|
543
|
-
* Keyed by `Provider.id`, one credential per provider; see `CredentialStore`.
|
|
544
|
-
* Writes are serialized per provider through a promise chain.
|
|
545
|
-
*/
|
|
546
|
-
var InMemoryCredentialStore = class {
|
|
547
|
-
credentials = /* @__PURE__ */ new Map();
|
|
548
|
-
chains = /* @__PURE__ */ new Map();
|
|
549
|
-
/** Serialize tasks per provider id without releasing the chain before active work settles. */
|
|
550
|
-
enqueue(providerId, task, options) {
|
|
551
|
-
const signal = operationSignal(options?.signal);
|
|
552
|
-
const previous = this.chains.get(providerId) ?? Promise.resolve();
|
|
553
|
-
const queued = (async () => {
|
|
554
|
-
await previous.catch(() => {});
|
|
555
|
-
signal.throwIfAborted();
|
|
556
|
-
return task();
|
|
557
|
-
})();
|
|
558
|
-
const tail = queued.catch(() => {});
|
|
559
|
-
this.chains.set(providerId, tail);
|
|
560
|
-
tail.then(() => {
|
|
561
|
-
if (this.chains.get(providerId) === tail) this.chains.delete(providerId);
|
|
562
|
-
});
|
|
563
|
-
return raceWithAbortSignal(queued, signal);
|
|
553
|
+
get present() {
|
|
554
|
+
return this.#llm !== void 0;
|
|
564
555
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
return this.credentials.get(providerId);
|
|
556
|
+
all() {
|
|
557
|
+
return [...this.#models];
|
|
568
558
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
return [...this.credentials].map(([providerId, credential]) => ({
|
|
572
|
-
providerId,
|
|
573
|
-
type: credential.type
|
|
574
|
-
}));
|
|
559
|
+
find(provider, modelId) {
|
|
560
|
+
return this.#resolved.get(`${provider}${modelId}`) ?? this.#models.find((model) => model.provider === provider && model.id === modelId);
|
|
575
561
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
return next ?? current;
|
|
583
|
-
}, options);
|
|
562
|
+
refresh() {
|
|
563
|
+
if (this.#llm === void 0) return Promise.resolve();
|
|
564
|
+
this.#refreshing ??= this.#refreshOnce().finally(() => {
|
|
565
|
+
this.#refreshing = void 0;
|
|
566
|
+
});
|
|
567
|
+
return this.#refreshing;
|
|
584
568
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
569
|
+
async #refreshOnce() {
|
|
570
|
+
const llm = this.#llm;
|
|
571
|
+
if (llm === void 0) return;
|
|
572
|
+
const next = [];
|
|
573
|
+
for (const provider of llm.listProviders()) try {
|
|
574
|
+
for (const info of await llm.listModels(provider.id)) next.push(piModelFromInfo({
|
|
575
|
+
...info,
|
|
576
|
+
provider: provider.id
|
|
577
|
+
}));
|
|
578
|
+
} catch {}
|
|
579
|
+
this.#models = next;
|
|
589
580
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
581
|
+
/** Exact-route metadata (context window, reasoning efforts), cached per route. */
|
|
582
|
+
async resolve(provider, modelId) {
|
|
583
|
+
if (this.#llm === void 0) return void 0;
|
|
584
|
+
const key = `${provider}${modelId}`;
|
|
585
|
+
const cached = this.#resolved.get(key);
|
|
586
|
+
if (cached !== void 0) return cached;
|
|
587
|
+
try {
|
|
588
|
+
const info = await this.#llm.resolveModelInfo(provider, modelId);
|
|
589
|
+
const model = piModelFromInfo(info);
|
|
590
|
+
const context = info.context;
|
|
591
|
+
if (typeof context?.contextWindow === "number") model.contextWindow = context.contextWindow;
|
|
592
|
+
const defaultMaxTokens = info.defaultMaxTokens;
|
|
593
|
+
if (typeof defaultMaxTokens === "number") model.maxTokens = defaultMaxTokens;
|
|
594
|
+
const reasoning = info.reasoning;
|
|
595
|
+
model.reasoning = Array.isArray(reasoning?.efforts) && reasoning.efforts.length > 0;
|
|
596
|
+
this.#resolved.set(key, model);
|
|
597
|
+
return model;
|
|
598
|
+
} catch {
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
606
601
|
}
|
|
607
602
|
};
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
return
|
|
603
|
+
function dshBlocksFromPiContent(content) {
|
|
604
|
+
if (typeof content === "string") return content.length > 0 ? [{
|
|
605
|
+
type: "text",
|
|
606
|
+
text: content
|
|
607
|
+
}] : [];
|
|
608
|
+
if (!Array.isArray(content)) return [];
|
|
609
|
+
const blocks = [];
|
|
610
|
+
for (const block of content) if (block.type === "text" && typeof block.text === "string") blocks.push({
|
|
611
|
+
type: "text",
|
|
612
|
+
text: block.text
|
|
613
|
+
});
|
|
614
|
+
else if (block.type === "thinking" && typeof block.thinking === "string") blocks.push({
|
|
615
|
+
type: "reasoning",
|
|
616
|
+
text: block.thinking
|
|
617
|
+
});
|
|
618
|
+
else if (block.type === "toolCall") blocks.push({
|
|
619
|
+
type: "tool-call",
|
|
620
|
+
id: String(block.id ?? ""),
|
|
621
|
+
name: String(block.name ?? ""),
|
|
622
|
+
arguments: typeof block.arguments === "string" ? block.arguments : JSON.stringify(block.arguments ?? {})
|
|
623
|
+
});
|
|
624
|
+
else if (block.type === "image") blocks.push({
|
|
625
|
+
type: "text",
|
|
626
|
+
text: `[image omitted by pi2dsh: ${String(block.mimeType ?? "unknown media type")}]`
|
|
627
|
+
});
|
|
628
|
+
return blocks;
|
|
614
629
|
}
|
|
615
630
|
/**
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
* nothing is stored. No silent env fallback after a failed refresh or for a
|
|
619
|
-
* credential type without a matching handler.
|
|
631
|
+
* Pi request context → DSH GenerateOptions parts. System prompt moves to the
|
|
632
|
+
* dedicated slot; toolResult messages become DSH tool-result user messages.
|
|
620
633
|
*/
|
|
621
|
-
function
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
if (stored.type === "api_key" && provider.auth.apiKey) {
|
|
637
|
-
const credential = overrides?.env ? {
|
|
638
|
-
...stored,
|
|
639
|
-
env: {
|
|
640
|
-
...stored.env,
|
|
641
|
-
...overrides.env
|
|
642
|
-
}
|
|
643
|
-
} : stored;
|
|
644
|
-
return resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, credential, signal);
|
|
634
|
+
function piRequestToDshMessages(context) {
|
|
635
|
+
const messages = [];
|
|
636
|
+
const source = Array.isArray(context.messages) ? context.messages : [];
|
|
637
|
+
for (const message of source) if (message.role === "user") messages.push({
|
|
638
|
+
role: "user",
|
|
639
|
+
content: dshBlocksFromPiContent(message.content),
|
|
640
|
+
source: { kind: "user" }
|
|
641
|
+
});
|
|
642
|
+
else if (message.role === "assistant") messages.push({
|
|
643
|
+
role: "assistant",
|
|
644
|
+
content: dshBlocksFromPiContent(message.content),
|
|
645
|
+
source: {
|
|
646
|
+
kind: "model",
|
|
647
|
+
provider: String(message.provider ?? context.provider ?? "pi2dsh"),
|
|
648
|
+
model: String(message.model ?? context.model ?? "unknown")
|
|
645
649
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
650
|
+
});
|
|
651
|
+
else if (message.role === "toolResult") messages.push({
|
|
652
|
+
role: "user",
|
|
653
|
+
content: [{
|
|
654
|
+
type: "tool-result",
|
|
655
|
+
toolCallId: String(message.toolCallId ?? ""),
|
|
656
|
+
content: dshBlocksFromPiContent(message.content),
|
|
657
|
+
isError: message.isError === true
|
|
658
|
+
}],
|
|
659
|
+
source: {
|
|
660
|
+
kind: "tool",
|
|
661
|
+
callId: String(message.toolCallId ?? "")
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
const system = typeof context.systemPrompt === "string" && context.systemPrompt.length > 0 ? context.systemPrompt : void 0;
|
|
665
|
+
return {
|
|
666
|
+
...system === void 0 ? {} : { system },
|
|
667
|
+
messages
|
|
668
|
+
};
|
|
649
669
|
}
|
|
650
|
-
function
|
|
670
|
+
function piUsageFromDsh(usage) {
|
|
671
|
+
const input = Number(usage?.inputTokens ?? 0);
|
|
672
|
+
const output = Number(usage?.outputTokens ?? 0);
|
|
673
|
+
const cacheRead = Number(usage?.cacheReadTokens ?? 0);
|
|
674
|
+
const cacheWrite = Number(usage?.cacheWriteTokens ?? 0);
|
|
651
675
|
return {
|
|
652
|
-
|
|
653
|
-
|
|
676
|
+
input,
|
|
677
|
+
output,
|
|
678
|
+
cacheRead,
|
|
679
|
+
cacheWrite,
|
|
680
|
+
totalTokens: input + output + cacheRead + cacheWrite,
|
|
681
|
+
cost: {
|
|
682
|
+
input: 0,
|
|
683
|
+
output: 0,
|
|
684
|
+
cacheRead: 0,
|
|
685
|
+
cacheWrite: 0,
|
|
686
|
+
total: 0
|
|
687
|
+
}
|
|
654
688
|
};
|
|
655
689
|
}
|
|
656
|
-
|
|
657
|
-
|
|
690
|
+
function piStopReason(finish) {
|
|
691
|
+
switch (finish?.kind) {
|
|
692
|
+
case "stop": return "stop";
|
|
693
|
+
case "max-tokens": return "length";
|
|
694
|
+
case "tool-calls": return "toolUse";
|
|
695
|
+
case "aborted": return "aborted";
|
|
696
|
+
default: return "error";
|
|
697
|
+
}
|
|
698
|
+
}
|
|
658
699
|
/**
|
|
659
|
-
*
|
|
660
|
-
*
|
|
661
|
-
* globally, and persist the rotated credential before release.
|
|
700
|
+
* Run one hand-built pi-ai model call on DSH's native llm service, translating
|
|
701
|
+
* the chunk stream into Pi's AssistantMessageEventStream vocabulary.
|
|
662
702
|
*/
|
|
663
|
-
|
|
664
|
-
const
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
703
|
+
function streamViaDshLlm(llm, request) {
|
|
704
|
+
const stream = new AssistantMessageEventStream();
|
|
705
|
+
const provider = String(request.model.provider ?? "");
|
|
706
|
+
const modelId = String(request.model.id ?? "");
|
|
707
|
+
const { system, messages } = piRequestToDshMessages({
|
|
708
|
+
...request.context,
|
|
709
|
+
provider,
|
|
710
|
+
model: modelId
|
|
711
|
+
});
|
|
712
|
+
const options = request.options ?? {};
|
|
713
|
+
const generate = {
|
|
714
|
+
provider,
|
|
715
|
+
model: modelId,
|
|
716
|
+
messages,
|
|
717
|
+
...system === void 0 ? {} : { system },
|
|
718
|
+
...Array.isArray(request.context.tools) ? { tools: normalizeToolSchemas(request.context.tools) } : {},
|
|
719
|
+
...typeof options.maxTokens === "number" ? { maxTokens: options.maxTokens } : {},
|
|
720
|
+
...typeof options.temperature === "number" ? { temperature: options.temperature } : {},
|
|
721
|
+
...options.signal instanceof AbortSignal ? { signal: options.signal } : {}
|
|
722
|
+
};
|
|
723
|
+
(async () => {
|
|
724
|
+
const partial = {
|
|
725
|
+
role: "assistant",
|
|
726
|
+
content: [],
|
|
727
|
+
provider,
|
|
728
|
+
model: modelId,
|
|
729
|
+
api: "dsh-llm"
|
|
730
|
+
};
|
|
731
|
+
const content = partial.content;
|
|
732
|
+
let usage;
|
|
733
|
+
stream.push({
|
|
734
|
+
type: "start",
|
|
735
|
+
partial
|
|
736
|
+
});
|
|
669
737
|
try {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
const
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
738
|
+
for await (const chunk of llm.stream(generate)) {
|
|
739
|
+
const type = String(chunk.type ?? "");
|
|
740
|
+
const index = Number(chunk.index ?? 0);
|
|
741
|
+
if (type === "block-start") {
|
|
742
|
+
const blockType = String(chunk.blockType ?? "");
|
|
743
|
+
if (blockType === "text") {
|
|
744
|
+
content[index] = {
|
|
745
|
+
type: "text",
|
|
746
|
+
text: ""
|
|
747
|
+
};
|
|
748
|
+
stream.push({
|
|
749
|
+
type: "text_start",
|
|
750
|
+
contentIndex: index,
|
|
751
|
+
partial
|
|
752
|
+
});
|
|
753
|
+
} else if (blockType === "reasoning") {
|
|
754
|
+
content[index] = {
|
|
755
|
+
type: "thinking",
|
|
756
|
+
thinking: ""
|
|
757
|
+
};
|
|
758
|
+
stream.push({
|
|
759
|
+
type: "thinking_start",
|
|
760
|
+
contentIndex: index,
|
|
761
|
+
partial
|
|
762
|
+
});
|
|
763
|
+
} else if (blockType === "tool-call") {
|
|
764
|
+
content[index] = {
|
|
765
|
+
type: "toolCall",
|
|
766
|
+
id: "",
|
|
767
|
+
name: "",
|
|
768
|
+
arguments: void 0,
|
|
769
|
+
partialJson: ""
|
|
770
|
+
};
|
|
771
|
+
stream.push({
|
|
772
|
+
type: "toolcall_start",
|
|
773
|
+
contentIndex: index,
|
|
774
|
+
partial
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
} else if (type === "text-delta") {
|
|
778
|
+
const block = content[index] ??= {
|
|
779
|
+
type: "text",
|
|
780
|
+
text: ""
|
|
781
|
+
};
|
|
782
|
+
block.text = String(block.text ?? "") + String(chunk.text ?? "");
|
|
783
|
+
stream.push({
|
|
784
|
+
type: "text_delta",
|
|
785
|
+
contentIndex: index,
|
|
786
|
+
delta: String(chunk.text ?? ""),
|
|
787
|
+
partial
|
|
788
|
+
});
|
|
789
|
+
} else if (type === "reasoning-delta") {
|
|
790
|
+
const block = content[index] ??= {
|
|
791
|
+
type: "thinking",
|
|
792
|
+
thinking: ""
|
|
793
|
+
};
|
|
794
|
+
block.thinking = String(block.thinking ?? "") + String(chunk.text ?? "");
|
|
795
|
+
stream.push({
|
|
796
|
+
type: "thinking_delta",
|
|
797
|
+
contentIndex: index,
|
|
798
|
+
delta: String(chunk.text ?? ""),
|
|
799
|
+
partial
|
|
800
|
+
});
|
|
801
|
+
} else if (type === "tool-call-delta") {
|
|
802
|
+
const block = content[index] ??= {
|
|
803
|
+
type: "toolCall",
|
|
804
|
+
id: "",
|
|
805
|
+
name: "",
|
|
806
|
+
arguments: void 0,
|
|
807
|
+
partialJson: ""
|
|
808
|
+
};
|
|
809
|
+
if (chunk.id !== void 0) block.id = String(chunk.id);
|
|
810
|
+
if (chunk.name !== void 0) block.name = String(chunk.name);
|
|
811
|
+
block.partialJson = String(block.partialJson ?? "") + String(chunk.argumentsDelta ?? "");
|
|
812
|
+
stream.push({
|
|
813
|
+
type: "toolcall_delta",
|
|
814
|
+
contentIndex: index,
|
|
815
|
+
delta: String(chunk.argumentsDelta ?? ""),
|
|
816
|
+
partial
|
|
817
|
+
});
|
|
818
|
+
} else if (type === "block-end") {
|
|
819
|
+
const block = chunk.block;
|
|
820
|
+
const blockType = String(block?.type ?? "");
|
|
821
|
+
if (blockType === "text") {
|
|
822
|
+
content[index] = {
|
|
823
|
+
type: "text",
|
|
824
|
+
text: String(block?.text ?? "")
|
|
825
|
+
};
|
|
826
|
+
stream.push({
|
|
827
|
+
type: "text_end",
|
|
828
|
+
contentIndex: index,
|
|
829
|
+
content: String(block?.text ?? ""),
|
|
830
|
+
partial
|
|
831
|
+
});
|
|
832
|
+
} else if (blockType === "reasoning") {
|
|
833
|
+
content[index] = {
|
|
834
|
+
type: "thinking",
|
|
835
|
+
thinking: String(block?.text ?? "")
|
|
836
|
+
};
|
|
837
|
+
stream.push({
|
|
838
|
+
type: "thinking_end",
|
|
839
|
+
contentIndex: index,
|
|
840
|
+
content: String(block?.text ?? ""),
|
|
841
|
+
partial
|
|
842
|
+
});
|
|
843
|
+
} else if (blockType === "tool-call") {
|
|
844
|
+
let parsed;
|
|
845
|
+
try {
|
|
846
|
+
parsed = JSON.parse(String(block?.arguments ?? "{}"));
|
|
847
|
+
} catch {
|
|
848
|
+
parsed = {};
|
|
849
|
+
}
|
|
850
|
+
content[index] = {
|
|
851
|
+
type: "toolCall",
|
|
852
|
+
id: String(block?.id ?? ""),
|
|
853
|
+
name: String(block?.name ?? ""),
|
|
854
|
+
arguments: parsed
|
|
855
|
+
};
|
|
856
|
+
stream.push({
|
|
857
|
+
type: "toolcall_end",
|
|
858
|
+
contentIndex: index,
|
|
859
|
+
toolCall: content[index],
|
|
860
|
+
partial
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
} else if (type === "usage") usage = piUsageFromDsh(chunk.usage);
|
|
864
|
+
else if (type === "finish") {
|
|
865
|
+
const finish = chunk.reason;
|
|
866
|
+
const stopReason = piStopReason(finish);
|
|
867
|
+
if (stopReason === "error" || stopReason === "aborted") {
|
|
868
|
+
const failure = finish?.failure;
|
|
869
|
+
const error = {
|
|
870
|
+
type: "error",
|
|
871
|
+
reason: stopReason === "aborted" ? "aborted" : "error",
|
|
872
|
+
error: new Error(String(failure?.message ?? `model call failed (${stopReason})`))
|
|
873
|
+
};
|
|
874
|
+
stream.push({
|
|
875
|
+
...error,
|
|
876
|
+
partial
|
|
877
|
+
});
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
const message = {
|
|
881
|
+
role: "assistant",
|
|
882
|
+
content: content.filter((block) => block !== void 0),
|
|
883
|
+
provider,
|
|
884
|
+
model: modelId,
|
|
885
|
+
api: "dsh-llm",
|
|
886
|
+
...usage === void 0 ? {} : { usage },
|
|
887
|
+
stopReason,
|
|
888
|
+
timestamp: Date.now()
|
|
889
|
+
};
|
|
890
|
+
stream.push({
|
|
891
|
+
type: "done",
|
|
892
|
+
reason: stopReason,
|
|
893
|
+
message
|
|
894
|
+
});
|
|
895
|
+
return;
|
|
678
896
|
}
|
|
679
|
-
}
|
|
897
|
+
}
|
|
898
|
+
stream.push({
|
|
899
|
+
type: "error",
|
|
900
|
+
reason: "error",
|
|
901
|
+
error: /* @__PURE__ */ new Error("pi2dsh: DSH llm stream ended without a finish chunk"),
|
|
902
|
+
partial
|
|
903
|
+
});
|
|
680
904
|
} catch (error) {
|
|
681
|
-
|
|
682
|
-
|
|
905
|
+
stream.push({
|
|
906
|
+
type: "error",
|
|
907
|
+
reason: "error",
|
|
908
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
909
|
+
partial
|
|
910
|
+
});
|
|
683
911
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
}
|
|
912
|
+
})();
|
|
913
|
+
return stream;
|
|
914
|
+
}
|
|
915
|
+
function normalizeToolSchemas(tools) {
|
|
916
|
+
return tools.map((tool) => ({
|
|
917
|
+
name: String(tool.name ?? ""),
|
|
918
|
+
description: String(tool.description ?? ""),
|
|
919
|
+
parameters: tool.parameters ?? tool.inputSchema ?? {
|
|
920
|
+
type: "object",
|
|
921
|
+
properties: {}
|
|
922
|
+
}
|
|
923
|
+
}));
|
|
696
924
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
925
|
+
/** DSH GenerateOptions parts → the Pi request context a provider.stream expects. */
|
|
926
|
+
function dshRequestToPiContext(options) {
|
|
927
|
+
const piMessages = [];
|
|
928
|
+
for (const message of Array.isArray(options.messages) ? options.messages : []) {
|
|
929
|
+
const content = Array.isArray(message.content) ? message.content : [];
|
|
930
|
+
const source = message.source;
|
|
931
|
+
if (message.role === "user" && source?.kind === "tool") {
|
|
932
|
+
const result = content[0];
|
|
933
|
+
piMessages.push({
|
|
934
|
+
role: "toolResult",
|
|
935
|
+
toolCallId: String(result?.toolCallId ?? ""),
|
|
936
|
+
content: piContentFromDshBlocks(Array.isArray(result?.content) ? result.content : []),
|
|
937
|
+
isError: result?.isError === true
|
|
938
|
+
});
|
|
939
|
+
} else if (message.role === "user") piMessages.push({
|
|
940
|
+
role: "user",
|
|
941
|
+
content: piContentFromDshBlocks(content)
|
|
942
|
+
});
|
|
943
|
+
else if (message.role === "assistant") piMessages.push({
|
|
944
|
+
role: "assistant",
|
|
945
|
+
content: piContentFromDshBlocks(content)
|
|
703
946
|
});
|
|
704
|
-
} catch (error) {
|
|
705
|
-
throw new ModelsError("auth", `API key auth failed for provider ${providerId}`, { cause: error });
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
async function readCredential(credentials, providerId, signal) {
|
|
709
|
-
try {
|
|
710
|
-
return await credentials.read(providerId, { signal });
|
|
711
|
-
} catch (error) {
|
|
712
|
-
throw new ModelsError("auth", `Credential store read failed for ${providerId}`, { cause: error });
|
|
713
947
|
}
|
|
714
|
-
}
|
|
715
|
-
//#endregion
|
|
716
|
-
//#region src/compat/vendor/pi-oauth-adapt.ts
|
|
717
|
-
function adaptOAuth(config) {
|
|
718
948
|
return {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
return {
|
|
723
|
-
...await config.login({
|
|
724
|
-
onAuth: (info) => callbacks.notify({
|
|
725
|
-
type: "auth_url",
|
|
726
|
-
...info
|
|
727
|
-
}),
|
|
728
|
-
onDeviceCode: (info) => callbacks.notify({
|
|
729
|
-
type: "device_code",
|
|
730
|
-
...info
|
|
731
|
-
}),
|
|
732
|
-
onPrompt: (prompt) => callbacks.prompt({
|
|
733
|
-
type: "text",
|
|
734
|
-
...prompt
|
|
735
|
-
}),
|
|
736
|
-
onProgress: (message) => callbacks.notify({
|
|
737
|
-
type: "progress",
|
|
738
|
-
message
|
|
739
|
-
}),
|
|
740
|
-
onManualCodeInput: () => callbacks.prompt({
|
|
741
|
-
type: "manual_code",
|
|
742
|
-
message: "Paste the authorization code"
|
|
743
|
-
}),
|
|
744
|
-
onSelect: (prompt) => callbacks.prompt({
|
|
745
|
-
type: "select",
|
|
746
|
-
...prompt
|
|
747
|
-
}),
|
|
748
|
-
signal: callbacks.signal
|
|
749
|
-
}),
|
|
750
|
-
type: "oauth"
|
|
751
|
-
};
|
|
752
|
-
},
|
|
753
|
-
refresh: async (credential, signal) => ({
|
|
754
|
-
...await config.refreshToken(credential, signal),
|
|
755
|
-
type: "oauth"
|
|
756
|
-
}),
|
|
757
|
-
toAuth: async (credential) => ({ apiKey: config.getApiKey(credential) })
|
|
949
|
+
...typeof options.system === "string" && options.system.length > 0 ? { systemPrompt: options.system } : {},
|
|
950
|
+
messages: piMessages,
|
|
951
|
+
...Array.isArray(options.tools) ? { tools: options.tools } : {}
|
|
758
952
|
};
|
|
759
953
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
954
|
+
function piContentFromDshBlocks(blocks) {
|
|
955
|
+
const out = [];
|
|
956
|
+
for (const block of blocks) if (block.type === "text") out.push({
|
|
957
|
+
type: "text",
|
|
958
|
+
text: String(block.text ?? "")
|
|
959
|
+
});
|
|
960
|
+
else if (block.type === "reasoning") out.push({
|
|
961
|
+
type: "thinking",
|
|
962
|
+
thinking: String(block.text ?? "")
|
|
963
|
+
});
|
|
964
|
+
else if (block.type === "tool-call") {
|
|
965
|
+
let parsed;
|
|
767
966
|
try {
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
await mkdir(dirname(this.#path), { recursive: true });
|
|
779
|
-
const temp = `${this.#path}.tmp-${process.pid}-${Math.floor(Math.random() * 1e9).toString(36)}`;
|
|
780
|
-
await writeFile(temp, `${JSON.stringify(data, null, 2)}\n`, { mode: 384 });
|
|
781
|
-
await rename(temp, this.#path);
|
|
967
|
+
parsed = JSON.parse(String(block.arguments ?? "{}"));
|
|
968
|
+
} catch {
|
|
969
|
+
parsed = {};
|
|
970
|
+
}
|
|
971
|
+
out.push({
|
|
972
|
+
type: "toolCall",
|
|
973
|
+
id: String(block.id ?? ""),
|
|
974
|
+
name: String(block.name ?? ""),
|
|
975
|
+
arguments: parsed
|
|
976
|
+
});
|
|
782
977
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
978
|
+
return out;
|
|
979
|
+
}
|
|
980
|
+
/** A Pi AssistantMessageEventStream → DSH StreamChunk sequence. */
|
|
981
|
+
async function* piEventsToDshChunks(events) {
|
|
982
|
+
let usage;
|
|
983
|
+
for await (const event of events) {
|
|
984
|
+
const type = String(event.type ?? "");
|
|
985
|
+
const index = Number(event.contentIndex ?? 0);
|
|
986
|
+
if (type === "text_start") yield {
|
|
987
|
+
type: "block-start",
|
|
988
|
+
index,
|
|
989
|
+
blockType: "text"
|
|
990
|
+
};
|
|
991
|
+
else if (type === "text_delta") yield {
|
|
992
|
+
type: "text-delta",
|
|
993
|
+
index,
|
|
994
|
+
text: String(event.delta ?? "")
|
|
995
|
+
};
|
|
996
|
+
else if (type === "text_end") yield {
|
|
997
|
+
type: "block-end",
|
|
998
|
+
index,
|
|
999
|
+
block: {
|
|
1000
|
+
type: "text",
|
|
1001
|
+
text: String(event.content ?? "")
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
else if (type === "thinking_start") yield {
|
|
1005
|
+
type: "block-start",
|
|
1006
|
+
index,
|
|
1007
|
+
blockType: "reasoning"
|
|
1008
|
+
};
|
|
1009
|
+
else if (type === "thinking_delta") yield {
|
|
1010
|
+
type: "reasoning-delta",
|
|
1011
|
+
index,
|
|
1012
|
+
text: String(event.delta ?? "")
|
|
1013
|
+
};
|
|
1014
|
+
else if (type === "thinking_end") yield {
|
|
1015
|
+
type: "block-end",
|
|
1016
|
+
index,
|
|
1017
|
+
block: {
|
|
1018
|
+
type: "reasoning",
|
|
1019
|
+
text: String(event.content ?? "")
|
|
789
1020
|
}
|
|
790
|
-
|
|
791
|
-
|
|
1021
|
+
};
|
|
1022
|
+
else if (type === "toolcall_start") yield {
|
|
1023
|
+
type: "block-start",
|
|
1024
|
+
index,
|
|
1025
|
+
blockType: "tool-call"
|
|
1026
|
+
};
|
|
1027
|
+
else if (type === "toolcall_delta") yield {
|
|
1028
|
+
type: "tool-call-delta",
|
|
1029
|
+
index,
|
|
1030
|
+
id: "",
|
|
1031
|
+
argumentsDelta: String(event.delta ?? "")
|
|
1032
|
+
};
|
|
1033
|
+
else if (type === "toolcall_end") {
|
|
1034
|
+
const call = event.toolCall;
|
|
1035
|
+
yield {
|
|
1036
|
+
type: "block-end",
|
|
1037
|
+
index,
|
|
1038
|
+
block: {
|
|
1039
|
+
type: "tool-call",
|
|
1040
|
+
id: String(call?.id ?? ""),
|
|
1041
|
+
name: String(call?.name ?? ""),
|
|
1042
|
+
arguments: typeof call?.arguments === "string" ? call.arguments : JSON.stringify(call?.arguments ?? {})
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
} else if (type === "done") {
|
|
1046
|
+
const message = event.message;
|
|
1047
|
+
const piUsage = message?.usage;
|
|
1048
|
+
if (piUsage !== void 0) {
|
|
1049
|
+
usage = {
|
|
1050
|
+
inputTokens: Number(piUsage.input ?? 0),
|
|
1051
|
+
outputTokens: Number(piUsage.output ?? 0),
|
|
1052
|
+
...piUsage.cacheRead === void 0 ? {} : { cacheReadTokens: Number(piUsage.cacheRead) },
|
|
1053
|
+
...piUsage.cacheWrite === void 0 ? {} : { cacheWriteTokens: Number(piUsage.cacheWrite) }
|
|
1054
|
+
};
|
|
1055
|
+
yield {
|
|
1056
|
+
type: "usage",
|
|
1057
|
+
usage
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
const stop = String(message?.stopReason ?? "stop");
|
|
1061
|
+
yield {
|
|
1062
|
+
type: "finish",
|
|
1063
|
+
reason: stop === "length" ? { kind: "max-tokens" } : stop === "toolUse" ? { kind: "tool-calls" } : stop === "aborted" ? {
|
|
1064
|
+
kind: "aborted",
|
|
1065
|
+
failure: {
|
|
1066
|
+
message: "aborted by caller",
|
|
1067
|
+
code: "ABORTED"
|
|
1068
|
+
}
|
|
1069
|
+
} : { kind: "stop" }
|
|
1070
|
+
};
|
|
1071
|
+
return;
|
|
1072
|
+
} else if (type === "error") {
|
|
1073
|
+
const error = event.error;
|
|
1074
|
+
yield {
|
|
1075
|
+
type: "finish",
|
|
1076
|
+
reason: {
|
|
1077
|
+
kind: String(event.reason ?? "") === "aborted" ? "aborted" : "error",
|
|
1078
|
+
failure: {
|
|
1079
|
+
message: error instanceof Error ? error.message : String(error ?? "provider stream error"),
|
|
1080
|
+
code: "PI_PROVIDER"
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
792
1086
|
}
|
|
793
|
-
|
|
794
|
-
|
|
1087
|
+
yield {
|
|
1088
|
+
type: "finish",
|
|
1089
|
+
reason: {
|
|
1090
|
+
kind: "error",
|
|
1091
|
+
failure: {
|
|
1092
|
+
message: "pi2dsh: Pi provider stream ended without done/error",
|
|
1093
|
+
code: "PI_PROVIDER"
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
//#endregion
|
|
1099
|
+
//#region src/provider-adapter.ts
|
|
1100
|
+
function providerCarriesTransport(value) {
|
|
1101
|
+
return typeof value?.stream === "function";
|
|
1102
|
+
}
|
|
1103
|
+
function providerModels(provider) {
|
|
1104
|
+
try {
|
|
1105
|
+
const models = provider.getModels?.();
|
|
1106
|
+
return Array.isArray(models) ? models : [];
|
|
1107
|
+
} catch {
|
|
1108
|
+
return [];
|
|
795
1109
|
}
|
|
796
|
-
}
|
|
797
|
-
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Wrap one Pi provider object as a DSH LlmAdapter-shaped route handler.
|
|
1113
|
+
* Structural typing carries it through `llm.registerAdapter`.
|
|
1114
|
+
*/
|
|
1115
|
+
function piProviderDshAdapter(providerId, provider, host) {
|
|
798
1116
|
return {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1117
|
+
providerInfo: (id) => ({
|
|
1118
|
+
id,
|
|
1119
|
+
name: typeof provider.name === "string" ? provider.name : id
|
|
1120
|
+
}),
|
|
1121
|
+
providerRetryPolicy: () => void 0,
|
|
1122
|
+
listModels: async (id) => providerModels(provider).map((model) => ({
|
|
1123
|
+
provider: id,
|
|
1124
|
+
id: String(model.id ?? ""),
|
|
1125
|
+
name: String(model.name ?? model.id ?? ""),
|
|
1126
|
+
...Array.isArray(model.input) ? { inputModalities: model.input.filter((m) => m === "text" || m === "image") } : {}
|
|
1127
|
+
})),
|
|
1128
|
+
resolveModel: async (id, modelId) => {
|
|
1129
|
+
const known = providerModels(provider).find((model) => model.id === modelId);
|
|
1130
|
+
return {
|
|
1131
|
+
provider: id,
|
|
1132
|
+
id: modelId,
|
|
1133
|
+
name: String(known?.name ?? modelId),
|
|
1134
|
+
...typeof known?.contextWindow === "number" ? { context: { contextWindow: known.contextWindow } } : {},
|
|
1135
|
+
...typeof known?.maxTokens === "number" ? { defaultMaxTokens: known.maxTokens } : {}
|
|
1136
|
+
};
|
|
807
1137
|
},
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
1138
|
+
async *stream(options) {
|
|
1139
|
+
const auth = (await host.resolveAuth())?.auth;
|
|
1140
|
+
const modelId = String(options.model ?? "");
|
|
1141
|
+
const model = providerModels(provider).find((entry) => entry.id === modelId) ?? {
|
|
1142
|
+
id: modelId,
|
|
1143
|
+
provider: providerId
|
|
1144
|
+
};
|
|
1145
|
+
const piContext = dshRequestToPiContext(options);
|
|
1146
|
+
const piOptions = {
|
|
1147
|
+
...auth?.apiKey === void 0 ? {} : { apiKey: auth.apiKey },
|
|
1148
|
+
...auth?.baseUrl === void 0 ? {} : { baseUrl: auth.baseUrl },
|
|
1149
|
+
...auth?.headers === void 0 ? {} : { headers: auth.headers },
|
|
1150
|
+
...options.signal instanceof AbortSignal ? { signal: options.signal } : {},
|
|
1151
|
+
...typeof options.maxTokens === "number" ? { maxTokens: options.maxTokens } : {},
|
|
1152
|
+
...typeof options.temperature === "number" ? { temperature: options.temperature } : {}
|
|
1153
|
+
};
|
|
1154
|
+
yield* piEventsToDshChunks(provider.stream(model, piContext, piOptions));
|
|
812
1155
|
}
|
|
813
1156
|
};
|
|
814
1157
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
return credential;
|
|
832
|
-
}
|
|
833
|
-
async function resolveOAuthApiKey(options) {
|
|
834
|
-
const oauthConfig = oauthConfigOf(options.providerConfig);
|
|
835
|
-
if (oauthConfig === void 0) return void 0;
|
|
836
|
-
return (await resolveProviderAuth({
|
|
837
|
-
id: options.providerId,
|
|
838
|
-
name: options.providerName ?? options.providerId,
|
|
839
|
-
auth: { oauth: oauthAdapterOf(oauthConfig) }
|
|
840
|
-
}, options.store, { env: async () => void 0 }, options.signal !== void 0 ? { signal: options.signal } : void 0))?.auth?.apiKey;
|
|
841
|
-
}
|
|
842
|
-
async function storedOAuthCredential(store, providerId) {
|
|
843
|
-
const stored = await store.read(providerId, void 0);
|
|
844
|
-
return stored?.type === "oauth" ? stored : void 0;
|
|
1158
|
+
/**
|
|
1159
|
+
* Register the provider as a live DSH route when it carries a transport and
|
|
1160
|
+
* an llm service is mounted. A route conflict (an adapter already owns the
|
|
1161
|
+
* name — e.g. a deployment-configured `deepseek`) keeps the existing route
|
|
1162
|
+
* and reports the skip; the package's registry entry still stands.
|
|
1163
|
+
* @returns the route disposer, or undefined when nothing was registered.
|
|
1164
|
+
*/
|
|
1165
|
+
function registerPiProviderRoute(options) {
|
|
1166
|
+
const { llm, providerId, provider, host } = options;
|
|
1167
|
+
if (llm === void 0 || !providerCarriesTransport(provider)) return void 0;
|
|
1168
|
+
try {
|
|
1169
|
+
return llm.registerAdapter([providerId], piProviderDshAdapter(providerId, provider, host));
|
|
1170
|
+
} catch (error) {
|
|
1171
|
+
host.warn(`[pi2dsh] Pi provider ${JSON.stringify(providerId)} was not added as a DSH llm route (${error instanceof Error ? error.message : String(error)}); the existing route keeps the name`);
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
845
1174
|
}
|
|
846
1175
|
//#endregion
|
|
847
1176
|
//#region src/runtime.ts
|
|
@@ -1084,6 +1413,26 @@ function agentSession(agent) {
|
|
|
1084
1413
|
if (typeof record.id !== "string") return void 0;
|
|
1085
1414
|
return record;
|
|
1086
1415
|
}
|
|
1416
|
+
function isSubagentOrigin(subject) {
|
|
1417
|
+
const session = subject?.session ?? subject;
|
|
1418
|
+
const header = session?.header;
|
|
1419
|
+
return header?.origin === "subagent" || (header?.meta)?.origin === "subagent" || (session?.meta)?.origin === "subagent";
|
|
1420
|
+
}
|
|
1421
|
+
function currentPiModel(state, agent) {
|
|
1422
|
+
const override = state.modelOverrides.get(agent);
|
|
1423
|
+
const options = agent.options;
|
|
1424
|
+
const provider = String(override?.provider ?? options?.provider ?? "");
|
|
1425
|
+
const id = String(override?.model ?? options?.model ?? "");
|
|
1426
|
+
if (id.length === 0) return override;
|
|
1427
|
+
return (provider.length > 0 ? state.modelCatalog?.find(provider, id) : void 0) ?? {
|
|
1428
|
+
id,
|
|
1429
|
+
name: id,
|
|
1430
|
+
provider,
|
|
1431
|
+
api: "dsh-llm",
|
|
1432
|
+
input: ["text"],
|
|
1433
|
+
reasoning: false
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1087
1436
|
function thinkingLevelOf(state, agent) {
|
|
1088
1437
|
if (agent !== void 0) {
|
|
1089
1438
|
const scoped = state.thinkingLevels.get(agent);
|
|
@@ -1168,6 +1517,29 @@ function contextFor(ctx, state, agent, signal, command = false) {
|
|
|
1168
1517
|
};
|
|
1169
1518
|
const session = agentSession(agent);
|
|
1170
1519
|
const providerConfig = (name) => state.providers.get(name);
|
|
1520
|
+
const catalog = state.modelCatalog;
|
|
1521
|
+
const piProviderModels = () => {
|
|
1522
|
+
const out = [];
|
|
1523
|
+
for (const [key, value] of state.providers) {
|
|
1524
|
+
let models;
|
|
1525
|
+
try {
|
|
1526
|
+
models = typeof value.getModels === "function" ? value.getModels() : value.models;
|
|
1527
|
+
} catch {
|
|
1528
|
+
continue;
|
|
1529
|
+
}
|
|
1530
|
+
if (!Array.isArray(models)) continue;
|
|
1531
|
+
for (const model of models) out.push({
|
|
1532
|
+
...model,
|
|
1533
|
+
provider: String(model.provider ?? key)
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
return out;
|
|
1537
|
+
};
|
|
1538
|
+
const allModels = () => {
|
|
1539
|
+
const fromLlm = catalog?.all() ?? [];
|
|
1540
|
+
const seen = new Set(fromLlm.map((model) => `${model.provider} ${model.id}`));
|
|
1541
|
+
return [...fromLlm, ...piProviderModels().filter((model) => !seen.has(`${String(model.provider)} ${String(model.id)}`))];
|
|
1542
|
+
};
|
|
1171
1543
|
const base = {
|
|
1172
1544
|
ui,
|
|
1173
1545
|
mode: "rpc",
|
|
@@ -1178,11 +1550,47 @@ function contextFor(ctx, state, agent, signal, command = false) {
|
|
|
1178
1550
|
events: []
|
|
1179
1551
|
}, cwdOf(agent)) : state.bridge.readonlySessionManager(session, cwdOf(agent)),
|
|
1180
1552
|
modelRegistry: {
|
|
1181
|
-
getAll: () =>
|
|
1182
|
-
getAvailable: () =>
|
|
1183
|
-
find: (
|
|
1553
|
+
getAll: () => allModels(),
|
|
1554
|
+
getAvailable: () => allModels(),
|
|
1555
|
+
find: (provider, modelId) => catalog?.find(provider, modelId) ?? piProviderModels().find((model) => model.provider === provider && model.id === modelId),
|
|
1184
1556
|
getError: () => void 0,
|
|
1185
|
-
hasConfiguredAuth: (
|
|
1557
|
+
hasConfiguredAuth: (model) => {
|
|
1558
|
+
const provider = String(model?.provider ?? "");
|
|
1559
|
+
return provider.length > 0 && (state.providers.has(provider) || (catalog?.all() ?? []).some((entry) => entry.provider === provider));
|
|
1560
|
+
},
|
|
1561
|
+
getApiKeyAndHeaders: async (model) => {
|
|
1562
|
+
const provider = String(model?.provider ?? "");
|
|
1563
|
+
const config = providerConfig(provider) ?? await realBuiltinProvider(provider);
|
|
1564
|
+
if (config !== void 0) {
|
|
1565
|
+
const auth = (await resolvePiProviderAuth({
|
|
1566
|
+
providerId: provider,
|
|
1567
|
+
providerConfig: config,
|
|
1568
|
+
store: oauthStoreOf(state)
|
|
1569
|
+
}))?.auth;
|
|
1570
|
+
if (auth?.apiKey === void 0) return { ok: false };
|
|
1571
|
+
return {
|
|
1572
|
+
ok: true,
|
|
1573
|
+
apiKey: auth.apiKey,
|
|
1574
|
+
...auth.headers === void 0 ? {} : { headers: auth.headers },
|
|
1575
|
+
...auth.baseUrl === void 0 && config.baseUrl === void 0 ? {} : { baseUrl: auth.baseUrl ?? config.baseUrl }
|
|
1576
|
+
};
|
|
1577
|
+
}
|
|
1578
|
+
try {
|
|
1579
|
+
const entry = llmOf(ctx)?.listConfigurableProviders?.()?.find((candidate) => candidate.provider === provider);
|
|
1580
|
+
if (entry === void 0) return { ok: false };
|
|
1581
|
+
const section = ctx.get("settings")?.get(entry.settingsNs);
|
|
1582
|
+
const ref = entry.settingsPath.reduce((node, key) => typeof node === "object" && node !== null ? node[key] : void 0, section)?.apiKeyEnv;
|
|
1583
|
+
if (typeof ref !== "string" || ref.length === 0) return { ok: false };
|
|
1584
|
+
const resolved = await ctx.get("credentials")?.resolve(ref);
|
|
1585
|
+
if (typeof resolved?.value !== "string" || resolved.value.length === 0) return { ok: false };
|
|
1586
|
+
return {
|
|
1587
|
+
ok: true,
|
|
1588
|
+
apiKey: resolved.value
|
|
1589
|
+
};
|
|
1590
|
+
} catch {
|
|
1591
|
+
return { ok: false };
|
|
1592
|
+
}
|
|
1593
|
+
},
|
|
1186
1594
|
getProviderAuthStatus: (provider) => providerSupportsOAuth(providerConfig(provider)) ? "oauth" : "none",
|
|
1187
1595
|
getProvider: (provider) => providerConfig(provider),
|
|
1188
1596
|
getRegisteredProviderConfig: (provider) => providerConfig(provider),
|
|
@@ -1193,42 +1601,44 @@ function contextFor(ctx, state, agent, signal, command = false) {
|
|
|
1193
1601
|
},
|
|
1194
1602
|
getProviderAuth: async (provider) => {
|
|
1195
1603
|
const config = providerConfig(provider);
|
|
1196
|
-
if (
|
|
1197
|
-
|
|
1198
|
-
const apiKey = await resolveOAuthApiKey({
|
|
1604
|
+
if (config === void 0) return void 0;
|
|
1605
|
+
const resolved = await resolvePiProviderAuth({
|
|
1199
1606
|
providerId: provider,
|
|
1200
1607
|
providerConfig: config,
|
|
1201
1608
|
store: oauthStoreOf(state)
|
|
1202
1609
|
});
|
|
1203
|
-
if (
|
|
1204
|
-
return {
|
|
1610
|
+
if (resolved?.auth === void 0) return resolved;
|
|
1611
|
+
return resolved.auth.baseUrl === void 0 && config.baseUrl !== void 0 ? {
|
|
1612
|
+
...resolved,
|
|
1205
1613
|
auth: {
|
|
1206
|
-
|
|
1614
|
+
...resolved.auth,
|
|
1207
1615
|
baseUrl: config.baseUrl
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
};
|
|
1616
|
+
}
|
|
1617
|
+
} : resolved;
|
|
1211
1618
|
},
|
|
1212
1619
|
getApiKeyForProvider: async (provider) => {
|
|
1213
1620
|
const config = providerConfig(provider);
|
|
1214
|
-
if (
|
|
1215
|
-
return
|
|
1621
|
+
if (config === void 0) return void 0;
|
|
1622
|
+
return ((await resolvePiProviderAuth({
|
|
1216
1623
|
providerId: provider,
|
|
1217
1624
|
providerConfig: config,
|
|
1218
1625
|
store: oauthStoreOf(state)
|
|
1219
|
-
});
|
|
1626
|
+
}))?.auth)?.apiKey;
|
|
1220
1627
|
},
|
|
1221
1628
|
isUsingOAuth: (model) => {
|
|
1222
1629
|
const provider = String(model?.provider ?? "");
|
|
1223
1630
|
return provider.length > 0 && providerSupportsOAuth(providerConfig(provider));
|
|
1224
1631
|
},
|
|
1225
|
-
refresh: async () =>
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1632
|
+
refresh: async () => {
|
|
1633
|
+
await catalog?.refresh();
|
|
1634
|
+
return {
|
|
1635
|
+
models: catalog?.all() ?? [],
|
|
1636
|
+
errors: []
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1229
1639
|
},
|
|
1230
|
-
model: agent === void 0 ? void 0 : state
|
|
1231
|
-
scopedModels: [],
|
|
1640
|
+
model: agent === void 0 ? void 0 : currentPiModel(state, agent),
|
|
1641
|
+
scopedModels: catalog?.all() ?? [],
|
|
1232
1642
|
thinkingLevel: thinkingLevelOf(state, agent),
|
|
1233
1643
|
isIdle: () => command,
|
|
1234
1644
|
isProjectTrusted: () => false,
|
|
@@ -1322,6 +1732,10 @@ function subscribeLifecycle(ctx, state) {
|
|
|
1322
1732
|
const warn = (event, error) => logger(ctx).warn(`[pi2dsh] ${event} handler failed: ${String(error)}`);
|
|
1323
1733
|
cordis.on("agent/session-start", (payload) => {
|
|
1324
1734
|
const agent = payload.agent;
|
|
1735
|
+
if (isSubagentOrigin(agent)) {
|
|
1736
|
+
state.activeAgents.add(agent);
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1325
1739
|
state.activeAgents.add(agent);
|
|
1326
1740
|
const session = agentSession(agent);
|
|
1327
1741
|
if (session !== void 0) state.bridge.load(session.id);
|
|
@@ -1340,13 +1754,14 @@ function subscribeLifecycle(ctx, state) {
|
|
|
1340
1754
|
}
|
|
1341
1755
|
if (typeof agent === "object" && agent !== null && !state.disposedAgents.has(agent)) {
|
|
1342
1756
|
state.disposedAgents.add(agent);
|
|
1343
|
-
dispatch(state, "session_shutdown", {
|
|
1757
|
+
if (!isSubagentOrigin(agent)) dispatch(state, "session_shutdown", {
|
|
1344
1758
|
type: "session_shutdown",
|
|
1345
1759
|
reason: "quit"
|
|
1346
1760
|
}, contextFor(ctx, state, agent, void 0)).catch((error) => warn("session_shutdown", error));
|
|
1347
1761
|
}
|
|
1348
1762
|
});
|
|
1349
1763
|
cordis.on("session/event", (session, event) => {
|
|
1764
|
+
if (isSubagentOrigin(session)) return;
|
|
1350
1765
|
const agent = [...state.activeAgents].find((candidate) => candidate.session === session);
|
|
1351
1766
|
const eventContext = contextFor(ctx, state, agent, void 0);
|
|
1352
1767
|
const type = event.type;
|
|
@@ -1596,6 +2011,13 @@ function oauthStoreOf(state) {
|
|
|
1596
2011
|
function ensureLoginCommand(ctx, state) {
|
|
1597
2012
|
if (state.loginCommandRegistered === true) return;
|
|
1598
2013
|
state.loginCommandRegistered = true;
|
|
2014
|
+
try {
|
|
2015
|
+
registerLoginCommand(ctx, state);
|
|
2016
|
+
} catch (error) {
|
|
2017
|
+
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)})`);
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
function registerLoginCommand(ctx, state) {
|
|
1599
2021
|
registerCommand(ctx, state, {
|
|
1600
2022
|
name: "login",
|
|
1601
2023
|
description: "Log in to a Pi provider through its own OAuth flow",
|
|
@@ -1838,16 +2260,66 @@ function createPiApi(ctx, state) {
|
|
|
1838
2260
|
},
|
|
1839
2261
|
getFlag: (name) => state.flags.get(name),
|
|
1840
2262
|
registerProvider(providerOrName, config) {
|
|
1841
|
-
const name = typeof providerOrName === "string" ? providerOrName : String(providerOrName?.name ?? "unnamed");
|
|
2263
|
+
const name = typeof providerOrName === "string" ? providerOrName : String(providerOrName?.id ?? providerOrName?.name ?? "unnamed");
|
|
1842
2264
|
const value = typeof providerOrName === "string" ? config ?? {} : providerOrName;
|
|
1843
2265
|
state.providers.set(name, value);
|
|
1844
2266
|
if (providerSupportsOAuth(value)) {
|
|
1845
2267
|
ensureLoginCommand(ctx, state);
|
|
1846
2268
|
logger(ctx).info(`[pi2dsh] Pi provider ${JSON.stringify(name)} supports OAuth — log in with /login ${name}`);
|
|
1847
|
-
}
|
|
2269
|
+
}
|
|
2270
|
+
const routeDisposer = registerPiProviderRoute({
|
|
2271
|
+
llm: llmOf(ctx),
|
|
2272
|
+
providerId: name,
|
|
2273
|
+
provider: value,
|
|
2274
|
+
host: {
|
|
2275
|
+
resolveAuth: async () => resolvePiProviderAuth({
|
|
2276
|
+
providerId: name,
|
|
2277
|
+
providerConfig: value,
|
|
2278
|
+
store: oauthStoreOf(state)
|
|
2279
|
+
}),
|
|
2280
|
+
warn: (message) => logger(ctx).warn(message)
|
|
2281
|
+
}
|
|
2282
|
+
});
|
|
2283
|
+
if (routeDisposer !== void 0) {
|
|
2284
|
+
state.providerRouteDisposers.set(name, routeDisposer);
|
|
2285
|
+
state.modelCatalog?.refresh();
|
|
2286
|
+
logger(ctx).info(`[pi2dsh] Pi provider ${JSON.stringify(name)} registered as a native DSH llm route`);
|
|
2287
|
+
} else if (!providerSupportsOAuth(value)) logger(ctx).info(`[pi2dsh] recorded Pi provider ${JSON.stringify(name)}; model calls stay on DSH llm adapters`);
|
|
2288
|
+
const refreshModels = value.refreshModels;
|
|
2289
|
+
if (typeof refreshModels === "function") (async () => {
|
|
2290
|
+
const apiKey = ((await resolvePiProviderAuth({
|
|
2291
|
+
providerId: name,
|
|
2292
|
+
providerConfig: value,
|
|
2293
|
+
store: oauthStoreOf(state)
|
|
2294
|
+
}).catch(() => void 0))?.auth)?.apiKey;
|
|
2295
|
+
await Promise.resolve(refreshModels.call(value, {
|
|
2296
|
+
stored: void 0,
|
|
2297
|
+
...apiKey === void 0 ? {} : { credential: {
|
|
2298
|
+
type: "api_key",
|
|
2299
|
+
key: apiKey
|
|
2300
|
+
} },
|
|
2301
|
+
store: {
|
|
2302
|
+
read: async () => void 0,
|
|
2303
|
+
write: async () => {},
|
|
2304
|
+
delete: async () => {}
|
|
2305
|
+
},
|
|
2306
|
+
allowNetwork: true,
|
|
2307
|
+
signal: new AbortController().signal,
|
|
2308
|
+
publish: async (publication) => {
|
|
2309
|
+
publication.update?.();
|
|
2310
|
+
return true;
|
|
2311
|
+
}
|
|
2312
|
+
}));
|
|
2313
|
+
state.modelCatalog?.refresh();
|
|
2314
|
+
})().catch((error) => 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)}`));
|
|
1848
2315
|
},
|
|
1849
2316
|
unregisterProvider(name) {
|
|
1850
2317
|
state.providers.delete(name);
|
|
2318
|
+
const routeDisposer = state.providerRouteDisposers.get(name);
|
|
2319
|
+
if (routeDisposer !== void 0) {
|
|
2320
|
+
state.providerRouteDisposers.delete(name);
|
|
2321
|
+
routeDisposer();
|
|
2322
|
+
}
|
|
1851
2323
|
},
|
|
1852
2324
|
registerMessageRenderer(customType, renderer) {
|
|
1853
2325
|
state.messageRenderers.set(customType, renderer);
|
|
@@ -2119,10 +2591,17 @@ async function applyPiPackage(ctx, options) {
|
|
|
2119
2591
|
globalThinkingLevel: "off",
|
|
2120
2592
|
argMutations: /* @__PURE__ */ new WeakMap(),
|
|
2121
2593
|
streamingTexts: /* @__PURE__ */ new Map(),
|
|
2122
|
-
lastLoggedModels: /* @__PURE__ */ new WeakMap()
|
|
2594
|
+
lastLoggedModels: /* @__PURE__ */ new WeakMap(),
|
|
2595
|
+
providerRouteDisposers: /* @__PURE__ */ new Map()
|
|
2123
2596
|
};
|
|
2124
2597
|
subscribeLifecycle(ctx, state);
|
|
2125
2598
|
subscribeInterceptors(ctx, state);
|
|
2599
|
+
for (const provider of builtinProviders()) state.providers.set(provider.id, {
|
|
2600
|
+
name: provider.name,
|
|
2601
|
+
baseUrl: provider.baseUrl,
|
|
2602
|
+
oauth: provider.auth.oauth
|
|
2603
|
+
});
|
|
2604
|
+
ensureLoginCommand(ctx, state);
|
|
2126
2605
|
if (options.manifest.skillDirs.length > 0) {
|
|
2127
2606
|
if (ctx.get("skills") === void 0) logger(ctx).warn("[pi2dsh] migrated skills were not mounted because this DSH composition has no ctx.skills");
|
|
2128
2607
|
else {
|
|
@@ -2135,6 +2614,20 @@ async function applyPiPackage(ctx, options) {
|
|
|
2135
2614
|
});
|
|
2136
2615
|
}
|
|
2137
2616
|
}
|
|
2617
|
+
const llm = llmOf(ctx);
|
|
2618
|
+
state.modelCatalog = new ModelCatalog(llm);
|
|
2619
|
+
if (llm !== void 0) {
|
|
2620
|
+
ctx.on("llm/adapters-updated", () => {
|
|
2621
|
+
state.modelCatalog?.refresh();
|
|
2622
|
+
});
|
|
2623
|
+
await state.modelCatalog.refresh();
|
|
2624
|
+
__setPiAiLlmBridge((model, context, callOptions) => streamViaDshLlm(llm, {
|
|
2625
|
+
model,
|
|
2626
|
+
context,
|
|
2627
|
+
options: callOptions
|
|
2628
|
+
}));
|
|
2629
|
+
ctx.effect(() => () => __setPiAiLlmBridge(void 0));
|
|
2630
|
+
}
|
|
2138
2631
|
__setSubagentSessionFactory((subagentOptions) => createBridgedAgentSession({
|
|
2139
2632
|
cordis: ctx,
|
|
2140
2633
|
cwd: () => cwdOf(currentAgent(state)),
|
|
@@ -2161,4 +2654,4 @@ const runtimeInternals = {
|
|
|
2161
2654
|
//#endregion
|
|
2162
2655
|
export { normalizeToolSchema as n, runtimeInternals as r, applyPiPackage as t };
|
|
2163
2656
|
|
|
2164
|
-
//# sourceMappingURL=runtime-
|
|
2657
|
+
//# sourceMappingURL=runtime-B9R7bDWT.mjs.map
|