pi2dsh 0.13.0 → 0.13.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.
Files changed (32) hide show
  1. package/README.md +35 -26
  2. package/README.zh.md +30 -21
  3. package/dist/{analyzer-CXNbeBAe.mjs → analyzer-CJFwQlSG.mjs} +2 -2
  4. package/dist/{analyzer-CXNbeBAe.mjs.map → analyzer-CJFwQlSG.mjs.map} +1 -1
  5. package/dist/cli.mjs +2 -2
  6. package/dist/compat/pi-ai.d.mts +2281 -5
  7. package/dist/compat/pi-ai.d.mts.map +1 -1
  8. package/dist/compat/pi-ai.mjs +2 -2
  9. package/dist/compat/pi-coding-agent.mjs +1 -1
  10. package/dist/{credentials-oauth-BakY-0PA.mjs → credentials-oauth-Txs6oew8.mjs} +13 -6
  11. package/dist/credentials-oauth-Txs6oew8.mjs.map +1 -0
  12. package/dist/credentials-oauth.mjs +1 -1
  13. package/dist/host.mjs +1 -1
  14. package/dist/index.d.mts.map +1 -1
  15. package/dist/index.mjs +18 -4
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/{mcp-config-CZepacin.mjs → mcp-config-_idn-pzI.mjs} +8 -7
  18. package/dist/mcp-config-_idn-pzI.mjs.map +1 -0
  19. package/dist/pi-ai-D7PqVeWs.mjs +11717 -0
  20. package/dist/pi-ai-D7PqVeWs.mjs.map +1 -0
  21. package/dist/{pi-coding-agent-D9skobb6.mjs → pi-coding-agent-BVZu0dHG.mjs} +0 -0
  22. package/dist/{pi-coding-agent-D9skobb6.mjs.map → pi-coding-agent-BVZu0dHG.mjs.map} +1 -1
  23. package/dist/{runtime-B-SlR8mJ.mjs → runtime-DEjs_Qlf.mjs} +143 -18
  24. package/dist/runtime-DEjs_Qlf.mjs.map +1 -0
  25. package/dist/runtime.d.mts.map +1 -1
  26. package/dist/runtime.mjs +1 -1
  27. package/package.json +30 -32
  28. package/dist/credentials-oauth-BakY-0PA.mjs.map +0 -1
  29. package/dist/mcp-config-CZepacin.mjs.map +0 -1
  30. package/dist/pi-ai-BA3V_J0V.mjs +0 -3104
  31. package/dist/pi-ai-BA3V_J0V.mjs.map +0 -1
  32. package/dist/runtime-B-SlR8mJ.mjs.map +0 -1
@@ -1,8 +1,8 @@
1
1
 
2
- import { J as AssistantMessageEventStream, Y as isContextOverflow, c as builtinProviders, i as __setPiAiLlmBridge, x as getSupportedThinkingLevels } from "./pi-ai-BA3V_J0V.mjs";
3
- import { P as generateBranchSummary, Tn as PiCapabilityError, b as Theme, d as ExtensionRunner, w as __setSubagentSessionFactory, wn as CapabilityLedger } from "./pi-coding-agent-D9skobb6.mjs";
2
+ import { X as isContextOverflow, Y as AssistantMessageEventStream, c as builtinProviders, i as __setPiAiLlmBridge, x as getSupportedThinkingLevels } from "./pi-ai-D7PqVeWs.mjs";
3
+ import { P as generateBranchSummary, Tn as PiCapabilityError, b as Theme, d as ExtensionRunner, w as __setSubagentSessionFactory, wn as CapabilityLedger } from "./pi-coding-agent-BVZu0dHG.mjs";
4
4
  import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
