@leoustc/service-llm 0.2.2 → 0.2.3
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 +10 -1
- package/VERSION +1 -1
- package/dist/http.js +33 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -144,9 +144,10 @@ Connect an MCP client to:
|
|
|
144
144
|
http://127.0.0.1:7060/mcp
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
-
The server provides
|
|
147
|
+
The server provides two tools:
|
|
148
148
|
|
|
149
149
|
- `ask`: accepts `prompt` and optional `model`, `tools`, and `tool_choice` arguments.
|
|
150
|
+
- `list_models`: lists available models and reports the currently configured default model and reasoning level.
|
|
150
151
|
|
|
151
152
|
Example JSON-RPC request:
|
|
152
153
|
|
|
@@ -168,6 +169,14 @@ curl http://127.0.0.1:7060/mcp \
|
|
|
168
169
|
|
|
169
170
|
Specify a model with the request's `model` field. If it is omitted or unavailable, the service uses your configured default. On first login, the lowest-cost available model is selected with low reasoning effort. Responses always report the model actually used.
|
|
170
171
|
|
|
172
|
+
List the models available to both Chat Completions and Responses clients:
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
curl http://127.0.0.1:7060/v1/models
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
When client authentication is enabled, include the same Bearer or `X-API-Key` header used for generation requests. The response includes `default_model` and `default_reasoning_effort` in addition to the OpenAI-compatible model list.
|
|
179
|
+
|
|
171
180
|
## Debug logging
|
|
172
181
|
|
|
173
182
|
Enable request, response, and SSE logs with:
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2.
|
|
1
|
+
0.2.3
|
package/dist/http.js
CHANGED
|
@@ -26,6 +26,23 @@ function sendJson(response, status, body) {
|
|
|
26
26
|
response.end(JSON.stringify(body));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export function modelCatalogResponse(catalog) {
|
|
30
|
+
const created = Math.floor(new Date(catalog.updated_at ?? 0).getTime() / 1000) || 0;
|
|
31
|
+
return {
|
|
32
|
+
object: "list",
|
|
33
|
+
data: catalog.models.map((model) => ({
|
|
34
|
+
id: model.id,
|
|
35
|
+
object: "model",
|
|
36
|
+
created,
|
|
37
|
+
owned_by: "openai-codex",
|
|
38
|
+
...(model.name ? { name: model.name } : {}),
|
|
39
|
+
})),
|
|
40
|
+
default_model: catalog.default_model,
|
|
41
|
+
default_reasoning_effort: catalog.default_reasoning_effort ?? "low",
|
|
42
|
+
updated_at: catalog.updated_at,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
29
46
|
async function readJson(request) {
|
|
30
47
|
const chunks = [];
|
|
31
48
|
let size = 0;
|
|
@@ -167,7 +184,20 @@ async function mcp(response, body) {
|
|
|
167
184
|
if (body.method === "initialize") return sendJson(response, 200, { ...base, result: { protocolVersion: body.params?.protocolVersion ?? "2025-03-26", capabilities: { tools: {} }, serverInfo: { name: "service-llm", version } } });
|
|
168
185
|
if (body.method === "notifications/initialized") return response.writeHead(202).end();
|
|
169
186
|
if (body.method === "ping") return sendJson(response, 200, { ...base, result: {} });
|
|
170
|
-
if (body.method === "tools/list") return sendJson(response, 200, { ...base, result: { tools: [
|
|
187
|
+
if (body.method === "tools/list") return sendJson(response, 200, { ...base, result: { tools: [
|
|
188
|
+
{ name: "ask", description: "Ask a Codex model a question and optionally allow it to return function tool calls. Tool calls are never executed.", inputSchema: { type: "object", properties: { prompt: { type: "string" }, model: { type: "string" }, tools: { type: "array", items: { type: "object" } }, tool_choice: {} }, required: ["prompt"], additionalProperties: false } },
|
|
189
|
+
{ name: "list_models", description: "List the available Codex models and report the model currently configured as the default.", inputSchema: { type: "object", properties: {}, additionalProperties: false } },
|
|
190
|
+
] } });
|
|
191
|
+
if (body.method === "tools/call" && body.params?.name === "list_models") {
|
|
192
|
+
const catalog = modelCatalogResponse(await listModels());
|
|
193
|
+
return sendJson(response, 200, {
|
|
194
|
+
...base,
|
|
195
|
+
result: {
|
|
196
|
+
content: [{ type: "text", text: JSON.stringify(catalog, null, 2) }],
|
|
197
|
+
structuredContent: catalog,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
171
201
|
if (body.method === "tools/call" && body.params?.name === "ask") {
|
|
172
202
|
if (typeof body.params.arguments?.prompt !== "string") return sendJson(response, 200, { ...base, error: { code: -32602, message: "ask requires a string prompt" } });
|
|
173
203
|
const answer = await ask({
|
|
@@ -209,6 +239,7 @@ export function startServer({ port = 7060, host = "127.0.0.1", apiKeys = [] } =
|
|
|
209
239
|
});
|
|
210
240
|
if (request.method === "GET" && url.pathname === "/health") return sendJson(response, 200, { status: "ok" });
|
|
211
241
|
if (!isAuthorized(request, allowedKeys)) return sendJson(response, 401, { error: { message: "Invalid API key", type: "authentication_error" } });
|
|
242
|
+
if (request.method === "GET" && url.pathname === "/v1/models") return sendJson(response, 200, modelCatalogResponse(await listModels()));
|
|
212
243
|
if (request.method !== "POST") return sendJson(response, 405, { error: { message: "Method not allowed" } });
|
|
213
244
|
const body = await readJson(request);
|
|
214
245
|
debug("request body", body);
|
|
@@ -245,6 +276,7 @@ export function startServer({ port = 7060, host = "127.0.0.1", apiKeys = [] } =
|
|
|
245
276
|
}
|
|
246
277
|
console.error("Endpoints:");
|
|
247
278
|
console.error(` Health: ${baseUrl}/health`);
|
|
279
|
+
console.error(` Models: ${baseUrl}/v1/models`);
|
|
248
280
|
console.error(` Chat Completions: ${baseUrl}/v1/chat/completions`);
|
|
249
281
|
console.error(` Responses: ${baseUrl}/v1/responses`);
|
|
250
282
|
console.error(` MCP: ${baseUrl}/mcp`);
|
package/package.json
CHANGED