pi-provider-litellm 1.2.4 → 1.2.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
@@ -40,6 +40,8 @@ Inside pi:
40
40
  /login litellm
41
41
  ```
42
42
 
43
+ You can also run `/login`, select `Use a subscription`, then select `LiteLLM`.
44
+
43
45
  You'll be prompted for the base URL and API key. Credentials are persisted to `~/.pi/agent/auth.json`.
44
46
 
45
47
  ### Option B — environment variables
package/dist/index.js CHANGED
@@ -318,10 +318,13 @@ export default async function (pi) {
318
318
  }
319
319
  }
320
320
  }
321
+ let updateCosts = () => undefined;
321
322
  const oauth = {
322
323
  name: "LiteLLM",
323
324
  login: (callbacks) => loginLiteLLM(callbacks, (next) => {
324
325
  cacheFetchedAt = next.fetchedAt;
326
+ registerProvider(next.baseUrl, next.models);
327
+ updateCosts(next.models);
325
328
  }),
326
329
  refreshToken: refreshLiteLLM,
327
330
  getApiKey: getLiteLLMApiKey,
@@ -344,7 +347,7 @@ export default async function (pi) {
344
347
  });
345
348
  }
346
349
  registerProvider(creds.baseUrl, models);
347
- const updateCosts = setupLiteLLMCostTracking(pi, models);
350
+ updateCosts = setupLiteLLMCostTracking(pi, models);
348
351
  let refreshInProgress = null;
349
352
  function discoveryDisabledReason() {
350
353
  if (isOffline())
@@ -379,6 +382,43 @@ export default async function (pi) {
379
382
  });
380
383
  return refreshInProgress;
381
384
  }
385
+ async function runLogin(ctx) {
386
+ const credential = await loginLiteLLM({
387
+ onAuth: () => undefined,
388
+ onDeviceCode: () => undefined,
389
+ onPrompt: async ({ message, placeholder }) => {
390
+ const value = await ctx.ui.input(message, placeholder);
391
+ if (value === undefined)
392
+ throw new Error("Login cancelled");
393
+ return value;
394
+ },
395
+ onProgress: (message) => ctx.ui.notify(message, "info"),
396
+ onSelect: async () => undefined,
397
+ signal: ctx.signal,
398
+ }, (next) => {
399
+ cacheFetchedAt = next.fetchedAt;
400
+ registerProvider(next.baseUrl, next.models);
401
+ updateCosts(next.models);
402
+ });
403
+ ctx.modelRegistry.authStorage.set(PROVIDER_NAME, { type: "oauth", ...credential });
404
+ ctx.modelRegistry.refresh();
405
+ ctx.ui.notify(`Logged in to LiteLLM. Credentials saved to ${getAuthPath()}`, "info");
406
+ }
407
+ pi.on("input", async (event, ctx) => {
408
+ if (event.text.trim() !== `/login ${PROVIDER_NAME}`)
409
+ return { action: "continue" };
410
+ if (!ctx.hasUI)
411
+ return { action: "continue" };
412
+ try {
413
+ await runLogin(ctx);
414
+ }
415
+ catch (error) {
416
+ const message = error instanceof Error ? error.message : String(error);
417
+ if (message !== "Login cancelled")
418
+ ctx.ui.notify(`LiteLLM login failed: ${message}`, "error");
419
+ }
420
+ return { action: "handled" };
421
+ });
382
422
  pi.registerCommand("litellm-refresh", {
383
423
  description: "Re-discover models from the LiteLLM proxy.",
384
424
  handler: async (_args, ctx) => {
package/dist/litellm.d.ts CHANGED
@@ -1,18 +1 @@
1
- import type { OAuthCredentials } from "@earendil-works/pi-ai";
2
- import type { ResolvedCredentials } from "./types.js";
3
- export declare const PROVIDER_NAME = "litellm";
4
- export declare const ENV_BASE_URL = "LITELLM_BASE_URL";
5
- export declare const ENV_API_KEY = "LITELLM_API_KEY";
6
- export declare const ENV_TIMEOUT = "LITELLM_DISCOVERY_TIMEOUT_MS";
7
- export declare const ENV_OFFLINE = "LITELLM_OFFLINE";
8
- export declare const DEFAULT_TIMEOUT_MS = 5000;
9
- export declare const LOGIN_TIMEOUT_MS = 10000;
10
- export declare const CACHE_FILENAME = "litellm-models.json";
11
- export declare function getAuthPath(): string;
12
- export declare function getCachePath(): string;
13
- export declare function resolveCredentials(): Promise<ResolvedCredentials>;
14
- export declare function getDiscoveryTimeoutMs(): number;
15
- export declare function isOffline(): boolean;
16
- export declare function isListModelsMode(): boolean;
17
1
  export declare function getSessionIdFromFile(sessionFile?: string): string | undefined;
18
- export type { OAuthCredentials };
package/dist/litellm.js CHANGED
@@ -1,62 +1,3 @@
1
- import { readFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import { AuthStorage, getAgentDir } from "@earendil-works/pi-coding-agent";
4
- import { normalizeBaseUrl } from "./discover.js";
5
- export const PROVIDER_NAME = "litellm";
6
- export const ENV_BASE_URL = "LITELLM_BASE_URL";
7
- export const ENV_API_KEY = "LITELLM_API_KEY";
8
- export const ENV_TIMEOUT = "LITELLM_DISCOVERY_TIMEOUT_MS";
9
- export const ENV_OFFLINE = "LITELLM_OFFLINE";
10
- export const DEFAULT_TIMEOUT_MS = 5000;
11
- export const LOGIN_TIMEOUT_MS = 10_000;
12
- export const CACHE_FILENAME = "litellm-models.json";
13
- export function getAuthPath() {
14
- return join(getAgentDir(), "auth.json");
15
- }
16
- export function getCachePath() {
17
- return join(getAgentDir(), CACHE_FILENAME);
18
- }
19
- async function readAuthEntry() {
20
- try {
21
- const raw = await readFile(getAuthPath(), "utf8");
22
- const parsed = JSON.parse(raw);
23
- return parsed?.[PROVIDER_NAME];
24
- }
25
- catch {
26
- return undefined;
27
- }
28
- }
29
- export async function resolveCredentials() {
30
- const entry = await readAuthEntry();
31
- const envBase = process.env[ENV_BASE_URL]?.trim();
32
- const envKey = process.env[ENV_API_KEY]?.trim();
33
- const authBase = entry?.type === "oauth" ? entry.baseUrl?.trim() : undefined;
34
- const authKey = entry?.type === "oauth"
35
- ? entry.access?.trim()
36
- : entry?.type === "api_key"
37
- ? (await AuthStorage.create(getAuthPath()).getApiKey(PROVIDER_NAME, { includeFallback: false }))?.trim()
38
- : undefined;
39
- const rawBase = authBase || envBase;
40
- return {
41
- baseUrl: rawBase ? normalizeBaseUrl(rawBase) : undefined,
42
- apiKey: authKey || envKey || undefined,
43
- };
44
- }
45
- export function getDiscoveryTimeoutMs() {
46
- const raw = process.env[ENV_TIMEOUT];
47
- if (raw === undefined)
48
- return DEFAULT_TIMEOUT_MS;
49
- const parsed = Number.parseInt(raw, 10);
50
- if (Number.isNaN(parsed) || parsed < 0)
51
- return DEFAULT_TIMEOUT_MS;
52
- return parsed;
53
- }
54
- export function isOffline() {
55
- return process.env[ENV_OFFLINE] === "1";
56
- }
57
- export function isListModelsMode() {
58
- return process.argv.includes("--list-models");
59
- }
60
1
  export function getSessionIdFromFile(sessionFile) {
61
2
  if (!sessionFile)
62
3
  return undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-provider-litellm",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "LiteLLM proxy provider extension for Pi",
5
5
  "type": "module",
6
6
  "license": "MIT",