5
- import { a as FileCredentialStore, c as providerSupportsOAuth, i as oauthCredentialRef, l as resolvePiProviderAuth, o as joinSignals, s as loginPiProvider, u as storedOAuthCredential } from "./credentials-oauth-BakY-0PA.mjs";
5
+ import { a as FileCredentialStore, c as providerSupportsOAuth, i as oauthCredentialRef, l as resolvePiProviderAuth, o as joinSignals, s as loginPiProvider, u as storedOAuthCredential } from "./credentials-oauth-Txs6oew8.mjs";
6
6
  import { createRequire } from "node:module";
7
7
  import { access, mkdir, readFile, writeFile } from "node:fs/promises";
8
8
  import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
@@ -2294,6 +2294,11 @@ function piProviderDshAdapter(providerId, provider, host) {
2294
2294
  ...typeof options.maxTokens === "number" ? { maxTokens: options.maxTokens } : {},
2295
2295
  ...typeof options.temperature === "number" ? { temperature: options.temperature } : {},
2296
2296
  ...typeof options.sessionId === "string" ? { sessionId: options.sessionId } : {},
2297
+ ...host.beforeProviderRequest === void 0 ? {} : { onPayload: (payload) => host.beforeProviderRequest(payload, {
2298
+ provider: providerId,
2299
+ model,
2300
+ ...options.signal instanceof AbortSignal ? { signal: options.signal } : {}
2301
+ }) },
2297
2302
  ...effort === void 0 || effort === "off" ? {} : { reasoning: effort }
2298
2303
  };
2299
2304
  const contextWindow = typeof model.contextWindow === "number" ? model.contextWindow : void 0;
@@ -2399,9 +2404,98 @@ const DSH_THINKING_FORMATS = /* @__PURE__ */ new Set([
2399
2404
  "together",
2400
2405
  "zai",
2401
2406
  "qwen",
2407
+ "chat-template",
2408
+ "qwen-chat-template",
2402
2409
  "string-thinking",
2403
2410
  "ant-ling"
2404
2411
  ]);
