@gajae-code/ai 0.5.2 → 0.5.4
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/CHANGELOG.md +18 -0
- package/dist/types/auth-storage.d.ts +17 -0
- package/dist/types/provider-models/openai-compat.d.ts +8 -1
- package/dist/types/providers/cursor.d.ts +2 -0
- package/dist/types/stream.d.ts +19 -0
- package/dist/types/types.d.ts +1 -1
- package/dist/types/utils/discovery/openai-compatible.d.ts +4 -2
- package/dist/types/utils/oauth/types.d.ts +2 -1
- package/dist/types/utils/oauth/xiaomi.d.ts +10 -4
- package/package.json +2 -2
- package/src/auth-storage.ts +48 -0
- package/src/model-manager.ts +6 -2
- package/src/model-thinking.ts +1 -1
- package/src/models.json +584 -20
- package/src/provider-models/descriptors.ts +18 -0
- package/src/provider-models/openai-compat.ts +107 -44
- package/src/providers/cursor.ts +34 -0
- package/src/providers/openai-codex-responses.ts +38 -19
- package/src/stream.ts +57 -3
- package/src/types.ts +3 -0
- package/src/utils/discovery/openai-compatible.ts +8 -2
- package/src/utils/oauth/index.ts +15 -0
- package/src/utils/oauth/types.ts +4 -0
- package/src/utils/oauth/xiaomi.ts +80 -18
|
@@ -4,23 +4,44 @@
|
|
|
4
4
|
* Xiaomi MiMo provides OpenAI-compatible models via
|
|
5
5
|
* https://api.xiaomimimo.com/v1.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* 2. User copies their API key
|
|
10
|
-
* 3. User pastes the API key into the CLI
|
|
7
|
+
* Standard Xiaomi login opens the pay-as-you-go API key console. Token Plan
|
|
8
|
+
* login opens plan management so users copy the regional `tp-...` key.
|
|
11
9
|
*/
|
|
12
10
|
|
|
11
|
+
import type { FetchImpl } from "../../types";
|
|
13
12
|
import type { OAuthController } from "./types";
|
|
14
13
|
|
|
15
14
|
const PROVIDER_ID = "xiaomi";
|
|
16
15
|
const PROVIDER_NAME = "Xiaomi MiMo";
|
|
17
16
|
const STANDARD_AUTH_URL = "https://platform.xiaomimimo.com/#/console/api-keys";
|
|
17
|
+
const TOKEN_PLAN_AUTH_URL = "https://platform.xiaomimimo.com/console/plan-manage";
|
|
18
18
|
const STANDARD_API_BASE_URL = "https://api.xiaomimimo.com/v1";
|
|
19
|
-
const TOKEN_PLAN_SGP_API_BASE_URL = "https://token-plan-sgp.xiaomimimo.com/v1";
|
|
20
|
-
const TOKEN_PLAN_AMS_API_BASE_URL = "https://token-plan-ams.xiaomimimo.com/v1";
|
|
21
19
|
const TOKEN_PLAN_KEY_PREFIX = "tp-";
|
|
22
20
|
const STANDARD_VALIDATION_MODEL = "mimo-v2-flash";
|
|
23
21
|
const TOKEN_PLAN_VALIDATION_MODEL = "mimo-v2.5";
|
|
22
|
+
const TOKEN_PLAN_SGP_API_BASE_URL = "https://token-plan-sgp.xiaomimimo.com/v1";
|
|
23
|
+
const TOKEN_PLAN_AMS_API_BASE_URL = "https://token-plan-ams.xiaomimimo.com/v1";
|
|
24
|
+
const TOKEN_PLAN_CN_API_BASE_URL = "https://token-plan-cn.xiaomimimo.com/v1";
|
|
25
|
+
|
|
26
|
+
/** Region codes accepted by the Xiaomi Token Plan login flow. */
|
|
27
|
+
export type XiaomiTokenPlanRegion = "sgp" | "ams" | "cn";
|
|
28
|
+
|
|
29
|
+
type XiaomiValidationEndpoint = {
|
|
30
|
+
baseUrl: string;
|
|
31
|
+
model: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const TOKEN_PLAN_VALIDATION_ENDPOINTS: Record<XiaomiTokenPlanRegion, XiaomiValidationEndpoint> = {
|
|
35
|
+
sgp: { baseUrl: TOKEN_PLAN_SGP_API_BASE_URL, model: TOKEN_PLAN_VALIDATION_MODEL },
|
|
36
|
+
ams: { baseUrl: TOKEN_PLAN_AMS_API_BASE_URL, model: TOKEN_PLAN_VALIDATION_MODEL },
|
|
37
|
+
cn: { baseUrl: TOKEN_PLAN_CN_API_BASE_URL, model: TOKEN_PLAN_VALIDATION_MODEL },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const TOKEN_PLAN_REGION_NAMES: Record<XiaomiTokenPlanRegion, string> = {
|
|
41
|
+
sgp: "Singapore",
|
|
42
|
+
ams: "Europe",
|
|
43
|
+
cn: "China",
|
|
44
|
+
};
|
|
24
45
|
|
|
25
46
|
function isTokenPlanKey(apiKey: string): boolean {
|
|
26
47
|
return apiKey.startsWith(TOKEN_PLAN_KEY_PREFIX);
|
|
@@ -28,15 +49,24 @@ function isTokenPlanKey(apiKey: string): boolean {
|
|
|
28
49
|
|
|
29
50
|
const VALIDATION_TIMEOUT_MS = 15_000;
|
|
30
51
|
|
|
31
|
-
async function validateXiaomiApiKey(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
52
|
+
async function validateXiaomiApiKey(
|
|
53
|
+
apiKey: string,
|
|
54
|
+
tokenPlanRegion: XiaomiTokenPlanRegion | undefined,
|
|
55
|
+
signal?: AbortSignal,
|
|
56
|
+
fetchOverride?: FetchImpl,
|
|
57
|
+
): Promise<void> {
|
|
58
|
+
const fetchImpl = fetchOverride ?? fetch;
|
|
59
|
+
// Region-specific Token Plan logins must validate against the selected
|
|
60
|
+
// cluster. Generic Xiaomi login keeps the historical SGP → AMS → CN fallback.
|
|
61
|
+
const endpoints = tokenPlanRegion
|
|
62
|
+
? [TOKEN_PLAN_VALIDATION_ENDPOINTS[tokenPlanRegion]]
|
|
63
|
+
: isTokenPlanKey(apiKey)
|
|
64
|
+
? [
|
|
65
|
+
TOKEN_PLAN_VALIDATION_ENDPOINTS.sgp,
|
|
66
|
+
TOKEN_PLAN_VALIDATION_ENDPOINTS.ams,
|
|
67
|
+
TOKEN_PLAN_VALIDATION_ENDPOINTS.cn,
|
|
68
|
+
]
|
|
69
|
+
: [{ baseUrl: STANDARD_API_BASE_URL, model: STANDARD_VALIDATION_MODEL }];
|
|
40
70
|
|
|
41
71
|
let lastError: Error | null = null;
|
|
42
72
|
|
|
@@ -47,11 +77,11 @@ async function validateXiaomiApiKey(apiKey: string, signal?: AbortSignal): Promi
|
|
|
47
77
|
const timeoutSignal = AbortSignal.timeout(VALIDATION_TIMEOUT_MS);
|
|
48
78
|
const requestSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
49
79
|
try {
|
|
50
|
-
const response = await
|
|
80
|
+
const response = await fetchImpl(`${ep.baseUrl}/chat/completions`, {
|
|
51
81
|
method: "POST",
|
|
52
82
|
headers: {
|
|
53
83
|
"Content-Type": "application/json",
|
|
54
|
-
|
|
84
|
+
Authorization: `Bearer ${apiKey}`,
|
|
55
85
|
},
|
|
56
86
|
body: JSON.stringify({
|
|
57
87
|
model: ep.model,
|
|
@@ -112,6 +142,7 @@ async function validateXiaomiApiKey(apiKey: string, signal?: AbortSignal): Promi
|
|
|
112
142
|
* Returns the API key directly (not OAuthCredentials - this isn't OAuth).
|
|
113
143
|
*/
|
|
114
144
|
export async function loginXiaomi(options: OAuthController): Promise<string> {
|
|
145
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
115
146
|
if (!options.onPrompt) {
|
|
116
147
|
throw new Error(`${PROVIDER_NAME} login requires onPrompt callback`);
|
|
117
148
|
}
|
|
@@ -132,6 +163,37 @@ export async function loginXiaomi(options: OAuthController): Promise<string> {
|
|
|
132
163
|
}
|
|
133
164
|
|
|
134
165
|
options.onProgress?.(`Validating ${PROVIDER_ID} API key...`);
|
|
135
|
-
await validateXiaomiApiKey(trimmed, options.signal);
|
|
166
|
+
await validateXiaomiApiKey(trimmed, undefined, options.signal, fetchImpl);
|
|
167
|
+
return trimmed;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Login to a regional Xiaomi Token Plan endpoint.
|
|
172
|
+
*
|
|
173
|
+
* Prompts for a token-plan API key and validates it against the selected region.
|
|
174
|
+
*/
|
|
175
|
+
export async function loginXiaomiTokenPlan(options: OAuthController, region: XiaomiTokenPlanRegion): Promise<string> {
|
|
176
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
177
|
+
if (!options.onPrompt) {
|
|
178
|
+
throw new Error(`Xiaomi Token Plan (${TOKEN_PLAN_REGION_NAMES[region]}) login requires onPrompt callback`);
|
|
179
|
+
}
|
|
180
|
+
options.onAuth?.({
|
|
181
|
+
url: TOKEN_PLAN_AUTH_URL,
|
|
182
|
+
instructions: `Copy your token-plan API key for the ${TOKEN_PLAN_REGION_NAMES[region]} region`,
|
|
183
|
+
});
|
|
184
|
+
const apiKey = await options.onPrompt({
|
|
185
|
+
message: `Paste your Xiaomi Token Plan ${TOKEN_PLAN_REGION_NAMES[region]} API key (tp-...)`,
|
|
186
|
+
placeholder: "tp-...",
|
|
187
|
+
});
|
|
188
|
+
if (options.signal?.aborted) {
|
|
189
|
+
throw new Error("Login cancelled");
|
|
190
|
+
}
|
|
191
|
+
const trimmed = apiKey.trim();
|
|
192
|
+
if (!trimmed) {
|
|
193
|
+
throw new Error("API key is required");
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
options.onProgress?.(`Validating Xiaomi Token Plan (${TOKEN_PLAN_REGION_NAMES[region]}) API key...`);
|
|
197
|
+
await validateXiaomiApiKey(trimmed, region, options.signal, fetchImpl);
|
|
136
198
|
return trimmed;
|
|
137
199
|
}
|