@oh-my-pi/pi-ai 8.11.14 → 8.12.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/usage/claude.ts +60 -1
- package/src/usage/kimi.ts +14 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-ai",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.12.2",
|
|
4
4
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"@connectrpc/connect-node": "^2.1.1",
|
|
64
64
|
"@google/genai": "^1.38.0",
|
|
65
65
|
"@mistralai/mistralai": "^1.13.0",
|
|
66
|
-
"@oh-my-pi/pi-utils": "8.
|
|
66
|
+
"@oh-my-pi/pi-utils": "8.12.2",
|
|
67
67
|
"@sinclair/typebox": "^0.34.48",
|
|
68
68
|
"@smithy/node-http-handler": "^4.4.8",
|
|
69
69
|
"ajv": "^8.17.1",
|
package/src/usage/claude.ts
CHANGED
|
@@ -15,6 +15,7 @@ const FIVE_HOURS_MS = 5 * 60 * 60 * 1000;
|
|
|
15
15
|
const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
|
|
16
16
|
const MAX_RETRIES = 3;
|
|
17
17
|
const BASE_RETRY_DELAY_MS = 500;
|
|
18
|
+
const PROFILE_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
18
19
|
|
|
19
20
|
const CLAUDE_HEADERS = {
|
|
20
21
|
accept: "application/json, text/plain, */*",
|
|
@@ -160,6 +161,64 @@ async function fetchUsagePayload(
|
|
|
160
161
|
return lastPayload ? { payload: lastPayload, orgId: lastOrgId } : null;
|
|
161
162
|
}
|
|
162
163
|
|
|
164
|
+
interface ClaudeProfile {
|
|
165
|
+
account?: {
|
|
166
|
+
uuid?: string;
|
|
167
|
+
email?: string;
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function fetchProfile(
|
|
172
|
+
baseUrl: string,
|
|
173
|
+
headers: Record<string, string>,
|
|
174
|
+
ctx: UsageFetchContext,
|
|
175
|
+
signal?: AbortSignal,
|
|
176
|
+
): Promise<ClaudeProfile | null> {
|
|
177
|
+
const url = `${baseUrl}/profile`;
|
|
178
|
+
try {
|
|
179
|
+
const response = await ctx.fetch(url, { headers, signal });
|
|
180
|
+
if (!response.ok) return null;
|
|
181
|
+
return (await response.json()) as ClaudeProfile;
|
|
182
|
+
} catch {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function buildProfileCacheKey(params: UsageFetchParams): string {
|
|
188
|
+
const credential = params.credential;
|
|
189
|
+
const token = credential.accessToken ?? credential.refreshToken;
|
|
190
|
+
const fingerprint = token && typeof token === "string" ? Bun.hash(token).toString(16) : "anonymous";
|
|
191
|
+
const baseUrl = params.baseUrl ?? DEFAULT_ENDPOINT;
|
|
192
|
+
return `profile:${params.provider}:${fingerprint}:${baseUrl}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function resolveEmail(
|
|
196
|
+
params: UsageFetchParams,
|
|
197
|
+
ctx: UsageFetchContext,
|
|
198
|
+
baseUrl: string,
|
|
199
|
+
headers: Record<string, string>,
|
|
200
|
+
): Promise<string | undefined> {
|
|
201
|
+
if (params.credential.email) return params.credential.email;
|
|
202
|
+
|
|
203
|
+
const cacheKey = buildProfileCacheKey(params);
|
|
204
|
+
const cached = await ctx.cache.get(cacheKey);
|
|
205
|
+
const now = ctx.now();
|
|
206
|
+
if (cached && cached.expiresAt > now && cached.value?.metadata?.email) {
|
|
207
|
+
return cached.value.metadata.email as string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const profile = await fetchProfile(baseUrl, headers, ctx, params.signal);
|
|
211
|
+
const email = profile?.account?.email;
|
|
212
|
+
if (email) {
|
|
213
|
+
const entry = {
|
|
214
|
+
value: { provider: params.provider, fetchedAt: now, limits: [], metadata: { email } },
|
|
215
|
+
expiresAt: now + PROFILE_CACHE_TTL_MS,
|
|
216
|
+
};
|
|
217
|
+
await ctx.cache.set(cacheKey, entry);
|
|
218
|
+
}
|
|
219
|
+
return email;
|
|
220
|
+
}
|
|
221
|
+
|
|
163
222
|
function buildUsageAmount(utilization: number | undefined): UsageAmount | undefined {
|
|
164
223
|
if (utilization === undefined) return undefined;
|
|
165
224
|
const clamped = Math.min(Math.max(utilization, 0), 100);
|
|
@@ -329,7 +388,7 @@ async function fetchClaudeUsage(params: UsageFetchParams, ctx: UsageFetchContext
|
|
|
329
388
|
if (limits.length === 0) return cachedValue;
|
|
330
389
|
const identity = extractUsageIdentity(payload, orgId);
|
|
331
390
|
const accountId = identity.accountId ?? credential.accountId;
|
|
332
|
-
const email = identity.email ??
|
|
391
|
+
const email = identity.email ?? (await resolveEmail(params, ctx, baseUrl, headers));
|
|
333
392
|
|
|
334
393
|
const report: UsageReport = {
|
|
335
394
|
provider: params.provider,
|
package/src/usage/kimi.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
UsageStatus,
|
|
10
10
|
UsageWindow,
|
|
11
11
|
} from "../usage";
|
|
12
|
-
import { getKimiCommonHeaders } from "../utils/oauth/kimi";
|
|
12
|
+
import { getKimiCommonHeaders, refreshKimiToken } from "../utils/oauth/kimi";
|
|
13
13
|
|
|
14
14
|
const DEFAULT_BASE_URL = "https://api.kimi.com/coding/v1";
|
|
15
15
|
const USAGE_PATH = "usages";
|
|
@@ -259,13 +259,23 @@ export const kimiUsageProvider: UsageProvider = {
|
|
|
259
259
|
const { credential } = params;
|
|
260
260
|
if (credential.type !== "oauth") return null;
|
|
261
261
|
|
|
262
|
-
|
|
262
|
+
let accessToken = credential.accessToken;
|
|
263
263
|
if (!accessToken) return null;
|
|
264
264
|
|
|
265
265
|
const nowMs = ctx.now();
|
|
266
266
|
if (credential.expiresAt !== undefined && credential.expiresAt <= nowMs) {
|
|
267
|
-
|
|
268
|
-
|
|
267
|
+
if (!credential.refreshToken) {
|
|
268
|
+
ctx.logger?.warn("Kimi usage token expired, no refresh token", { provider: params.provider });
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
ctx.logger?.debug("Kimi usage token expired, refreshing", { provider: params.provider });
|
|
273
|
+
const refreshed = await refreshKimiToken(credential.refreshToken);
|
|
274
|
+
accessToken = refreshed.access;
|
|
275
|
+
} catch (error) {
|
|
276
|
+
ctx.logger?.warn("Kimi usage token refresh failed", { provider: params.provider, error: String(error) });
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
269
279
|
}
|
|
270
280
|
|
|
271
281
|
const baseUrl = normalizeBaseUrl(params.baseUrl);
|