@magpie-community/opencode-zen-free-auth 0.1.15 → 0.1.17
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 +9 -2
- package/models.mjs +19 -1
- package/package.json +1 -1
- package/provider.mjs +17 -13
package/README.md
CHANGED
|
@@ -6,8 +6,15 @@ OpenCode Zen's free models in magpie and OpenCode. Provider id:
|
|
|
6
6
|
Since 2026-10-13 Zen's free tier answers 403 FreeTierError ("can only be
|
|
7
7
|
used from within OpenCode") to a request that isn't OpenCode's. From
|
|
8
8
|
0.1.6 the plugin sends a free-model request with exactly the headers
|
|
9
|
-
OpenCode
|
|
10
|
-
|
|
9
|
+
OpenCode sends to Zen, and a session id of OpenCode's own form. Older
|
|
10
|
+
versions (0.1.1 on npm before it) get the 403: update the plugin.
|
|
11
|
+
|
|
12
|
+
Since 2026-10-26 Zen's free tier answers `429 FreeUsageLimitError`
|
|
13
|
+
("Free models work in OpenCode") to the User-Agent OpenCode 1.19.0 sent,
|
|
14
|
+
which 0.1.6 to 0.1.15 sent on every request. From 0.1.16 the plugin
|
|
15
|
+
sends OpenCode 2.0.25's headers (`opencode/latest/2.0.25/cli`, its
|
|
16
|
+
session id under `x-session-affinity` and `x-session-id` too): update
|
|
17
|
+
the plugin.
|
|
11
18
|
|
|
12
19
|
## Install
|
|
13
20
|
|
package/models.mjs
CHANGED
|
@@ -53,6 +53,18 @@ function listedFree(id) {
|
|
|
53
53
|
return /-free$/.test(id);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
// "258K" is the model's working label, not an exact maximum. Zen's live
|
|
57
|
+
// catalog lists deepseek-v4.1-flash-free at 200000, but on 2026-10-26 a
|
|
58
|
+
// request whose upstream usage was in 576 + cache_read 258,048 = 258,624
|
|
59
|
+
// tokens got a 200 from the free tier. That is the measured floor; the
|
|
60
|
+
// later 283,545-token attempt was magpie's own estimate, not upstream
|
|
61
|
+
// usage, so it is not a ceiling. Reporting more than the vendor accepts
|
|
62
|
+
// routes requests that then fail, so the floor is used until a source
|
|
63
|
+
// says more. Remove this when the catalog carries the real value.
|
|
64
|
+
const CONTEXT_FLOOR = {
|
|
65
|
+
"deepseek-v4.1-flash-free": 258_624,
|
|
66
|
+
};
|
|
67
|
+
|
|
56
68
|
export function buildModels(ids, provider, protocols, baseURL) {
|
|
57
69
|
const result = {};
|
|
58
70
|
for (const id of ids) {
|
|
@@ -81,7 +93,13 @@ export function buildModels(ids, provider, protocols, baseURL) {
|
|
|
81
93
|
providerID: PROVIDER,
|
|
82
94
|
name: model.name ?? id,
|
|
83
95
|
api: { id, url: baseURL, npm: SDK[protocol] },
|
|
84
|
-
limit: {
|
|
96
|
+
limit: {
|
|
97
|
+
output: 4096,
|
|
98
|
+
...model.limit,
|
|
99
|
+
context: CONTEXT_FLOOR[id]
|
|
100
|
+
? Math.max(model.limit?.context ?? 0, CONTEXT_FLOOR[id])
|
|
101
|
+
: model.limit?.context ?? 32768,
|
|
102
|
+
},
|
|
85
103
|
capabilities: {
|
|
86
104
|
temperature: model.temperature ?? true,
|
|
87
105
|
reasoning: model.reasoning ?? false,
|
package/package.json
CHANGED
package/provider.mjs
CHANGED
|
@@ -33,13 +33,17 @@ const CORE_PARAMETER = {
|
|
|
33
33
|
grep: "pattern",
|
|
34
34
|
read: "filePath",
|
|
35
35
|
};
|
|
36
|
-
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
// What OpenCode 2.0.25 sends as its User-Agent on every protocol:
|
|
37
|
+
// `opencode/${channel}/${version}/${name}` (its App service, read from the
|
|
38
|
+
// release binary and captured from its requests on 2026-10-25). Since
|
|
39
|
+
// 2026-10-26 Zen's free tier answers 429 FreeUsageLimitError ("Free models
|
|
40
|
+
// work in OpenCode") to the exact User-Agent 0.1.6 to 0.1.15 sent, OpenCode
|
|
41
|
+
// 1.19.0's `opencode/1.19.0 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.14`,
|
|
42
|
+
// whatever the body says; the same request under any other string, OpenCode
|
|
43
|
+
// 2.0.25's included, is served.
|
|
44
|
+
const OPENCODE_VERSION = "2.0.25";
|
|
45
|
+
export function userAgent() {
|
|
46
|
+
return `opencode/latest/${OPENCODE_VERSION}/cli`;
|
|
43
47
|
}
|
|
44
48
|
// How long a request for a model the last list didn't have waits before it
|
|
45
49
|
// asks Zen's list again: a model Zen made free since is served at once,
|
|
@@ -375,24 +379,24 @@ async function server(_input, options = {}) {
|
|
|
375
379
|
addEnvironment(body, protocol);
|
|
376
380
|
if (protocol === "chat")
|
|
377
381
|
body.stream_options = { ...body.stream_options, include_usage: true };
|
|
378
|
-
// Only what OpenCode
|
|
379
|
-
// caller's own headers (an agent's User-Agent, x-stainless-*,
|
|
380
|
-
//
|
|
381
|
-
// OpenCode's (packages/opencode/src/session/llm/request.ts).
|
|
382
|
+
// Only what OpenCode 2.0.25 itself sends to its gateway, so a
|
|
383
|
+
// caller's own headers (an agent's User-Agent, x-stainless-*, ...)
|
|
384
|
+
// never mark the request as not OpenCode's.
|
|
382
385
|
const given = request.headers;
|
|
383
386
|
const session = sessionID(given, body);
|
|
384
387
|
const project = _input?.project;
|
|
385
388
|
const headers = new Headers({
|
|
386
389
|
"content-type": "application/json",
|
|
387
390
|
accept: "*/*",
|
|
388
|
-
"user-agent": userAgent(
|
|
391
|
+
"user-agent": userAgent(),
|
|
389
392
|
"x-opencode-project":
|
|
390
393
|
given.get("x-opencode-project") ||
|
|
391
394
|
(project?.vcs === "git" && project.id ? project.id : "global"),
|
|
392
395
|
"x-opencode-session": session,
|
|
393
|
-
"x-opencode-request": opencodeID("msg", false),
|
|
394
396
|
"x-opencode-client": "cli",
|
|
395
397
|
"x-opencode-session-id": session,
|
|
398
|
+
"x-session-affinity": session,
|
|
399
|
+
"x-session-id": session,
|
|
396
400
|
});
|
|
397
401
|
if (protocol === "anthropic") {
|
|
398
402
|
headers.set("x-api-key", "public");
|