@leoustc/service-llm 0.2.6 → 0.2.7
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/README.md +1 -1
- package/VERSION +1 -1
- package/dist/auth.js +12 -5
- package/dist/codex.js +38 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ For a headless or remote machine:
|
|
|
35
35
|
service-llm login --device-code
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
Credentials are stored securely at `~/.service-llm/auth.json`.
|
|
38
|
+
Credentials are stored securely at `~/.service-llm/auth.json`. During login, the service fetches the available Codex API models and records them at `~/.service-llm/models.json`.
|
|
39
39
|
|
|
40
40
|
If you start the service before logging in, the first model request returns a device code and verification URL. Complete the browser login, then retry the request.
|
|
41
41
|
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2.
|
|
1
|
+
0.2.7
|
package/dist/auth.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
loginOpenAICodexDeviceCode,
|
|
8
8
|
refreshOpenAICodexToken,
|
|
9
9
|
} from "./codex-oauth.js";
|
|
10
|
-
import { getModels } from "./codex.js";
|
|
10
|
+
import { fetchModels, getModels } from "./codex.js";
|
|
11
11
|
|
|
12
12
|
export const authPath = join(homedir(), ".service-llm", "auth.json");
|
|
13
13
|
export const modelsPath = join(homedir(), ".service-llm", "models.json");
|
|
@@ -23,8 +23,15 @@ function smallestModel(models) {
|
|
|
23
23
|
})[0];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
async function saveModelCatalog() {
|
|
27
|
-
|
|
26
|
+
async function saveModelCatalog(accessToken) {
|
|
27
|
+
let models = getModels("openai-codex");
|
|
28
|
+
if (accessToken) {
|
|
29
|
+
try {
|
|
30
|
+
models = await fetchModels(accessToken);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error(`Unable to refresh the Codex model catalog; using the bundled fallback: ${error.message}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
28
35
|
const fallback = smallestModel(models);
|
|
29
36
|
if (!fallback) throw new Error("No OpenAI Codex models are available");
|
|
30
37
|
let previousDefault;
|
|
@@ -108,7 +115,7 @@ export async function login({ deviceCode = false } = {}) {
|
|
|
108
115
|
const data = await readAuth();
|
|
109
116
|
data["openai-codex"] = { type: "oauth", ...credentials };
|
|
110
117
|
await saveAuth(data);
|
|
111
|
-
const catalog = await saveModelCatalog();
|
|
118
|
+
const catalog = await saveModelCatalog(credentials.access);
|
|
112
119
|
console.error(`Authentication saved to ${authPath}`);
|
|
113
120
|
console.error(`Loaded ${catalog.models.length} models; default is ${catalog.default_model} with low reasoning`);
|
|
114
121
|
}
|
|
@@ -150,7 +157,7 @@ async function beginDeviceLogin() {
|
|
|
150
157
|
const data = await readAuth();
|
|
151
158
|
data["openai-codex"] = { type: "oauth", ...credentials };
|
|
152
159
|
await saveAuth(data);
|
|
153
|
-
await saveModelCatalog();
|
|
160
|
+
await saveModelCatalog(credentials.access);
|
|
154
161
|
console.error(`Authentication completed and saved to ${authPath}`);
|
|
155
162
|
})
|
|
156
163
|
.catch((error) => {
|
package/dist/codex.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Codex Responses transport adapted from @earendil-works/pi-ai (MIT).
|
|
2
|
-
import { platform, release, arch } from "node:os";
|
|
3
2
|
|
|
4
3
|
const BASE_URL = "https://chatgpt.com/backend-api/codex/responses";
|
|
4
|
+
const MODELS_URL = "https://chatgpt.com/backend-api/codex/models";
|
|
5
|
+
const CODEX_CLIENT_VERSION = "0.144.1";
|
|
5
6
|
const MODEL_DATA = [
|
|
6
7
|
["gpt-5.3-codex-spark", "GPT-5.3 Codex Spark", 1.75, 14],
|
|
7
8
|
["gpt-5.4", "GPT-5.4", 2.5, 15],
|
|
@@ -24,6 +25,40 @@ export function getModel(provider, id) {
|
|
|
24
25
|
return provider === "openai-codex" ? models.find((model) => model.id === id) : undefined;
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
export async function fetchModels(accessToken, request = fetch) {
|
|
29
|
+
const id = accountId(accessToken);
|
|
30
|
+
if (!id) throw new Error("Failed to extract the ChatGPT account ID from the access token");
|
|
31
|
+
const url = new URL(MODELS_URL);
|
|
32
|
+
url.searchParams.set("client_version", CODEX_CLIENT_VERSION);
|
|
33
|
+
const response = await request(url, {
|
|
34
|
+
headers: {
|
|
35
|
+
authorization: `Bearer ${accessToken}`,
|
|
36
|
+
"chatgpt-account-id": id,
|
|
37
|
+
originator: "codex_cli_rs",
|
|
38
|
+
"user-agent": `codex_cli_rs/${CODEX_CLIENT_VERSION}`,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
if (!response.ok) throw new Error(`Codex model discovery failed (${response.status})`);
|
|
42
|
+
const body = await response.json();
|
|
43
|
+
return (body.models ?? [])
|
|
44
|
+
.filter((model) => model.visibility === "list" && model.supported_in_api !== false)
|
|
45
|
+
.map((model) => {
|
|
46
|
+
const builtin = getModel("openai-codex", model.slug);
|
|
47
|
+
if (builtin) return builtin;
|
|
48
|
+
const discovered = {
|
|
49
|
+
id: model.slug,
|
|
50
|
+
name: model.display_name ?? model.slug,
|
|
51
|
+
provider: "openai-codex",
|
|
52
|
+
api: "openai-codex-responses",
|
|
53
|
+
baseUrl: BASE_URL,
|
|
54
|
+
cost: { input: Infinity, output: Infinity },
|
|
55
|
+
input: model.input_modalities ?? ["text"],
|
|
56
|
+
};
|
|
57
|
+
models.push(discovered);
|
|
58
|
+
return discovered;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
27
62
|
function accountId(token) {
|
|
28
63
|
try {
|
|
29
64
|
return JSON.parse(Buffer.from(token.split(".")[1], "base64url").toString("utf8"))?.["https://api.openai.com/auth"]?.chatgpt_account_id;
|
|
@@ -110,8 +145,8 @@ export function stream(model, context, options = {}) {
|
|
|
110
145
|
headers: {
|
|
111
146
|
authorization: `Bearer ${options.apiKey}`,
|
|
112
147
|
"chatgpt-account-id": id,
|
|
113
|
-
originator: "
|
|
114
|
-
"user-agent": `
|
|
148
|
+
originator: "codex_cli_rs",
|
|
149
|
+
"user-agent": `codex_cli_rs/${CODEX_CLIENT_VERSION}`,
|
|
115
150
|
"openai-beta": "responses=experimental",
|
|
116
151
|
accept: "text/event-stream",
|
|
117
152
|
"content-type": "application/json",
|
package/package.json
CHANGED