Files
zeekay 6c65e3e941 @hanzo/app 0.2.0: the app SDK, renamed from @hanzo/rooms
Every import, the catalog pin and the docs name @hanzo/app and
github.com/hanzoai/app. lib/rooms.ts is lib/app.ts and
components/rooms.tsx is components/app.tsx.
2026-10-22 19:07:20 -07:00

386 lines
17 KiB
TypeScript

'use client'
/**
* /sdks — the two SDK lines, and where each language's real code lives.
*
* NO TAILWIND AND NO STYLE OBJECTS. The two lower section frames are
* `components/marketing/band`'s `Band`; @hanzo/ui's marketing components carry
* the type and the controls (`Display`, `Lede`, `Title`, `Eyebrow`, `Chip`,
* `Action`, `Leaf`); everything left is gui props over @hanzo/design's tokens.
*
* `Head` is deliberately NOT used for those two: it centres, and this page's
* section heads are left-aligned under a label. The frame is shared; the
* alignment is this page's. The agent prompt and the closing block are the
* shared blocks whole, head and all.
*
* Three things the swap moves, each the shared shape winning over this page's
* own copy of it:
*
* - the section headings take `Title quiet` and the label above each one
* takes `Eyebrow`, so the ladder is the site's rather than this page's.
* - `px-6 py-3 rounded-md`, filled and outlined, becomes `Action` at its two
* weights — the same control every other page draws.
* - a language card is `Leaf`, which is what its `group` + `hover:border-…`
* pair was spelling out by hand. The `group` had no `group-hover:` under it
* at all, so it was doing nothing; it is gone rather than carried.
*/
import { motion } from "@/components/motion"
import type { ReactNode } from "react"
import { ArrowRight, Cloud, Package, Sparkles, Terminal } from "lucide-react"
import { Github } from "@/components/brand"
import { SDKSection } from "@/components/products/SDKSection"
import { CodeExamplesSection, type Example } from "@/components/products/CodeExamplesSection"
import { hanzoSDKs } from "@/lib/data/upstream-projects"
import { Box, Text, XStack } from '@hanzo/ui'
import { Grid } from '@hanzo/ui/grid'
import { Band } from '@/components/marketing/band'
import { AgentPrompt } from '@/components/product/AgentPrompt'
import { Related } from '@/components/product/Related'
import { product } from '@/lib/product'
import { OWNED } from '@/lib/go-modules'
import { Action, Chip, Display, Eyebrow, Lede, Title, Leaf, Line } from '@hanzo/ui/marketing'
import { mix } from '@hanzo/app/lib/mix'
// ---------------------------------------------------------------------------
// /sdks — the SDK ecosystem landing. One canonical story, two lines:
// 1. Full Cloud SDK — generated from the Hanzo OpenAPI, one per language.
// Real code lives in the per-language org (hanzo-<lang>/sdk); the thin
// wrapper/docs face is hanzoai/<lang>-sdk; the umbrella meta is hanzoai/sdk.
// 2. AI + Agents — the hand-crafted flagship (Python `hanzo`, Node `@hanzo/ai`).
// ---------------------------------------------------------------------------
/** What the agent prompt and the closing block read, off the one table that
* holds a product's name, route, audited command and docs page. */
const PRODUCT = product('sdks')
/** The inks this page draws in. */
const INK = 'var(--foreground)'
const DIM = 'var(--muted-foreground)'
const SOFT = '$color/80'
/** The hairline tile this page sets everything in. */
const CARD = { p: 24, rounded: 'var(--radius-xl)', borderWidth: 1, borderColor: 'var(--border)', bg: mix('var(--secondary)', 40) } as const
/** The two small rungs, each on the leading its utility paired it with. */
const XS = { fontSize: '$1', lineHeight: '1.3333' } as const
const SM = { fontSize: '$2', lineHeight: '1.4286' } as const
/** A language card: `Leaf` with its edge drawn at rest and 20px inside. */
const ORG = { p: 20, borderColor: "var(--border)", bg: mix('var(--secondary)', 40), hoverStyle: { borderColor: mix('var(--foreground)', 30) } } as const
/** The command a card hands you, set in mono on the page ground. */
const Command = ({ children }: { children: ReactNode }) => (
<Line render="div" display="block" mb={16} p={12} rounded="var(--radius-lg)" bg="var(--background)" fontFamily="$mono" {...SM} overflowX="auto" color={SOFT}>
{children}
</Line>
)
/** A repository chip: its key in a quieter ink, then the repository. */
const Repo = ({ name, children }: { name: string; children: ReactNode }) => (
<Line display="inline-flex" items="center" gap={6} px={10} py={4} rounded="var(--radius-md)" borderWidth={1} borderColor="var(--border)" bg="var(--background)" fontFamily="$mono" {...XS} color={SOFT}>
<Text color={mix('var(--foreground)', 40)}>{name}</Text>
{children}
</Line>
)
const STATE = { px: 8, py: 2, borderColor: "var(--border)", bg: "var(--background)", fontSize: 10, lineHeight: "1.6", fontWeight: "500", textTransform: "uppercase", letterSpacing: "0.05em", color: mix('var(--foreground)', 70) } as const
/** Where a line's code lives, in small mono. */
const Home = ({ children }: { children: ReactNode }) => (
<Line fontFamily="$mono" {...XS} color={DIM}>
{children}
</Line>
)
const CardTitle = ({ render, children }: { render: 'h2' | 'h3'; children: ReactNode }) => (
<Text render={render} display="block" fontWeight="600" color={INK}>
{children}
</Text>
)
const CardBody = ({ children }: { children: ReactNode }) => (
<Line render="p" display="block" {...SM} color={DIM}>
{children}
</Line>
)
/** Mono inside a sentence: `unset` hands the line back to the paragraph, where
* the face's own leading would open the line it sits on. */
const Mono = ({ children }: { children: ReactNode }) => (
<Text fontFamily="$mono" lineHeight="unset" color={SOFT}>
{children}
</Text>
)
/** A paragraph under a section head, at the head's measure. */
const Note = ({ mb, children }: { mb: number; children: ReactNode }) => (
<Text render="p" display="block" mb={mb} width="100%" maxW={672} color={DIM}>
{children}
</Text>
)
/** The disc a card's mark sits on. */
const Disc = ({ children }: { children: ReactNode }) => (
<XStack width={40} height={40} items="center" justify="center" rounded="var(--radius-lg)" bg="var(--neutral-800)">
{children}
</XStack>
)
type LangOrg = {
lang: string
org: string // per-language GitHub org (real code)
realRepo: string // hanzo-<lang>/sdk — generated cloud SDK
wrapper: string // hanzoai/<lang>-sdk — docs/landing
install: string // a command that resolves today
ai?: string // AI + agents package for this language (only shown when it resolves today)
flagship?: boolean
}
// Per-language orgs — "we genuinely adopt + love each language." The card links
// the org (always live); the generated SDK + wrapper repos are its canonical homes.
// install strings verified against PyPI / npm / Go modules / crates / GitHub.
const perLanguageOrgs: LangOrg[] = [
{ lang: "Python", org: "hanzo-py", realRepo: "hanzo-py/sdk", wrapper: "hanzoai/python-sdk", install: "pip install hanzoai", ai: "hanzo", flagship: true },
{ lang: "Go", org: "hanzo-go", realRepo: "hanzo-go/sdk", wrapper: "hanzoai/go-sdk", install: "go get github.com/hanzoai/go-sdk" },
{ lang: "TypeScript", org: "hanzo-js", realRepo: "hanzo-js/sdk", wrapper: "hanzoai/js-sdk", install: "npm install @hanzo/sdk", ai: "@hanzo/ai" },
{ lang: "Rust", org: "hanzo-rs", realRepo: "hanzo-rs/sdk", wrapper: "hanzoai/rust-sdk", install: "cargo add hanzo", ai: "hanzo" },
{ lang: "Swift", org: "hanzo-swift", realRepo: "hanzo-swift/sdk", wrapper: "hanzoai/swift-sdk", install: ".package(url: \"https://github.com/hanzo-swift/sdk\")" },
{ lang: "Kotlin", org: "hanzo-kt", realRepo: "hanzo-kt/sdk", wrapper: "hanzoai/kotlin-sdk", install: 'implementation("com.github.hanzo-kt:sdk:v8.0.0")' },
]
// The AI + agents flagship line — distinct from the generated cloud SDK.
const aiFlagship: { lang: string; package: string; install: string; home: string; note: string }[] = [
{ lang: "Python", package: "hanzo", install: "pip install hanzo", home: "hanzoai/python-sdk", note: "Flagship — the most complete AI + agents library." },
{ lang: "Node", package: "@hanzo/ai", install: "npm install @hanzo/ai", home: "hanzo-js/ai", note: "Models, agents, tools, memory, and MCP for TypeScript." },
{ lang: "Rust", package: "hanzo", install: "cargo add hanzo", home: "hanzo-rs/sdk", note: "The AI + agents crate for Rust — crypto, DID, MCP, agents, embeddings, feature-gated." },
]
export default function SdksPage({ openai, anthropic }: { openai: Example[]; anthropic: Example[] }) {
return (
<Box minH="100vh" $platform-web={{ color: 'var(--foreground)' }}>
{/* Hero */}
<Box
render="section"
position="relative"
overflow="hidden"
pt={128}
pb={64}
px={16}
$md={{ px: 32 }}
>
<Box position="relative" z="var(--z-raised)" width="100%" maxW={896} mx="auto" $platform-web={{ textAlign: 'center' }}>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<Chip mb={24} px={12} py={4} fontSize="$1" lineHeight="1.3333" fontWeight="500" textTransform="uppercase" letterSpacing="0.05em" borderColor="var(--border)" bg={mix('var(--foreground)', 5)} color={mix('var(--foreground)', 70)}>
<Package width={14} height={14} /> SDKs
</Chip>
<Display mb={24}>
SDKs for every language
</Display>
<Lede mb={32} width="100%" maxW={672} mx="auto">
Two lines, not one. A <Text color={INK}>full Cloud SDK</Text> generated from
the OpenAPI document the API itself serves, so it is never behind the API — and a
hand-written <Text color={INK}>AI + Agents</Text> library for the work a
generator cannot express. Real code lives in the per-language org; the umbrella{" "}
<Text fontFamily="$mono" lineHeight="unset" color={INK}>hanzoai/sdk</Text> points at all of them.
</Lede>
<XStack gap={12} justify="center" flexWrap="wrap">
<Action
href="https://github.com/hanzoai/sdk"
target="_blank"
rel="noopener noreferrer"
fill
>
<Github width={16} height={16} /> hanzoai/sdk
</Action>
<Action
href="https://docs.hanzo.ai/docs/openapi/"
>
API reference <ArrowRight width={16} height={16} />
</Action>
</XStack>
</motion.div>
</Box>
</Box>
{PRODUCT && <AgentPrompt product={PRODUCT} />}
{/* Two SDK lines */}
<Box render="section" pb={16} px={16} $md={{ px: 32 }}>
<Box width="100%" maxW={896} mx="auto">
<Grid columns={{ min: 320, max: 2 }} gap={16}>
<Box render={<motion.div initial={{ opacity: 0, y: 12 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.4 }} />} {...CARD}>
<XStack items="center" gap={12} mb={12}>
<Disc>
<Cloud width={20} height={20} color={mix('var(--foreground)', 80)} />
</Disc>
<CardTitle render="h2">Full Cloud SDK</CardTitle>
</XStack>
<CardBody>
Generated from one document and never edited by hand, so every route is reachable the day
it ships — models, agents, data, compute, network, security, platform and chain. Method and
class names are the document&apos;s operation ids, which is what makes a client checkable
against a release instead of against somebody&apos;s memory. Real code lives in{" "}
<Mono>hanzo-&lt;lang&gt;/sdk</Mono>.
</CardBody>
</Box>
<Box render={<motion.div initial={{ opacity: 0, y: 12 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.4, delay: 0.05 }} />} {...CARD}>
<XStack items="center" gap={12} mb={12}>
<Disc>
<Sparkles width={20} height={20} color={mix('var(--foreground)', 80)} />
</Disc>
<CardTitle render="h2">AI + Agents</CardTitle>
</XStack>
<CardBody>
The hand-crafted flagship: models, agents, tools, memory, and MCP. Python{" "}
<Mono>hanzo</Mono> is the most complete; Node ships{" "}
<Mono>@hanzo/ai</Mono>. Distinct from the generated
cloud SDK — this is the &quot;we love this language&quot; library.
</CardBody>
</Box>
</Grid>
</Box>
</Box>
{/* Cloud SDK — install grid, every language */}
<CodeExamplesSection
title="Use the OpenAI SDK"
subtitle="POST /v1/chat/completions — identical request/response to OpenAI Chat Completions."
examples={openai}
/>
<CodeExamplesSection
title="Use the Anthropic SDK"
subtitle="POST /v1/messages — the native Anthropic Messages API, x-api-key auth and content-block responses."
examples={anthropic}
/>
<SDKSection productName="Cloud" sdks={hanzoSDKs} />
{/* Per-language orgs */}
<Band pad="$10" measure={1024}>
<XStack items="center" gap={8} mb={8}>
<Terminal width={20} height={20} color={INK} />
<Eyebrow render="span">
Per-language orgs
</Eyebrow>
</XStack>
<Title quiet mb={8}>
A home for every ecosystem
</Title>
<Note mb={16}>
Each language has its own org holding the generated cloud SDK, an AI + agents library and
the split-out packages. Every one of them ships the same six runnable examples — prove the
key works, one completion, balance and usage, a store round-trip, create and run an agent,
list the tools — so knowing one language&apos;s set is enough to navigate another&apos;s.
</Note>
<Grid columns={{ min: 320, max: 2 }} gap={16} mt={32}>
{perLanguageOrgs.map((l, i) => (
<Leaf
render={<motion.a initial={{ opacity: 0, y: 10 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.35, delay: i * 0.04 }} />}
key={l.lang}
href={`https://github.com/${l.org}`}
target="_blank"
rel="noopener noreferrer"
{...ORG}
>
<XStack items="flex-start" justify="space-between" mb={12}>
<XStack items="center" gap={12}>
<CardTitle render="h3">{l.lang}</CardTitle>
{l.flagship && (
<Line display="inline-flex" items="center" px={8} py={2} {...XS} rounded="var(--radius)" borderWidth={1} borderColor="var(--border)" bg="var(--white-10)" color={SOFT}>
Flagship
</Line>
)}
<Chip {...STATE}>
GA
</Chip>
</XStack>
<Home>{l.org}</Home>
</XStack>
<Command>
{l.install}
</Command>
<XStack gap={8} flexWrap="wrap">
<Repo name="sdk">{l.realRepo}</Repo>
<Repo name="docs">{l.wrapper}</Repo>
{l.ai && <Repo name="ai">{l.ai}</Repo>}
</XStack>
</Leaf>
))}
</Grid>
</Band>
{/* AI + Agents flagship */}
<Band pad="$10" measure={1024}>
<XStack items="center" gap={8} mb={8}>
<Sparkles width={20} height={20} color={INK} />
<Eyebrow render="span">
AI + Agents SDK
</Eyebrow>
</XStack>
<Title quiet mb={8}>
The flagship AI library
</Title>
<Note mb={32}>
Models, agents, tools, memory, and MCP — hand-crafted, not generated. Python leads;
Rust and Node follow.
</Note>
<Grid columns={{ min: 280, max: 3 }} gap={16}>
{aiFlagship.map((a, i) => (
<Box
key={a.lang}
render={<motion.div initial={{ opacity: 0, y: 10 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.35, delay: i * 0.04 }} />}
{...CARD}
p={20}
>
<XStack items="center" justify="space-between" mb={12}>
<XStack items="center" gap={8}>
<CardTitle render="h3">{a.lang}</CardTitle>
<Chip {...STATE}>
GA
</Chip>
</XStack>
<Home>{a.home}</Home>
</XStack>
<Command>
{a.install}
</Command>
<CardBody>{a.note}</CardBody>
</Box>
))}
</Grid>
</Band>
{/* The Go modules served at hanzo.ai/<name>: each page carries the go-import
tag the go tool reads, and this list is how a reader finds them. */}
<Band pad="$10" measure={1024}>
<Eyebrow render="span">Go modules</Eyebrow>
<Title quiet my={8}>
Served at hanzo.ai
</Title>
<Note mb={24}>
Each module has a page at its import path, with its source and its reference.
</Note>
<XStack flexWrap="wrap" gap={8}>
{OWNED.map((mod) => (
<Chip href={`/${mod}`} key={mod} px={12} py={4} fontFamily="var(--font-mono)">
hanzo.ai/{mod}
</Chip>
))}
</XStack>
</Band>
{PRODUCT && <Related product={PRODUCT} />}
</Box>
)
}