You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is about which host serves the Jev model, not about replacing Jev with another model. Two different things get mixed together and they should stay apart:
Jev from another source (this issue). Exactly two hosts are baked into the code today. A third host that serves the same Jev model -- a partner or reseller, an internal gateway in front of api.typesafe.ai, an egress-controlled corporate deployment -- cannot be used without a code change and a release.
A different model acting as judge (that is Use Laya and other fast local models instead of paid APIs #34). A local model (Ollama, llama.cpp, MLX, vLLM) or any OpenAI-compatible provider answering the guards' questions instead of Jev. That is not "another source of Jev": it is a different model doing the job, it needs a protocol adapter, and feat: laya-mlx local judge backend #28 showed the quality risk is real.
I am asking for (1) first, with a config shape that does not preclude (2).
A working example: Command Code already serves Jev
Endpoint: POST https://api.commandcode.ai/provider/v1/systemone with Authorization: Bearer <Command Code key>
Pricing: $0.04/M input tokens at cost; output is free.
Plans: "Available on GOAT and above, the plans with Provider API access."
Not listed in the chat-model catalog, by design: "Jev is a decision model, not a chat model. It answers typed questions about a state with probabilities and never produces text ... It is not in /model and cannot drive an interactive session."
The wire shape is the same one @typesafe-ai/sdk already speaks (/v1/systemone, noul/choice/score questions):
curl https://api.commandcode.ai/provider/v1/systemone \
-H "Authorization: Bearer $COMMANDCODE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "typesafe/jev", "state": "Payments failed for three days.", "questions": {"urgent": {"type": "noul", "instructions": "Does this need urgent attention?"}}}'# {"model":"typesafe/jev","answers":{"urgent":{"type":"noul","noul":0.95}},# "usage":{"input_tokens":41,"output_tokens":12}}
So this is not a protocol change: pi-typesafe already rewrites the SDK's fixed paths per backend (backendFetch with the registry's path), which is how OpenRouter works. Serving Jev through Command Code should be a registry entry, not an adapter:
That is the whole argument of this issue: the model is already reachable, and the only reason a Pi user with a Command Code plan cannot use it is that host and keyEnv are constants.
Current state (0.73.0)
~/.pi/agent/pi-warden/config.jsontypesafeBackend accepts two values; anything else silently falls back to typesafe (pi-warden/dist/backend.js, resolveBackend).
The registry is hardcoded in pi-typesafe/dist/backends.js:
host and keyEnv are per-entry constants, and there is no config path to the registry (DECISIONS_BACKENDS is exported and its comment says "Extendable by callers", but nothing reads it from config).
Requests go through @typesafe-ai/sdk's TypeSafeClient, which appends fixed paths (/v1/systemone, /v1/models); backendFetch rewrites them per backend.
The consent text is built from the host: pi-warden/dist/backend.js reads DECISIONS_BACKENDS[backend].host and substitutes the destination into the disclosure. A configurable host has to flow into that text and into /warden status.
The invariants that already exist for this key must hold:
User file only. A project file must not be able to redirect judgments (the same rule mode and typesafeBackend have today). Otherwise a checked-out repository could aim the judge at a host it controls and read everything the guards send.
Consent names the real destination. The disclosure text and /warden status are built from the backend host today; a configurable host must appear there.
The answer is still validated. A configurable endpoint does not relax the Choice/Score/Noul schema check, and a malformed reply must fail the way a network error does (fail-open per action.failOpen, with the existing judge cooldown and the one-time notice).
One detail worth deciding while adding a third entry: modelsVerifyKey. A key check against a model list proves something only when the list is private. Command Code's /provider/v1/models answers anonymously (82 chat models, verified), so a key check against it would pass with a bad key -- and typesafe/jev is not in that list at all, so the list cannot confirm that the configured model is reachable either.
If (2) is picked up later
The same config could grow an api: "openai-completions" field plus a model id for a model that is not Jev. That is #34's scope and it needs the adapter described there: build the prompt from the question set, ask for JSON, validate it. Two notes for that path:
Keep the two cases visibly different in the status line and the trace, so it is clear whether Jev or a stand-in answered.
A per-backend guard scope may be the honest default (a small local model should not decide holds), with the per-rule threshold: header already available to compensate.
Open questions
Is the decisions protocol documented for third parties (Command Code's own docs describe it for one host)? If it is not, a third host has to reverse-engineer it, and (2) becomes the only open path.
Should the registry become extensible at runtime, or should a config value be the only route? The latter is easier to keep user-file-only, which is the invariant that matters.
Alternatives
Add hosts one at a time to DECISIONS_BACKENDS (what feat: add OpenRouter as a configurable judgment backend #12 did for OpenRouter). Each addition needs a code change and a release in pi-typesafe, and a private gateway can never be covered this way.
Run the model inside the extension (feat: laya-mlx local judge backend #28, laya-mlx). Pins one model, one platform and one runtime, and makes the extension carry model downloads and a Python bridge.
Related: #34 (a different model as judge, open), #12 (OpenRouter added as a backend, closed), #28 (laya-mlx local backend, closed).
Correction: an earlier revision of this issue said Command Code does not serve Jev. That was wrong -- I had checked the chat-model catalog, where decision models are deliberately absent.
Summary
This is about which host serves the Jev model, not about replacing Jev with another model. Two different things get mixed together and they should stay apart:
api.typesafe.ai, an egress-controlled corporate deployment -- cannot be used without a code change and a release.I am asking for (1) first, with a config shape that does not preclude (2).
A working example: Command Code already serves Jev
Verified 2026-09-28 from https://commandcode.ai/models/jev:
typesafe/jevPOST https://api.commandcode.ai/provider/v1/systemonewithAuthorization: Bearer <Command Code key>$0.04/M input tokens at cost; output is free./modeland cannot drive an interactive session."The wire shape is the same one
@typesafe-ai/sdkalready speaks (/v1/systemone,noul/choice/scorequestions):So this is not a protocol change:
pi-typesafealready rewrites the SDK's fixed paths per backend (backendFetchwith the registry'spath), which is how OpenRouter works. Serving Jev through Command Code should be a registry entry, not an adapter:That is the whole argument of this issue: the model is already reachable, and the only reason a Pi user with a Command Code plan cannot use it is that
hostandkeyEnvare constants.Current state (0.73.0)
~/.pi/agent/pi-warden/config.jsontypesafeBackendaccepts two values; anything else silently falls back totypesafe(pi-warden/dist/backend.js,resolveBackend).The registry is hardcoded in
pi-typesafe/dist/backends.js:hostandkeyEnvare per-entry constants, and there is no config path to the registry (DECISIONS_BACKENDSis exported and its comment says "Extendable by callers", but nothing reads it from config).Requests go through
@typesafe-ai/sdk'sTypeSafeClient, which appends fixed paths (/v1/systemone,/v1/models);backendFetchrewrites them per backend.The consent text is built from the host:
pi-warden/dist/backend.jsreadsDECISIONS_BACKENDS[backend].hostand substitutes the destination into the disclosure. A configurable host has to flow into that text and into/warden status.Proposal
Let the user file name the endpoint:
{ "typesafeBackend": { "label": "commandcode", "baseUrl": "https://api.commandcode.ai", "path": "/provider/v1/systemone", "apiKeyEnv": "COMMANDCODE_API_KEY", "model": "typesafe/jev" } }The invariants that already exist for this key must hold:
modeandtypesafeBackendhave today). Otherwise a checked-out repository could aim the judge at a host it controls and read everything the guards send./warden statusare built from the backend host today; a configurable host must appear there.Choice/Score/Noulschema check, and a malformed reply must fail the way a network error does (fail-open peraction.failOpen, with the existing judge cooldown and the one-time notice).One detail worth deciding while adding a third entry:
modelsVerifyKey. A key check against a model list proves something only when the list is private. Command Code's/provider/v1/modelsanswers anonymously (82 chat models, verified), so a key check against it would pass with a bad key -- andtypesafe/jevis not in that list at all, so the list cannot confirm that the configured model is reachable either.If (2) is picked up later
The same config could grow an
api: "openai-completions"field plus a model id for a model that is not Jev. That is #34's scope and it needs the adapter described there: build the prompt from the question set, ask for JSON, validate it. Two notes for that path:threshold:header already available to compensate.Open questions
Alternatives
DECISIONS_BACKENDS(what feat: add OpenRouter as a configurable judgment backend #12 did for OpenRouter). Each addition needs a code change and a release inpi-typesafe, and a private gateway can never be covered this way.Related: #34 (a different model as judge, open), #12 (OpenRouter added as a backend, closed), #28 (laya-mlx local backend, closed).
Correction: an earlier revision of this issue said Command Code does not serve Jev. That was wrong -- I had checked the chat-model catalog, where decision models are deliberately absent.