@f5xc-salesdemos/pi-ai 17.4.1 → 17.4.2
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 -7
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5xc-salesdemos/pi-ai",
|
|
4
|
-
"version": "17.4.
|
|
4
|
+
"version": "17.4.2",
|
|
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.4.
|
|
48
|
+
"@f5xc-salesdemos/pi-utils": "17.4.2",
|
|
49
49
|
"@sinclair/typebox": "^0.34",
|
|
50
50
|
"@smithy/node-http-handler": "^4.4",
|
|
51
51
|
"ajv": "^8.18",
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Anthropic Authentication
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 7-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.
|
|
10
|
+
* 6. Anthropic provider credentials from models.yml
|
|
11
|
+
* 7. LiteLLM passthrough (LITELLM_BASE_URL / LITELLM_API_KEY)
|
|
11
12
|
*/
|
|
12
|
-
import { $env, getAgentDbPath } from "@f5xc-salesdemos/pi-utils";
|
|
13
|
+
import { $env, getAgentDbPath, readProviderFromModelsYml } from "@f5xc-salesdemos/pi-utils";
|
|
13
14
|
import { type AuthCredential, AuthCredentialStore } from "../auth-storage";
|
|
14
15
|
import {
|
|
15
16
|
buildAnthropicHeaders as buildProviderAnthropicHeaders,
|
|
@@ -106,6 +107,47 @@ async function readAnthropicOAuthCredentials(store?: AuthCredentialStore): Promi
|
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Resolves Anthropic provider credentials from models.yml (written by LiteLLM auto-config).
|
|
112
|
+
* Skips shell-backed secrets, which this tier cannot resolve.
|
|
113
|
+
* @returns AnthropicAuthConfig or null if unavailable
|
|
114
|
+
*/
|
|
115
|
+
function readAnthropicAuthFromModelsYml(): AnthropicAuthConfig | null {
|
|
116
|
+
const block = readProviderFromModelsYml("anthropic");
|
|
117
|
+
if (!block?.baseUrl || !block.apiKey) return null;
|
|
118
|
+
|
|
119
|
+
let apiKey: string | undefined;
|
|
120
|
+
switch (block.apiKey.kind) {
|
|
121
|
+
case "envVar":
|
|
122
|
+
apiKey = process.env[block.apiKey.name];
|
|
123
|
+
break;
|
|
124
|
+
case "literal":
|
|
125
|
+
apiKey = block.apiKey.value;
|
|
126
|
+
break;
|
|
127
|
+
case "shellSecret":
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!apiKey) return null;
|
|
132
|
+
return { apiKey, baseUrl: block.baseUrl, isOAuth: false };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Strips known suffixes (`/` repeats, `/anthropic`, `/api/v1`, `/v1`) from a
|
|
137
|
+
* LiteLLM base URL until no further suffix matches. Handles inputs like
|
|
138
|
+
* `https://proxy/api/v1/anthropic` in any order.
|
|
139
|
+
*/
|
|
140
|
+
function normalizeLitellmBase(url: string): string {
|
|
141
|
+
const suffixes = [/\/+$/, /\/anthropic$/, /\/api\/v\d+$/, /\/v\d+$/];
|
|
142
|
+
let prev: string;
|
|
143
|
+
let current = url;
|
|
144
|
+
do {
|
|
145
|
+
prev = current;
|
|
146
|
+
for (const re of suffixes) current = current.replace(re, "");
|
|
147
|
+
} while (current !== prev);
|
|
148
|
+
return current;
|
|
149
|
+
}
|
|
150
|
+
|
|
109
151
|
/**
|
|
110
152
|
* Finds Anthropic auth config using priority:
|
|
111
153
|
* 1. ANTHROPIC_SEARCH_API_KEY / ANTHROPIC_SEARCH_BASE_URL
|
|
@@ -113,7 +155,8 @@ async function readAnthropicOAuthCredentials(store?: AuthCredentialStore): Promi
|
|
|
113
155
|
* 3. OAuth in agent.db (with 5-minute expiry buffer)
|
|
114
156
|
* 4. API key in agent.db
|
|
115
157
|
* 5. ANTHROPIC_API_KEY / ANTHROPIC_BASE_URL fallback
|
|
116
|
-
* 6.
|
|
158
|
+
* 6. Anthropic provider credentials from models.yml
|
|
159
|
+
* 7. LiteLLM passthrough (LITELLM_BASE_URL / LITELLM_API_KEY)
|
|
117
160
|
* @param store - Optional credential store (creates one from default db path if not provided)
|
|
118
161
|
* @returns The first valid auth configuration found, or null if none available
|
|
119
162
|
*/
|
|
@@ -193,14 +236,21 @@ export async function findAnthropicAuth(store?: AuthCredentialStore): Promise<An
|
|
|
193
236
|
};
|
|
194
237
|
}
|
|
195
238
|
|
|
196
|
-
// 6.
|
|
239
|
+
// 6. Anthropic provider credentials from models.yml
|
|
240
|
+
try {
|
|
241
|
+
const modelsYmlAuth = readAnthropicAuthFromModelsYml();
|
|
242
|
+
if (modelsYmlAuth) return modelsYmlAuth;
|
|
243
|
+
} catch {
|
|
244
|
+
/* Best-effort — don't block env-var fallback */
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// 7. Derive from litellm passthrough credentials
|
|
197
248
|
const litellmBaseUrl = $env.LITELLM_BASE_URL;
|
|
198
249
|
const litellmApiKey = $env.LITELLM_API_KEY;
|
|
199
250
|
if (litellmBaseUrl && litellmApiKey) {
|
|
200
|
-
const normalized = litellmBaseUrl.replace(/\/+$/, "").replace(/\/anthropic$/, "");
|
|
201
251
|
return {
|
|
202
252
|
apiKey: litellmApiKey,
|
|
203
|
-
baseUrl: `${
|
|
253
|
+
baseUrl: `${normalizeLitellmBase(litellmBaseUrl)}/anthropic`,
|
|
204
254
|
isOAuth: false,
|
|
205
255
|
};
|
|
206
256
|
}
|