@magpie-community/opencode-zen-free-auth 0.1.15 → 0.1.16

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.
Files changed (3) hide show
  1. package/README.md +9 -2
  2. package/package.json +1 -1
  3. 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 1.19.0 sends to Zen, and a session id of OpenCode's own form.
10
- Older versions (0.1.1 on npm before it) get the 403: update the plugin.
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-zen-free-auth",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "OpenCode Zen free models through the public credential, with native streaming protocols",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",
package/provider.mjs CHANGED
@@ -33,13 +33,17 @@ const CORE_PARAMETER = {
33
33
  grep: "pattern",
34
34
  read: "filePath",
35
35
  };
36
- const OPENCODE_VERSION = "1.19.0";
37
- // What OpenCode 1.19.0 sends as its User-Agent, ai-sdk and Bun included.
38
- // Each protocol's ai-sdk package bundles its own provider-utils, so the
39
- // version differs by protocol (captured from the release binary's requests).
40
- const PROVIDER_UTILS = { chat: "4.0.23", responses: "4.0.40", anthropic: "4.0.46" };
41
- export function userAgent(protocol) {
42
- return `opencode/${OPENCODE_VERSION} ai-sdk/provider-utils/${PROVIDER_UTILS[protocol]} runtime/bun/1.3.14`;
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 1.19.0 itself sends to its gateway, so a
379
- // caller's own headers (an agent's User-Agent, x-stainless-*,
380
- // x-session-affinity, ...) never mark the request as not
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(protocol),
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");