2412
+ const DSH_MAX_TOKENS_FIELDS = /* @__PURE__ */ new Set(["max_completion_tokens", "max_tokens"]);
2413
+ const DSH_CACHE_CONTROL_FORMATS = /* @__PURE__ */ new Set(["anthropic"]);
2414
+ const DSH_CHAT_TEMPLATE_VARS = /* @__PURE__ */ new Set(["thinking.enabled", "thinking.effort"]);
2415
+ const COMPLETIONS = /* @__PURE__ */ new Set(["openai-completions"]);
2416
+ const ANTHROPIC = /* @__PURE__ */ new Set(["anthropic-messages"]);
2417
+ const COMPLETIONS_AND_RESPONSES = /* @__PURE__ */ new Set(["openai-completions", "openai-responses"]);
2418
+ const DSH_COMPAT_FIELD_PROTOCOLS = {
2419
+ supportsStore: COMPLETIONS,
2420
+ supportsDeveloperRole: COMPLETIONS_AND_RESPONSES,
2421
+ supportsReasoningEffort: COMPLETIONS,
2422
+ supportsUsageInStreaming: COMPLETIONS,
2423
+ maxTokensField: COMPLETIONS,
2424
+ requiresToolResultName: COMPLETIONS,
2425
+ requiresAssistantAfterToolResult: COMPLETIONS,
2426
+ requiresThinkingAsText: COMPLETIONS,
2427
+ requiresReasoningContentOnAssistantMessages: COMPLETIONS,
2428
+ thinkingFormat: COMPLETIONS,
2429
+ chatTemplateKwargs: COMPLETIONS,
2430
+ supportsStrictMode: COMPLETIONS_AND_RESPONSES,
2431
+ cacheControlFormat: COMPLETIONS,
2432
+ supportsLongCacheRetention: new Set(DSH_PROTOCOLS),
2433
+ supportsEagerToolInputStreaming: ANTHROPIC,
2434
+ supportsCacheControlOnTools: ANTHROPIC,
2435
+ supportsTemperature: ANTHROPIC,
2436
+ forceAdaptiveThinking: ANTHROPIC,
2437
+ allowEmptySignature: ANTHROPIC,
2438
+ supportsStrictTools: ANTHROPIC
2439
+ };
2440
+ function recordOf(value) {
2441
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
2442
+ }
2443
+ function chatTemplateKwargsOf(value) {
2444
+ const input = recordOf(value);
2445
+ if (input === void 0) return void 0;
2446
+ const output = {};
2447
+ for (const [key, candidate] of Object.entries(input)) {
2448
+ if (candidate === null || typeof candidate === "string" || typeof candidate === "boolean" || typeof candidate === "number" && Number.isFinite(candidate)) {
2449
+ output[key] = candidate;
2450
+ continue;
2451
+ }
2452
+ const placeholder = recordOf(candidate);
2453
+ if (placeholder === void 0 || typeof placeholder.$var !== "string" || !DSH_CHAT_TEMPLATE_VARS.has(placeholder.$var) || placeholder.omitWhenOff !== void 0 && typeof placeholder.omitWhenOff !== "boolean") continue;
2454
+ output[key] = {
2455
+ $var: placeholder.$var,
2456
+ ...typeof placeholder.omitWhenOff === "boolean" ? { omitWhenOff: placeholder.omitWhenOff } : {}
2457
+ };
2458
+ }
2459
+ return Object.keys(output).length === 0 ? void 0 : output;
2460
+ }
2461
+ /**
2462
+ * The part of Pi's model compat that rc.8's official adapter deliberately
2463
+ * offers for this protocol. Vendor-owned catalog switches remain withheld:
2464
+ * forwarding one unknown key rejects the entire settings section, so this is
2465
+ * an explicit field gate rather than a spread.
2466
+ */
2467
+ function compatProfileOf(value, api) {
2468
+ const compat = recordOf(value);
2469
+ if (compat === void 0 || api === void 0) return {};
2470
+ const output = {};
2471
+ const fields = Object.entries(DSH_COMPAT_FIELD_PROTOCOLS);
2472
+ for (const [field, protocols] of fields) {
2473
+ if (!protocols.has(api)) continue;
2474
+ const candidate = compat[field];
2475
+ if (field === "maxTokensField") {
2476
+ if (typeof candidate === "string" && DSH_MAX_TOKENS_FIELDS.has(candidate)) output[field] = candidate;
2477
+ } else if (field === "thinkingFormat") {
2478
+ if (typeof candidate === "string" && DSH_THINKING_FORMATS.has(candidate)) output[field] = candidate;
2479
+ } else if (field === "chatTemplateKwargs") {
2480
+ const kwargs = chatTemplateKwargsOf(candidate);
2481
+ if (kwargs !== void 0) output[field] = kwargs;
2482
+ } else if (field === "cacheControlFormat") {
2483
+ if (typeof candidate === "string" && DSH_CACHE_CONTROL_FORMATS.has(candidate)) output[field] = candidate;
2484
+ } else if (typeof candidate === "boolean") output[field] = candidate;
2485
+ }
2486
+ return output;
2487
+ }
2488
+ function reasoningEffortsOf(model) {
2489
+ if (model.reasoning === false) return false;
2490
+ if (model.reasoning !== true) return void 0;
2491
+ const levelMap = recordOf(model.thinkingLevelMap);
2492
+ const efforts = {};
2493
+ for (const level of getSupportedThinkingLevels(model)) {
2494
+ const wire = levelMap?.[level];
2495
+ efforts[level] = level === "off" && wire === void 0 ? null : wire ?? level;
2496
+ }
2497
+ return Object.keys(efforts).some((level) => level !== "off") ? efforts : void 0;
2498
+ }
2405
2499
  /** A positive whole number, or undefined — the profile schema rejects 0 and fractions. */
