pi2dsh 0.4.0 → 0.6.0

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 (93) hide show
  1. package/README.md +54 -14
  2. package/README.zh.md +43 -14
  3. package/cordis.patch.yml +3 -0
  4. package/dist/cli.mjs +1 -1
  5. package/dist/compat/pi-ai.mjs +1 -1
  6. package/dist/compat/pi-coding-agent.mjs +1 -1
  7. package/dist/credentials-oauth.mjs +3 -3
  8. package/dist/host.mjs +2 -2
  9. package/dist/index.d.mts +30 -1
  10. package/dist/index.d.mts.map +1 -1
  11. package/dist/index.mjs +98 -2
  12. package/dist/index.mjs.map +1 -0
  13. package/dist/{mcp-config-B3h5jTBb.mjs → mcp-config-vU1LZ7fC.mjs} +6 -6
  14. package/dist/mcp-config-vU1LZ7fC.mjs.map +1 -0
  15. package/dist/{oauth-bridge-C6fL1qSv.mjs → oauth-bridge-CfyImWx4.mjs} +2 -2
  16. package/dist/{oauth-bridge-C6fL1qSv.mjs.map → oauth-bridge-CfyImWx4.mjs.map} +1 -1
  17. package/dist/{pi-ai-B_88Wb0r.mjs → pi-ai-7HR3ciAs.mjs} +4 -42
  18. package/dist/{pi-ai-B_88Wb0r.mjs.map → pi-ai-7HR3ciAs.mjs.map} +1 -1
  19. package/dist/{pi-coding-agent-COMX0KHL.mjs → pi-coding-agent-CznNsOnV.mjs} +3 -3
  20. package/dist/{pi-coding-agent-COMX0KHL.mjs.map → pi-coding-agent-CznNsOnV.mjs.map} +1 -1
  21. package/dist/{runtime-B7mEIRf-.mjs → runtime-xNd10ACP.mjs} +194 -21
  22. package/dist/runtime-xNd10ACP.mjs.map +1 -0
  23. package/dist/runtime.d.mts.map +1 -1
  24. package/dist/runtime.mjs +1 -1
  25. package/package.json +9 -2
  26. package/dist/all-DSpxKvHa.mjs +0 -28512
  27. package/dist/all-DSpxKvHa.mjs.map +0 -1
  28. package/dist/anthropic-messages-BL9N1Idv.mjs +0 -6438
  29. package/dist/anthropic-messages-BL9N1Idv.mjs.map +0 -1
  30. package/dist/azure-openai-responses-A67VbaZ1.mjs +0 -209
  31. package/dist/azure-openai-responses-A67VbaZ1.mjs.map +0 -1
  32. package/dist/deferred-tools-BD4g5QUx.mjs +0 -32
  33. package/dist/deferred-tools-BD4g5QUx.mjs.map +0 -1
  34. package/dist/diagnostics-CJye1UFh.mjs +0 -99
  35. package/dist/diagnostics-CJye1UFh.mjs.map +0 -1
  36. package/dist/dist-BYA74yh_.mjs +0 -1246
  37. package/dist/dist-BYA74yh_.mjs.map +0 -1
  38. package/dist/dist-DeonWo7m.mjs +0 -1089
  39. package/dist/dist-DeonWo7m.mjs.map +0 -1
  40. package/dist/error-body-DKA3lknR.mjs +0 -104
  41. package/dist/error-body-DKA3lknR.mjs.map +0 -1
  42. package/dist/github-copilot-headers-CZo2QHrt.mjs +0 -25
  43. package/dist/github-copilot-headers-CZo2QHrt.mjs.map +0 -1
  44. package/dist/google-generative-ai-DT5S8D8y.mjs +0 -358
  45. package/dist/google-generative-ai-DT5S8D8y.mjs.map +0 -1
  46. package/dist/google-shared-DYP_9cnK.mjs +0 -29042
  47. package/dist/google-shared-DYP_9cnK.mjs.map +0 -1
  48. package/dist/google-vertex-Dpq7O7Be.mjs +0 -402
  49. package/dist/google-vertex-Dpq7O7Be.mjs.map +0 -1
  50. package/dist/hash-Dbggamac.mjs +0 -19
  51. package/dist/hash-Dbggamac.mjs.map +0 -1
  52. package/dist/headers-CPzZhJQn.mjs +0 -17
  53. package/dist/headers-CPzZhJQn.mjs.map +0 -1
  54. package/dist/images-models-DJtHo9Rp.mjs +0 -1068
  55. package/dist/images-models-DJtHo9Rp.mjs.map +0 -1
  56. package/dist/json-parse-Dz5sKMTv.mjs +0 -384
  57. package/dist/json-parse-Dz5sKMTv.mjs.map +0 -1
  58. package/dist/mcp-config-B3h5jTBb.mjs.map +0 -1
  59. package/dist/mistral-conversations-BsxbCCWx.mjs +0 -42007
  60. package/dist/mistral-conversations-BsxbCCWx.mjs.map +0 -1
  61. package/dist/multipart-parser-woKCuALW.mjs +0 -301
  62. package/dist/multipart-parser-woKCuALW.mjs.map +0 -1
  63. package/dist/openai-DkzRh5_G.mjs +0 -6732
  64. package/dist/openai-DkzRh5_G.mjs.map +0 -1
  65. package/dist/openai-codex-responses-C7vviVT2.mjs +0 -1169
  66. package/dist/openai-codex-responses-C7vviVT2.mjs.map +0 -1
  67. package/dist/openai-completions-By8QNX1P.mjs +0 -947
  68. package/dist/openai-completions-By8QNX1P.mjs.map +0 -1
  69. package/dist/openai-prompt-cache-BDWtZRKh.mjs +0 -11
  70. package/dist/openai-prompt-cache-BDWtZRKh.mjs.map +0 -1
  71. package/dist/openai-responses-DboJUcFN.mjs +0 -247
  72. package/dist/openai-responses-DboJUcFN.mjs.map +0 -1
  73. package/dist/openai-responses-shared-BDzn7nJY.mjs +0 -572
  74. package/dist/openai-responses-shared-BDzn7nJY.mjs.map +0 -1
  75. package/dist/openrouter-images-fG3Aj6M4.mjs +0 -127
  76. package/dist/openrouter-images-fG3Aj6M4.mjs.map +0 -1
  77. package/dist/otel-PimLMoiV.mjs +0 -24935
  78. package/dist/otel-PimLMoiV.mjs.map +0 -1
  79. package/dist/pi-messages-B-7Xo_I0.mjs +0 -306
  80. package/dist/pi-messages-B-7Xo_I0.mjs.map +0 -1
  81. package/dist/provider-env-D-cCRWzv.mjs +0 -40
  82. package/dist/provider-env-D-cCRWzv.mjs.map +0 -1
  83. package/dist/provider-retry-Cw6YJ4cr.mjs +0 -80
  84. package/dist/provider-retry-Cw6YJ4cr.mjs.map +0 -1
  85. package/dist/runtime-B7mEIRf-.mjs.map +0 -1
  86. package/dist/sanitize-unicode-wLA11KvZ.mjs +0 -29
  87. package/dist/sanitize-unicode-wLA11KvZ.mjs.map +0 -1
  88. package/dist/src-BEl3QrGL.mjs +0 -5031
  89. package/dist/src-BEl3QrGL.mjs.map +0 -1
  90. package/dist/transform-messages-DGq9mvhA.mjs +0 -379
  91. package/dist/transform-messages-DGq9mvhA.mjs.map +0 -1
  92. package/dist/uuid-DtFT7tOE.mjs +0 -65
  93. package/dist/uuid-DtFT7tOE.mjs.map +0 -1
