pi2dsh 0.3.1 → 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 +15 -10
- package/README.zh.md +15 -10
- 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 +16 -3
- package/dist/compat/pi-ai.d.mts.map +1 -1
- package/dist/compat/pi-ai.mjs +3 -3
- 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.mjs +3 -3
- 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 +13 -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-BpPrppjR.mjs → oauth-bridge-C6fL1qSv.mjs} +20 -4
- 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-CWFlgigJ.mjs → pi-ai-DhYGgq4Y.mjs} +49 -12
- package/dist/{pi-ai-CWFlgigJ.mjs.map → pi-ai-DhYGgq4Y.mjs.map} +1 -1
- 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-6DefpI6h.mjs → runtime-B9R7bDWT.mjs} +874 -37
- 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 +1 -1
- package/dist/mcp-config-gqg7GJEE.mjs.map +0 -1
- package/dist/oauth-bridge-BpPrppjR.mjs.map +0 -1
- package/dist/rolldown-runtime-D-uZhY3_.mjs +0 -16
- package/dist/runtime-6DefpI6h.mjs.map +0 -1
|
@@ -1,18 +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-
|
|
4
|
-
import { a as
|
|
5
|
-
import {
|
|
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";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { access, readFile } from "node:fs/promises";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
10
11
|
import { EventEmitter } from "node:events";
|
|
11
12
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
12
13
|
import { createJiti } from "jiti";
|
|
13
14
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
14
15
|
import { renderPrompt } from "@deepseek-ai/dsh-system-prompt";
|
|
15
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
16
16
|
import { randomUUID } from "node:crypto";
|
|
17
17
|
//#region src/session-bridge.ts
|
|
18
18
|
function sidecarDir() {
|
|
@@ -435,11 +435,13 @@ var PiBridgedAgentSession = class {
|
|
|
435
435
|
}
|
|
436
436
|
abort() {
|
|
437
437
|
this.#aborted = true;
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
438
|
+
try {
|
|
439
|
+
const cancel = this.#handle.agent.cancel;
|
|
440
|
+
cancel?.({
|
|
441
|
+
kind: "hook",
|
|
442
|
+
reason: "pi2dsh subagent abort()"
|
|
443
|
+
});
|
|
444
|
+
} catch {}
|
|
443
445
|
}
|
|
444
446
|
setSessionName(name) {
|
|
445
447
|
this.#sessionName = String(name);
|
|
@@ -479,14 +481,34 @@ async function createBridgedAgentSession(host, options) {
|
|
|
479
481
|
const sessionId = `pi2dsh-sub-${Date.now().toString(36)}-${subagentSerial}`;
|
|
480
482
|
let handle;
|
|
481
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;
|
|
482
489
|
handle = await agents.create({
|
|
483
490
|
sessionId,
|
|
484
491
|
meta: {
|
|
485
492
|
cwd: typeof options.cwd === "string" ? options.cwd : host.cwd(),
|
|
486
493
|
origin: "subagent",
|
|
487
494
|
...host.parentSessionId() !== void 0 ? { parentSession: host.parentSessionId() } : {}
|
|
488
|
-
}
|
|
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
|
+
} } : {}
|
|
489
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
|
+
}
|
|
490
512
|
} catch (error) {
|
|
491
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)})`);
|
|
492
514
|
}
|
|
@@ -494,6 +516,663 @@ async function createBridgedAgentSession(host, options) {
|
|
|
494
516
|
return { session: new PiBridgedAgentSession(host, handle, tools) };
|
|
495
517
|
}
|
|
496
518
|
//#endregion
|
|
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
|
+
}
|
|
528
|
+
}
|
|
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
|
+
};
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
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).
|
|
544
|
+
*/
|
|
545
|
+
var ModelCatalog = class {
|
|
546
|
+
#llm;
|
|
547
|
+
#models = [];
|
|
548
|
+
#resolved = /* @__PURE__ */ new Map();
|
|
549
|
+
#refreshing;
|
|
550
|
+
constructor(llm) {
|
|
551
|
+
this.#llm = llm;
|
|
552
|
+
}
|
|
553
|
+
get present() {
|
|
554
|
+
return this.#llm !== void 0;
|
|
555
|
+
}
|
|
556
|
+
all() {
|
|
557
|
+
return [...this.#models];
|
|
558
|
+
}
|
|
559
|
+
find(provider, modelId) {
|
|
560
|
+
return this.#resolved.get(`${provider}${modelId}`) ?? this.#models.find((model) => model.provider === provider && model.id === modelId);
|
|
561
|
+
}
|
|
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;
|
|
568
|
+
}
|
|
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;
|
|
580
|
+
}
|
|
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
|
+
}
|
|
601
|
+
}
|
|
602
|
+
};
|
|
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;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Pi request context → DSH GenerateOptions parts. System prompt moves to the
|
|
632
|
+
* dedicated slot; toolResult messages become DSH tool-result user messages.
|
|
633
|
+
*/
|
|
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")
|
|
649
|
+
}
|
|
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
|
+
};
|
|
669
|
+
}
|
|
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);
|
|
675
|
+
return {
|
|
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
|
+
}
|
|
688
|
+
};
|
|
689
|
+
}
|
|
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
|
+
}
|
|
699
|
+
/**
|
|
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.
|
|
702
|
+
*/
|
|
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
|
+
});
|
|
737
|
+
try {
|
|
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;
|
|
896
|
+
}
|
|
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
|
+
});
|
|
904
|
+
} catch (error) {
|
|
905
|
+
stream.push({
|
|
906
|
+
type: "error",
|
|
907
|
+
reason: "error",
|
|
908
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
909
|
+
partial
|
|
910
|
+
});
|
|
911
|
+
}
|
|
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
|
+
}));
|
|
924
|
+
}
|
|
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)
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
return {
|
|
949
|
+
...typeof options.system === "string" && options.system.length > 0 ? { systemPrompt: options.system } : {},
|
|
950
|
+
messages: piMessages,
|
|
951
|
+
...Array.isArray(options.tools) ? { tools: options.tools } : {}
|
|
952
|
+
};
|
|
953
|
+
}
|
|
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;
|
|
966
|
+
try {
|
|
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
|
+
});
|
|
977
|
+
}
|
|
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 ?? "")
|
|
1020
|
+
}
|
|
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
|
+
}
|
|
1086
|
+
}
|
|
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 [];
|
|
1109
|
+
}
|
|
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) {
|
|
1116
|
+
return {
|
|
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
|
+
};
|
|
1137
|
+
},
|
|
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));
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
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
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
//#endregion
|
|
497
1176
|
//#region src/runtime.ts
|
|
498
1177
|
function logger(ctx) {
|
|
499
1178
|
const candidate = ctx.logger;
|
|
@@ -734,6 +1413,26 @@ function agentSession(agent) {
|
|
|
734
1413
|
if (typeof record.id !== "string") return void 0;
|
|
735
1414
|
return record;
|
|
736
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
|
+
}
|
|
737
1436
|
function thinkingLevelOf(state, agent) {
|
|
738
1437
|
if (agent !== void 0) {
|
|
739
1438
|
const scoped = state.thinkingLevels.get(agent);
|
|
@@ -818,6 +1517,29 @@ function contextFor(ctx, state, agent, signal, command = false) {
|
|
|
818
1517
|
};
|
|
819
1518
|
const session = agentSession(agent);
|
|
820
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
|
+
};
|
|
821
1543
|
const base = {
|
|
822
1544
|
ui,
|
|
823
1545
|
mode: "rpc",
|
|
@@ -828,11 +1550,47 @@ function contextFor(ctx, state, agent, signal, command = false) {
|
|
|
828
1550
|
events: []
|
|
829
1551
|
}, cwdOf(agent)) : state.bridge.readonlySessionManager(session, cwdOf(agent)),
|
|
830
1552
|
modelRegistry: {
|
|
831
|
-
getAll: () =>
|
|
832
|
-
getAvailable: () =>
|
|
833
|
-
find: (
|
|
1553
|
+
getAll: () => allModels(),
|
|
1554
|
+
getAvailable: () => allModels(),
|
|
1555
|
+
find: (provider, modelId) => catalog?.find(provider, modelId) ?? piProviderModels().find((model) => model.provider === provider && model.id === modelId),
|
|
834
1556
|
getError: () => void 0,
|
|
835
|
-
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
|
+
},
|
|
836
1594
|
getProviderAuthStatus: (provider) => providerSupportsOAuth(providerConfig(provider)) ? "oauth" : "none",
|
|
837
1595
|
getProvider: (provider) => providerConfig(provider),
|
|
838
1596
|
getRegisteredProviderConfig: (provider) => providerConfig(provider),
|
|
@@ -843,42 +1601,44 @@ function contextFor(ctx, state, agent, signal, command = false) {
|
|
|
843
1601
|
},
|
|
844
1602
|
getProviderAuth: async (provider) => {
|
|
845
1603
|
const config = providerConfig(provider);
|
|
846
|
-
if (
|
|
847
|
-
|
|
848
|
-
const apiKey = await resolveOAuthApiKey({
|
|
1604
|
+
if (config === void 0) return void 0;
|
|
1605
|
+
const resolved = await resolvePiProviderAuth({
|
|
849
1606
|
providerId: provider,
|
|
850
1607
|
providerConfig: config,
|
|
851
1608
|
store: oauthStoreOf(state)
|
|
852
1609
|
});
|
|
853
|
-
if (
|
|
854
|
-
return {
|
|
1610
|
+
if (resolved?.auth === void 0) return resolved;
|
|
1611
|
+
return resolved.auth.baseUrl === void 0 && config.baseUrl !== void 0 ? {
|
|
1612
|
+
...resolved,
|
|
855
1613
|
auth: {
|
|
856
|
-
|
|
1614
|
+
...resolved.auth,
|
|
857
1615
|
baseUrl: config.baseUrl
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
};
|
|
1616
|
+
}
|
|
1617
|
+
} : resolved;
|
|
861
1618
|
},
|
|
862
1619
|
getApiKeyForProvider: async (provider) => {
|
|
863
1620
|
const config = providerConfig(provider);
|
|
864
|
-
if (
|
|
865
|
-
return
|
|
1621
|
+
if (config === void 0) return void 0;
|
|
1622
|
+
return ((await resolvePiProviderAuth({
|
|
866
1623
|
providerId: provider,
|
|
867
1624
|
providerConfig: config,
|
|
868
1625
|
store: oauthStoreOf(state)
|
|
869
|
-
});
|
|
1626
|
+
}))?.auth)?.apiKey;
|
|
870
1627
|
},
|
|
871
1628
|
isUsingOAuth: (model) => {
|
|
872
1629
|
const provider = String(model?.provider ?? "");
|
|
873
1630
|
return provider.length > 0 && providerSupportsOAuth(providerConfig(provider));
|
|
874
1631
|
},
|
|
875
|
-
refresh: async () =>
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1632
|
+
refresh: async () => {
|
|
1633
|
+
await catalog?.refresh();
|
|
1634
|
+
return {
|
|
1635
|
+
models: catalog?.all() ?? [],
|
|
1636
|
+
errors: []
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
879
1639
|
},
|
|
880
|
-
model: agent === void 0 ? void 0 : state
|
|
881
|
-
scopedModels: [],
|
|
1640
|
+
model: agent === void 0 ? void 0 : currentPiModel(state, agent),
|
|
1641
|
+
scopedModels: catalog?.all() ?? [],
|
|
882
1642
|
thinkingLevel: thinkingLevelOf(state, agent),
|
|
883
1643
|
isIdle: () => command,
|
|
884
1644
|
isProjectTrusted: () => false,
|
|
@@ -972,6 +1732,10 @@ function subscribeLifecycle(ctx, state) {
|
|
|
972
1732
|
const warn = (event, error) => logger(ctx).warn(`[pi2dsh] ${event} handler failed: ${String(error)}`);
|
|
973
1733
|
cordis.on("agent/session-start", (payload) => {
|
|
974
1734
|
const agent = payload.agent;
|
|
1735
|
+
if (isSubagentOrigin(agent)) {
|
|
1736
|
+
state.activeAgents.add(agent);
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
975
1739
|
state.activeAgents.add(agent);
|
|
976
1740
|
const session = agentSession(agent);
|
|
977
1741
|
if (session !== void 0) state.bridge.load(session.id);
|
|
@@ -990,13 +1754,14 @@ function subscribeLifecycle(ctx, state) {
|
|
|
990
1754
|
}
|
|
991
1755
|
if (typeof agent === "object" && agent !== null && !state.disposedAgents.has(agent)) {
|
|
992
1756
|
state.disposedAgents.add(agent);
|
|
993
|
-
dispatch(state, "session_shutdown", {
|
|
1757
|
+
if (!isSubagentOrigin(agent)) dispatch(state, "session_shutdown", {
|
|
994
1758
|
type: "session_shutdown",
|
|
995
1759
|
reason: "quit"
|
|
996
1760
|
}, contextFor(ctx, state, agent, void 0)).catch((error) => warn("session_shutdown", error));
|
|
997
1761
|
}
|
|
998
1762
|
});
|
|
999
1763
|
cordis.on("session/event", (session, event) => {
|
|
1764
|
+
if (isSubagentOrigin(session)) return;
|
|
1000
1765
|
const agent = [...state.activeAgents].find((candidate) => candidate.session === session);
|
|
1001
1766
|
const eventContext = contextFor(ctx, state, agent, void 0);
|
|
1002
1767
|
const type = event.type;
|
|
@@ -1246,6 +2011,13 @@ function oauthStoreOf(state) {
|
|
|
1246
2011
|
function ensureLoginCommand(ctx, state) {
|
|
1247
2012
|
if (state.loginCommandRegistered === true) return;
|
|
1248
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) {
|
|
1249
2021
|
registerCommand(ctx, state, {
|
|
1250
2022
|
name: "login",
|
|
1251
2023
|
description: "Log in to a Pi provider through its own OAuth flow",
|
|
@@ -1488,16 +2260,66 @@ function createPiApi(ctx, state) {
|
|
|
1488
2260
|
},
|
|
1489
2261
|
getFlag: (name) => state.flags.get(name),
|
|
1490
2262
|
registerProvider(providerOrName, config) {
|
|
1491
|
-
const name = typeof providerOrName === "string" ? providerOrName : String(providerOrName?.name ?? "unnamed");
|
|
2263
|
+
const name = typeof providerOrName === "string" ? providerOrName : String(providerOrName?.id ?? providerOrName?.name ?? "unnamed");
|
|
1492
2264
|
const value = typeof providerOrName === "string" ? config ?? {} : providerOrName;
|
|
1493
2265
|
state.providers.set(name, value);
|
|
1494
2266
|
if (providerSupportsOAuth(value)) {
|
|
1495
2267
|
ensureLoginCommand(ctx, state);
|
|
1496
2268
|
logger(ctx).info(`[pi2dsh] Pi provider ${JSON.stringify(name)} supports OAuth — log in with /login ${name}`);
|
|
1497
|
-
}
|
|
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)}`));
|
|
1498
2315
|
},
|
|
1499
2316
|
unregisterProvider(name) {
|
|
1500
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
|
+
}
|
|
1501
2323
|
},
|
|
1502
2324
|
registerMessageRenderer(customType, renderer) {
|
|
1503
2325
|
state.messageRenderers.set(customType, renderer);
|
|
@@ -1769,7 +2591,8 @@ async function applyPiPackage(ctx, options) {
|
|
|
1769
2591
|
globalThinkingLevel: "off",
|
|
1770
2592
|
argMutations: /* @__PURE__ */ new WeakMap(),
|
|
1771
2593
|
streamingTexts: /* @__PURE__ */ new Map(),
|
|
1772
|
-
lastLoggedModels: /* @__PURE__ */ new WeakMap()
|
|
2594
|
+
lastLoggedModels: /* @__PURE__ */ new WeakMap(),
|
|
2595
|
+
providerRouteDisposers: /* @__PURE__ */ new Map()
|
|
1773
2596
|
};
|
|
1774
2597
|
subscribeLifecycle(ctx, state);
|
|
1775
2598
|
subscribeInterceptors(ctx, state);
|
|
@@ -1791,6 +2614,20 @@ async function applyPiPackage(ctx, options) {
|
|
|
1791
2614
|
});
|
|
1792
2615
|
}
|
|
1793
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
|
+
}
|
|
1794
2631
|
__setSubagentSessionFactory((subagentOptions) => createBridgedAgentSession({
|
|
1795
2632
|
cordis: ctx,
|
|
1796
2633
|
cwd: () => cwdOf(currentAgent(state)),
|
|
@@ -1817,4 +2654,4 @@ const runtimeInternals = {
|
|
|
1817
2654
|
//#endregion
|
|
1818
2655
|
export { normalizeToolSchema as n, runtimeInternals as r, applyPiPackage as t };
|
|
1819
2656
|
|
|
1820
|
-
//# sourceMappingURL=runtime-
|
|
2657
|
+
//# sourceMappingURL=runtime-B9R7bDWT.mjs.map
|