2406
2500
  function wholeAbove(value) {
2407
2501
  return typeof value === "number" && Number.isInteger(value) && value >= 1 ? value : void 0;
@@ -2411,23 +2505,17 @@ function wholeAbove(value) {
2411
2505
  *
2412
2506
  * Field by field on purpose. The two vocabularies overlap but do not match:
2413
2507
  * Pi's `maxTokens` is routinely 0 for "unstated" while DSH requires at least 1,
2414
- * Pi's `compat` carries gateway dialect flags DSH's profile has no slot for,
2415
2508
  * and Pi's `reasoning` is a boolean where DSH's `reasoningEfforts` is a map of
2416
- * offered levels. Forwarding any of those verbatim rejects the whole settings
2417
- * section — one bad key takes down every route in it.
2509
+ * offered levels. rc.8 gives compat a real profile slot, but only for a gated
2510
+ * protocol-specific subset. Forwarding these objects verbatim still rejects
2511
+ * the whole settings section — one bad key takes down every route in it.
2418
2512
  * @param model - the Pi model descriptor as its package declared it.
2419
- * @param api - the wire protocol this route resolved to, which decides whether
2420
- * the reasoning compat switches are even a legal thing to state.
2513
+ * @param api - the wire protocol this route resolved to, which decides which
2514
+ * compat fields are legal to state.
2421
2515
  */
2422
2516
  function modelProfileOf(model, api) {
2423
- const compat = model.compat;
2424
- const reasoningCompatAllowed = api === "openai-completions";
2425
- const thinkingFormat = reasoningCompatAllowed && typeof compat?.thinkingFormat === "string" && DSH_THINKING_FORMATS.has(compat.thinkingFormat) ? { thinkingFormat: compat.thinkingFormat } : {};
2426
- const supportsReasoningEffort = reasoningCompatAllowed && typeof compat?.supportsReasoningEffort === "boolean" ? { supportsReasoningEffort: compat.supportsReasoningEffort } : {};
2427
- const carriedCompat = {
2428
- ...thinkingFormat,
2429
- ...supportsReasoningEffort
2430
- };
2517
+ const carriedCompat = compatProfileOf(model.compat, api);
2518
+ const reasoningEfforts = reasoningEffortsOf(model);
2431
2519
  const input = Array.isArray(model.input) ? model.input.filter((entry) => typeof entry === "string" && DSH_MODALITIES.has(entry)) : [];
2432
2520
  const contextWindow = wholeAbove(model.contextWindow);
2433
2521
  const maxTokens = wholeAbove(model.maxTokens);
@@ -2437,6 +2525,7 @@ function modelProfileOf(model, api) {
2437
2525
  ...contextWindow === void 0 ? {} : { contextWindow },
2438
2526
  ...maxTokens === void 0 ? {} : { maxTokens },
2439
2527
  ...input.length === 0 ? {} : { input },
2528
+ ...reasoningEfforts === void 0 ? {} : { reasoningEfforts },
2440
2529
  ...Object.keys(carriedCompat).length === 0 ? {} : { compat: carriedCompat }
2441
2530
  };
2442
2531
  }
@@ -2464,12 +2553,14 @@ function registerCatalogOnlyRoute(options) {
2464
2553
  const apiKeyEnv = envReferenceOf(provider.apiKey);
2465
2554
  const api = protocolOf(provider.api) ?? protocolOf(first.api);
2466
2555
  const baseURL = typeof provider.baseUrl === "string" ? provider.baseUrl : typeof first.baseUrl === "string" ? first.baseUrl : void 0;
2556
+ const providerCompat = compatProfileOf(provider.compat, api);
2467
2557
  return {
2468
2558
  displayName: typeof provider.name === "string" ? provider.name : providerId,
2469
2559
  ...apiKeyEnv === void 0 ? {} : { apiKeyEnv },
2470
2560
  ...api === void 0 ? {} : { api },
2471
2561
  ...baseURL === void 0 ? {} : { baseURL },
2472
- ...models.length === 0 ? {} : { models: models.map((model) => modelProfileOf(model, api)) }
2562
+ ...Object.keys(providerCompat).length === 0 ? {} : { compat: providerCompat },
2563
+ ...models.length === 0 ? {} : { models: models.map((model) => modelProfileOf(model, api ?? protocolOf(model.api))) }
2473
2564
  };
2474
2565
  }, `[pi2dsh] Pi provider ${JSON.stringify(providerId)} declares a catalog only; DSH's official llm-pi-ai adapter now serves it as a native route`);
2475
2566
  }
