@f5xc-salesdemos/pi-ai 17.0.2 → 17.1.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5xc-salesdemos/pi-ai",
4
- "version": "17.0.2",
4
+ "version": "17.1.0",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://github.com/f5xc-salesdemos/xcsh",
7
7
  "author": "Can Boluk",
@@ -45,7 +45,7 @@
45
45
  "@aws-sdk/client-bedrock-runtime": "^3",
46
46
  "@bufbuild/protobuf": "^2.11",
47
47
  "@google/genai": "^1.43",
48
- "@f5xc-salesdemos/pi-utils": "17.0.2",
48
+ "@f5xc-salesdemos/pi-utils": "17.1.0",
49
49
  "@sinclair/typebox": "^0.34",
50
50
  "@smithy/node-http-handler": "^4.4",
51
51
  "ajv": "^8.18",
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * Anthropic Authentication
3
3
  *
4
- * 5-tier auth resolution:
4
+ * 6-tier auth resolution:
5
5
  * 1. ANTHROPIC_SEARCH_API_KEY / ANTHROPIC_SEARCH_BASE_URL env vars
6
6
  * 2. ANTHROPIC_FOUNDRY_API_KEY override when Foundry mode is enabled
7
7
  * 3. OAuth credentials in ~/.xcsh/agent/agent.db (with expiry check)
8
8
  * 4. API key credentials in ~/.xcsh/agent/agent.db
9
9
  * 5. Generic Anthropic fallback (ANTHROPIC_API_KEY / ANTHROPIC_BASE_URL)
10
+ * 6. LiteLLM passthrough (LITELLM_BASE_URL / LITELLM_API_KEY)
10
11
  */
11
12
  import { $env, getAgentDbPath } from "@f5xc-salesdemos/pi-utils";
12
13
  import { type AuthCredential, AuthCredentialStore } from "../auth-storage";
@@ -112,6 +113,7 @@ async function readAnthropicOAuthCredentials(store?: AuthCredentialStore): Promi
112
113
  * 3. OAuth in agent.db (with 5-minute expiry buffer)
113
114
  * 4. API key in agent.db
114
115
  * 5. ANTHROPIC_API_KEY / ANTHROPIC_BASE_URL fallback
116
+ * 6. LiteLLM passthrough (LITELLM_BASE_URL / LITELLM_API_KEY)
115
117
  * @param store - Optional credential store (creates one from default db path if not provided)
116
118
  * @returns The first valid auth configuration found, or null if none available
117
119
  */
@@ -137,38 +139,47 @@ export async function findAnthropicAuth(store?: AuthCredentialStore): Promise<An
137
139
  };
138
140
  }
139
141
 
140
- // Tiers 3-4 use the credential store; manage lifecycle once
141
- const ownsStore = !store;
142
- const effectiveStore = store ?? (await AuthCredentialStore.open(getAgentDbPath()));
142
+ // Tiers 3-4 use the credential store; wrapped in try/catch so DB
143
+ // failures (missing file, corruption, locking) never prevent the
144
+ // env-var fallback tiers from running.
145
+ let storeError: unknown;
143
146
  try {
144
- // 3. OAuth credentials in agent.db (with 5-minute expiry buffer)
145
- const expiryBuffer = 5 * 60 * 1000; // 5 minutes
146
- const now = Date.now();
147
- const credentials = await readAnthropicOAuthCredentials(effectiveStore);
148
- for (const credential of credentials) {
149
- if (!credential.access) continue;
150
- if (credential.expires > now + expiryBuffer) {
147
+ const ownsStore = !store;
148
+ const effectiveStore = store ?? (await AuthCredentialStore.open(getAgentDbPath()));
149
+ try {
150
+ // 3. OAuth credentials in agent.db (with 5-minute expiry buffer)
151
+ const expiryBuffer = 5 * 60 * 1000; // 5 minutes
152
+ const now = Date.now();
153
+ const credentials = await readAnthropicOAuthCredentials(effectiveStore);
154
+ for (const credential of credentials) {
155
+ if (!credential.access) continue;
156
+ if (credential.expires > now + expiryBuffer) {
157
+ return {
158
+ apiKey: credential.access,
159
+ baseUrl: DEFAULT_BASE_URL,
160
+ isOAuth: true,
161
+ };
162
+ }
163
+ }
164
+
165
+ // 4. API key credentials in agent.db
166
+ const storedApiKey = effectiveStore.getApiKey("anthropic");
167
+ if (storedApiKey) {
151
168
  return {
152
- apiKey: credential.access,
153
- baseUrl: DEFAULT_BASE_URL,
154
- isOAuth: true,
169
+ apiKey: storedApiKey,
170
+ baseUrl: resolveAnthropicBaseUrlFromEnv() ?? DEFAULT_BASE_URL,
171
+ isOAuth: isOAuthToken(storedApiKey),
155
172
  };
156
173
  }
174
+ } finally {
175
+ if (ownsStore) {
176
+ effectiveStore.close();
177
+ }
157
178
  }
158
-
159
- // 4. API key credentials in agent.db
160
- const storedApiKey = effectiveStore.getApiKey("anthropic");
161
- if (storedApiKey) {
162
- return {
163
- apiKey: storedApiKey,
164
- baseUrl: resolveAnthropicBaseUrlFromEnv() ?? DEFAULT_BASE_URL,
165
- isOAuth: isOAuthToken(storedApiKey),
166
- };
167
- }
168
- } finally {
169
- if (ownsStore) {
170
- effectiveStore.close();
171
- }
179
+ } catch (err) {
180
+ // DB unavailable fall through to env-var tiers, but preserve the
181
+ // error so it can be surfaced if no later tier succeeds.
182
+ storeError = err;
172
183
  }
173
184
 
174
185
  // 5. Generic ANTHROPIC_API_KEY fallback
@@ -182,6 +193,24 @@ export async function findAnthropicAuth(store?: AuthCredentialStore): Promise<An
182
193
  };
183
194
  }
184
195
 
196
+ // 6. Derive from litellm passthrough credentials
197
+ const litellmBaseUrl = $env.LITELLM_BASE_URL;
198
+ const litellmApiKey = $env.LITELLM_API_KEY;
199
+ if (litellmBaseUrl && litellmApiKey) {
200
+ const normalized = litellmBaseUrl.replace(/\/+$/, "").replace(/\/anthropic$/, "");
201
+ return {
202
+ apiKey: litellmApiKey,
203
+ baseUrl: `${normalized}/anthropic`,
204
+ isOAuth: false,
205
+ };
206
+ }
207
+
208
+ // No auth tier succeeded. If the credential store threw, surface
209
+ // that error so a broken DB isn't silently hidden as "unconfigured".
210
+ if (storeError) {
211
+ throw storeError;
212
+ }
213
+
185
214
  return null;
186
215
  }
187
216