mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-24 20:09:02 +00:00
Tell Zen one way, in Zen's names
The Zen page called zen6 a 27B dense model and led with no reason to pick Zen; the models index listed Zen 7 as "upcoming" and HIP-0904 as "dense, coder and ternary checkpoints"; examples called zen5 and one called zen5-coder-32b-instruct, which the gateway does not serve. Zen is now told as the gateway serves it: Zen 7 in research preview with Request access, Zen 6 the new Zen architecture (zen6, zen6-coder), Zen 5.8 the one before, Zen 5 earlier. It leads with its two jobs, agentic coding on your own machine and marketing work, and names Zoo Labs Foundation, a 501(c)(3) non-profit, as its maker. Examples call zen6. Upstream base models appear only in the Architecture value and the License & attribution section, both data-upstream. check-zen reads every Zen page in pre-build and fails the build on a name from zen.upstream anywhere else.
This commit is contained in:
@@ -137,9 +137,9 @@ zt-docs) predate the unified `content/docs/` model — migrate their content int
|
||||
`content/docs/<section>/` (or a `hanzo-docs/<team>` submodule) then archive the
|
||||
app.
|
||||
|
||||
## Two build guards, and why prose needs them
|
||||
## Build guards, and why prose needs them
|
||||
|
||||
`scripts/pre-build.ts` ends with two checks that fail the build. Both exist for
|
||||
`scripts/pre-build.ts` ends with checks that fail the build. The first two exist for
|
||||
the same reason: a generated page cannot be wrong about the API, an authored one
|
||||
can, and a reader cannot tell which kind of page they are on.
|
||||
|
||||
@@ -149,6 +149,12 @@ can, and a reader cannot tell which kind of page they are on.
|
||||
and `api-keys.mdx` must teach every class the document carries. Both
|
||||
directions, so renaming, adding or removing a key class in cloud stops the
|
||||
build here instead of publishing a stale page.
|
||||
- **`check-zen.ts`** — a Zen page (`models/index.mdx`, `models/zen*`) names no
|
||||
upstream base model outside a `data-upstream` element. Two places carry one:
|
||||
the Architecture value (the loader string from the weights' own config) and
|
||||
the License & attribution section. The names live in `apps/docs/zen.upstream`
|
||||
and only there; title and description are read too, since they become the
|
||||
meta and OG tags.
|
||||
|
||||
The key classes come from `Document.keys` (`openapi-doc.ts`), read out of the
|
||||
`/v1/keys` prose — cloud's own Go doc comments, lifted by zipdoc. `secretKey(doc)`
|
||||
|
||||
@@ -18,7 +18,7 @@ const use = [
|
||||
['Python', 'python', `# pip install hanzoai\nfrom hanzoai.cloud import AiApi, ApiClient, Configuration\n\nai = AiApi(ApiClient(Configuration()))\n\nprint(len(ai.get_models().data or []), "models")`],
|
||||
['Go', 'go', `// go get github.com/hanzoai/go-sdk/v8\nimport hanzoai "github.com/hanzoai/go-sdk/v8"\n\nclient := hanzoai.NewAPIClient(hanzoai.NewConfiguration())\n\nmodels, _, err := client.AiAPI.GetModels(ctx).Execute()`],
|
||||
['Rust', 'rust', `// cargo add hanzo-client\nuse hanzo_client::apis::{ai_api, configuration::Configuration};\n\nlet cfg = Configuration::new();\n\nlet models = ai_api::get_models(&cfg).await?;`],
|
||||
['HTTP', 'bash', `curl https://api.hanzo.ai/v1/chat/completions \\\n -H "Authorization: Bearer $HANZO_API_KEY" \\\n -H "Content-Type: application/json" \\\n -d '{"model":"zen5","messages":[{"role":"user","content":"Hello!"}]}'`],
|
||||
['HTTP', 'bash', `curl https://api.hanzo.ai/v1/chat/completions \\\n -H "Authorization: Bearer $HANZO_API_KEY" \\\n -H "Content-Type: application/json" \\\n -d '{"model":"zen6","messages":[{"role":"user","content":"Hello!"}]}'`],
|
||||
] as const;
|
||||
|
||||
function Group({ rows }: { rows: readonly (readonly [string, string, string])[] }) {
|
||||
|
||||
@@ -102,9 +102,9 @@ const commands = [
|
||||
];
|
||||
|
||||
const zen = [
|
||||
{ name: 'zen6', spec: '27B dense, 1M context' },
|
||||
{ name: 'zen6-coder', spec: 'Agentic code' },
|
||||
{ name: 'zen6-flash', spec: 'Ternary vision' },
|
||||
{ name: 'zen6', spec: 'New architecture' },
|
||||
{ name: 'zen6-coder', spec: 'Local agentic code' },
|
||||
{ name: 'zen5.8', spec: 'Previous generation' },
|
||||
{ name: 'zen5', spec: 'Hosted' },
|
||||
{ name: 'zen-embedding', spec: 'Retrieval' },
|
||||
{ name: 'zen-guard', spec: 'Safety' },
|
||||
@@ -381,7 +381,7 @@ export function Landing({ install, use }: { install: ReactNode; use: ReactNode }
|
||||
</Text>
|
||||
</XStack>
|
||||
<Text fontSize={14} lineHeight={22} maxW={672} whiteSpace="normal" {...muted}>
|
||||
The generative family: reasoning, code, vision, speech, embeddings and safety. Weights on Hugging Face; the same ids hosted on api.hanzo.ai, routed by Enso.
|
||||
The generative family, chosen for two jobs: agentic coding that runs on your own machine, and marketing work — copy in your brand's voice and the images and speech beside it. Weights on Hugging Face; the same ids hosted on api.hanzo.ai, routed by Enso.
|
||||
</Text>
|
||||
<Grid columns={{ min: 130, max: 6 }} gap={12}>
|
||||
{zen.map((m) => (
|
||||
|
||||
@@ -38,14 +38,14 @@ curl https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "zen5",
|
||||
"model": "zen6",
|
||||
"messages": [{"role": "user", "content": "Hello, Zen."}]
|
||||
}'
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
hanzo chat completions \
|
||||
--model zen5 \
|
||||
--model zen6 \
|
||||
--messages '[{"role":"user","content":"Hello, Zen."}]'
|
||||
```
|
||||
|
||||
@@ -55,7 +55,7 @@ import { Hanzo } from '@hanzo/ai'
|
||||
const hanzo = new Hanzo({ secretKey: process.env.HANZO_API_KEY })
|
||||
|
||||
const completion = await hanzo.chat.completions.create({
|
||||
model: 'zen5',
|
||||
model: 'zen6',
|
||||
messages: [{ role: 'user', content: 'Hello, Zen.' }],
|
||||
})
|
||||
console.log(completion.choices[0].message.content)
|
||||
@@ -71,7 +71,7 @@ client = OpenAI(
|
||||
)
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="zen5",
|
||||
model="zen6",
|
||||
messages=[{"role": "user", "content": "Hello, Zen."}]
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
@@ -80,7 +80,7 @@ print(response.choices[0].message.content)
|
||||
`/v1/chat/completions` takes and returns the chat-completions JSON shape, which
|
||||
is why the Python tab is the `openai` client with its base URL moved: any client
|
||||
already written against that shape works here unchanged. Model ids are not
|
||||
portable across vendors, though — `zen5` and `enso` exist only here. [The
|
||||
portable across vendors, though — `zen6` and `enso` exist only here. [The
|
||||
SDKs](/docs/sdks) covers what each language ships and when to reach past the
|
||||
chat route into the rest of `/v1`.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ icon: Rocket
|
||||
One key authenticates every request. `sk-` keys resolve to a user and belong on a server; `pk-` keys resolve only to an organisation and are safe in a browser.
|
||||
|
||||
```bash
|
||||
export HANZO_API_KEY=sk-... # platform.hanzo.ai
|
||||
export HANZO_API_KEY=sk-... # console.hanzo.ai
|
||||
hanzo auth login # or sign in through Hanzo IAM
|
||||
```
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ from agno.agent import Agent
|
||||
from agno.models.openai.like import OpenAILike
|
||||
|
||||
model = OpenAILike(
|
||||
id="zen5",
|
||||
id="zen6",
|
||||
api_key="sk-...",
|
||||
base_url="https://api.hanzo.ai/v1",
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ from autogen_ext.models.openai import OpenAIChatCompletionClient
|
||||
from autogen_core.models import ModelFamily
|
||||
|
||||
client = OpenAIChatCompletionClient(
|
||||
model="zen5",
|
||||
model="zen6",
|
||||
base_url="https://api.hanzo.ai/v1",
|
||||
api_key="sk-...",
|
||||
model_info={
|
||||
|
||||
@@ -27,7 +27,7 @@ export class Researcher extends Agent {
|
||||
this.ctx.waitUntil(
|
||||
(async () => {
|
||||
const stream = await client.chat.completions.create({
|
||||
model: "zen5",
|
||||
model: "zen6",
|
||||
messages: [{ role: "user", content: await request.text() }],
|
||||
stream: true,
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ pip install crewai
|
||||
from crewai import LLM, Agent
|
||||
|
||||
llm = LLM(
|
||||
model="openai/zen5",
|
||||
model="openai/zen6",
|
||||
base_url="https://api.hanzo.ai/v1",
|
||||
api_key="sk-...",
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@ pip install dspy
|
||||
import dspy
|
||||
|
||||
lm = dspy.LM(
|
||||
"openai/zen5",
|
||||
"openai/zen6",
|
||||
api_base="https://api.hanzo.ai/v1",
|
||||
api_key="sk-...",
|
||||
model_type="chat",
|
||||
|
||||
@@ -14,7 +14,7 @@ from google.adk.agents import LlmAgent
|
||||
from google.adk.models.lite_llm import LiteLlm
|
||||
|
||||
model = LiteLlm(
|
||||
model="openai/zen5",
|
||||
model="openai/zen6",
|
||||
api_base="https://api.hanzo.ai/v1",
|
||||
api_key="sk-...",
|
||||
)
|
||||
|
||||
@@ -35,7 +35,7 @@ Each page below says which one its snippet lands on.
|
||||
curl -s https://api.hanzo.ai/v1/models | jq -r '.data[].id'
|
||||
```
|
||||
|
||||
Pass the `id` through verbatim as the framework's model name — `zen5`, `claude-sonnet-4-6`, `gpt-5.5`. Every record carries `id`, `owned_by` and `premium`; `pricing` and `context_window` are on nearly all of them; `supports_tools` and `supports_vision` on a handful. An absent field is undeclared, not false.
|
||||
Pass the `id` through verbatim as the framework's model name — `zen6`, `claude-sonnet-4-6`, `gpt-5.5`. Every record carries `id`, `owned_by` and `premium`; `pricing` and `context_window` are on nearly all of them; `supports_tools` and `supports_vision` on a handful. An absent field is undeclared, not false.
|
||||
|
||||
Some frameworks want those same facts restated in their own constructor — AutoGen's `model_info`, LlamaIndex's `is_chat_model` — and the page says so where it applies.
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ from langchain_openai import ChatOpenAI
|
||||
from langchain.agents import create_agent
|
||||
|
||||
model = ChatOpenAI(
|
||||
model="zen5",
|
||||
model="zen6",
|
||||
base_url="https://api.hanzo.ai/v1",
|
||||
api_key="sk-...",
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@ pip install llama-index-llms-openai-like
|
||||
from llama_index.llms.openai_like import OpenAILike
|
||||
|
||||
llm = OpenAILike(
|
||||
model="zen5",
|
||||
model="zen6",
|
||||
api_base="https://api.hanzo.ai/v1",
|
||||
api_key="sk-...",
|
||||
context_window=1000000,
|
||||
|
||||
@@ -17,7 +17,7 @@ export const agent = new Agent({
|
||||
name: "Researcher",
|
||||
instructions: "Answer precisely.",
|
||||
model: {
|
||||
id: "hanzo/zen5",
|
||||
id: "hanzo/zen6",
|
||||
url: "https://api.hanzo.ai/v1",
|
||||
apiKey: process.env.HANZO_API_KEY,
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@ from agents import Agent, Runner, AsyncOpenAI, OpenAIChatCompletionsModel, set_t
|
||||
set_tracing_disabled(disabled=True)
|
||||
|
||||
client = AsyncOpenAI(api_key="sk-...", base_url="https://api.hanzo.ai/v1")
|
||||
model = OpenAIChatCompletionsModel(model="zen5", openai_client=client)
|
||||
model = OpenAIChatCompletionsModel(model="zen6", openai_client=client)
|
||||
|
||||
agent = Agent(name="Assistant", instructions="Answer precisely.", model=model)
|
||||
result = Runner.run_sync(agent, "Hello")
|
||||
|
||||
@@ -15,7 +15,7 @@ from pydantic_ai.models.openai import OpenAIChatModel
|
||||
from pydantic_ai.providers.openai import OpenAIProvider
|
||||
|
||||
model = OpenAIChatModel(
|
||||
'zen5',
|
||||
'zen6',
|
||||
provider=OpenAIProvider(base_url='https://api.hanzo.ai/v1', api_key='sk-...'),
|
||||
)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ using Microsoft.SemanticKernel;
|
||||
|
||||
IKernelBuilder builder = Kernel.CreateBuilder();
|
||||
builder.AddOpenAIChatCompletion(
|
||||
modelId: "zen5",
|
||||
modelId: "zen6",
|
||||
apiKey: "sk-...",
|
||||
endpoint: new Uri("https://api.hanzo.ai/v1")
|
||||
);
|
||||
@@ -37,7 +37,7 @@ from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
|
||||
|
||||
kernel = Kernel()
|
||||
kernel.add_service(OpenAIChatCompletion(
|
||||
ai_model_id="zen5",
|
||||
ai_model_id="zen6",
|
||||
async_client=AsyncOpenAI(base_url="https://api.hanzo.ai/v1", api_key="sk-..."),
|
||||
))
|
||||
```
|
||||
|
||||
@@ -14,7 +14,7 @@ import os
|
||||
from smolagents import OpenAIModel, CodeAgent
|
||||
|
||||
model = OpenAIModel(
|
||||
model_id="zen5",
|
||||
model_id="zen6",
|
||||
api_base="https://api.hanzo.ai/v1",
|
||||
api_key=os.environ["HANZO_API_KEY"],
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ const hanzo = createOpenAICompatible({
|
||||
});
|
||||
|
||||
const { text } = await generateText({
|
||||
model: hanzo('zen5'),
|
||||
model: hanzo('zen6'),
|
||||
prompt: 'Name the three laws of thermodynamics.',
|
||||
});
|
||||
```
|
||||
|
||||
@@ -135,7 +135,7 @@ Hanzo. The call is the trace, and the second command is a read, not a write:
|
||||
curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"model":"zen5","messages":[{"role":"user","content":"how do I rotate a key?"}]}'
|
||||
-d '{"model":"zen6","messages":[{"role":"user","content":"how do I rotate a key?"}]}'
|
||||
|
||||
curl -sS "https://api.hanzo.ai/v1/o11y/llm/traces?limit=20" \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY"
|
||||
|
||||
@@ -39,7 +39,7 @@ curl -sS -X POST https://api.hanzo.ai/v1/account/keys \
|
||||
curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"model":"zen5","messages":[{"role":"user","content":"summarise Q3"}]}'
|
||||
-d '{"model":"zen6","messages":[{"role":"user","content":"summarise Q3"}]}'
|
||||
|
||||
# 3. Evaluator's benchmark mode, as an admission rather than a local run
|
||||
curl -sS -X POST https://api.hanzo.ai/v1/benchmark/runs \
|
||||
@@ -50,7 +50,7 @@ curl -sS -X POST https://api.hanzo.ai/v1/benchmark/runs \
|
||||
|
||||
Step 2 is the request your code already sends. NIM and the NVIDIA API are
|
||||
OpenAI-shaped, so the body is unchanged and the edit is the base URL, the key and
|
||||
the model name; `GET /v1/models` publishes the names, `zen5` among them. Step 3
|
||||
the model name; `GET /v1/models` publishes the names, `zen6` among them. Step 3
|
||||
answers 202 with a receipt, and the numbers appear on
|
||||
`GET /v1/benchmark/leaderboard` as the harness completes them — the same
|
||||
benchmarks `nel eval run --bench` would run on your machine, run for you.
|
||||
@@ -74,7 +74,7 @@ Five tables, one per NeMo concern.
|
||||
|
||||
| NeMo | Hanzo |
|
||||
|---|---|
|
||||
| Nemotron, called through `integrate.api.nvidia.com/v1` | `zen5`, `zen5-pro`, `zen5-coder`, `zen5-flash`, `zen5-mini` at `POST /v1/chat/completions` — 14 Zen models among the 432 that `GET /v1/models` lists |
|
||||
| Nemotron, called through `integrate.api.nvidia.com/v1` | `zen6` and `zen6-coder`, with the `zen5.8` and `zen5` lines beside them, at `POST /v1/chat/completions`; `GET /v1/models` lists every Zen id |
|
||||
| NIM container serving `/v1/chat/completions` on your GPU | The same address, served. No container to pull; the model is a name in the catalogue |
|
||||
| NIM embedding and reranker microservices | `POST /v1/embeddings` with `zen-embedding`, `POST /v1/rerank` with `zen-rerank` |
|
||||
| Nemotron content-safety model | `zen-guard`, a 128K-context safety classifier, called like any other model |
|
||||
@@ -177,7 +177,7 @@ curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
|
||||
curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"model":"zen5","messages":[{"role":"user","content":"summarise Q3"}]}'
|
||||
-d '{"model":"zen6","messages":[{"role":"user","content":"summarise Q3"}]}'
|
||||
|
||||
curl -sS "https://api.hanzo.ai/v1/o11y/llm/traces?limit=20" \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY"
|
||||
|
||||
@@ -30,7 +30,7 @@ curl -sS -X POST https://api.hanzo.ai/v1/account/keys \
|
||||
curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"model":"zen5","messages":[{"role":"user","content":"summarise Q3"}]}'
|
||||
-d '{"model":"zen6","messages":[{"role":"user","content":"summarise Q3"}]}'
|
||||
|
||||
# 3. the catalogue the model name in step 2 comes from
|
||||
curl -sS https://api.hanzo.ai/v1/models
|
||||
@@ -175,7 +175,7 @@ Plain inference is the base URL and nothing else:
|
||||
curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"model":"zen5","messages":[{"role":"user","content":"summarise Q3"}]}'
|
||||
-d '{"model":"zen6","messages":[{"role":"user","content":"summarise Q3"}]}'
|
||||
```
|
||||
|
||||
The run call answers the run — id, status, model, `output`, duration, error —
|
||||
|
||||
@@ -182,7 +182,7 @@ languages. See [Engineering Philosophy](/docs/architecture/philosophy) for the *
|
||||
- [SDKs](/docs/sdks) — Python, TypeScript, Go, Rust and more, all derived from one contract
|
||||
- [API reference](/docs/openapi) — every endpoint, generated from its spec
|
||||
- [ZAP protocol](/docs/zap) — Zero-Copy App Proto, the wire the Go and Rust halves speak
|
||||
- [Zen models](https://zenlm.org) — frontier open-weight models, 4B edge to 1T+ reasoning
|
||||
- [Zen models](https://zenlm.org) — open-weight models for agentic coding that runs locally and for marketing work
|
||||
- [Architecture](/docs/architecture) — one binary, one contract, and why
|
||||
|
||||
## Resources
|
||||
|
||||
@@ -11,7 +11,7 @@ ones you can download, and which ids the gateway serves right now.**
|
||||
|
||||
| Family | Role | Weights | Reach it at | Status |
|
||||
|---|---|---|---|---|
|
||||
| **[Zen](/docs/models/zen)** | generates: reasoning, code, language, vision, speech, embeddings | open, on [Hugging Face](https://huggingface.co/zenlm) | `zen*` ids on `/v1/chat/completions` | shipped |
|
||||
| **[Zen](/docs/models/zen)** | generates: agentic coding that runs locally, marketing copy and assets; also vision, speech, embeddings | open, on [Hugging Face](https://huggingface.co/zenlm) | `zen*` ids on `/v1/chat/completions` | shipped |
|
||||
| **[Enso](/docs/models/enso)** | routes and orchestrates: picks the model, context and tools per request | router code open ([hanzoai/engine](https://github.com/hanzoai/engine)); family SKUs hosted | `model: "auto"` and `enso-*` ids | shipped |
|
||||
| **[Kai](/docs/models/kai)** | decides: typed, calibrated answers to bounded questions | hosted, not published; the baseline it starts from is open ([hanzoai/kai-1-multilingual](https://huggingface.co/hanzoai/kai-1-multilingual)) | `model: "kai"` on [`POST /v1/decisions`](/docs/decisions) | live: stage a7, $0.021 per million input tokens |
|
||||
| **Policy** | governs: deterministic allow / ask / deny | — | your rules, in every Decision Program | a part of Hanzo Decision, not a model |
|
||||
@@ -27,8 +27,8 @@ action, and a model can make a verdict stricter, never looser.
|
||||
|
||||
| Name | What it is | Status |
|
||||
|---|---|---|
|
||||
| **Zen7** | the next Zen generation; succeeds Satori | upcoming — no release, no weights |
|
||||
| **Satori** | a video-generation line, never trained | retiring; replaced by Zen7 |
|
||||
| **Zen 7** | the next Zen generation; succeeds Satori | research preview — no weights, no id to call · [Request access](https://hanzo.ai/research-access) |
|
||||
| **Satori** | a video-generation line, never trained | retiring; replaced by Zen 7 |
|
||||
| **Jin** | a multimodal model specified in [HIP-0003](https://hips.hanzo.ai/docs/hip-0003-jin-multimodal-ai-architecture) | not built; no weights |
|
||||
| **Enso Diffusion** | a sparse mixture-of-experts diffusion transformer, forked from DiT-MoE: [zenlm/enso](https://github.com/zenlm/enso) | research code, no released weights |
|
||||
| **Enso Browser** | a Firefox-based desktop browser | not released |
|
||||
@@ -74,7 +74,7 @@ covers what happens when the balance runs out.
|
||||
|---|---|---|
|
||||
| [HIP-0511](https://hips.hanzo.ai/docs/hip-0511-model-families) | Model families: every line, its HIP, its API and where it runs | Living |
|
||||
| [HIP-0039](https://hips.hanzo.ai/docs/hip-0039-zen-model-architecture) | Zen model architecture | Final |
|
||||
| [HIP-0904](https://hips.hanzo.ai/docs/hip-0904-zen6) | Zen6: dense, coder and ternary checkpoints | Final |
|
||||
| [HIP-0904](https://hips.hanzo.ai/docs/hip-0904-zen6) | The `zenlm/zen6*` repositories on Hugging Face: what each holds | Final |
|
||||
| [HIP-0510](https://hips.hanzo.ai/docs/hip-0510-enso-learned-router) | Enso: learned per-request routing | Final |
|
||||
| [HIP-1332](https://hips.hanzo.ai/docs/hip-1332-kai-the-decision-model) | Kai: the decision model and the decision plane | Draft |
|
||||
| [HIP-0003](https://hips.hanzo.ai/docs/hip-0003-jin-multimodal-ai-architecture) | Jin: a multimodal model that was not built | Draft |
|
||||
|
||||
@@ -1,15 +1,30 @@
|
||||
---
|
||||
title: Zen
|
||||
description: "Zen generates: open-weight models for reasoning, code, vision, speech, embeddings and safety. Download them, or call them hosted."
|
||||
description: "Zen is the open-weight model family from Zoo Labs Foundation, for two jobs: agentic coding that runs on your own machine, and marketing work — campaign copy in your brand's voice and the images and speech that go with it."
|
||||
icon: Sparkle
|
||||
---
|
||||
|
||||
**After this page you can call a Zen model on the API, find its weights, and
|
||||
know which generation is current.**
|
||||
**After this page you know which Zen model does which job, how to call it,
|
||||
where its weights are, and which generation is current.**
|
||||
|
||||
Zen is the generative family: open questions — reason, write, code, explain —
|
||||
answered in text, images or audio. Weights are published under
|
||||
[huggingface.co/zenlm](https://huggingface.co/zenlm); each model card states its
|
||||
Zen is the open-weight generative family of Zen LM, from [Zoo Labs Foundation](https://zoo.ngo), a
|
||||
501(c)(3) non-profit, and served first-party on `api.hanzo.ai`. It is chosen for two jobs.
|
||||
|
||||
**Agentic coding that runs locally.** `zen6-coder` is a mixture of 512 experts
|
||||
that sends each token through 10 of them, reads 262,144 tokens natively, and
|
||||
takes tool definitions in its chat template, so it can drive a coding loop over
|
||||
a whole repository on your own machine. A multi-token-prediction drafter ships
|
||||
beside it for faster decoding. The weights are GGUF for llama.cpp, 97.8 GB with
|
||||
the drafter; the model card reports prefill on an AMD Strix Halo machine with
|
||||
128 GB of unified memory. Hosted, the same id takes a 1,000,000-token context.
|
||||
|
||||
**Marketing work.** [`POST /v1/content/generate`](/docs/openapi/content/post-content-generate) drafts
|
||||
campaigns and social posts from a brief, with the brand-voice guidance you pass
|
||||
and the Zen model you name, and files each one in the CMS as a draft. `zen-vl`
|
||||
reads images, documents and charts. The Zen 3 weights make the images
|
||||
(`zen3-image`) and speech (`zen3-tts`) that go with the copy.
|
||||
|
||||
Weights are published under [huggingface.co/zenlm](https://huggingface.co/zenlm); each model card states its
|
||||
license, base and serving instructions. The same ids answer hosted on
|
||||
`api.hanzo.ai`.
|
||||
|
||||
@@ -17,17 +32,31 @@ license, base and serving instructions. The same ids answer hosted on
|
||||
|
||||
| Generation | Models | Where | Status |
|
||||
|---|---|---|---|
|
||||
| **Zen7** | — | — | upcoming; replaces Satori, which is retiring |
|
||||
| **Zen6** | [`zen6`](https://huggingface.co/zenlm/zen6) — 27B dense, NVFP4, 1M-token context (YaRN) · [`zen6-coder`](https://huggingface.co/zenlm/zen6-coder) — mixture-of-experts for agentic coding · [`zen6-flash`](https://huggingface.co/zenlm/zen6-flash) — 27B ternary vision-language model for one GPU or a laptop | weights on Hugging Face; `zen6` and `zen6-coder` hosted | shipped |
|
||||
| **Zen5** | `zen5`, `zen5-coder`, `zen5-pro`, `zen5-flash`, `zen5-mini`, `zen5.8`, `zen5.8-coder` | hosted; GGUF builds on Hugging Face (`zen5-gguf`, `zen5-coder-gguf`, …) | shipped |
|
||||
| **Zen3** | speech (`zen3-asr`, `zen3-tts`), image (`zen3-image`), `zen3-vl`, `zen3-omni`, `zen3-nano`, `zen3-guard` | weights on Hugging Face | shipped |
|
||||
| **Zen 7** | — | no weights; no id to call | research preview · [Request access](https://hanzo.ai/research-access) · succeeds Satori |
|
||||
| **Zen 6** | `zen6`, `zen6-coder` — the new Zen architecture | hosted; weights at [`zenlm/zen6-coder`](https://huggingface.co/zenlm/zen6-coder) | available now |
|
||||
| **Zen 5.8** | `zen5.8`, `zen5.8-coder`, `zen5.8-evo`, `zen5.8-spark` | hosted | previous generation |
|
||||
| **Zen 5** | `zen5`, `zen5-coder`, `zen5-flash`, `zen5-mini`, `zen5-pro`, `zen5-evo`, `zen5-spark` | hosted; GGUF builds on Hugging Face (`zen5-gguf`, `zen5-coder-gguf`, …) | earlier |
|
||||
| **Zen 3** | speech (`zen3-asr`, `zen3-tts`), image (`zen3-image`), `zen3-vl`, `zen3-omni`, `zen3-nano`, `zen3-guard` | weights on Hugging Face | shipped |
|
||||
|
||||
Task lines sit beside the generations: `zen-embedding` and `zen-reranker`
|
||||
(0.6B, 4B, 8B) for retrieval, `zen-guard` for safety, `zen-vl`
|
||||
for vision. [`zen-router`](https://huggingface.co/zenlm/zen-router) is a
|
||||
for vision. `zen-free` and `hanzo/zen` answer on the gateway too.
|
||||
[`zen-router`](https://huggingface.co/zenlm/zen-router) is a
|
||||
classifier, not a generator; the gateway also accepts its name as an alias for
|
||||
[`auto`](/docs/models/enso).
|
||||
|
||||
## Zen 6 weights
|
||||
|
||||
| | [`zenlm/zen6-coder`](https://huggingface.co/zenlm/zen6-coder) |
|
||||
|---|---|
|
||||
| Format | GGUF, IQ4_XS in three files, with a multi-token-prediction drafter |
|
||||
| Size | 97.8 GB with the drafter |
|
||||
| Experts | 512, 10 active per token |
|
||||
| Layers | 48 |
|
||||
| Context | 262,144 tokens |
|
||||
| Tools | tool definitions in the chat template |
|
||||
| Architecture | <span data-upstream>`qwen4exp`</span> (GGUF `general.architecture`) |
|
||||
|
||||
## Call one
|
||||
|
||||
```bash
|
||||
@@ -54,12 +83,16 @@ that command disagree, believe the command.
|
||||
## Run one yourself
|
||||
|
||||
```bash
|
||||
hf download zenlm/zen6 --local-dir zen6
|
||||
hf download zenlm/zen6-coder --local-dir zen6-coder
|
||||
```
|
||||
|
||||
Each card carries the serving command its model was built for: an SGLang launch
|
||||
for `zen6`, llama.cpp for `zen6-coder`, `zen6-flash` and the GGUF builds. A server that speaks
|
||||
`/v1/chat/completions` takes the same request as above with its own base URL.
|
||||
Each card carries the serving command its model was built for: llama.cpp for
|
||||
`zen6-coder` and the GGUF builds. A server that speaks `/v1/chat/completions`
|
||||
takes the same request as above with its own base URL.
|
||||
|
||||
Two more repositories carry the Zen 6 name, [`zenlm/zen6`](https://huggingface.co/zenlm/zen6)
|
||||
and [`zenlm/zen6-flash`](https://huggingface.co/zenlm/zen6-flash); each card
|
||||
says what it holds.
|
||||
|
||||
## Where Zen sits
|
||||
|
||||
@@ -69,4 +102,21 @@ questions a typed answer settles — that is [Kai](/docs/models/kai). An agent
|
||||
built on all three spends generative compute only where generation is the work.
|
||||
|
||||
Specifications: [HIP-0039](https://hips.hanzo.ai/docs/hip-0039-zen-model-architecture) for the
|
||||
family, [HIP-0904](https://hips.hanzo.ai/docs/hip-0904-zen6) for Zen6.
|
||||
family; [HIP-0904](https://hips.hanzo.ai/docs/hip-0904-zen6) records what each `zenlm/zen6*`
|
||||
repository on Hugging Face holds.
|
||||
|
||||
<section data-upstream>
|
||||
|
||||
## License & attribution
|
||||
|
||||
Each repository's own license governs its files; the model card names it.
|
||||
|
||||
- `zenlm/zen6-coder`: `qwen-community-1.0`, as its card declares. Built with
|
||||
Qwen3.8-Flash-Next by the Qwen team (`Qwen/Qwen3.8-Flash-Next`); GGUF
|
||||
quantization by Unsloth (`unsloth/Qwen3.8-Flash-Next-GGUF`).
|
||||
- `zenlm/zen6`: Apache-2.0. Base models, as its card declares:
|
||||
`RadixArk/Qwen3.8-27B-NVFP4` and `incoai/Qwen3.8-27B-DFlash2`.
|
||||
- `zenlm/zen6-flash`: Apache-2.0. Base models, as its card declares:
|
||||
`prism-ml/Ternary-Bonsai-2-27B-gguf` and `ProCreations/Ternary-Bonsai-2-27B-DFlash2`.
|
||||
|
||||
</section>
|
||||
|
||||
@@ -43,7 +43,7 @@ number that changes every run. PoAI removes the non-determinism:
|
||||
### Roadmap
|
||||
|
||||
- **Production-size models.** The precompile runs a small reference model today;
|
||||
a Qwen3-0.6B / zen-nano port is in progress. The model line is small,
|
||||
a zen-nano port is in progress. The model line is small,
|
||||
fully-verifiable models plus sampled verification of large ones.
|
||||
- **Cryptographic proofs.** zkML proofs and TEE confidential execution are
|
||||
designed and stubbed for a later release. Today's guarantee is determinism you
|
||||
|
||||
@@ -102,7 +102,7 @@ await ast.recordInteraction({
|
||||
role: 'assistant',
|
||||
content: 'Quantum computing uses quantum bits (qubits) that can be 0, 1, or both at the same time...',
|
||||
},
|
||||
model: 'zen5-coder-32b-instruct',
|
||||
model: 'zen6',
|
||||
tokens: { input: 42, output: 156 },
|
||||
latencyMs: 1240,
|
||||
},
|
||||
@@ -224,7 +224,7 @@ app.post('/v1/chat', async (req, res) => {
|
||||
const { messages } = req.body;
|
||||
|
||||
const completion = await llm.chat.completions.create({
|
||||
model: 'zen5-coder-32b-instruct',
|
||||
model: 'zen6',
|
||||
messages,
|
||||
});
|
||||
|
||||
@@ -284,7 +284,7 @@ AST stores all records in a normalized JSON format compatible with common fine-t
|
||||
},
|
||||
"output": {
|
||||
"message": {"role": "assistant", "content": "..."},
|
||||
"model": "zen5-coder-32b-instruct",
|
||||
"model": "zen6",
|
||||
"tokens": {"input": 42, "output": 156},
|
||||
"latency_ms": 1240
|
||||
},
|
||||
|
||||
@@ -140,7 +140,7 @@ import { Hanzo } from '@hanzo/ai'
|
||||
const hanzo = new Hanzo({ secretKey: process.env.HANZO_API_KEY })
|
||||
|
||||
const answer = await hanzo.chat.completions.create({
|
||||
model: 'zen5',
|
||||
model: 'zen6',
|
||||
messages: [{ role: 'user', content: 'Explain quantum computing' }],
|
||||
})
|
||||
```
|
||||
|
||||
@@ -69,7 +69,7 @@ client = OpenAI(
|
||||
)
|
||||
|
||||
answer = client.chat.completions.create(
|
||||
model="zen5",
|
||||
model="zen6",
|
||||
messages=[{"role": "user", "content": "Explain quantum computing"}],
|
||||
)
|
||||
print(answer.choices[0].message.content)
|
||||
|
||||
@@ -40,7 +40,7 @@ import { Hanzo } from '@hanzo/ai'
|
||||
const hanzo = new Hanzo({ secretKey: process.env.HANZO_API_KEY })
|
||||
|
||||
const answer = await hanzo.chat.completions.create({
|
||||
model: 'zen5',
|
||||
model: 'zen6',
|
||||
messages: [{ role: 'user', content: 'Explain quantum computing' }],
|
||||
})
|
||||
|
||||
@@ -63,7 +63,7 @@ chunks:
|
||||
|
||||
```typescript
|
||||
const stream = await hanzo.chat.completions.create({
|
||||
model: 'zen5-coder',
|
||||
model: 'zen6',
|
||||
messages: [{ role: 'user', content: 'Write a haiku about AI' }],
|
||||
stream: true,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import type { Nodes, Root } from 'mdast';
|
||||
import { remark } from 'remark';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import remarkMdx from 'remark-mdx';
|
||||
import YAML from 'yaml';
|
||||
|
||||
// Zen is told in Zen's names.
|
||||
//
|
||||
// A Zen page reads as Zen from its title to its last table. The upstream models
|
||||
// some Zen weights are built from are named in two places only, and both carry
|
||||
// `data-upstream` so this check can step over them:
|
||||
//
|
||||
// Architecture the loader string from the weights' own config.json or
|
||||
// GGUF header, which a developer passes verbatim
|
||||
// License & attribution the fine print at the bottom of the page
|
||||
//
|
||||
// Everything else a reader meets is read here: the title and description (the
|
||||
// page's meta and OG tags), headings, prose, tables, code, image alt text and
|
||||
// the string props of components. A name from zen.upstream in any of it fails
|
||||
// the build. The list lives in that one file.
|
||||
|
||||
const APP = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const MODELS = path.join(APP, 'content/docs/models');
|
||||
export const NAMES = path.join(APP, 'zen.upstream');
|
||||
|
||||
/** The Zen pages: the families overview, which carries Zen's generations, and every zen page. */
|
||||
export const isZen = (rel: string) => rel === 'index.mdx' || rel.startsWith('zen');
|
||||
|
||||
/** The names in zen.upstream: one per line, `#` comments and blank lines ignored. */
|
||||
export function loadNames(file = NAMES): string[] {
|
||||
const names = fs
|
||||
.readFileSync(file, 'utf8')
|
||||
.split('\n')
|
||||
.map((l) => l.replace(/#.*$/, '').trim())
|
||||
.filter(Boolean);
|
||||
if (!names.length) throw new Error(`${file} names nothing, so the check would pass anything`);
|
||||
return names;
|
||||
}
|
||||
|
||||
/** Any of `names` as a whole word, in any case: no letter directly before or after it. */
|
||||
export function matcher(names: string[]): RegExp {
|
||||
const alt = names.map((n) => n.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
|
||||
return new RegExp(`(?<![a-z])(?:${alt})(?![a-z])`, 'gi');
|
||||
}
|
||||
|
||||
type Jsx = Extract<Nodes, { type: 'mdxJsxFlowElement' | 'mdxJsxTextElement' }>;
|
||||
|
||||
const isJsx = (n: Nodes): n is Jsx =>
|
||||
n.type === 'mdxJsxFlowElement' || n.type === 'mdxJsxTextElement';
|
||||
|
||||
/** Every string of an MDX page a reader reads, leaving out `data-upstream` elements. */
|
||||
export function readThrough(src: string): string[] {
|
||||
const out: string[] = [];
|
||||
let body = src;
|
||||
const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n/.exec(src);
|
||||
if (fm) {
|
||||
const meta = (YAML.parse(fm[1]) ?? {}) as Record<string, unknown>;
|
||||
for (const key of ['title', 'description']) {
|
||||
if (typeof meta[key] === 'string') out.push(meta[key]);
|
||||
}
|
||||
body = src.slice(fm[0].length);
|
||||
}
|
||||
const visit = (node: Nodes) => {
|
||||
if (isJsx(node)) {
|
||||
if (node.attributes.some((a) => a.type === 'mdxJsxAttribute' && a.name === 'data-upstream'))
|
||||
return;
|
||||
for (const a of node.attributes) {
|
||||
if (a.type === 'mdxJsxAttribute' && typeof a.value === 'string') out.push(a.value);
|
||||
}
|
||||
}
|
||||
// Imports, exports and `{/* comments */}` are the page's source, never rendered.
|
||||
const unread =
|
||||
node.type === 'mdxjsEsm' ||
|
||||
((node.type === 'mdxFlowExpression' || node.type === 'mdxTextExpression') &&
|
||||
/^\s*\/\*[\s\S]*\*\/\s*$/.test(node.value));
|
||||
if ('value' in node && typeof node.value === 'string' && !unread) out.push(node.value);
|
||||
if ('alt' in node && node.alt) out.push(node.alt);
|
||||
if ('title' in node && node.title) out.push(node.title);
|
||||
if ('children' in node) for (const child of node.children) visit(child as Nodes);
|
||||
};
|
||||
visit(remark().use(remarkMdx).use(remarkGfm).parse(body) as Root);
|
||||
return out;
|
||||
}
|
||||
|
||||
export interface ZenCheck {
|
||||
/** The Zen pages read, relative to content/docs/models. */
|
||||
pages: string[];
|
||||
/** Page, the name found, and the text it was found in. */
|
||||
found: Array<[string, string, string]>;
|
||||
}
|
||||
|
||||
export function checkZen(): ZenCheck {
|
||||
const re = matcher(loadNames());
|
||||
const pages = fs
|
||||
.readdirSync(MODELS, { recursive: true, encoding: 'utf8' })
|
||||
.filter((rel) => rel.endsWith('.mdx') && isZen(rel))
|
||||
.sort();
|
||||
// A check over no pages passes everything: the section moved, not the story.
|
||||
if (!pages.length) throw new Error(`no Zen pages under ${MODELS}`);
|
||||
const found: ZenCheck['found'] = [];
|
||||
for (const rel of pages) {
|
||||
for (const text of readThrough(fs.readFileSync(path.join(MODELS, rel), 'utf8'))) {
|
||||
for (const m of text.matchAll(re)) {
|
||||
const at = m.index ?? 0;
|
||||
found.push([
|
||||
rel,
|
||||
m[0],
|
||||
text.slice(Math.max(0, at - 40), at + m[0].length + 40).replace(/\s+/g, ' '),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return { pages, found };
|
||||
}
|
||||
|
||||
/** Report every upstream name a Zen page says outside `data-upstream`. */
|
||||
export function report(found: ZenCheck['found']): void {
|
||||
for (const [page, name, text] of found)
|
||||
console.error(` models/${page}: "${name}" in …${text}…`);
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
const { pages, found } = checkZen();
|
||||
if (found.length) {
|
||||
console.error(`[zen] FAIL — ${found.length} upstream name(s) outside data-upstream:`);
|
||||
report(found);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(
|
||||
`[zen] ${pages.length} Zen pages read; no name from zen.upstream outside data-upstream`,
|
||||
);
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { checkCapabilities, report as reportCapabilities } from './check-capabil
|
||||
import { checkRoutes, report as reportRoutes } from './check-routes';
|
||||
import { checkEndpoints, report } from './check-endpoints';
|
||||
import { checkKeys, report as reportKeys } from './check-keys';
|
||||
import { checkZen, report as reportZen } from './check-zen';
|
||||
|
||||
async function main() {
|
||||
// The document first, then its projections: the reference (one page per
|
||||
@@ -129,6 +130,16 @@ async function main() {
|
||||
`[keys] ${keys.checked} credential literals checked against ` +
|
||||
keys.keys.map((k) => k.prefix).join(' / '),
|
||||
);
|
||||
|
||||
// A Zen page tells Zen's story in Zen's names: an upstream model's name may
|
||||
// stand only in a `data-upstream` element — the Architecture value and the
|
||||
// License & attribution section. zen.upstream holds the names.
|
||||
const zen = checkZen();
|
||||
if (zen.found.length) {
|
||||
reportZen(zen.found);
|
||||
throw new Error(`${zen.found.length} upstream model name(s) in the read-through of a Zen page`);
|
||||
}
|
||||
console.log(`[zen] ${zen.pages.length} Zen pages read, no upstream name outside data-upstream`);
|
||||
}
|
||||
|
||||
await main().catch((e) => {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# The upstream names a Zen page does not tell Zen's story with. Read by
|
||||
# scripts/check-zen.ts, which runs in pre-build and fails the build on a hit.
|
||||
#
|
||||
# One name per line; `#` starts a comment. Case is ignored and a name matches as
|
||||
# a whole word — no letter directly before or after it — so `Qwen` also catches
|
||||
# Qwen3, Qwen3.5, qwen4exp and Qwen3_5ForConditionalGeneration.
|
||||
#
|
||||
# A Zen page says these names in two places only, and marks both `data-upstream`:
|
||||
# the Architecture value (the loader string from the weights' own config, which a
|
||||
# developer has to pass verbatim) and the License & attribution section at the
|
||||
# bottom. Everything else on the page — title, description, headings, prose,
|
||||
# tables, code, alt text — says Zen.
|
||||
#
|
||||
# The list starts from the base models the zenlm cards on Hugging Face declare
|
||||
# (`base_model`), by the name a reader would meet them under. A new one goes
|
||||
# here, and nowhere else.
|
||||
Qwen
|
||||
QwenLM
|
||||
Flash-Next
|
||||
Nemotron
|
||||
Bonsai
|
||||
DeepSeek
|
||||
MiniMax
|
||||
FLUX
|
||||
Wan
|
||||
TRELLIS
|
||||
YuE
|
||||
Granite
|
||||
SSD-1B
|
||||
Reference in New Issue
Block a user