27788 Commits
Author SHA1 Message Date
zeekay ecdc089858 fix(csp): allow hanzo.app so the Contribute widget loads
hanzo.chat embeds hanzo.app/edit.js on every page, but script-src listed
only analytics + cloudflareinsights, so the widget was CSP-blocked. Add
hanzo.app to script-src (load) and connect-src (its /v1 calls).
2026-07-25 10:53:05 -07:00
Hanzo Dev 8a604750b1 fix(csp): allow hanzo.app in script-src so the Contribute widget loads
hanzo.chat embeds hanzo.app/edit.js but script-src only listed analytics
and cloudflareinsights, so the widget was CSP-blocked on every page.
2026-07-25 10:52:24 -07:00
Hanzo Dev d53b82d5ce ci: neutralize deploy-dev.yml to sync-notice — native deploy is .hanzo/workflows/deploy.yml (GitHub is a mirror) 2026-07-24 15:15:38 -07:00
Hanzo Dev 64f31f2f55 ci: neutralize tag-images.yml to sync-notice — native deploy is .hanzo/workflows/deploy.yml (GitHub is a mirror) 2026-07-24 15:15:37 -07:00
Hanzo Dev 33c26607a6 ci: neutralize dev-staging-images.yml to sync-notice — native deploy is .hanzo/workflows/deploy.yml (GitHub is a mirror) 2026-07-24 15:15:36 -07:00
Hanzo Dev d1d7d4df25 ci: neutralize dev-images.yml to sync-notice — native deploy is .hanzo/workflows/deploy.yml (GitHub is a mirror) 2026-07-24 15:15:34 -07:00
Hanzo Dev 8ce12d8d8b ci: neutralize dev-branch-images.yml to sync-notice — native deploy is .hanzo/workflows/deploy.yml (GitHub is a mirror) 2026-07-24 15:15:34 -07:00
Hanzo Dev ec9c105a6e ci: neutralize main-image-workflow.yml to sync-notice — native deploy is .hanzo/workflows/deploy.yml (GitHub is a mirror) 2026-07-24 15:15:32 -07:00
Hanzo Dev 4d2580772f ci: neutralize docker-publish.yml to sync-notice — native deploy is .hanzo/workflows/deploy.yml (GitHub is a mirror) 2026-07-24 15:15:31 -07:00
Hanzo Dev 7594b95570 ci: native Hanzo deploy pipeline (act_runner + BuildKit -> ghcr.io/hanzoai/chat -> operator patch app/chat)
Push to main -> in-cluster act_runner -> BuildKit builds ./Dockerfile ->
ghcr.io/hanzoai/chat:<sha> -> kubectl patch app/chat -> operator reconcile -> hanzocd.
GitHub Actions image build/deploy workflows reduced to sync-only.
2026-07-24 15:15:00 -07:00
Hanzo AI e0fd669598 feat(guest): forward-port anonymous guest-composer chat (@hanzo/iam-compatible)
Re-adds the deliberately-deleted (98d0dad34b) guest stack so an anonymous
visitor lands on the chat composer and can chat ONE free model without login,
then hits the SSO wall after a small per-IP quota. Adapted to today's code
(@hanzochat/* package names, @hanzo/iam bridge, tenant-bearer billing) — NOT a
blind revert: hanzoCloudKey.ts stays deleted.

Server (fail-closed, server-enforced):
- services/guestConfig.js: env-gated config + ephemeral guest principal/user +
  guest-scoped endpoints/models builders (default model zen5-flash).
- controllers/auth/GuestController.js + POST /v1/chat/auth/guest: short-lived
  guest JWT ({guest:true}, per-token random id) signed with JWT_SECRET; the
  route is per-IP mint-limited (guestTokenLimiter).
- middleware/requireGuestOrJwtAuth.js: accepts guest tokens ONLY where mounted;
  the jwt strategy still rejects guests everywhere else (clean 401, no CastError).
- middleware/enforceGuestScope.js: pins endpoint+model, strips
  agents/tools/files/spec/preset; 403 on any other endpoint/model.
- limiters/{guestLimiters,guestMessageLimiter}.js + utils/guestClientIp.js:
  per-REAL-IP quota (CF-Connecting-IP, not the token) via in-memory limiterCache
  (correct at replicas:1/Recreate; Redis NOT required). Exhaust -> 402 GUEST_LIMIT.
- endpoints/custom/initialize.ts: guest principal -> shared capped GUEST_API_KEY
  (KMS chat-guest-key), skipping per-user hk-/bearer billing; fail-closed if
  unset. Authenticated bearer path unchanged.
- agents/index.js: guest-capable completion chain; guest-safe /chat/active poll;
  AND the guest SSE read-back — GET /chat/stream/:streamId registered with
  requireGuestOrJwtAuth ABOVE the strict guard (else a guest 401s reading its own
  stream -> empty reply). Per-job ownership check (job.metadata.userId===req.user.id)
  is unchanged: foreign=403, missing=404, no cross-principal stream leak.
- Wire models/endpoints + guest-safe bootstrap (user/convos/favorites) to
  requireGuestOrJwtAuth; emit allowGuestChat/guestMessageMax in /v1/config;
  balance-gate bypass for guests (no org, bounded by limiter + capped key).

Tests: restored 6 guest specs (40/40 green) + 3 guest-billing cases in
initialize.spec. Client already guest-ready (zero client changes).

Docs: LLM.md guest section corrected to in-memory-at-replicas:1 + GUEST_API_KEY.

Do NOT deploy: red security review next, then cto native build + CR image pin.
2026-07-24 13:13:41 -07:00
Hanzo AI cebbd5a42c hanzo-edit: mount the contribute widget (repo=hanzoai/chat) 2026-07-24 01:31:06 -07:00
zeekayandClaude Opus 4.8 8c6478cb82 feat(auth): @hanzo/iam session-bridge — one-way SPA login without breaking OBO
Complete the chat auth migration onto @hanzo/iam. The @hanzo/iam SPA runs
Authorization-Code + PKCE entirely in the browser; a new backend session-bridge
turns the IAM-verified identity into the EXISTING Chat session, so live login,
reload-persistence, the 401->refresh interceptor, and the cloud-agent
on-behalf-of (OBO) flow all keep working. This is a session-bridge, not a blind
swap — the change is purely additive server-side.

Backend
- POST /oauth/iam/session (api/server/controllers/auth/iamSession.js): accepts
  { accessToken, idToken } from the SPA, JWKS-validates the id_token against
  hanzo.id (issuer + RS256 signature + expiry), reconciles the Mongo User by
  `sub` (openidId, provider=openid — create/migrate via findOpenIDUser), issues
  the existing Chat session via setAuthTokens (refresh cookie + Mongo Session +
  token_provider=chat + Chat JWT), and persists the id_token server-side
  (persistOpenIDTokensToSession) so resolveTenantBearer can forward it on OBO
  cloud calls. IAM tokens never become the app bearer; the id_token stays
  server-side.
- api/server/services/iamToken.js: standalone JWKS verifier (the openIdJwtStrategy
  JWKS path promoted to a callable), self-contained via OIDC discovery of
  OPENID_ISSUER — no dependency on the Passport OpenID login strategy.

Frontend
- OAuthCallback: after IAM.handleCallback(), POST the token to /oauth/iam/session
  and set the returned Chat JWT (dispatchTokenUpdatedEvent). Fixes the prior
  broken callback that set the IAM token as the app bearer (rejected by
  requireJwtAuth) and created no server session.
- data-provider: add the iamSession() endpoint + export.

Deps
- @hanzo/iam ^0.13.1 -> ^0.13.8 (relocked).

Verification
- New unit tests green (iamSession 10, iamToken 5); AuthService + CloudAgentsClient
  green (52 in-scope tests pass). Typecheck introduces 0 new errors.
- verifyIamToken integration-tested against LIVE hanzo.id JWKS: forged (real kid,
  wrong key), unknown-kid, and empty tokens all rejected.

The server-initiated /oauth/openid routes are kept as a dormant, unreferenced
fallback (the SPA uses only the bridge); their deletion is deferred until the
full browser login flow is verified live end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 22:51:11 -07:00
zeekay a31f4517c1 merge: adopt @hanzogui/shell in hanzo.chat (Meet Hanzo launcher + brand tokens + landing header/footer) 2026-07-23 21:12:53 -07:00
zeekay 8b4edcf187 chore(chat): bump @hanzogui/shell ^7.4.2 (mobile account fix) 2026-07-23 21:07:31 -07:00
zeekay de5ae59f68 feat(landing): adopt shared HanzoHeader + PreFooterCTA + HanzoFooter on marketing page 2026-07-23 20:45:00 -07:00
zeekay a65406448c feat(nav): add Meet Hanzo cross-app launcher to chat header 2026-07-23 20:43:29 -07:00
zeekay 908cd5493e style(brand): import @hanzo/brand tokens + surface shared hanzo scale in tailwind 2026-07-23 20:42:52 -07:00
zeekay 364da76d9e chore(deps): add @hanzogui/shell@^7.4.1 + @hanzo/brand@^1.4.1 to frontend 2026-07-23 20:42:17 -07:00
Hanzo AI eb15c057c8 analytics: canonical hz.js tag (hanzo.chat)
Replace the script.js/data-website-id snippet in client/index.html <head> with the ONE canonical <script async src=https://analytics.hanzo.ai/hz.js data-site="hanzo.chat">. Drops the %VITE_ANALYTICS_SITE_ID% build placeholder (site key is now the static domain).
2026-07-23 01:35:17 -07:00
hanzo-dev 16e3b451db fix(build): sync pnpm-lock.yaml with client/package.json (@hanzo/logo)
The 'logo single-source' change added @hanzo/logo@^1.0.13 to client/package.json
but did not update pnpm-lock.yaml, so the Docker build's `pnpm install --frozen-lockfile`
has failed (ERR_PNPM_OUTDATED_LOCKFILE) on every build since — chat main was
unbuildable. Regenerated with the pinned pnpm@10.27.0 (--lockfile-only). @hanzo/logo
is a public npm package; peer-dep warnings are pre-existing (legacy-peer-deps).
v0.9.29
2026-07-22 19:16:17 -07:00
hanzo-dev 79e884dd44 chore(brand): scrub LibreChat brand mentions → Hanzo
Removes the upstream LibreChat brand from user-visible + internal surfaces (pt-PT
locale string, MCP trust-warning template, code comments, the libreChatProxy var,
the LIBRE_CHAT_DOCKER_TAG build-script env, README prose). App UI was already
Hanzo-branded; this cleans the residue.

KEPT deliberately:
- LICENSE / packages/data-schemas/LICENSE 'Copyright (c) … LibreChat' — the MIT
  license REQUIRES the attribution; stripping it would violate the license.
- All LibreOffice references (packages/api/src/files/documents/libreoffice.ts) —
  that is the office-suite doc-preview dependency, NOT LibreChat; removing it
  breaks document preview.
2026-07-22 19:09:55 -07:00
Hanzo Dev 256595062b merge(feat/logo-single-source): consolidate onto main 2026-07-21 17:08:35 -07:00
Hanzo Dev f0312ac278 merge(feat/enso-default-model): consolidate onto main 2026-07-21 17:08:17 -07:00
hanzo-dev b4988a2a6c fix: router-routes-caller — /v1/get-routing-defaults -> /v1/router/defaults 2026-07-21 16:49:51 -07:00
Hanzo Dev ab14835c8b chat: default model → enso (Enso Pro, gated)
Prepend enso to the Hanzo endpoint (customOrder 0) models.default list, so a new
conversation opens on enso — the balanced orchestrated tier that routes each
request to the best-fit model. zen5-* stay selectable; titleModel/summaryModel
stay zen5-flash (fast, in-catalog title generation, unrelated to the composer).

GATED — config mirror only, do not deploy: the authoritative prod list is the
universe chat-config ConfigMap (repo chat.yaml mirrors it), so go-live is a
ConfigMap update gated on enso being served on api.hanzo.ai (ENSO_URL in ai) and
enso-ultra preservation validation.
2026-07-21 14:47:35 -07:00
Hanzo Dev fff0b4cf27 refactor(logo): HanzoLogoIcon consumes @hanzo/logo (single source)
Stop re-typing the block-H path data — import MARK_PATHS/MARK_VIEWBOX from
@hanzo/logo (the one geometry home). Byte-identical mark, same props
(className/size/currentColor), 4 consumers unaffected. Needs @hanzo/logo
published install to update the pnpm lock (deploy-gate); scoped tsc of the
changed file green against real react + logo types.
2026-07-21 09:35:43 -07:00
Hanzo Dev b81e6561fb auth: make @hanzo/iam the single login path
Re-implement the IAM-only rip on the re-rooted @hanzochat main (the old
auth/iam-only branch shares no history and is unmergeable). @hanzo/iam owns
every credential step via redirect-PKCE to hanzo.id; /auth/callback completes
the token exchange.

Client
- iam.ts: one always-configured IAM SDK singleton (env + prod defaults
  hanzo.id / hanzo-chat), redirect_uri ${origin}/auth/callback
- Login.tsx: single "Log in with Hanzo" -> signinRedirect(); auto-redirect
  on mount unless ?redirect=false
- drop LoginForm, Registration, ResetPassword, RequestPasswordReset,
  SocialButton, SocialLoginRender (+ specs); drop the register / forgot /
  reset routes
- GuestLimitDialog / LandingPage / login.ts: login = IAM signinRedirect

Server
- delete local + third-party passport strategies (local, apple, discord,
  facebook, github, google, ldap, saml) and their specs
- keep jwt / openid / openidJwt strategies for IAM JWT validation
- socialLogins: Hanzo IAM (OpenID Connect) only
- auth routes: drop /login, /register, /requestPasswordReset, /resetPassword
- remove dead requireLocalAuth / requireLdapAuth middleware + LoginController

Build
- give the @hanzochat/api rollup enough heap (cross-env
  NODE_OPTIONS=--max-old-space-size=8192) to fix the OOM exit 134
- raise the Dockerfile heap default to 8192 to match
v0.9.28
2026-07-21 08:54:29 -07:00
Hanzo AI ac47ffd674 chore(chat): migrate @hanzo/capture -> @hanzo/event (superset API) v0.9.27 2026-07-20 23:27:22 -07:00
Hanzo Dev ce490f1462 Merge feat/community-git: showcase only apps built on git.hanzo.ai
The community showcase lists ONLY apps whose repository lives on
git.hanzo.ai. git.ts is the one place that decides "lives on Hanzo Git"
for both sides: isHanzoGitUrl (client link guard) and HANZO_GIT_URL_PATTERN
(server store query, matched case-insensitively). The marketplace query
pins source=git.hanzo.ai; the plain builder list is unaffected.
2026-07-20 17:29:56 -07:00
Hanzo Dev 05258972f0 chat: align showcase server filter with the client git.hanzo.ai predicate
The showcase decides "lives on git.hanzo.ai" in one place: git.ts. It now
also exports HANZO_GIT_URL_PATTERN (built from HANZO_GIT_HOST) for the
server store query; the agents list handler matches it case-insensitively.
Server and client (isHanzoGitUrl) now accept the same URLs -- http(s),
exact host, any case -- so a repo stored with non-canonical scheme or
casing is no longer silently dropped from the showcase.
2026-07-20 17:27:37 -07:00
Hanzo Dev a6b2b407f6 chat: community showcase lists only apps built on git.hanzo.ai
The agent/app marketplace is the community showcase. Apps are built in
hanzo.app, which clones each into git.hanzo.ai; scope the showcase to those
apps and surface only their git.hanzo.ai repositories.

- data-provider/git: one source of truth for the host (git.hanzo.ai), the
  canonical base URL, and isHanzoGitUrl() — shared by the marketplace query,
  the server-side list filter, and the client link guard.
- Agent record gains `repository` (its git.hanzo.ai clone); the list projection
  returns it.
- getMarketplaceAgents pins source=git.hanzo.ai; getListAgentsHandler restricts
  the result to agents whose `repository` is on git.hanzo.ai only when that
  source is set, so the builder's plain agent list is unaffected.
- Agent detail renders a repository link guarded by isHanzoGitUrl, so only
  git.hanzo.ai URLs are ever shown.

Producer follow-on (cross-repo): hanzo.app sets `repository` to the git.hanzo.ai
clone URL when it builds an app.
2026-07-20 17:04:36 -07:00
zeekayandClaude bfa2e347fb chore(models): prune unserved zen ids from picker mirror (matches chat-config CM)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-19 05:48:30 -07:00
zeekayandClaude ca5768bdeb feat(models): add Anthropic + OpenAI picker families (reference mirror of chat-config CM)
Co-Authored-By: Claude <noreply@anthropic.com>
v0.9.26
2026-07-18 23:59:27 -07:00
zeekayandClaude 61b1bfe506 feat(golive): unify build-app handoff to hanzo.app, refresh landing, surface SSE 5xx, fix dead help links
Directive 1 — every "build an app" affordance now DIRECTS to hanzo.app
(chat stays chat; hanzo.app is the builder sibling). One destination via
openAppBuilder/buildAppUrl:
- Composer BuildAppButton opens hanzo.app seeded from the composer text
  (was: toggled an inline placeholder pane).
- Landing starter row gains a "Build an app" link-out chip (plain-model
  default only; agent/assistant starters untouched).
- /build deep-link redirects to hanzo.app; the /build command + message
  action already handed off.
- Retired the inline build shell (BuildPreviewPane, buildMode atom,
  ChatView split) — it only ever placeheld before the same handoff.

Directive 2 + landing refresh — LandingPage (logged-out front door):
- Pricing block -> unified plans $20/$100/$200/mo, "shared AI usage across
  every Hanzo app (chat, app builder, API) + pay-as-you-go", each linking
  to hanzo.ai/pricing; kept the real $5 free-credit line.
- Zen showcase -> current house families (enso, enso-flash, zen5,
  zen5-coder, zen3-omni); dropped param/context chips (no repo source to
  cite). Demo terminal zen4-coder -> zen5-coder.
- Third-party wall -> models served today (Claude Opus 4.8, Claude 5
  Sonnet, GPT-5.2, DeepSeek V4, Qwen3.5, Llama 4).

Directive 3 — dead help/docs links repointed to the live docs
(docs.hanzo.ai/chat; hanzo.ai/docs/chat is 404): landing nav/hero/CTA/
footer, AdminSettingsDialog, ApiKeyDialog, Usage routing link, and the
helpAndFaqURL server default.

Directive 4 — useResumableSSE surfaces a completions 5xx that carries a
structured error body immediately instead of spinning through 5 reconnect
attempts (~30s) then a generic message. sse.js always sets responseCode on
an HTTP failure, so a 5xx-with-body previously missed the surface branch;
bodyless/non-JSON failures still reconnect (transient-drop resilience). +2 tests.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-18 23:59:26 -07:00
zeekayandClaude Opus 4.8 95b00c9e9a chat: hero-style landing empty state (heading + enlarged composer + prefill chips)
Match the hanzo.ai hero on the new-conversation empty state, reusing the
ONE existing composer + submit path (presentation only, no second input).

- Landing: default heading is now "What can I help with?" (localized
  com_ui_landing_title); admin customWelcome still wins. Short headings
  scale up to a hero size (text-3xl -> md:text-5xl), responsive.
- ChatForm: derive one isLanding memo; reuse it to center (existing logic,
  de-duplicated) AND enlarge the composer on the empty state only (taller
  initial height + text-base md:text-lg -> bigger placeholder/pill).
- ConversationStarters: reshape the existing chips into a centered
  monochrome pill row; clicking now PREFILLS the composer via the canonical
  submitPrompt (arms activePrompt, honors autoSendPrompts) instead of a
  second send path. Honest generic defaults: Summarize / Write code /
  Explain / Brainstorm. Agent/assistant author starters still flow through.

Monochrome throughout via existing brand tokens (text/surface/border-*);
SendButton is already the circular arrow-up. No new deps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
v0.9.25
2026-07-18 09:51:34 -07:00
c0e4df7788 feat(images): Fix action + previous-image picker for generated images (#73)
Add a 'Fix' affordance on AI-generated images (hover pill on the message
thumbnail and an action in the fullscreen dialog) that attaches the image
to the composer as a reference file and seeds a 'Fix this image: ' prompt,
so the user only describes the fix.

Three attach paths, all reusing the existing file pipeline:
- Fix: attaches the generated image by reference (file_id, no re-upload) via
  useAttachImage, injecting a completed ExtendedFile (attached: true) into the
  composer file map — the send path forwards it verbatim as multimodal content.
- Drag-and-drop: plain image/file drops with no tool-resource choice now attach
  straight into the current conversation instead of a single-option dead-end modal.
- Attach a previous image: new attach-menu item opens a picker of the current
  conversation's images (collectConversationImages) and attaches by reference.

Pure helper collectConversationImages/resolveImageUrl unit-tested (10 cases).
i18n keys added to the default locale. No backend changes.

Co-authored-by: Hanzo AI <ai@hanzo.ai>
2026-07-16 12:59:21 -07:00
b2aab4aff9 refactor: repoint reward-signal client onto the shared @hanzo/ai SDK (#72)
The content-free router-training feedback transport now lives once, in
`@hanzo/ai` `sendFeedback` (v0.2.1). `client/src/utils/rewardSignal.ts` becomes
a THIN adapter: it keeps the exact public `sendRewardSignal(requestId, signal,
rating?)` the message-actions and model-selector surfaces wire to, plus the
local `VITE_HANZO_FEEDBACK` opt-out, and delegates emission to the SDK with the
chat-specific `baseUrl` (VITE_HANZO_API_URL, cross-origin gateway) and the
end-user bearer lifted from axios defaults. The SDK owns the whitelisted
`{request_id, signal, rating?}` body, the dedupe, and the fire-and-forget
transport — so no prompt/response/code can transit, exactly as before.

The existing spec passes untouched (behavior preserved end-to-end through the
SDK; jsdom has no sendBeacon, so the SDK falls back to the same keepalive fetch
with the same headers).

Tests: client/src/utils/rewardSignal.spec.ts — 13/13 passed.

Claude-Session: https://claude.ai/code/session_015Z1iLf7QBrq1LhignJrzDw

Co-authored-by: hanzo-dev <dev@hanzo.ai>
2026-07-16 11:15:34 -07:00
zandGitHub 3f4addac86 feat(analytics): instrument chat with @hanzo/capture (#70)
Client-side product analytics via @hanzo/capture: pageviews, identify(user.id), and CHAT_STARTED/CHAT_MESSAGE_SENT with endpoint+model identifiers only — no message content or PII. Lockfile + tsconfig subpath mapping included.
v0.9.23
2026-07-16 10:14:12 -07:00
f2778c26cb feat(reward-signals): emit content-free router-training feedback to gateway (v0.9.23) (#71)
Emit CONTENT-FREE reward signals to `POST {VITE_HANZO_API_URL}/v1/feedback` so
the router training loop gets production feedback. Payload carries ONLY
{request_id, signal, rating?} — never any prompt/response/tag/text/filename/code.
Fire-and-forget: never blocks UX, silent no-op on any failure.

The routing ledger keys each RoutingEvent on the upstream gateway response id
(chatcmpl-…/msg_…). The chat client previously held only locally-minted UUIDs,
so capture the REAL id server-side and thread it to the client as one field:

- server: ModelEndHandler captures `data.output.response_metadata.id ?? .id`
  (the last CHAT_MODEL_END = the visible answer) into a shared `runMetadata`;
  AgentClient surfaces it via `this.metadata` → `feedbackRequestId` on the saved
  response message, riding the SSE final event + DB save to the client.
- schema: add optional `feedbackRequestId` to tMessageSchema (zod), IMessage
  (mongo type) and the mongoose message schema (persists; SQLite keeps it in its
  JSON doc blob automatically). Absent id ⇒ signal no-ops (never fabricated).

Client signals wired via new `client/src/utils/rewardSignal.ts`:
- thumbs up/down → up/down; regenerate → regenerate; copy → up (weak positive);
  model-switch right after a response → switch (last assistant msg's id).
Dedicated cross-origin credentialed fetch (keepalive) to the Hanzo API — NOT the
same-origin chat backend — forwarding the end-user bearer for per-org attribution.
Honors local opt-out `VITE_HANZO_FEEDBACK=0|false|off` (server-side org/user
training opt-in is the preferred enforcement). 13 unit tests, all green.

Claude-Session: https://claude.ai/code/session_015Z1iLf7QBrq1LhignJrzDw

Co-authored-by: hanzo-dev <dev@hanzo.ai>
2026-07-16 09:19:20 -07:00
Hanzo AI 12bc51f901 fix: CloudUsage.js imports @hanzochat/data-schemas (not @librechat) — 0.9.22
The controller required '@librechat/data-schemas', but this fork renames all
internal packages to @hanzochat/* (214 other files use @hanzochat/data-schemas;
that upstream name resolves to nothing). Runtime-only failure (require-time), so
the green build hid it and 0.9.21 CrashLooped at CloudUsage.js:1 MODULE_NOT_FOUND
— AFTER clearing the 0.9.21 zod/v4 fix. One-line name fix; all other requires in
the usage backend already resolve.
v0.9.22
2026-07-16 01:25:03 -07:00
Hanzo AI dff9f48c17 fix: force zod@3.24.4→3.25.76 so openai@6 resolves zod/v4 (0.9.21)
Any fresh chat image built after 74954c3f8 (@hanzo/iam 0.13 lockfile regen,
which pulled openai@6.46.0) crashes on boot:

  ERR_PACKAGE_PATH_NOT_EXPORTED: subpath './v4' is not defined by
  "exports" in openai/node_modules/zod/package.json

openai@6.46.0 declares zod '^3.25 || ^4.0' and imports zod/v4, but pnpm
mis-resolved its peer to the older zod@3.24.4 (which has no ./v4 subpath).
The deployed 0.9.19 image predates openai@6 entering the tree, so it never
hit this — 0.9.20 was simply the first rebuild to trip the latent landmine.

Fix: a single pnpm override zod@3.24.4 → 3.25.76 (already in-tree, a
backward-compatible superset that ships the zod/v4 compat subpath),
collapsing to ONE zod. Verified: no other package floated; openai@6.46.0
now pairs zod@3.25.76. Unblocks the whole chat build pipeline, not just
the 0.9.20 usage panel.
v0.9.21
2026-07-16 01:04:18 -07:00
Hanzo AI 7a24877eaf usage: canonical cloud usage in Settings (proxy /v1/get-cloud-usages, @hanzo/usage)
Adds the shared Hanzo usage read to LibreChat's Usage tab, beside (not
replacing) the Mongo token-credit view. Backend CloudUsage.js proxies
cloud's GET /v1/get-cloud-usages on-behalf-of (hanzo.id bearer resolved
server-side, never to browser); client renders the CloudUsageOverview
with @hanzo/usage's headless normalizeCloudUsage over native Tailwind.
Honest when unavailable: 200 {enabled:false} hides the section.
2026-07-15 18:26:33 -07:00
Hanzo Dev 01597b9bb2 merge: complete @hanzochat fork + org/project/user switcher
Brings the fork completion (de-librechat, @hanzochat scope rename, @hanzo/iam
0.13 API) and the org/project/user switcher (validated active-org -> X-Org-Id
on both cloud seams) onto main for release.
v1.0.6
2026-07-14 12:46:42 -07:00
Hanzo Dev 9c4488d66e chat: org/project/user switcher — active org rides X-Org-Id to cloud
The account menu shows user -> org -> project and lets a multi-org member
switch their working org. The switch pins hanzo_active_org (httpOnly),
validated server-side against the caller's own membership set (owner + groups)
via POST /v1/chat/user/active-org. resolveActiveOrg() forwards it as X-Org-Id
on both on-behalf-of seams — the inference path (custom/initialize.ts) and
cloud agents (CloudAgentsClient) — where the gateway re-validates it in the
member's set (HIP-0026), so the header is a validated selection, never a trust
assertion. Adds Account/Console/Billing links. openidStrategy persists
organization/project/groups from the JWT claims; the user schema + TUser carry
them and getUserController serves them.
2026-07-14 12:46:26 -07:00
Hanzo Dev b237551ffa chat: de-librechat — CHAT_ env, chat.yaml, Chat identifiers; README rewrite + zh
- env vars LIBRECHAT_* -> CHAT_* (USER_ID, GRAPH_ACCESS_TOKEN, OPENID_*, LOG_DIR, ...)
- config file librechat.yaml -> chat.yaml (matches prod CONFIG_PATH) + .example
- identifiers LibreChat -> Chat (extractChatParams, ChatKeys, ChatParams, importChatConvo)
- lowercase librechat -> chat: i18n keys, helm charts (helm/chat, helm/chat-rag-api),
  CI workflows, OTel service/span keys, codeapi JWT issuer, x-chat-thread-id header
- README.md rewritten (Node 24, pnpm 10, Zen family, Cloud Agents, hanzo.id OIDC);
  README.zh.md added (Simplified Chinese)

MIT LICENSE copyright + one 'Forked from LibreChat (MIT)' attribution retained.
Build 5/5 green.
2026-07-14 10:41:50 -07:00
Hanzo Dev c7f7ef984e chat: drop all librechat.ai URLs; attribute as Hanzo
- librechat.ai doc/ToS/privacy URLs -> hanzo.ai / hanzo.chat
- OpenRouter attribution HTTP-Referer + X-Title -> https://hanzo.chat / Hanzo Chat
  (source + specs updated in lockstep)
- registry.librechat.ai dev images -> hanzoai/chat + ghcr.io/hanzoai/rag-api
- remove upstream README.zh.md (Hanzo zh translation follows)

MIT LICENSE copyright retained (legal attribution).
2026-07-14 10:31:38 -07:00
Hanzo Dev 74954c3f81 fix: @hanzo/iam 0.13 API (BrowserIamSdk->IAM) + regenerate pnpm-lock
The static/IAM SPA path (client/src/utils/iam.ts, OAuthCallback.tsx) imported
BrowserIamSdk, removed when @hanzo/iam bumped 0.4->0.13 (HIP-0111); the class is
now IAM with an identical constructor config. pnpm-lock.yaml regenerated for the
@hanzochat rename. Fork now builds 5/5 tasks green.
2026-07-14 10:23:39 -07:00
Hanzo Dev e9b4c41d2d fork: complete @hanzochat rename — agents runtime + lockfile canonicalization
- @librechat/agents -> @hanzochat/agents@^3.2.63 (published fork of
  danny-avila/agents at github.com/hanzochat/agents; upstream remote kept
  so agent-runtime fixes stay pullable)
- final sweep: zero @librechat/* package refs (chat internals + runtime)
- remove dead packages/agents residue (stale dist, no package.json)
- drop stale npm/bun lockfiles; pnpm-lock.yaml is the canonical lockfile
2026-07-14 09:31:40 -07:00
Hanzo Dev ba0eb6f2d2 fork: rename internal workspace packages to @hanzochat scope
librechat-data-provider  → @hanzochat/data-provider
@librechat/data-schemas  → @hanzochat/data-schemas
@librechat/client        → @hanzochat/client
(@hanzochat/api already forked; external @librechat/agents fork follows)

All imports, package.json names/deps, tsconfig path aliases, jest
moduleNameMapper, and rollup/vite build aliases updated. The data-provider
react-query subpath resolves via the exports map. Lockfiles regenerated in a
follow-on once the canonical package manager is confirmed.
2026-07-14 05:55:49 -07:00