@vizuh/sabi 0.2.0 → 0.2.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/README.md +22 -7
- package/mod/sabi.mjs +30 -2
- package/package.json +14 -7
- package/sabi.config.json +2 -1
package/README.md
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
|
-
# @vizuh/sabi: Command Code
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
# @vizuh/sabi: Sabi inference adapter (Command Code mod)
|
|
2
|
+
|
|
3
|
+
Sabi is harness-independent adaptive inference scheduling for coding-agent trajectories:
|
|
4
|
+
per-round routing of model, effort and provider from trajectory evidence, while each host
|
|
5
|
+
harness keeps its own loop. Sabi promotes no single harness; every host below is a
|
|
6
|
+
peer surface with its own install path.
|
|
7
|
+
|
|
8
|
+
This npm artifact is the Command Code mod — one Sabi surface, not the whole product.
|
|
9
|
+
See the [adapter directory](../../../docs/adapters/README.md) for the product map and
|
|
10
|
+
evidence boundaries.
|
|
11
|
+
|
|
12
|
+
| Harness | Sabi surface | Install |
|
|
13
|
+
| --- | --- | --- |
|
|
14
|
+
| Claude Code | Controller hooks (task/session, fail-open) | `npm install --global @vizuh/sabi-controller` then `sabi setup` |
|
|
15
|
+
| Codex | Controller hooks (task/session, fail-open) | `npm install --global @vizuh/sabi-controller` then `sabi setup` |
|
|
16
|
+
| Command Code | This package: in-process mod, per-round model + reasoning effort | `cmd mods add -g npm:@vizuh/sabi` |
|
|
17
|
+
| Hermes | Local proxy + native `llm_request` middleware | Checkout-based setup in [the install guide](../../../docs/install.md) |
|
|
18
|
+
| Oh My Pi | Local proxy via OpenAI-compatible extension provider | Checkout: `omp --extension packages/adapters/oh-my-pi/src/sabi-extension.mjs --model sabi/sabi-code` |
|
|
19
|
+
| OpenCode | Local proxy, plus optional controller hook | Checkout-based proxy (`npm start` + `npm run connect:opencode`); hooks via `@vizuh/sabi-controller` |
|
|
20
|
+
| Orca | Controller plugin + inventory/dispatch bridge | `npm install --global @vizuh/sabi-controller` then `sabi setup` |
|
|
21
|
+
| DeepSeek Harness, Kilo, Cline, Prime Agent | Proxy or bundle paths | See the [adapter directory](../../../docs/adapters/README.md) |
|
|
7
22
|
|
|
8
23
|
Adaptive inference scheduling for [Command Code](https://commandcode.ai): a mod that plans each
|
|
9
24
|
continuing round, including model and reasoning effort, from the trajectory's own state (tool calls and
|
|
@@ -17,7 +32,7 @@ The two paths are independent:
|
|
|
17
32
|
|
|
18
33
|
- The Command Code mod needs no Sabi provider key or proxy. It routes the subscription already
|
|
19
34
|
available to Command Code.
|
|
20
|
-
- The local proxy works with
|
|
35
|
+
- The local proxy works with Hermes, Oh My Pi, OpenCode, and other OpenAI-compatible clients (including Cline, Kilo and Prime Agent paths). It uses
|
|
21
36
|
OpenRouter, Ollama, or another configured upstream. In the shipped default the OpenRouter
|
|
22
37
|
upstream is **free-models-only** (`paidModelsAllowed: false`): a priced model id is refused
|
|
23
38
|
before the request leaves the process, so the proxy cannot spend on its own.
|
package/mod/sabi.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @vizuh/sabi 0.2.
|
|
1
|
+
// @vizuh/sabi 0.2.1 — generated by pack.mjs from packages/adapters/command-code/mod/sabi.ts.
|
|
2
2
|
// Source and docs: https://github.com/vizuh/sabi
|
|
3
3
|
|
|
4
4
|
// packages/core/src/telemetry.ts
|
|
@@ -323,7 +323,11 @@ var TRANSPORT_LIMIT_PATTERNS = [
|
|
|
323
323
|
{ re: /too many requests/i, label: "rate-limited" },
|
|
324
324
|
{ re: /\b(?:session|usage|weekly|monthly|daily|hourly|subscription|plan)\s+limit\b/i, label: "quota-exceeded" },
|
|
325
325
|
{ re: /quota[- ]?exceeded/i, label: "quota-exceeded" },
|
|
326
|
-
{ re: /insufficient_quota|insufficient quota/i, label: "quota-exceeded" }
|
|
326
|
+
{ re: /insufficient_quota|insufficient quota/i, label: "quota-exceeded" },
|
|
327
|
+
// A dropped connection is the transport failing. Without this, the wording a client prints after
|
|
328
|
+
// a transport deadline reads as a task failure and the next round escalates straight back to the
|
|
329
|
+
// tier that just timed out — ten consecutive 120s rounds in one real session.
|
|
330
|
+
{ re: /socket (?:connection )?(?:was )?closed|socket hang up|ECONNRESET|other side closed|connection reset/i, label: "connection-closed" }
|
|
327
331
|
];
|
|
328
332
|
var TRANSPORT_PATTERNS = [
|
|
329
333
|
{ re: /\b429\b/, label: "rate-limited" },
|
|
@@ -863,6 +867,12 @@ function validateConfig(value, source = "<inline>") {
|
|
|
863
867
|
if (upstream.paidModelsAllowed !== void 0 && typeof upstream.paidModelsAllowed !== "boolean") {
|
|
864
868
|
throw new Error(`Sabi config ${source}: upstream '${name}'.paidModelsAllowed must be a boolean`);
|
|
865
869
|
}
|
|
870
|
+
if (upstream.auth !== void 0 && upstream.auth !== "passthrough") {
|
|
871
|
+
throw new Error(`Sabi config ${source}: upstream '${name}'.auth must be 'passthrough'`);
|
|
872
|
+
}
|
|
873
|
+
if (upstream.auth === "passthrough" && upstream.apiKey !== void 0 && upstream.apiKey !== false) {
|
|
874
|
+
throw new Error(`Sabi config ${source}: upstream '${name}' is auth:passthrough and must not declare apiKey`);
|
|
875
|
+
}
|
|
866
876
|
}
|
|
867
877
|
if (!Object.keys(models).length) throw new Error(`Sabi config ${source}: no models declared`);
|
|
868
878
|
for (const [name, model] of Object.entries(models)) {
|
|
@@ -904,6 +914,21 @@ function validateConfig(value, source = "<inline>") {
|
|
|
904
914
|
throw new Error(`Sabi config ${source}: transportFallback.enabled must be a boolean`);
|
|
905
915
|
}
|
|
906
916
|
}
|
|
917
|
+
const passthrough = config.passthrough;
|
|
918
|
+
if (passthrough !== void 0) {
|
|
919
|
+
if (!isObject(passthrough)) throw new Error(`Sabi config ${source}: passthrough must be an object`);
|
|
920
|
+
for (const field of Object.keys(passthrough)) {
|
|
921
|
+
if (field !== "alias") throw new Error(`Sabi config ${source}: passthrough.${field} is not a supported field`);
|
|
922
|
+
}
|
|
923
|
+
if (passthrough.alias !== void 0) {
|
|
924
|
+
if (typeof passthrough.alias !== "string" || !passthrough.alias.trim()) {
|
|
925
|
+
throw new Error(`Sabi config ${source}: passthrough.alias must be a nonempty string`);
|
|
926
|
+
}
|
|
927
|
+
if (aliases[passthrough.alias] !== "auto") {
|
|
928
|
+
throw new Error(`Sabi config ${source}: passthrough.alias '${passthrough.alias}' must name an alias targeting 'auto'`);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
907
932
|
const judge = config.judge;
|
|
908
933
|
if (judge !== void 0) {
|
|
909
934
|
if (typeof judge !== "object" || judge === null || typeof judge.enabled !== "boolean") {
|
|
@@ -1210,6 +1235,9 @@ function sanitizeDecisionRecord(record, config) {
|
|
|
1210
1235
|
state,
|
|
1211
1236
|
cache: record.cache,
|
|
1212
1237
|
judge: record.judge,
|
|
1238
|
+
// Effort labels are short provider-declared strings, never transcript text; still bounded.
|
|
1239
|
+
...typeof record.effort === "string" && record.effort.trim() ? { effort: record.effort.trim().slice(0, 64) } : {},
|
|
1240
|
+
...record.effortSource === "client" || record.effortSource === "scheduled" || record.effortSource === "unspecified" ? { effortSource: record.effortSource } : {},
|
|
1213
1241
|
usage: record.usage,
|
|
1214
1242
|
cost: record.cost,
|
|
1215
1243
|
latencyMs: record.latencyMs,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizuh/sabi",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Sabi inference adapter for Command Code, part of harness-independent adaptive routing for Claude Code, Codex, Command Code, Hermes, Oh My Pi, OpenCode and Orca.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -11,13 +11,20 @@
|
|
|
11
11
|
},
|
|
12
12
|
"homepage": "https://github.com/vizuh/sabi#readme",
|
|
13
13
|
"keywords": [
|
|
14
|
-
"
|
|
14
|
+
"sabi",
|
|
15
|
+
"ai-agents",
|
|
16
|
+
"claude-code",
|
|
17
|
+
"codex",
|
|
15
18
|
"command-code",
|
|
19
|
+
"commandcode",
|
|
20
|
+
"hermes",
|
|
21
|
+
"inference-scheduling",
|
|
22
|
+
"llm-routing",
|
|
16
23
|
"mod",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
24
|
+
"oh-my-pi",
|
|
25
|
+
"opencode",
|
|
26
|
+
"openai-compatible",
|
|
27
|
+
"orca"
|
|
21
28
|
],
|
|
22
29
|
"publishConfig": {
|
|
23
30
|
"access": "public"
|
package/sabi.config.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"provenance": "Operator rule (2026-09-22): OpenRouter may serve FREE models only. The openrouter upstream declares paidModelsAllowed:false, so any model whose price is unknown or non-zero is refused at dispatch (packages/core/src/compatibility.ts) — a config mistake cannot spend money. Every openrouter model id below carries the :free variant and cost 0. Ids, context windows, output ceilings, modalities and zero pricing verified live from https://openrouter.ai/api/v1/models and a real completion per id on 2026-09-22. Jev (TypeSafe judge) is a separate upstream and unaffected by this rule.",
|
|
2
|
+
"provenance": "Operator rule (2026-09-22): OpenRouter may serve FREE models only. The openrouter upstream declares paidModelsAllowed:false, so any model whose price is unknown or non-zero is refused at dispatch (packages/core/src/compatibility.ts) — a config mistake cannot spend money. Every openrouter model id below carries the :free variant and cost 0. Ids, context windows, output ceilings, modalities and zero pricing verified live from https://openrouter.ai/api/v1/models and a real completion per id on 2026-09-22. Jev (TypeSafe judge) is a separate upstream and unaffected by this rule. Operator rule (2026-09-23): Claude Code and Codex are used through their own subscriptions — Sabi installs hooks into them and never writes a provider base URL, an API key or a model override into either harness, so neither can become per-token spend through Sabi. Guarded by packages/controller/test/hooks.test.ts.",
|
|
3
3
|
"server": { "host": "127.0.0.1", "port": 8787 },
|
|
4
4
|
"upstreams": {
|
|
5
5
|
"openrouter": {
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"upstream": "ollama",
|
|
48
48
|
"model": "qwen2.5-coder:7b",
|
|
49
49
|
"contextWindow": 32768,
|
|
50
|
+
"maxOutputTokens": 32768,
|
|
50
51
|
"capabilities": { "inputModalities": ["text"] },
|
|
51
52
|
"cost": { "input": 0, "output": 0 }
|
|
52
53
|
}
|