@f5xc-salesdemos/pi-ai 17.4.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5xc-salesdemos/pi-ai",
4
- "version": "17.4.0",
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.0",
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
- * 6-tier auth resolution:
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. LiteLLM passthrough (LITELLM_BASE_URL / LITELLM_API_KEY)
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. LiteLLM passthrough (LITELLM_BASE_URL / LITELLM_API_KEY)
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. Derive from litellm passthrough credentials
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: `${normalized}/anthropic`,
253
+ baseUrl: `${normalizeLitellmBase(litellmBaseUrl)}/anthropic`,
204
254
  isOAuth: false,
205
255
  };
206
256
  }