@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 +2 -2
- package/src/utils/anthropic-auth.ts +57 -28
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
|
|
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
|
|
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
|
-
*
|
|
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;
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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:
|
|
153
|
-
baseUrl: DEFAULT_BASE_URL,
|
|
154
|
-
isOAuth:
|
|
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
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
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
|
|