ocb-cli 1.0.2 → 1.0.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/dist/proxy.js +73 -9
- package/package.json +1 -1
- package/src/proxy.ts +77 -9
package/dist/proxy.js
CHANGED
|
@@ -19,7 +19,9 @@ async function fetchModelsFromOpenCode() {
|
|
|
19
19
|
if (data.all) {
|
|
20
20
|
providers = {};
|
|
21
21
|
availableModels = [];
|
|
22
|
-
|
|
22
|
+
const providerList = Array.isArray(data.all) ? data.all : Object.values(data.all);
|
|
23
|
+
for (const providerData of providerList) {
|
|
24
|
+
const providerID = providerData.id || providerData.providerID;
|
|
23
25
|
const p = providerData;
|
|
24
26
|
providers[providerID] = { name: p.name, source: p.source };
|
|
25
27
|
if (p.models) {
|
|
@@ -109,7 +111,8 @@ app.use(express.json());
|
|
|
109
111
|
app.use((req, res, next) => {
|
|
110
112
|
res.header("Access-Control-Allow-Origin", "*");
|
|
111
113
|
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
|
112
|
-
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
114
|
+
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, x-api-key");
|
|
115
|
+
res.header("Content-Type", "application/json");
|
|
113
116
|
if (req.method === "OPTIONS")
|
|
114
117
|
return res.sendStatus(200);
|
|
115
118
|
next();
|
|
@@ -158,16 +161,77 @@ app.post("/api/reset-stats", (req, res) => {
|
|
|
158
161
|
totalRequests = 0;
|
|
159
162
|
res.json({ success: true });
|
|
160
163
|
});
|
|
164
|
+
const modelAliases = {
|
|
165
|
+
"claude-opus-4-5": "opencode/minimax-m2.5-free",
|
|
166
|
+
"claude-opus-4-5-thinking": "opencode/minimax-m2.5-free",
|
|
167
|
+
"claude-opus-4-6": "opencode/minimax-m2.5-free",
|
|
168
|
+
"claude-opus-4-6-thinking": "opencode/minimax-m2.5-free",
|
|
169
|
+
"claude-sonnet-4-5": "opencode/minimax-m2.5-free",
|
|
170
|
+
"claude-sonnet-4-5-thinking": "opencode/minimax-m2.5-free",
|
|
171
|
+
"claude-sonnet-4-5-20250929": "opencode/minimax-m2.5-free",
|
|
172
|
+
"claude-sonnet-4-5-20250929-thinking": "opencode/minimax-m2.5-free",
|
|
173
|
+
"claude-haiku-4-5": "opencode/minimax-m2.5-free",
|
|
174
|
+
"claude-haiku-4-5-20251001": "opencode/minimax-m2.5-free",
|
|
175
|
+
};
|
|
161
176
|
app.post("/api/reset-session", async (req, res) => {
|
|
162
177
|
currentSessionId = await createSession(process.cwd());
|
|
163
178
|
res.json({ success: true, sessionId: currentSessionId });
|
|
164
179
|
});
|
|
165
180
|
app.get("/v1/authenticate", (req, res) => res.json({ type: "authentication", authenticated: true }));
|
|
166
181
|
app.get("/v1/whoami", (req, res) => res.json({ type: "user", id: "opencode-user", email: "opencode@local" }));
|
|
167
|
-
app.get("/v1/models", (req, res) =>
|
|
168
|
-
|
|
182
|
+
app.get("/v1/models", (req, res) => {
|
|
183
|
+
const aliasModels = Object.keys(modelAliases).map(id => ({
|
|
184
|
+
id,
|
|
185
|
+
type: "model",
|
|
186
|
+
name: id,
|
|
187
|
+
display_name: id,
|
|
188
|
+
supports_cached_previews: true,
|
|
189
|
+
supports_system_instructions: true,
|
|
190
|
+
supports_reasoning: true,
|
|
191
|
+
supports_vision: false
|
|
192
|
+
}));
|
|
193
|
+
const allModels = [...aliasModels, ...availableModels.map(m => ({
|
|
194
|
+
id: m.id,
|
|
195
|
+
type: "model",
|
|
196
|
+
name: m.name,
|
|
197
|
+
display_name: m.name,
|
|
198
|
+
supports_cached_previews: true,
|
|
199
|
+
supports_system_instructions: true,
|
|
200
|
+
supports_reasoning: true,
|
|
201
|
+
supports_vision: false
|
|
202
|
+
}))];
|
|
203
|
+
res.json({ data: allModels });
|
|
204
|
+
});
|
|
205
|
+
app.get("/v1/models/list", (req, res) => {
|
|
206
|
+
const aliasModels = Object.keys(modelAliases).map(id => ({
|
|
207
|
+
id,
|
|
208
|
+
type: "model",
|
|
209
|
+
name: id,
|
|
210
|
+
display_name: id,
|
|
211
|
+
supports_cached_previews: true,
|
|
212
|
+
supports_system_instructions: true,
|
|
213
|
+
supports_reasoning: true,
|
|
214
|
+
supports_vision: false
|
|
215
|
+
}));
|
|
216
|
+
const allModels = [...aliasModels, ...availableModels.map(m => ({
|
|
217
|
+
id: m.id,
|
|
218
|
+
type: "model",
|
|
219
|
+
name: m.name,
|
|
220
|
+
display_name: m.name,
|
|
221
|
+
supports_cached_previews: true,
|
|
222
|
+
supports_system_instructions: true,
|
|
223
|
+
supports_reasoning: true,
|
|
224
|
+
supports_vision: false
|
|
225
|
+
}))];
|
|
226
|
+
res.json({ data: allModels });
|
|
227
|
+
});
|
|
169
228
|
app.post("/v1/messages", async (req, res) => {
|
|
170
229
|
try {
|
|
230
|
+
const requestedModel = req.body?.model || currentModel;
|
|
231
|
+
const actualModel = modelAliases[requestedModel] || requestedModel;
|
|
232
|
+
if (modelAliases[requestedModel]) {
|
|
233
|
+
currentModel = modelAliases[requestedModel];
|
|
234
|
+
}
|
|
171
235
|
if (req.body?.max_tokens === undefined && req.body?.messages) {
|
|
172
236
|
let totalTokens = 0;
|
|
173
237
|
for (const msg of req.body.messages) {
|
|
@@ -180,7 +244,7 @@ app.post("/v1/messages", async (req, res) => {
|
|
|
180
244
|
const { text, tokens } = await sendMessage(currentSessionId, req.body.messages);
|
|
181
245
|
totalRequests++;
|
|
182
246
|
totalTokensUsed += tokens;
|
|
183
|
-
res.json({ id: `msg_${Date.now()}`, type: "message", role: "assistant", content: [{ type: "text", text }], model:
|
|
247
|
+
res.json({ id: `msg_${Date.now()}`, type: "message", role: "assistant", content: [{ type: "text", text }], model: actualModel, stop_reason: "end_turn", usage: { input_tokens: Math.ceil(JSON.stringify(req.body.messages).length / 4), output_tokens: Math.ceil(text.length / 4) } });
|
|
184
248
|
}
|
|
185
249
|
catch (error) {
|
|
186
250
|
res.status(500).json({ error: { type: "api_error", message: error instanceof Error ? error.message : String(error) } });
|
|
@@ -330,9 +394,9 @@ function generateHTML() {
|
|
|
330
394
|
<div class="bg-zinc-950 rounded-xl p-4 font-mono text-sm text-zinc-300 overflow-x-auto">
|
|
331
395
|
<pre id="configJson">{
|
|
332
396
|
"env": {
|
|
333
|
-
"ANTHROPIC_BASE_URL": "http://localhost:8300
|
|
334
|
-
"
|
|
335
|
-
"ANTHROPIC_MODEL": "
|
|
397
|
+
"ANTHROPIC_BASE_URL": "http://localhost:8300",
|
|
398
|
+
"ANTHROPIC_API_KEY": "test",
|
|
399
|
+
"ANTHROPIC_MODEL": "claude-sonnet-4-5"
|
|
336
400
|
}
|
|
337
401
|
}</pre>
|
|
338
402
|
</div>
|
|
@@ -460,7 +524,7 @@ function generateHTML() {
|
|
|
460
524
|
currentModelId = modelId;
|
|
461
525
|
loadStatus();
|
|
462
526
|
renderModels(currentProvider === 'all' ? allModels : (groupedModels[currentProvider] || []));
|
|
463
|
-
document.getElementById('configJson').textContent = JSON.stringify({ env: { ANTHROPIC_BASE_URL: "http://localhost:8300
|
|
527
|
+
document.getElementById('configJson').textContent = JSON.stringify({ env: { ANTHROPIC_BASE_URL: "http://localhost:8300", ANTHROPIC_API_KEY: "test", ANTHROPIC_MODEL: modelId } }, null, 2);
|
|
464
528
|
}
|
|
465
529
|
}
|
|
466
530
|
|
package/package.json
CHANGED
package/src/proxy.ts
CHANGED
|
@@ -34,7 +34,10 @@ async function fetchModelsFromOpenCode() {
|
|
|
34
34
|
providers = {};
|
|
35
35
|
availableModels = [];
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
const providerList = Array.isArray(data.all) ? data.all : Object.values(data.all);
|
|
38
|
+
|
|
39
|
+
for (const providerData of providerList) {
|
|
40
|
+
const providerID = providerData.id || providerData.providerID;
|
|
38
41
|
const p = providerData as { name: string; source: string; models: Record<string, any> };
|
|
39
42
|
providers[providerID] = { name: p.name, source: p.source };
|
|
40
43
|
|
|
@@ -136,7 +139,8 @@ app.use(express.json());
|
|
|
136
139
|
app.use((req, res, next) => {
|
|
137
140
|
res.header("Access-Control-Allow-Origin", "*");
|
|
138
141
|
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
|
139
|
-
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
142
|
+
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, x-api-key");
|
|
143
|
+
res.header("Content-Type", "application/json");
|
|
140
144
|
if (req.method === "OPTIONS") return res.sendStatus(200);
|
|
141
145
|
next();
|
|
142
146
|
});
|
|
@@ -190,6 +194,19 @@ app.post("/api/reset-stats", (req, res) => {
|
|
|
190
194
|
res.json({ success: true });
|
|
191
195
|
});
|
|
192
196
|
|
|
197
|
+
const modelAliases: Record<string, string> = {
|
|
198
|
+
"claude-opus-4-5": "opencode/minimax-m2.5-free",
|
|
199
|
+
"claude-opus-4-5-thinking": "opencode/minimax-m2.5-free",
|
|
200
|
+
"claude-opus-4-6": "opencode/minimax-m2.5-free",
|
|
201
|
+
"claude-opus-4-6-thinking": "opencode/minimax-m2.5-free",
|
|
202
|
+
"claude-sonnet-4-5": "opencode/minimax-m2.5-free",
|
|
203
|
+
"claude-sonnet-4-5-thinking": "opencode/minimax-m2.5-free",
|
|
204
|
+
"claude-sonnet-4-5-20250929": "opencode/minimax-m2.5-free",
|
|
205
|
+
"claude-sonnet-4-5-20250929-thinking": "opencode/minimax-m2.5-free",
|
|
206
|
+
"claude-haiku-4-5": "opencode/minimax-m2.5-free",
|
|
207
|
+
"claude-haiku-4-5-20251001": "opencode/minimax-m2.5-free",
|
|
208
|
+
};
|
|
209
|
+
|
|
193
210
|
app.post("/api/reset-session", async (req, res) => {
|
|
194
211
|
currentSessionId = await createSession(process.cwd());
|
|
195
212
|
res.json({ success: true, sessionId: currentSessionId });
|
|
@@ -198,11 +215,62 @@ app.post("/api/reset-session", async (req, res) => {
|
|
|
198
215
|
app.get("/v1/authenticate", (req, res) => res.json({ type: "authentication", authenticated: true }));
|
|
199
216
|
app.get("/v1/whoami", (req, res) => res.json({ type: "user", id: "opencode-user", email: "opencode@local" }));
|
|
200
217
|
|
|
201
|
-
app.get("/v1/models", (req, res) =>
|
|
202
|
-
|
|
218
|
+
app.get("/v1/models", (req, res) => {
|
|
219
|
+
const aliasModels = Object.keys(modelAliases).map(id => ({
|
|
220
|
+
id,
|
|
221
|
+
type: "model" as const,
|
|
222
|
+
name: id,
|
|
223
|
+
display_name: id,
|
|
224
|
+
supports_cached_previews: true,
|
|
225
|
+
supports_system_instructions: true,
|
|
226
|
+
supports_reasoning: true,
|
|
227
|
+
supports_vision: false
|
|
228
|
+
}));
|
|
229
|
+
const allModels = [...aliasModels, ...availableModels.map(m => ({
|
|
230
|
+
id: m.id,
|
|
231
|
+
type: "model" as const,
|
|
232
|
+
name: m.name,
|
|
233
|
+
display_name: m.name,
|
|
234
|
+
supports_cached_previews: true,
|
|
235
|
+
supports_system_instructions: true,
|
|
236
|
+
supports_reasoning: true,
|
|
237
|
+
supports_vision: false
|
|
238
|
+
}))];
|
|
239
|
+
res.json({ data: allModels });
|
|
240
|
+
});
|
|
241
|
+
app.get("/v1/models/list", (req, res) => {
|
|
242
|
+
const aliasModels = Object.keys(modelAliases).map(id => ({
|
|
243
|
+
id,
|
|
244
|
+
type: "model" as const,
|
|
245
|
+
name: id,
|
|
246
|
+
display_name: id,
|
|
247
|
+
supports_cached_previews: true,
|
|
248
|
+
supports_system_instructions: true,
|
|
249
|
+
supports_reasoning: true,
|
|
250
|
+
supports_vision: false
|
|
251
|
+
}));
|
|
252
|
+
const allModels = [...aliasModels, ...availableModels.map(m => ({
|
|
253
|
+
id: m.id,
|
|
254
|
+
type: "model" as const,
|
|
255
|
+
name: m.name,
|
|
256
|
+
display_name: m.name,
|
|
257
|
+
supports_cached_previews: true,
|
|
258
|
+
supports_system_instructions: true,
|
|
259
|
+
supports_reasoning: true,
|
|
260
|
+
supports_vision: false
|
|
261
|
+
}))];
|
|
262
|
+
res.json({ data: allModels });
|
|
263
|
+
});
|
|
203
264
|
|
|
204
265
|
app.post("/v1/messages", async (req, res) => {
|
|
205
266
|
try {
|
|
267
|
+
const requestedModel = req.body?.model || currentModel;
|
|
268
|
+
const actualModel = modelAliases[requestedModel] || requestedModel;
|
|
269
|
+
|
|
270
|
+
if (modelAliases[requestedModel]) {
|
|
271
|
+
currentModel = modelAliases[requestedModel];
|
|
272
|
+
}
|
|
273
|
+
|
|
206
274
|
if (req.body?.max_tokens === undefined && req.body?.messages) {
|
|
207
275
|
let totalTokens = 0;
|
|
208
276
|
for (const msg of req.body.messages) {
|
|
@@ -214,7 +282,7 @@ app.post("/v1/messages", async (req, res) => {
|
|
|
214
282
|
const { text, tokens } = await sendMessage(currentSessionId, req.body.messages);
|
|
215
283
|
totalRequests++;
|
|
216
284
|
totalTokensUsed += tokens;
|
|
217
|
-
res.json({ id: `msg_${Date.now()}`, type: "message", role: "assistant", content: [{ type: "text", text }], model:
|
|
285
|
+
res.json({ id: `msg_${Date.now()}`, type: "message", role: "assistant", content: [{ type: "text", text }], model: actualModel, stop_reason: "end_turn", usage: { input_tokens: Math.ceil(JSON.stringify(req.body.messages).length / 4), output_tokens: Math.ceil(text.length / 4) } });
|
|
218
286
|
} catch (error) {
|
|
219
287
|
res.status(500).json({ error: { type: "api_error", message: error instanceof Error ? error.message : String(error) } });
|
|
220
288
|
}
|
|
@@ -365,9 +433,9 @@ function generateHTML() {
|
|
|
365
433
|
<div class="bg-zinc-950 rounded-xl p-4 font-mono text-sm text-zinc-300 overflow-x-auto">
|
|
366
434
|
<pre id="configJson">{
|
|
367
435
|
"env": {
|
|
368
|
-
"ANTHROPIC_BASE_URL": "http://localhost:8300
|
|
369
|
-
"
|
|
370
|
-
"ANTHROPIC_MODEL": "
|
|
436
|
+
"ANTHROPIC_BASE_URL": "http://localhost:8300",
|
|
437
|
+
"ANTHROPIC_API_KEY": "test",
|
|
438
|
+
"ANTHROPIC_MODEL": "claude-sonnet-4-5"
|
|
371
439
|
}
|
|
372
440
|
}</pre>
|
|
373
441
|
</div>
|
|
@@ -495,7 +563,7 @@ function generateHTML() {
|
|
|
495
563
|
currentModelId = modelId;
|
|
496
564
|
loadStatus();
|
|
497
565
|
renderModels(currentProvider === 'all' ? allModels : (groupedModels[currentProvider] || []));
|
|
498
|
-
document.getElementById('configJson').textContent = JSON.stringify({ env: { ANTHROPIC_BASE_URL: "http://localhost:8300
|
|
566
|
+
document.getElementById('configJson').textContent = JSON.stringify({ env: { ANTHROPIC_BASE_URL: "http://localhost:8300", ANTHROPIC_API_KEY: "test", ANTHROPIC_MODEL: modelId } }, null, 2);
|
|
499
567
|
}
|
|
500
568
|
}
|
|
501
569
|
|