@@ -1,13 +1,14 @@
1
1
 
2
- import { C as realBuiltinProvider, R as AssistantMessageEventStream, S as openAIResponsesApi, a as builtinProviders, i as anthropicMessagesApi, r as __setPiAiLlmBridge, x as openAICompletionsApi } from "./pi-ai-B_88Wb0r.mjs";
2
+ import { C as realBuiltinProvider, R as AssistantMessageEventStream, S as openAIResponsesApi, a as builtinProviders, i as anthropicMessagesApi, r as __setPiAiLlmBridge, x as openAICompletionsApi } from "./pi-ai-7HR3ciAs.mjs";
3
3
  import { r as normalizePath, t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
4
- import { E as __setSubagentSessionFactory, S as Theme, f as ExtensionRunner } from "./pi-coding-agent-COMX0KHL.mjs";
5
- import { a as resolvePiProviderAuth, n as loginPiProvider, r as providerSupportsOAuth, t as FileCredentialStore } from "./oauth-bridge-C6fL1qSv.mjs";
4
+ import { E as __setSubagentSessionFactory, S as Theme, f as ExtensionRunner } from "./pi-coding-agent-CznNsOnV.mjs";
5
+ import { a as resolvePiProviderAuth, n as loginPiProvider, r as providerSupportsOAuth, t as FileCredentialStore } from "./oauth-bridge-CfyImWx4.mjs";
6
6
  import { createRequire } from "node:module";
7
- import { access, readFile } from "node:fs/promises";
7
+ import { access, mkdir, readFile, writeFile } from "node:fs/promises";
8
+ import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
8
9
  import { join } from "node:path";
9
10
  import { fileURLToPath } from "node:url";
10
- import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
11
+ import { tmpdir } from "node:os";
11
12
  import { EventEmitter } from "node:events";
12
13
  import { AsyncLocalStorage } from "node:async_hooks";
13
14
  import { createJiti } from "jiti";
@@ -494,6 +495,7 @@ async function createBridgedAgentSession(host, options) {
494
495
  meta: {
495
496
  cwd: typeof options.cwd === "string" ? options.cwd : host.cwd(),
496
497
  origin: "subagent",
498
+ delegationDepth: host.parentDelegationDepth() + 1,
497
499
  ...host.parentSessionId() !== void 0 ? { parentSession: host.parentSessionId() } : {}
498
500
  },
499
501
  ...typeof requestedModel?.id === "string" && requestedModel.id.length > 0 ? { agentOptions: {
@@ -1750,8 +1752,17 @@ function modelsJsonPath() {
1750
1752
  const emptySnapshot = () => ({
1751
1753
  models: [],
1752
1754
  providers: /* @__PURE__ */ new Map(),
1753
- errors: []
1755
+ errors: [],
1756
+ companions: /* @__PURE__ */ new Map()
1754
1757
  });
1758
+ function companionImageModels(provider) {
1759
+ if (provider.baseUrl !== void 0 || provider.models !== void 0 || provider.apiKey !== void 0) return void 0;
1760
+ const overrides = provider.modelOverrides;
1761
+ if (overrides === void 0) return void 0;
1762
+ const imageModels = /* @__PURE__ */ new Set();
1763
+ for (const [modelId, override] of Object.entries(overrides)) if (Array.isArray(override.input) && override.input.includes("image")) imageModels.add(modelId);
1764
+ return imageModels.size > 0 ? imageModels : void 0;
1765
+ }
1755
1766
  /**
1756
1767
  * One load of models.json projected to Pi Model objects. Mirrors Pi's
1757
1768
  * composeModelProvider composition order: base (builtin) models →
@@ -1770,6 +1781,11 @@ async function loadModelsJsonSnapshot(baseProviderOf) {
1770
1781
  for (const providerId of config.getProviderIds()) {
1771
1782
  const providerConfig = config.getProvider(providerId);
1772
1783
  if (providerConfig === void 0) continue;
1784
+ const imageModels = companionImageModels(providerConfig);
1785
+ if (imageModels !== void 0) {
1786
+ snapshot.companions.set(providerId, imageModels);
1787
+ continue;
1788
+ }
1773
1789
  try {
1774
1790
  const base = await baseProviderOf?.(providerId);
1775
1791
  const composed = applyModelsJson(providerId, typeof base?.getModels === "function" ? base.getModels() : [], providerConfig).map((model) => {
@@ -2002,6 +2018,77 @@ function piProviderDshAdapter(providerId, provider, host) {
2002
2018
  }
2003
2019
  };
2004
2020
  }
2021
+ const IMAGE_OMITTED_TEXT = "[image attachment omitted: the selected model reads text only]";
2022
+ const imageNoticeText = (path) => path === void 0 ? IMAGE_OMITTED_TEXT : `[image attached at ${path} — the selected model reads text only; use an image-capable tool to view it]`;
2023
+ async function textOnlyBlocks(blocks, materialize) {
2024
+ const out = [];
2025
+ for (const block of blocks) if (block.type === "image") {
2026
+ const attachment = block.attachment;
2027
+ const path = typeof attachment === "object" && attachment !== null ? await materialize(attachment) : void 0;
2028
+ out.push({
2029
+ type: "text",
2030
+ text: imageNoticeText(path)
2031
+ });
2032
+ } else if (block.type === "tool-result" && Array.isArray(block.content)) out.push({
2033
+ ...block,
2034
+ content: await textOnlyBlocks(block.content, materialize)
2035
+ });
2036
+ else out.push(block);
2037
+ return out;
2038
+ }
2039
+ async function textOnlyMessages(messages, materialize) {
2040
+ return Promise.all(messages.map(async (message) => Array.isArray(message.content) ? {
2041
+ ...message,
2042
+ content: await textOnlyBlocks(message.content, materialize)
2043
+ } : message));
2044
+ }
2045
+ /**
2046
+ * A DSH route that admits images on behalf of a text-only route — the
2047
+ * single-directory answer to models.json modelOverrides declaring
2048
+ * `input: ["text", "image"]` for models of a route this bridge does not own.
2049
+ * The companion honestly declares image input (so the host's admission and
2050
+ * model-switch checks pass), replaces image blocks with an explicit notice,
2051
+ * and forwards every call to the original route. It never carries a wire
2052
+ * transport of its own; the images themselves are served by whatever vision
2053
+ * extension handles the turn's entering messages.
2054
+ */
2055
+ function imageAdmissionCompanionAdapter(options) {
2056
+ const { originalId, imageModels, llm } = options;
2057
+ const materialize = options.materializeImage ?? (async () => void 0);
2058
+ const admitImage = (info, id) => {
2059
+ const modalities = Array.isArray(info.inputModalities) ? info.inputModalities.slice() : ["text"];
2060
+ if (!modalities.includes("image")) modalities.push("image");
2061
+ return {
2062
+ ...info,
2063
+ provider: id,
2064
+ inputModalities: modalities
2065
+ };
2066
+ };
2067
+ return {
2068
+ providerInfo: (id) => {
2069
+ return {
2070
+ id,
2071
+ name: `${llm.listProviders().find((provider) => provider.id === originalId)?.name ?? originalId} + Vision Bridge`
2072
+ };
2073
+ },
2074
+ providerRetryPolicy: () => void 0,
2075
+ listModels: async (id) => (await llm.listModels(originalId)).filter((model) => imageModels.has(String(model.id))).map((model) => admitImage(model, id)),
2076
+ resolveModel: async (id, modelId) => {
2077
+ const info = await llm.resolveModelInfo(originalId, modelId);
2078
+ return imageModels.has(modelId) ? admitImage(info, id) : {
2079
+ ...info,
2080
+ provider: id
2081
+ };
2082
+ },
2083
+ async *stream(streamOptions) {
2084
+ yield* llm.stream({
2085
+ ...streamOptions,
2086
+ provider: originalId,
2087
+ ...Array.isArray(streamOptions.messages) ? { messages: await textOnlyMessages(streamOptions.messages, materialize) } : {}
2088
+ });
2089
+ }
2090
+ };
2091
+ }
2005
2092
  /**
2006
2093
  * Register the provider as a live DSH route when an llm service is mounted.
2007
2094
  * A provider carrying its own transport streams through it; a config-only
@@ -2271,7 +2358,8 @@ function isSubagentOrigin(subject) {
2271
2358
  function currentPiModel(state, agent) {
2272
2359
  const override = state.modelOverrides.get(agent);
2273
2360
  const options = agent.options;
2274
- const provider = String(override?.provider ?? options?.provider ?? "");
2361
+ const selectedProvider = String(override?.provider ?? options?.provider ?? "");
2362
+ const provider = state.companionRoutes.get(selectedProvider) ?? selectedProvider;
2275
2363
  const id = String(override?.model ?? options?.model ?? "");
2276
2364
  if (id.length === 0) return override;
2277
2365
  return (provider.length > 0 ? state.modelCatalog?.find(provider, id) : void 0) ?? {
@@ -2541,7 +2629,7 @@ function contextFor(ctx, state, agent, signal, command = false) {
2541
2629
  return provider.length > 0 && providerSupportsOAuth(providerConfig(provider));
2542
2630
  },
2543
2631
  refresh: async () => {
2544
- await reloadModelsJson(ctx, state);
2632
+ await reloadModelsJson(ctx, state, true);
2545
2633
  await catalog?.refresh();
2546
2634
  return {
2547
2635
  models: allModels(),
@@ -3079,18 +3167,39 @@ async function collectPiImages(ctx, messages) {
3079
3167
  return images;
3080
3168
  }
3081
3169
  function oauthStoreOf(state) {
3082
- state.oauthStore ??= new FileCredentialStore(join(getAgentDir(), "auth.json"));
3083
- return state.oauthStore;
3170
+ state.shared.oauthStore ??= new FileCredentialStore(join(getAgentDir(), "auth.json"));
3171
+ return state.shared.oauthStore;
3084
3172
  }
3085
3173
  const MODELS_JSON_ROUTE_PREFIX = "models.json/";
3086
- async function reloadModelsJson(ctx, state) {
3174
+ const SHARED_HOST_STATE = /* @__PURE__ */ new WeakMap();
3175
+ function sharedHostStateOf(ctx) {
3176
+ const key = ctx.root ?? ctx;
3177
+ let shared = SHARED_HOST_STATE.get(key);
3178
+ if (shared === void 0) {
3179
+ shared = {
3180
+ modelsJsonProviders: /* @__PURE__ */ new Map(),
3181
+ companionRoutes: /* @__PURE__ */ new Map(),
3182
+ providerRouteDisposers: /* @__PURE__ */ new Map(),
3183
+ providers: /* @__PURE__ */ new Map()
3184
+ };
3185
+ SHARED_HOST_STATE.set(key, shared);
3186
+ }
3187
+ return shared;
3188
+ }
3189
+ async function reloadModelsJson(ctx, state, force = false) {
3190
+ if (!force && state.shared.modelsJson !== void 0) {
3191
+ state.modelsJson = state.shared.modelsJson;
3192
+ return;
3193
+ }
3087
3194
  for (const [key, dispose] of state.providerRouteDisposers) {
3088
3195
  if (!key.startsWith(MODELS_JSON_ROUTE_PREFIX)) continue;
3089
3196
  state.providerRouteDisposers.delete(key);
3090
3197
  dispose();
3091
3198
  }
3092
3199
  state.modelsJsonProviders.clear();
3200
+ state.companionRoutes.clear();
3093
3201
  state.modelsJson = await loadModelsJsonSnapshot(realBuiltinProvider);
3202
+ state.shared.modelsJson = state.modelsJson;
3094
3203
  for (const problem of state.modelsJson.errors) logger(ctx).warn(`[pi2dsh] models.json: ${problem}`);
3095
3204
  for (const [providerId, providerConfig] of state.modelsJson.providers) {
3096
3205
  const models = state.modelsJson.models.filter((model) => model.provider === providerId);
@@ -3118,10 +3227,61 @@ async function reloadModelsJson(ctx, state) {
3118
3227
  logger(ctx).info(`[pi2dsh] models.json provider ${JSON.stringify(providerId)} registered as a native DSH llm route (${models.length} models)`);
3119
3228
  }
3120
3229
  }
3230
+ registerCompanionRoutes(ctx, state);
3231
+ }
3232
+ function registerCompanionRoutes(ctx, state) {
3233
+ const companions = state.modelsJson?.companions;
3234
+ if (companions === void 0 || companions.size === 0) return;
3235
+ const llm = llmOf(ctx);
3236
+ if (llm === void 0) return;
3237
+ for (const [originalId, imageModels] of companions) {
3238
+ if (!llm.listProviders().some((provider) => provider.id === originalId)) {
3239
+ logger(ctx).warn(`[pi2dsh] models.json: modelOverrides for ${JSON.stringify(originalId)} declare image input, but no such llm route exists; no companion route was registered`);
3240
+ continue;
3241
+ }
3242
+ const companionId = `${originalId}-vision`;
3243
+ state.companionRoutes.set(companionId, originalId);
3244
+ try {
3245
+ const dispose = llm.registerAdapter([companionId], imageAdmissionCompanionAdapter({
3246
+ originalId,
3247
+ imageModels,
3248
+ llm,
3249
+ materializeImage: (attachment) => materializeAttachmentImage(ctx, attachment)
3250
+ }));
3251
+ state.providerRouteDisposers.set(`${MODELS_JSON_ROUTE_PREFIX}${companionId}`, dispose);
3252
+ logger(ctx).info(`[pi2dsh] image-admission companion route ${JSON.stringify(companionId)} registered for ${JSON.stringify(originalId)} (${imageModels.size} models)`);
3253
+ } catch (error) {
3254
+ logger(ctx).warn(`[pi2dsh] companion route ${JSON.stringify(companionId)} already has a live adapter in this host (${error instanceof Error ? error.message : String(error)}); reusing it`);
3255
+ }
3256
+ }
3257
+ }
3258
+ const IMAGE_EXTENSIONS = {
3259
+ "image/png": "png",
3260
+ "image/jpeg": "jpg",
3261
+ "image/webp": "webp",
3262
+ "image/gif": "gif"
3263
+ };
3264
+ async function materializeAttachmentImage(ctx, attachment) {
3265
+ const attachments = ctx.get("attachments");
3266
+ const id = typeof attachment.attachmentId === "string" ? attachment.attachmentId : void 0;
3267
+ if (attachments === void 0 || id === void 0) return void 0;
3268
+ const extension = IMAGE_EXTENSIONS[String(attachment.mediaType)] ?? "png";
3269
+ const dir = join(tmpdir(), "pi2dsh-attached-images");
3270
+ const filePath = join(dir, `${id}.${extension}`);
3271
+ try {
3272
+ if (!existsSync(filePath)) {
3273
+ const stored = await attachments.readImage(attachment);
3274
+ await mkdir(dir, { recursive: true });
3275
+ await writeFile(filePath, Buffer.from(stored.data));
3276
+ }
3277
+ return filePath;
3278
+ } catch {
3279
+ return;
3280
+ }
3121
3281
  }
3122
3282
  function ensureLoginCommand(ctx, state) {
3123
- if (state.loginCommandRegistered === true) return;
3124
- state.loginCommandRegistered = true;
3283
+ if (state.shared.loginRegistered === true) return;
3284
+ state.shared.loginRegistered = true;
3125
3285
  try {
3126
3286
  registerLoginCommand(ctx, state);
3127
3287
  } catch (error) {
@@ -3689,7 +3849,9 @@ async function applyPiPackage(ctx, options) {
3689
3849
  origin: "package"
3690
3850
  }
3691
3851
  }));
3852
+ const shared = sharedHostStateOf(ctx);
3692
3853
  const state = {
3854
+ shared,
3693
3855
  handlers: /* @__PURE__ */ new Map(),
3694
3856
  tools: runtimeTools,
3695
3857
  runner: new ExtensionRunner(piToolRecords),
@@ -3697,7 +3859,8 @@ async function applyPiPackage(ctx, options) {
3697
3859
  toolRestrictions: /* @__PURE__ */ new WeakMap(),
3698
3860
  commands: /* @__PURE__ */ new Map(),
3699
3861
  commandDisposers: /* @__PURE__ */ new Map(),
3700
- modelsJsonProviders: /* @__PURE__ */ new Map(),
3862
+ modelsJsonProviders: shared.modelsJsonProviders,
3863
+ companionRoutes: shared.companionRoutes,
3701
3864
  flags: /* @__PURE__ */ new Map(),
3702
3865
  notifications: [],
3703
3866
  activeAgents: /* @__PURE__ */ new Set(),
@@ -3711,7 +3874,7 @@ async function applyPiPackage(ctx, options) {
3711
3874
  shortcuts: /* @__PURE__ */ new Map(),
3712
3875
  messageRenderers: /* @__PURE__ */ new Map(),
3713
3876
  entryRenderers: /* @__PURE__ */ new Map(),
3714
- providers: /* @__PURE__ */ new Map(),
3877
+ providers: shared.providers,
3715
3878
  autocompleteProviders: [],
3716
3879
  editorBuffers: /* @__PURE__ */ new WeakMap(),
3717
3880
  toolsExpanded: false,
@@ -3722,7 +3885,7 @@ async function applyPiPackage(ctx, options) {
3722
3885
  argMutations: /* @__PURE__ */ new WeakMap(),
3723
3886
  streamingTexts: /* @__PURE__ */ new Map(),
3724
3887
  lastLoggedModels: /* @__PURE__ */ new WeakMap(),
3725
- providerRouteDisposers: /* @__PURE__ */ new Map()
3888
+ providerRouteDisposers: shared.providerRouteDisposers
3726
3889
  };
3727
3890
  subscribeLifecycle(ctx, state);
3728
3891
  subscribeInterceptors(ctx, state);
@@ -3745,12 +3908,15 @@ async function applyPiPackage(ctx, options) {
3745
3908
  }
3746
3909
  }
3747
3910
  const llm = llmOf(ctx);
3748
- state.modelCatalog = new ModelCatalog(llm);
3911
+ state.modelCatalog = shared.modelCatalog ??= new ModelCatalog(llm);
3749
3912
  await reloadModelsJson(ctx, state);
3750
3913
  if (llm !== void 0) {
3751
- ctx.on("llm/adapters-updated", () => {
3752
- state.modelCatalog?.refresh();
3753
- });
3914
+ if (shared.catalogSubscribed !== true) {
3915
+ shared.catalogSubscribed = true;
3916
+ ctx.on("llm/adapters-updated", () => {
3917
+ shared.modelCatalog?.refresh();
3918
+ });
3919
+ }
3754
3920
  await state.modelCatalog.refresh();
3755
3921
  __setPiAiLlmBridge((model, context, callOptions) => streamViaDshLlm(llm, {
3756
3922
  model,
@@ -3766,6 +3932,13 @@ async function applyPiPackage(ctx, options) {
3766
3932
  const session = agentSession(currentAgent(state));
3767
3933
  return session === void 0 ? void 0 : String(session.id ?? "") || void 0;
3768
3934
  },
3935
+ parentDelegationDepth: () => {
3936
+ const parent = currentAgent(state);
3937
+ const header = agentSession(parent)?.header;
3938
+ const fromHeader = typeof header?.delegationDepth === "number" ? header.delegationDepth : 0;
3939
+ const fromOptions = typeof parent?.options?.subagentDepth === "number" ? parent.options.subagentDepth : 0;
3940
+ return Math.max(fromHeader, fromOptions);
3941
+ },
3769
3942
  piContentToDsh: (content) => piToDshContent(ctx, content),
3770
3943
  deliver: (agent, message, mode) => deliverAgentMessage(agent, message, mode),
3771
3944
  messageFromSessionEvent,
@@ -3785,4 +3958,4 @@ const runtimeInternals = {
3785
3958
  //#endregion
3786
3959
  export { normalizeToolSchema as n, runtimeInternals as r, applyPiPackage as t };
3787
3960
 
3788
- //# sourceMappingURL=runtime-B7mEIRf-.mjs.map
3961
+ //# sourceMappingURL=runtime-xNd10ACP.mjs.map