@@ -2937,6 +3028,14 @@ function contextFor(ctx, state, agent, signal, command = false, sessionOverride)
2937
3028
  question: String(title),
2938
3029
  ...placeholder === void 0 ? {} : { detail: String(placeholder) }
2939
3030
  }),
3031
+ deviceCode: async (title, detail, promptSignal) => {
3032
+ await askOne(ctx, agent, joinSignals(signal, promptSignal), {
3033
+ id: "pi2dsh-device-code",
3034
+ question: String(title),
3035
+ detail: String(detail),
3036
+ options: [{ label: "Cancel login" }]
3037
+ });
3038
+ },
2940
3039
  editor: (title, prefill) => askOne(ctx, agent, signal, {
2941
3040
  id: "pi2dsh-editor",
2942
3041
  question: String(title),
@@ -3386,6 +3485,31 @@ async function dispatch(state, eventName, event, eventContext) {
3386
3485
  return results;
3387
3486
  }
3388
3487
  /**
3488
+ * Pi's request-body event is a waterfall over the body the provider transport
3489
+ * will actually send. Only package-registered Pi transports expose that body
3490
+ * through SimpleStreamOptions.onPayload; native DSH adapters build it behind
3491
+ * their own boundary and never call this function.
3492
+ */
3493
+ async function dispatchBeforeProviderRequest(ctx, state, payload, request) {
3494
+ let current = payload;
3495
+ const agent = currentAgent(state);
3496
+ const eventContext = contextFor(ctx, state, agent, request.signal);
3497
+ eventContext.model = {
3498
+ ...request.model,
3499
+ provider: request.provider
3500
+ };
3501
+ for (const handler of state.handlers.get("before_provider_request") ?? []) try {
3502
+ const result = await state.agentScope.run(agent, () => handler({
3503
+ type: "before_provider_request",
3504
+ payload: current
3505
+ }, eventContext));
3506
+ if (result !== void 0 && typeof result === "object" && result !== null) current = result;
3507
+ } catch (error) {
3508
+ logger(ctx).warn(`[pi2dsh] before_provider_request handler failed: ${error instanceof Error ? error.message : String(error)}`);
3509
+ }
3510
+ return current;
3511
+ }
3512
+ /**
3389
3513
  * What triggered a compaction, in Pi's vocabulary.
3390
3514
  *
3391
3515
  * DSH's durable lifecycle events say two things about the trigger: a manual
@@ -4863,6 +4987,7 @@ function createPiApi(ctx, state) {
4863
4987
  store: oauthStoreOf(state)
4864
4988
  }),
4865
4989
  warn: (message) => logger(ctx).warn(message),
4990
+ beforeProviderRequest: (payload, request) => dispatchBeforeProviderRequest(ctx, state, payload, request),
4866
4991
  resolveAttachments: () => optionalService(ctx, "attachments")
4867
4992
  }
4868
4993
  });
@@ -5372,4 +5497,4 @@ const runtimeInternals = {
5372
5497
  //#endregion
5373
5498
  export { runtimeInternals as i, normalizeToolSchema as n, registerVisionCompanions as r, applyPiPackage as t };
5374
5499
 
5375
- //# sourceMappingURL=runtime-B-SlR8mJ.mjs.map
5500
+ //# sourceMappingURL=runtime-DEjs_Qlf.mjs.map