mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
The sign-in callback, initiate and logout pages, authz, auto, the
connectors page, base, the blog index and its three posts, and the Go
module page wrap their copy: server pages with <T>, client pages with
t(), and copy held in data with phrase(). Figures in the posts' prose
are values; product names, code and IAM's own codes stay as written.
Models says its two sentences whole ("{n}+ models", "every model on
the gateway"); the noun prop no caller passed is gone.
226 lines
10 KiB
TypeScript
226 lines
10 KiB
TypeScript
import type { Metadata } from 'next'
|
|
import Link from 'next/link'
|
|
import { ArrowLeft, Calendar, Clock } from 'lucide-react'
|
|
import { phrase } from '@hanzo/i18n'
|
|
import { T } from '@hanzo/i18n/react'
|
|
import { Text, XStack, YStack } from '@/components/ui'
|
|
import { Band, Card } from '@/components/marketing/band'
|
|
import { Action, Chip, Display, Lede, Title } from '@hanzo/ui/marketing'
|
|
import { Grid } from '@hanzo/ui/grid'
|
|
import { Code } from '@/components/code'
|
|
import { DOCS } from '@/components/home/nav-data'
|
|
|
|
/**
|
|
* Kai 1: what a decision model is and how to call it. Every figure is the
|
|
* public cookbook's (hanzoai/kai) or production's read of 2026-10-10; the code
|
|
* is the cookbook's SDK calls. Results live on /kai, derived from the runs.
|
|
*/
|
|
|
|
const TYPESCRIPT = `import { AiApi, Configuration } from 'hanzoai'
|
|
|
|
const ai = new AiApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }))
|
|
const { data: decision } = await ai.postDecisions({
|
|
aiDecisionsRequest: {
|
|
model: 'kai',
|
|
state: { tool_call: 'bash.exec', command: 'pytest -v tests/test_agent.py' },
|
|
questions: {
|
|
next: {
|
|
type: 'choice',
|
|
instructions: 'What should the agent do with this command?',
|
|
criteria: { approve: 'safe to run', reject: 'unsafe', clarify: 'needs the user first' },
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
console.log(decision.answers.next.choice, decision.answers.next.probabilities)`
|
|
|
|
const PYTHON = `import os
|
|
|
|
from hanzoai.cloud import ApiClient, Configuration
|
|
from hanzoai.cloud.api import AiApi
|
|
from hanzoai.cloud.models.ai_decisions_request import AiDecisionsRequest
|
|
|
|
ai = AiApi(ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"])))
|
|
decision = ai.post_decisions(AiDecisionsRequest.from_dict({
|
|
"model": "kai",
|
|
"state": {"tool_call": "bash.exec", "command": "pytest -v tests/test_agent.py"},
|
|
"questions": {
|
|
"next": {
|
|
"type": "choice",
|
|
"instructions": "What should the agent do with this command?",
|
|
"criteria": {"approve": "safe to run", "reject": "unsafe", "clarify": "needs the user first"},
|
|
},
|
|
},
|
|
}))
|
|
|
|
print(decision.answers["next"].choice, decision.answers["next"].probabilities)`
|
|
|
|
/** Four facts, each measured: production's read and the cookbook's. The note's figures are its values. */
|
|
const FACTS: readonly [string, string, string, Record<string, string>?][] = [
|
|
[phrase('Decision Latency'), '<1 ms', phrase('p50 (one question, GPU bf16)')],
|
|
[phrase('Output'), '0 tokens', phrase('Kai writes no text; output is not billed')],
|
|
[phrase('Price'), '$0.021', phrase('Per million input tokens; Jev costs {price}'), { price: '$0.042' }],
|
|
[phrase('Context Window'), '32,768', phrase('Native reach across text, code, and multimodal state')],
|
|
]
|
|
|
|
const TITLE = 'Kai 1: Decisions, Not Completions — Hanzo AI'
|
|
const DESCRIPTION = 'Kai answers typed questions with a probability for each answer and writes no text. What it is, how to call it, and its limits.'
|
|
|
|
export const metadata: Metadata = {
|
|
title: TITLE,
|
|
description: DESCRIPTION,
|
|
alternates: { canonical: 'https://hanzo.ai/blog/kai-decision-models' },
|
|
openGraph: { title: TITLE, description: DESCRIPTION, url: 'https://hanzo.ai/blog/kai-decision-models', siteName: 'Hanzo AI', type: 'article' },
|
|
twitter: { card: 'summary_large_image', title: TITLE, description: DESCRIPTION },
|
|
}
|
|
|
|
const BODY = { fontSize: '$3', color: 'var(--text-secondary)', '$platform-web': { lineHeight: '1.8em' } } as const
|
|
|
|
export default function KaiDecisionModelsPage() {
|
|
return (
|
|
<YStack minH="100vh" bg="var(--background)">
|
|
<Band rule={false} pad="$14" measure={860}>
|
|
<YStack gap={24}>
|
|
<XStack render={<Link href="/blog" />} items="center" gap={6}>
|
|
<ArrowLeft size={14} color="var(--muted-foreground)" data-i18n-mirror />
|
|
<Text fontSize="$1" color="var(--muted-foreground)">
|
|
<T>Back to Blog</T>
|
|
</Text>
|
|
</XStack>
|
|
|
|
<XStack items="center" justify="space-between" flexWrap="wrap" gap={12}>
|
|
<Chip px={10} py={3} fontSize="$1" fontFamily="$mono" color="var(--foreground)" borderWidth={0} bg="var(--glass-strong)">
|
|
KAI 1
|
|
</Chip>
|
|
<XStack items="center" gap={16}>
|
|
<XStack items="center" gap={6}>
|
|
<Calendar size={13} color="var(--muted-foreground)" />
|
|
<Text fontSize="$1" color="var(--muted-foreground)">
|
|
September 28, 2026
|
|
</Text>
|
|
</XStack>
|
|
<XStack items="center" gap={6}>
|
|
<Clock size={13} color="var(--muted-foreground)" />
|
|
<Text fontSize="$1" color="var(--muted-foreground)">
|
|
<T values={{ n: 3 }}>{'{n} min read'}</T>
|
|
</Text>
|
|
</XStack>
|
|
</XStack>
|
|
</XStack>
|
|
|
|
<Display mb={0} text="left">
|
|
<T>Kai 1: Decisions, Not Completions</T>
|
|
</Display>
|
|
|
|
<Lede mb={0} text="left">
|
|
<T>{"Kai is Hanzo's decision model. Give it a state and a question whose answers you list, and it returns a probability for each answer. It writes no text."}</T>
|
|
</Lede>
|
|
</YStack>
|
|
</Band>
|
|
|
|
<Band rule={true} pad="$10" measure={860}>
|
|
<Grid columns={{ min: 200, max: 4 }} gap={16}>
|
|
{FACTS.map(([label, figure, note, values]) => (
|
|
<Card key={label} p={20} bg="$panel" borderWidth={0} rounded="var(--radius-xl)">
|
|
<YStack gap={6}>
|
|
<Text fontSize="$1" fontFamily="$mono" color="var(--muted-foreground)">
|
|
<T>{label}</T>
|
|
</Text>
|
|
<Text fontSize="$6" fontWeight="600" color="var(--foreground)">
|
|
{figure}
|
|
</Text>
|
|
<Text fontSize="$1" color="var(--muted-foreground)">
|
|
<T values={values}>{note}</T>
|
|
</Text>
|
|
</YStack>
|
|
</Card>
|
|
))}
|
|
</Grid>
|
|
</Band>
|
|
|
|
<Band rule={true} pad="$12" measure={860}>
|
|
<YStack gap={40}>
|
|
<YStack gap={16}>
|
|
<Title quiet={false}><T>Why not generate the decision</T></Title>
|
|
<Text {...BODY}>
|
|
<T>{'An agent spends many of its steps on choices: which tool, whether a test passed, whether to stop. Asking a language model to write that choice as JSON means parsing what it wrote, retrying when it does not parse, and guessing how sure it was.'}</T>
|
|
</Text>
|
|
<Text {...BODY}>
|
|
<T
|
|
values={{
|
|
choice: <Text fontFamily="$mono">choice</Text>,
|
|
score: <Text fontFamily="$mono">score</Text>,
|
|
noul: <Text fontFamily="$mono">noul</Text>,
|
|
}}
|
|
>
|
|
{'Kai answers in the shape of the question. A {choice} gets a probability for every option, a {score} a distribution over its levels, a {noul} the probability that it holds. Nothing is generated, so nothing is parsed.'}
|
|
</T>
|
|
</Text>
|
|
</YStack>
|
|
|
|
<YStack gap={16}>
|
|
<Title quiet={false}><T>One call</T></Title>
|
|
<Text {...BODY}>
|
|
<T
|
|
values={{
|
|
endpoint: <Text fontFamily="$mono">POST https://api.hanzo.ai/v1/decisions</Text>,
|
|
sdk: <Text fontFamily="$mono">hanzoai</Text>,
|
|
kai: <Text fontFamily="$mono">kai</Text>,
|
|
auto: <Text fontFamily="$mono">"auto"</Text>,
|
|
fast: <Text fontFamily="$mono">"fast"</Text>,
|
|
deep: <Text fontFamily="$mono">"deep"</Text>,
|
|
pin15: <Text fontFamily="$mono">kai-1.5</Text>,
|
|
pin14: <Text fontFamily="$mono">kai-1.4</Text>,
|
|
pin13: <Text fontFamily="$mono">kai-1.3</Text>,
|
|
}}
|
|
>
|
|
{'{endpoint}, from the {sdk} SDKs or over HTTP. The model id {kai} answers as the unified decision model with adaptive reasoning ({auto}, {fast}, {deep}; Kai-1.7 target). Version pins {pin15}, {pin14}, and {pin13} provide deterministic reproducibility across text, code, and long-context evidence.'}
|
|
</T>
|
|
</Text>
|
|
<Card p="$4" bg="$panel">
|
|
<Code lang="typescript" code={TYPESCRIPT} />
|
|
</Card>
|
|
<Card p="$4" bg="$panel">
|
|
<Code lang="python" code={PYTHON} />
|
|
</Card>
|
|
</YStack>
|
|
|
|
<YStack gap={16}>
|
|
<Title quiet={false}><T>Limits</T></Title>
|
|
<Text {...BODY}>
|
|
<T
|
|
values={{
|
|
trained: '1,024',
|
|
reach: '32,768',
|
|
flag: <Text fontFamily="$mono">routing.extrapolated</Text>,
|
|
pin: <Text fontFamily="$mono">kai-1.4</Text>,
|
|
}}
|
|
>
|
|
{'kai-1.3, the default, was trained on {trained} tokens of state beside each question. It reads up to {reach} and marks a longer read {flag}; past {trained} its answers are unreliable. Keep the state to what decides the question, or ask for {pin}, which was trained on long states and marks no read up to {reach} extrapolated.'}
|
|
</T>
|
|
</Text>
|
|
</YStack>
|
|
|
|
<Card p={36} bg="$panel" borderWidth={1} borderColor="var(--border)" rounded="var(--radius-2xl)" mt={24}>
|
|
<YStack items="center" gap={16} $platform-web={{ textAlign: 'center' }}>
|
|
<Text fontSize="$5" fontWeight="600" color="var(--foreground)">
|
|
<T>Results, request shapes and limits</T>
|
|
</Text>
|
|
<XStack items="center" justify="center" gap={12} flexWrap="wrap" mt={8}>
|
|
<Action href="/kai/guide" fill>
|
|
<T>How to use Kai</T>
|
|
</Action>
|
|
<Action href="/kai#benchmarks"><T>Kai against Jev</T></Action>
|
|
<Action href={`${DOCS}/docs/decisions`} target="_blank" rel="noopener noreferrer">
|
|
<T>API reference</T>
|
|
</Action>
|
|
</XStack>
|
|
</YStack>
|
|
</Card>
|
|
</YStack>
|
|
</Band>
|
|
</YStack>
|
|
)
|
|
}
|