@byokit/openclaw 0.21.0 → 0.22.1
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/CHANGELOG.md +10 -0
- package/README.md +6 -1
- package/dist/keys.js +21 -5
- package/engine/patches.json +12 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.22.1 (2026-10-19)
|
|
6
|
+
|
|
7
|
+
- FIX: a funded OpenRouter key now signs in and runs the model the person chooses. Before, `addKey` answered `{ status: 'not_included', reason: 'model' }` for every OpenRouter key, so apps showed a plan refusal and never reached the model: the pinned engine planned the key's live test on `openrouter/auto` but staged the route as the provider normalizes it, and refused the key as unavailable before sending it. A bundled engine patch now plans the test on the staged route; a key whose account has no credits (OpenRouter's HTTP 402) now answers `{ status: 'invalid', reason: 'billing' }`, never a plan refusal. An OpenRouter key pasted under OpenRouter's browser sign-in choice (`addKey(member, { authChoice: 'openrouter-oauth', apiKey })`) also takes OpenRouter's one key route (`openrouter-api-key`); a choice of a provider with exactly one key route billed alike maps the same way, and any other choice that takes no key throws its cause (`openai takes no API key: add the key with openai-api-key.`) instead of a plan refusal.
|
|
8
|
+
|
|
9
|
+
## 0.22.0 (2026-10-19)
|
|
10
|
+
|
|
11
|
+
- FEAT: a helper's delegated run is visible from start to finish on `onEvent('byokit.delegated')`: `admitted` carries `run.tools` (its app-tool subset, also on `delegatedRuns()`), and the one `ended` says why in `reason`: `terminal`, `cancelled` (a kit or engine abort, or ended admission), `error` (with the engine's `message`) or `resting`, where the model's usage limit ended a helper's run and the kit rests that helper's account `until` the stated reset, as a kit run's resting end does.
|
|
12
|
+
- FEAT: `Approval.helper` names the helper whose run asks, for gate approvals and for native approvals on a helper's `agent:<agent>:h-<helper>:` key.
|
|
13
|
+
- FEAT: `kit.adoptHelperSession({ member, sessionKey }, helper)` moves a conversation from before helpers into a helper: its whole transcript forks to `agent:<member>:h-<helper>:<tail>` on the helper's account agent and the old session is deleted, with no model request, credential or SQLite copy. A conversation still in flight (live run, parked approval or admitted delegated child) is refused `busy` and keeps its exact old key and approval owner until it settles.
|
|
14
|
+
|
|
5
15
|
## 0.21.0 (2026-10-19)
|
|
6
16
|
|
|
7
17
|
- FEAT: `run({ helperDelegates: { writer: ['report'] } })` lets a run hand work to the member's own helpers: the engine's native `sessions_send` to the exact key `agent:<the helper's agent>:h-<helper>:<rest>`, on an ordinary account or the plan-key lane, is admitted from its receipt as that helper's delegated run (`RunRef.helper`), so its app-tool calls cross the same gate, approvals and tool subset as any delegated child. `abort(rootSessionKey)` revokes them.
|
package/README.md
CHANGED
|
@@ -32,6 +32,8 @@ hashes. The Gateway Workshop review patch writes content-free, durable usage fac
|
|
|
32
32
|
accounting environment. The separately bundled worker and all other detached kinds remain uncovered.
|
|
33
33
|
The Claude CLI route also uses the bundled [Tooling-name correction](../../docs/runtime-kits.md#516-bundled-engine-patches-and-engine-started-usage-d19);
|
|
34
34
|
apps do not need consumer tool aliases.
|
|
35
|
+
A key setup plan patch lets an OpenRouter API key activate: stock plans the key's live test on a route other than the
|
|
36
|
+
one it stages and refuses every OpenRouter key before sending it.
|
|
35
37
|
The full upstream MIT notice ships in [engine/OPENCLAW-LICENSE](engine/OPENCLAW-LICENSE).
|
|
36
38
|
|
|
37
39
|
Each `prepare()` verifies the **entire** selected engine tree, including unpatched files. The kit installs stock
|
|
@@ -149,7 +151,10 @@ returns what that run would choose now, refusals included, without running. `ste
|
|
|
149
151
|
|
|
150
152
|
For an owner who explicitly offers keys, `kit.addKey('ana', { authChoice: 'openai-api-key', apiKey })` is a thenable
|
|
151
153
|
handle: `await` it for `{ status: 'ok' }` or `{ status: 'invalid' | 'not_included' | 'retry', reason }`, and call
|
|
152
|
-
`cancel()` to stop a pending add (clears any partial key; settles `retry`/`busy`).
|
|
154
|
+
`cancel()` to stop a pending add (clears any partial key; settles `retry`/`busy`). `authChoice` may also name another
|
|
155
|
+
sign-in of a provider with exactly one key route billed alike (`openrouter-oauth` adds an `openrouter-api-key`); any
|
|
156
|
+
other choice that takes no key (a subscription such as `openai`, a provider with several key routes, an unknown choice)
|
|
157
|
+
throws its cause before anything is sent.
|
|
153
158
|
`reason` is `auth` (provider refused the key) or `billing` (the provider's billing refused it; the kit words it and never passes
|
|
154
159
|
provider text): both are `invalid`, and an unchanged key must not be retried. `empty` is a blank key, rejected locally before any
|
|
155
160
|
provider call, also `invalid`. `model` is an unsupported route or unknown model (`not_included`), or a live model the engine did not
|
package/dist/keys.js
CHANGED
|
@@ -77,12 +77,28 @@ export function createKeys(ctx) {
|
|
|
77
77
|
const rows = (answer.models ?? []).map((m) => ({ ...m, id: canonical(String(m.id)) }));
|
|
78
78
|
return [...new Map(rows.map((m) => [String(m.id), m])).values()];
|
|
79
79
|
};
|
|
80
|
+
// The key route a choice names: its own, or the only key route of the provider whose other sign-in it names, billed
|
|
81
|
+
// alike (an OpenRouter key pasted under `openrouter-oauth` is an `openrouter-api-key`). Anything else is the app's
|
|
82
|
+
// mistake, refused with its cause before anything is sent: never a plan refusal, never a subscription turned per-use.
|
|
83
|
+
const keyRoute = (authChoice) => {
|
|
84
|
+
const all = ctx.routes();
|
|
85
|
+
const named = all.find((r) => r.choice === authChoice);
|
|
86
|
+
if (!named)
|
|
87
|
+
throw new Error(`No sign-in is named ${authChoice}.`);
|
|
88
|
+
if (named.keyEntry)
|
|
89
|
+
return named;
|
|
90
|
+
const keyed = all.filter((r) => r.provider === named.provider && r.keyEntry);
|
|
91
|
+
if (keyed.length === 1 && keyed[0].billing === named.billing)
|
|
92
|
+
return keyed[0];
|
|
93
|
+
throw new Error(keyed.length ? `${authChoice} takes no API key: add the key with ${keyed.map((r) => r.choice).join(' or ')}.`
|
|
94
|
+
: `${authChoice} takes no API key.`);
|
|
95
|
+
};
|
|
80
96
|
const listed = (provider, rows) => modelsOf(provider, { models: rows.map((m) => ({ ...m, provider })) });
|
|
81
97
|
const models = async (member, o) => {
|
|
82
98
|
if (!check(member))
|
|
83
99
|
throw new Error('Choose your own member.');
|
|
84
|
-
const route =
|
|
85
|
-
if (
|
|
100
|
+
const route = keyRoute(o.authChoice);
|
|
101
|
+
if (route.readiness !== 'ready' || !LIVE_CATALOGS.includes(route.provider))
|
|
86
102
|
return [];
|
|
87
103
|
try {
|
|
88
104
|
return listed(route.provider, await catalog(member, route.provider));
|
|
@@ -111,8 +127,8 @@ export function createKeys(ctx) {
|
|
|
111
127
|
throw new Error('Choose your own member.');
|
|
112
128
|
if (!o.apiKey.trim())
|
|
113
129
|
return failure('invalid', 'empty');
|
|
114
|
-
const route =
|
|
115
|
-
if (
|
|
130
|
+
const route = keyRoute(o.authChoice);
|
|
131
|
+
if (route.readiness !== 'ready' || (o.model !== undefined && !LIVE_CATALOGS.includes(route.provider)))
|
|
116
132
|
return failure('not_included', 'model');
|
|
117
133
|
const model = o.model === undefined ? undefined : canonicalModel(o.model);
|
|
118
134
|
// A workspace names a Go login's own workspace only; another route takes no header, and a
|
|
@@ -193,7 +209,7 @@ export function createKeys(ctx) {
|
|
|
193
209
|
sent = true;
|
|
194
210
|
if (ac.signal.aborted)
|
|
195
211
|
return abandon(cancelled());
|
|
196
|
-
const result = await activate(ctx, { kind: 'api-key', agentId, authChoice:
|
|
212
|
+
const result = await activate(ctx, { kind: 'api-key', agentId, authChoice: route.choice, apiKey: o.apiKey }, { timeoutMs: 180_000, signal: ac.signal });
|
|
197
213
|
if (ac.signal.aborted)
|
|
198
214
|
return abandon(cancelled());
|
|
199
215
|
if (!result.ok && !result.late)
|
package/engine/patches.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"v": 1,
|
|
3
|
-
"id": "
|
|
3
|
+
"id": "dcd1cf72add44075",
|
|
4
4
|
"upstream": {
|
|
5
5
|
"name": "openclaw",
|
|
6
6
|
"version": "2026.8.35",
|
|
@@ -65,6 +65,17 @@
|
|
|
65
65
|
"replace": "let systemPrompt = !skipsTurnPreparation ? backendResolved.transformSystemPrompt?.({\n\t\t\tconfig: params.config,\n\t\t\tworkspaceDir,\n\t\t\tprovider: params.provider,\n\t\t\tmodelId,\n\t\t\tmodelDisplay,\n\t\t\tagentId: sessionAgentId,\n\t\t\tsystemPrompt: builtSystemPrompt\n\t\t}) ?? builtSystemPrompt : builtSystemPrompt;\n\t\t// BYOKit: Claude wire names for the Tooling list (ch-cli-tool-prefix). The Claude wire catalog\n\t\t// exposes OpenClaw tools as mcp__openclaw__<name>, so the printed Tooling list on that route must\n\t\t// use those exact names. Every other route keeps the stock prompt byte-identical; already-prefixed\n\t\t// names are never prefixed again. Order, summaries and error semantics are unchanged.\n\t\tif (!skipsTurnPreparation && isClaudeCli && promptTools.length > 0) {\n\t\t\tconst byokitBareNames = new Set(promptTools.map((tool) => tool?.name).filter((name) => typeof name === \"string\" && name.length > 0 && !name.startsWith(\"mcp__openclaw__\")));\n\t\t\tif (byokitBareNames.size > 0) {\n\t\t\t\tconst byokitLines = systemPrompt.split(\"\\n\");\n\t\t\t\tlet byokitInTooling = false;\n\t\t\t\tlet byokitToolingArmed = false;\n\t\t\t\tfor (let byokitI = 0; byokitI < byokitLines.length; byokitI++) {\n\t\t\t\t\tconst byokitLine = byokitLines[byokitI];\n\t\t\t\t\tif (byokitLine.startsWith(\"## \")) {\n\t\t\t\t\t\tbyokitInTooling = byokitLine === \"## Tooling\";\n\t\t\t\t\t\tbyokitToolingArmed = false;\n\t\t\t\t\t} else if (byokitInTooling && !byokitToolingArmed) {\n\t\t\t\t\t\tif (byokitLine === \"Tools policy-filtered. Names case-sensitive; call exact.\") byokitToolingArmed = true;\n\t\t\t\t\t} else if (byokitInTooling && byokitToolingArmed && byokitLine.startsWith(\"- \")) {\n\t\t\t\t\t\tconst byokitMatch = /^- (\\S+?)(:.*)?$/.exec(byokitLine);\n\t\t\t\t\t\tif (byokitMatch && byokitBareNames.has(byokitMatch[1])) byokitLines[byokitI] = `- mcp__openclaw__${byokitMatch[1]}${byokitMatch[2] ?? \"\"}`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tsystemPrompt = byokitLines.join(\"\\n\");\n\t\t\t}\n\t\t}\n"
|
|
66
66
|
}
|
|
67
67
|
]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"path": "dist/setup-inference-Dpvv_U7x.js",
|
|
71
|
+
"before": "e38ba4aa4a31376a03609b8732fcd69026df17149849d15caa6a8a59a865d6d7",
|
|
72
|
+
"after": "71f7103b5f88db7e3b98433a54b05a5a18557d6e83385d09cddaabe053254823",
|
|
73
|
+
"edits": [
|
|
74
|
+
{
|
|
75
|
+
"find": "\t\t\treturn {\n\t\t\t\trunner: \"embedded\",\n\t\t\t\t...ref,\n\t\t\t\tmodelRef,\n\t\t\t\tagentDir: params.agentDir,\n\t\t\t\tconfig: preparedAuth.config,",
|
|
76
|
+
"replace": "\t\t\t// BYOKit: plan the route the engine stages. A provider-normalized starter (OpenRouter keeps its bare `auto` as\n\t\t\t// `openrouter/auto`) is planned as the staged route names it, so a key activation matches its staged route.\n\t\t\tconst byokitModelRef = canonicalizeSetupModelRef({\n\t\t\t\tcfg: preparedAuth.config,\n\t\t\t\traw: modelRef,\n\t\t\t\tdefaultProvider: ref.provider\n\t\t\t});\n\t\t\treturn {\n\t\t\t\trunner: \"embedded\",\n\t\t\t\t...parseRef(byokitModelRef),\n\t\t\t\tmodelRef: byokitModelRef,\n\t\t\t\tagentDir: params.agentDir,\n\t\t\t\tconfig: preparedAuth.config,"
|
|
77
|
+
}
|
|
78
|
+
]
|
|
68
79
|
}
|
|
69
80
|
]
|
|
70
81
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byokit/openclaw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.1",
|
|
4
4
|
"description": "The OpenClaw runtime kit: the pinned engine's full operator surface with plain-words helpers for members, sign-in, runs and approvals.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|