Commit Graph
12 Commits
Author SHA1 Message Date
zeekayandHanzo Dev 5960df513a Delete the LiteLLM proxy this repo has not been for a long time
266 files of upstream residue, none of it reachable from anything that builds
or runs. chat is a Node application that reaches models through api.hanzo.ai;
what came out is a Python proxy's build system, test suite and CI:

  docker/    every image in it CMDs `litellm`, one is FROM ghcr.io/berriai/litellm
             — the upstream vendor's own image — and Dockerfile.dev is
             python:3.11-slim + pip install litellm[proxy]
  tests/     231 files, 181 of them .py, including an enterprise/ tree; wired to
             no suite in this repo
  ci_cd/     Prisma migration scripts for schema.prisma, which declares
             LiteLLM_BudgetTable and friends while no package.json anywhere
             depends on prisma
  deploy/    the migrations those scripts generate
  config.yaml, the proxy's model_list; compose.dev.yml, whose `command: npm run
  dev` was aimed at that Python image and could never have run; docker-compose.yml,
  a near-identical twin of compose.yml; .pre-commit-config.yaml, whose hooks
  filter on litellm/, litellm_proxy_extras/ and enterprise/.

The Makefile is the part that was actively wrong rather than merely dead:
`build-prod` ran `docker build -f docker/Dockerfile -t hanzoai/chat:latest`,
which builds the LiteLLM image and tags it as chat. `dev` and `dev-full` drove
compose.dev.yml and a with-router profile pointing at hanzoai/llm:latest. dev
now runs the two watch commands this repo actually has, build-prod builds
Dockerfile.multi — the image deploy.yml ships — and dev-full and logs-router are
gone with the router they logged.

Verified before cutting: nothing under Dockerfile.multi, Dockerfile.static,
compose.yml, hanzo.yml, package.json or .hanzo/workflows/ reaches any deleted
path. The `docker/` hits in deploy.yml are docker/setup-buildx-action, an action
namespace. `.do/gitnexus` copies its own entrypoint.sh, not the one in docker/.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-20 21:04:06 -07:00
zooqueen 543a547bb9 release: tag the version, stop trying to commit it
The release ended RED on a build that had already shipped. `deploy.yml` pushed
the image, tagged it, pinned universe — and then failed on
`git push origin HEAD:main`, because the forge refuses an Actions-token push to
a protected branch. Its five-attempt loop was written for a race ("main moved
under us") and was retrying a refusal it could never win.

The write-back kept a COPY in sync, and the copy has no authority: imgver takes
`max(declared, published) + 1`, so once an image is published the registry
carries the floor and package.json can only restate it. What the file does buy
— a deliberate jump to, say, 1.1.0 — is a human editing it, which max() still
honours. This repo's own comment already said a stale floor "breaks nothing. It
just loses."

So the commit half is gone and the TAG half stays: `git push origin v${v}`
succeeds (v1.0.150 is on the forge), and the pre-build stamp stays too, so the
tree that gets tagged is byte-identical to the tree that was built.

hanzo.yml's `version-drift` gate goes with it, and NOT as collateral — the two
are one mechanism. That gate's stated job was "to prove the write-back landed",
so keeping it after removing the writer would have been a gate that goes red on
every push and PR, forever, about a number nothing can fix. `scripts/version.sh`
loses `check` and its two helpers for the same reason; `published` remains and
still answers 1.0.150.

Same resolution hanzo-apps/app reached for the identical pairing, so the fleet
now has one answer to it rather than two.
2026-08-10 17:44:41 -07:00
zeekayandHanzo Dev 7982ded6c3 chat: CI writes the version it ships, and starts tagging again
package.json said 1.0.77 while ghcr.io/hanzoai/chat shipped 1.0.113 — 36 patches
of drift that broke nothing on the way, which is why it lasted.

The cause is one sentence: the declared version is an INPUT to imgver
(max(declared, published)+1) that no writer ever writes. published advances once
per release, declared never moves, and the gap grows by exactly one forever.

So CI becomes the writer. The release job stamps package.json BEFORE the build,
then commits that exact tree and tags THAT commit — the tag now names both the
bytes that shipped and the number they call themselves. Ordering preserves every
existing invariant: verify-pullable, then commit+tag, then pin (the deploy), then
push main last, so bookkeeping can never un-ship a good build.

It also tags at all, which it never did — the tag stream stalled at v1.0.109
while images ran to 1.0.113, so `git tag` was not evidence of anything.

scripts/version.sh check enforces one invariant: the declared version must never
be BEHIND the highest published version of its stream. Equal means CI wrote it;
ahead means a human is preparing a release. Wired as a version-drift gate in
hanzo.yml, which hanzoai/ci runs on every push and PR. It works without a
GH_PAT — the registry half degrades to git tags and SAYS SO on stderr rather
than silently passing.

Corrected forward only, 1.0.77 -> 1.0.113. Nothing renumbered, nothing retagged;
the next release is 1.0.114.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-06 18:36:52 -07:00
zeekayandHanzo Dev a020c31ab3 iam: drop /api/ path prefix, use /v1/iam/
Hanzo standard (hanzoai/openapi): every route is /v1/<service>/<resource>.
The /api/ dialect is dead on the deployed IAM (iam v1.33.24 serves 154
paths, all under /v1/iam). Prefix only; route spelling unchanged.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 11:38:55 -07:00
zeekayandHanzo Dev 482ab24c97 check(barrel): drop the allowlist — a real build exports all four
The four names were only missing from the STALE dist committed in the repo. A
freshly built one carries them: 'published: 200 names required of 479 exported,
0 missing'. The anti-rot assertion I put on the list is what said so — it failed
the build with 'these are exported now — delete them from KNOWN', which is
exactly the job an allowlist should do to itself.

So there is no allowlist. Both invariants are enforced with no exceptions.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-26 19:22:01 -07:00
zeekayandHanzo Dev 87984243f8 fix(api): publish nine more, and let the gate enforce what it has proven
The published check found thirteen names api/server/** requires that the barrel
never carried. Nine are now published by their own sub-barrels — middleware
(capabilities, preAuthTenant), files/retention, agents/skillConfigurable,
mcp/oauth/obo.

Two are NOT published, deliberately:

  ./admin — nothing mounts routes/admin/{config,grants,groups,roles,users}.js
    (routes/index.js mounts only admin/auth), and src/admin/* does not typecheck
    against the current siblings (TS2305: data-schemas exports no IConfig,
    isValidCapability, RoleConflictError…). Dead surface; publishing it drags
    broken modules into the bundle for code that never runs.
  ./middleware/remoteAgentAuth — it cannot be bundled at all:
    RollupError: "normalizeOpenIdIssuer" is not exported by src/auth/openid.ts.

Publishing remoteAgentAuth is also what pulled jwks-rsa into the graph, so the
externalizable check caught that in the same build — the two invariants working
together, which is the point of having both.

Four names remain missing from a freshly built dist even though index.ts
re-exports the modules that define them (rum/proxy, endpoints→custom→
tenantBearer): getRumProxy{BodyLimit}, isRumProxyEnabled, proxyRumRequest,
resolveRequestOrg. That is a different defect — something drops them between
source and dist — and it is not diagnosed. Rather than switch the check off
until it is, they are listed in KNOWN: the gate runs green and enforces
everything else today, the list may only shrink, and the check FAILS if one of
them starts being exported, so the list cannot rot silently.

Also reverted an `export * from './rum'` I briefly added: index.ts already
exports './rum/proxy', and two star-exports of the same names make them
ambiguous — the exact way a name disappears from a barrel.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-26 19:16:39 -07:00
zeekayandHanzo Dev 36e0935d9d fix(api): declare what the barrel imports, and gate it
One defect shipped five times wearing four faces — createSkillsHandlers is not
a function, Cannot find module 'jszip', Could not load the "sharp" module,
canAccessSkillResource is not a function — and each fix surfaced the next,
because everyone was fixing the face.

The cause: rollup's `external` list for @hanzochat/api is built from that
package's own declared deps, and packages/api declared NONE of its runtime
imports (0 dependencies). Anything it imports and does not declare is therefore
not external, so rollup INLINES it — and an inlined module whose loader does a
native or dynamic require (sharp, jszip) produces a bundle that throws at load.
Whether the server booted came down to whether a re-export happened to pull in
a module that survives inlining. That is not a property anyone can hold in
their head, which is why it kept recurring.

So: every VALUE import reachable from src/index.ts is now declared — dedent,
get-stream, lodash, nanoid (jszip was declared earlier for the same reason).
Rollup externalizes them; the host already provides all four, so the lockfile
grows 12 lines and nothing resolves differently.

NOT declared: the seven type-only imports (@anthropic-ai/sdk, @aws-sdk/types,
@langchain/{google-common,openai}, @redis/client, openai, winston). `import
type` is erased before rollup sees it, so it cannot be inlined and declaring it
buys no safety — while `openai` alone would pin a second major into the graph.
Widening the dependency graph is a cost; paying it for nothing is not honesty.

scripts/check-barrel.cjs enforces both invariants against the dist that was just
built, so this is a red build rather than a dead pod:

  externalizable — every bare value import reachable from the barrel entry is
    declared. Walks the same module graph rollup bundles.
  published — every name api/server/** destructures from @hanzochat/api exists
    in the built barrel's exports.

Both static. The earlier version `require()`d the barrel, which coupled it to
the whole transitive graph; it was RIGHT about the fatal thing (jszip) and
noisy about 132 others, and the noise got the signal thrown away. Fixed here:
the destructure body is [^{}] so a match cannot run past its own closing brace
into the next require (that was the whole false-positive class), the export
surface is parsed from dist rather than required, template literals and
comments are stripped before scanning (prompts/artifacts documents `import
{ useState } from "react"` in prose), and a parser that reads ZERO exports
reports itself as stale instead of declaring every name missing.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-26 19:02:36 -07:00
zeekay 868905ebcf feat: rebrand as Hanzo Chat with zen4 models and OIDC integration
- Replace all LibreChat/danny-avila image refs with hanzoai/chat
- Remove LibreChat branding from UI, emails, docs, and configs
- Configure zen4 model series as defaults via api.hanzo.ai
- Add Hanzo IAM OIDC authentication (hanzo.id)
- Update Docker publish workflow for GHCR + Docker Hub
- Add librechat.yaml with Hanzo Cloud endpoint config
2026-02-19 16:52:55 -08:00
zeekay dc481954f4 feat: Add GitHub Actions workflow for Docker builds
- Add docker-publish.yml workflow for ghcr.io
- Add production-ready Dockerfile (if missing)
- Enable automated builds on push to main
- Support for semantic versioning tags
2025-07-23 23:06:15 -05:00
zeekay 127960720c feat: Add Hanzo IAM SSO integration and rebrand to Hanzo Router
- Added HanzoIAMSSOHandler class for Hanzo IAM authentication
- Integrated Hanzo IAM as an SSO provider alongside Google, Microsoft, and generic SSO
- Updated login UI from 'LiteLLM' to 'Hanzo Router' branding
- Changed error messages to reference Hanzo Router instead of LiteLLM
- Added .env.hanzo-iam.example configuration file
- Updated environment variable from LITELLM_MASTER_KEY to ROUTER_MASTER_KEY (with backward compatibility)
- Added support for HANZO_IAM_CLIENT_ID, HANZO_IAM_CLIENT_SECRET, and HANZO_IAM_SERVER_URL
- Maintained compatibility with existing authentication methods (built-in auth and other SSO providers)
2025-07-15 23:17:03 -05:00
zeekay 914bedbad4 feat: integrate Hanzo Runtime API for AI code execution
- Add Runtime service to Docker Compose stack
- Configure Runtime API integration in Router config
- Add mock Runtime server for development
- Update Router with Runtime API environment variables
- Update Makefile to include Runtime health checks
- Configure runtime execution models (Python/TypeScript)
- Fix Hanzo Router branding (build with enterprise colors)
- Add runtime access points to documentation
2025-07-15 01:27:32 -05:00
zeekay 77284015a0 feat: add demo user initialization for local development
- Add [email protected] demo user with password demo1234
- Create seed_demo_user.js script to initialize demo account
- Add demo-init service to compose.yml for automatic setup
- Add compose.dev.yml for development with mounted volumes
- Create init-demo-user.sh for manual demo user creation
- Add Makefile.hanzo with comprehensive stack management
- Include README-demo-user.md with usage instructions
- Configure Hanzo Router branding in hanzo-config.yaml
2025-07-14 16:20:44 -05:00