pi-provider-litellm 2.0.5 → 2.0.6

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 CHANGED
@@ -137,6 +137,8 @@ LiteLLM Skills and MCP integration are enabled by default. Disable either featur
137
137
 
138
138
  Setting `skills.enabled` to `false` disables the Skills Gateway management tools, skill fetching, and system-prompt injection. Setting `mcp.enabled` to `false` disables LiteLLM MCP discovery and tool registration. Restart Pi after changing these settings so previously registered tools are removed.
139
139
 
140
+ Treat the configured LiteLLM proxy as trusted: Skills can add instructions to the system prompt, and MCP can expose tools the agent may call. Disable these integrations when the proxy, its administrators, or its configured content are not fully trusted.
141
+
140
142
  ## Use
141
143
 
142
144
  ```
@@ -156,6 +158,8 @@ Setting `skills.enabled` to `false` disables the Skills Gateway management tools
156
158
  | `LITELLM_VERBOSE_DISCOVERY` | unset | If `1`, enable progress messages during model and MCP discovery (login, refresh, startup); discovery is silent by default |
157
159
  | `LITELLM_MODELS_DEV` | enabled | Set to `0` to disable models.dev metadata enrichment, including its cache and network request; `/v1/models` still uses Pi catalog metadata and defaults |
158
160
 
161
+ Only use a trusted `LITELLM_API_KEY_HELPER` or `!command`. Prefer an absolute executable path, keep secrets out of command arguments, and print only the token to stdout without logging it to stderr.
162
+
159
163
  `LITELLM_DISCOVERY_TIMEOUT_MS=0` disables automatic and explicit refresh model discovery. It does not replace the base URL or API key settings required to send requests when you are not using `/login litellm`.
160
164
 
161
165
  Models.dev metadata is cached in `litellm-models-dev.json` under the Pi agent directory for 28 days. Fresh data avoids the public request; stale data is used immediately while one background refresh updates the cache. Set `LITELLM_MODELS_DEV=0` when your LiteLLM metadata is authoritative and no external enrichment is wanted.
package/dist/discover.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { readFile } from "node:fs/promises";
2
+ import { isIP } from "node:net";
2
3
  import { getModels, getProviders } from "@earendil-works/pi-ai/compat";
3
4
  import { writeJsonAtomic } from "./cache.js";
4
5
  const DEFAULT_TIMEOUT_MS = 5000;
@@ -10,6 +11,12 @@ const MODELS_DEV_CACHE_TTL_MS = 28 * 24 * 60 * 60 * 1000;
10
11
  const modelsDevCaches = new Map();
11
12
  const modelsDevRefreshes = new Map();
12
13
  export function normalizeBaseUrl(input) {
14
+ const url = new URL(input);
15
+ const hostname = url.hostname.toLowerCase();
16
+ const loopback = hostname === "localhost" || hostname === "[::1]" || (isIP(hostname) === 4 && hostname.startsWith("127."));
17
+ if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
18
+ throw new Error("LiteLLM base URL must use HTTPS except for loopback hosts");
19
+ }
13
20
  return input.replace(/\/+$/, "").replace(/\/v1\/?$/i, "");
14
21
  }
15
22
  const RESPONSES_MODE_PATTERN = /^responses?$/i;
@@ -355,6 +362,21 @@ function mapModelsDevMetadata(model) {
355
362
  }
356
363
  return metadata;
357
364
  }
365
+ function mapReasoningEfforts(info) {
366
+ const flags = [
367
+ ["off", "none", info.supports_none_reasoning_effort],
368
+ ["minimal", "minimal", info.supports_minimal_reasoning_effort],
369
+ ["low", "low", info.supports_low_reasoning_effort],
370
+ ["medium", "medium", info.supports_medium_reasoning_effort],
371
+ ["high", "high", info.supports_high_reasoning_effort],
372
+ ["xhigh", "xhigh", info.supports_xhigh_reasoning_effort],
373
+ ["max", "max", info.supports_max_reasoning_effort],
374
+ ];
375
+ const map = Object.fromEntries(flags
376
+ .filter(([, , supported]) => supported !== undefined)
377
+ .map(([level, value, supported]) => [level, supported ? value : null]));
378
+ return Object.keys(map).length > 0 ? map : undefined;
379
+ }
358
380
  function mapFromModelInfo(entry) {
359
381
  const id = entry.model_name;
360
382
  if (!id)
@@ -364,11 +386,15 @@ function mapFromModelInfo(entry) {
364
386
  return undefined;
365
387
  const responsesMode = isResponsesMode(info.mode);
366
388
  const catalogModel = findCatalogModel(id);
389
+ const reasoningEffortMap = mapReasoningEfforts(info);
390
+ const thinkingLevelMap = catalogModel?.thinkingLevelMap || reasoningEffortMap
391
+ ? { ...catalogModel?.thinkingLevelMap, ...reasoningEffortMap }
392
+ : undefined;
367
393
  return {
368
394
  id,
369
395
  name: id,
370
396
  reasoning: info.supports_reasoning ?? false,
371
- ...(catalogModel?.thinkingLevelMap ? { thinkingLevelMap: catalogModel.thinkingLevelMap } : {}),
397
+ ...(thinkingLevelMap ? { thinkingLevelMap } : {}),
372
398
  input: info.supports_vision ? ["text", "image"] : ["text"],
373
399
  cost: mapModelInfoCost(info, catalogModel?.cost),
374
400
  contextWindow: info.max_input_tokens ?? DEFAULT_CONTEXT_WINDOW,
@@ -85,7 +85,7 @@ async function exchangeRefreshToken(credentials) {
85
85
  signal: AbortSignal.timeout(10_000),
86
86
  });
87
87
  if (!response.ok) {
88
- console.warn(`LiteLLM gcloud auth: Token exchange failed (${response.status}): ${await response.text()}`);
88
+ console.warn(`LiteLLM gcloud auth: Token exchange failed (${response.status})`);
89
89
  return null;
90
90
  }
91
91
  const data = (await response.json());
package/dist/index.js CHANGED
@@ -140,8 +140,7 @@ async function generateVirtualKey(baseUrl, userToken, signal, headers) {
140
140
  signal: boundedSignal,
141
141
  });
142
142
  if (!response.ok) {
143
- const text = await response.text().catch(() => "");
144
- throw new Error(`Virtual key generation failed (${response.status}): ${text}`);
143
+ throw new Error(`Virtual key generation failed (${response.status})`);
145
144
  }
146
145
  const data = (await response.json());
147
146
  if (typeof data.key !== "string" || !data.key)
@@ -948,11 +947,7 @@ export default async function (pi) {
948
947
  context.credential) {
949
948
  const auth = await authForCredential(definition, context.credential);
950
949
  defaultRuntimeAuth = auth;
951
- const registration = registerMcpTools(auth, context.signal);
952
- if (context.signal)
953
- await registration;
954
- else
955
- void registration.catch(() => undefined);
950
+ void registerMcpTools(auth, context.signal).catch(() => undefined);
956
951
  }
957
952
  }
958
953
  };
package/dist/provider.js CHANGED
@@ -34,14 +34,7 @@ export function createLiteLLMProvider(options) {
34
34
  ...provider,
35
35
  refreshModels: (context) => refreshModels({
36
36
  ...context,
37
- store: {
38
- async read() {
39
- const entry = await context.store.read();
40
- return entry && { ...entry, models: entry.models.map(enrichCachedModel) };
41
- },
42
- write: (entry) => context.store.write(entry),
43
- delete: () => context.store.delete(),
44
- },
37
+ stored: context.stored && { ...context.stored, models: context.stored.models.map(enrichCachedModel) },
45
38
  }),
46
39
  };
47
40
  }
package/dist/types.d.ts CHANGED
@@ -31,6 +31,13 @@ export interface ModelInfoEntry {
31
31
  max_input_tokens?: number;
32
32
  max_output_tokens?: number;
33
33
  supports_reasoning?: boolean;
34
+ supports_none_reasoning_effort?: boolean;
35
+ supports_minimal_reasoning_effort?: boolean;
36
+ supports_low_reasoning_effort?: boolean;
37
+ supports_medium_reasoning_effort?: boolean;
38
+ supports_high_reasoning_effort?: boolean;
39
+ supports_xhigh_reasoning_effort?: boolean;
40
+ supports_max_reasoning_effort?: boolean;
34
41
  supports_vision?: boolean;
35
42
  };
36
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-provider-litellm",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "LiteLLM proxy provider extension for Pi",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -68,13 +68,14 @@
68
68
  },
69
69
  "overrides": {
70
70
  "basic-ftp": "6.0.1",
71
+ "nanoid": "3.3.18",
71
72
  "protobufjs": "8.7.1",
72
73
  "undici": "8.9.0"
73
74
  },
74
75
  "devDependencies": {
75
76
  "@biomejs/biome": "^2.4.15",
76
- "@earendil-works/pi-ai": "^0.83.0",
77
- "@earendil-works/pi-coding-agent": "^0.83.0",
77
+ "@earendil-works/pi-ai": "^0.84.2",
78
+ "@earendil-works/pi-coding-agent": "^0.84.2",
78
79
  "@kitlangton/terminal-control": "0.6.0",
79
80
  "@types/node": "^26.0.0",
80
81
  "@typescript/native-preview": "7.0.0-dev.20260707.2",