From 66a8d6703933a7e0a929b806fb04074338093dc9 Mon Sep 17 00:00:00 2001 From: Le Ha Quang Date: Mon, 22 Jun 2026 16:53:46 +0200 Subject: [PATCH 1/3] chore: rebrand HexaUI / HexUI -> HexKit Pure prose rename across 56 files. Identifier-preserving: every Python module name (`platform_backend`, `hexa_events`, `agent_server`), every npm package name (`agent-ui`, `front-app`), and every directory path stays the same. Only product-facing prose changes. Touched: docs (README, QUICKSTART, CONTRACT, IMPROVEMENTS), docstrings in every Python package, comments in the TypeScript widgets and the frontend shell, the demo-users.yaml header. One non-prose change: `proxy-server/pyproject.toml` project name moves from `hexaui-proxy` to `hexkit-proxy` (caught by the same case rule; no external consumer depends on this name yet). The README CI badge URL is kept at `github.com/HexamindOrganisation/HexUI` since the GitHub repo itself hasn't been renamed. make check stays green: ruff clean, 90/90 proxy tests, tsc clean on both TypeScript projects. --- CONTRACT.md | 12 ++++++------ Makefile | 2 +- QUICKSTART.md | 4 ++-- README.md | 14 +++++++------- custom-UI/src/lib/context-card.tsx | 2 +- custom-UI/src/registry/builtin.ts | 2 +- custom-UI/src/schema/page.ts | 2 +- custom-UI/src/shadcn.css | 14 +++++++------- custom-UI/src/styles.css | 4 ++-- custom-UI/src/widgets/ai-chat-input.tsx | 2 +- custom-UI/src/widgets/tool-calls.tsx | 2 +- demo-users.yaml | 4 ++-- demo/agent-server/pyproject.toml | 4 ++-- demo/agent-server/src/agent_server/__init__.py | 2 +- .../src/agent_server/agents/base.py | 2 +- .../src/agent_server/agents/devops.py | 6 +++--- .../src/agent_server/agents/devops_agent.py | 8 ++++---- .../src/agent_server/agents/healthcare.py | 6 +++--- .../agent_server/agents/healthcare_agent.py | 6 +++--- .../agent-server/src/agent_server/agents/hr.py | 4 ++-- .../src/agent_server/agents/hr_agent.py | 6 +++--- .../src/agent_server/agents/itsm.py | 6 +++--- .../src/agent_server/agents/itsm_agent.py | 6 +++--- .../src/agent_server/agents/itsm_db.py | 2 +- .../src/agent_server/agents/openai_agents.py | 6 +++--- demo/agent-server/src/agent_server/protocol.py | 2 +- demo/agent-server/src/agent_server/roster.py | 2 +- .../src/agent_server/routes/agents.py | 2 +- .../src/agent_server/server/app.py | 4 ++-- demo/hexgate-agent/README.md | 18 +++++++++--------- demo/hexgate-agent/pyproject.toml | 2 +- .../src/hexgate_agent/__init__.py | 2 +- demo/hexgate-agent/src/hexgate_agent/agent.py | 12 ++++++------ demo/hexgate-agent/src/hexgate_agent/app.py | 4 ++-- demo/scripts/README.md | 2 +- demo/scripts/run-backends.sh | 4 ++-- demo/scripts/verify_backend.py | 8 ++++---- demo/starter-agent/pyproject.toml | 2 +- demo/starter-agent/src/starter_agent/app.py | 6 +++--- front-app/README.md | 2 +- front-app/src/api/agents.ts | 2 +- front-app/src/layout/AppShell.tsx | 2 +- front-app/src/lib/fileFx.tsx | 2 +- front-app/src/main.tsx | 2 +- front-app/src/pages/FilesPage.tsx | 2 +- front-app/src/pages/SettingsPage.tsx | 6 +++--- front-app/src/styles.css | 4 ++-- packages/hexa-events/pyproject.toml | 2 +- .../hexa-events/src/hexa_events/__init__.py | 4 ++-- packages/hexa-events/src/hexa_events/events.py | 4 ++-- packages/hexa-events/src/hexa_events/sse.py | 2 +- proxy-server/pyproject.toml | 6 +++--- proxy-server/src/platform_backend/access.py | 2 +- .../src/platform_backend/models/user.py | 2 +- proxy-server/src/platform_backend/routes/me.py | 2 +- .../src/platform_backend/runtime_client.py | 2 +- 56 files changed, 123 insertions(+), 123 deletions(-) diff --git a/CONTRACT.md b/CONTRACT.md index 659599b..15d738c 100644 --- a/CONTRACT.md +++ b/CONTRACT.md @@ -1,6 +1,6 @@ -# HexaUI Developer Contract (v1) +# HexKit Developer Contract (v1) -> The contract between a **developer's agent backend** and the **HexaUI proxy**. +> The contract between a **developer's agent backend** and the **HexKit proxy**. > It imposes only the **shape of the API** (five endpoints) and that each stream > frame is **tagged with the framework that produced it**. You do *not* rewrite > your agent's events: you forward your framework's **native** events, tagged, @@ -15,7 +15,7 @@ ## 1. Roles ``` -browser ──HTTP/SSE──▶ HexaUI proxy ──HTTP/SSE──▶ your agent backend +browser ──HTTP/SSE──▶ HexKit proxy ──HTTP/SSE──▶ your agent backend (this platform) (you implement this) ``` @@ -65,16 +65,16 @@ previous revision; see those sections at the end.) - `run_id` — opaque id the proxy assigns; accept it on `cancel`. - `input.messages` — the chat transcript. -- **Provider API keys are *not* in the context.** HexUI does not store or forward +- **Provider API keys are *not* in the context.** HexKit does not store or forward them — your backend reads its own provider keys (OpenAI, Google, …) from its own environment. The platform never holds your model credentials. - `context.files` — files the user attached to the conversation (persist across turns; forwarded every run). `content` is the decoded text for text mimes, `null` for binary (fetch by `id` is post-v1). Inline them into the prompt / provider content blocks as your framework needs. -- `context.user` — caller identity. Always exactly three keys: `id` (the HexUI +- `context.user` — caller identity. Always exactly three keys: `id` (the HexKit user uuid), `name` (display name or `null`), and `role` (free-text string or - `null`). HexUI does not interpret `role`; it's there so policy-aware runtimes + `null`). HexKit does not interpret `role`; it's there so policy-aware runtimes (hexgate, etc.) can scope per-call decisions to the calling user. **NEVER** includes email, password hash, or any internal identifier. An agent backend that doesn't use this can ignore the block. diff --git a/Makefile b/Makefile index 1d2240d..ea0ccd9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# HexaUI dev Makefile — see QUICKSTART.md for prerequisites (uv + Node 18+). +# HexKit dev Makefile — see QUICKSTART.md for prerequisites (uv + Node 18+). # # Common flow on a fresh clone: # diff --git a/QUICKSTART.md b/QUICKSTART.md index 44a22cc..22797af 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -22,7 +22,7 @@ Without API keys the agents reply with an echo placeholder. That's fine for a fi ## One-time setup -From the repo root (`HexUI/`): +From the repo root (`HexKit/`): ```bash make setup @@ -58,7 +58,7 @@ To enable real LLM replies (instead of echo), prepend the env var: AGENT_ENABLE_LLM=1 bash demo/scripts/run-backends.sh ``` -Provider keys live in the **agent backend's** environment, not the app — set `OPENAI_API_KEY` (Probe + healthcare/devops) and/or `GOOGLE_API_KEY` (Orbit) in your shell or in `demo/agent-server/.env` before starting the backends. HexUI never holds your model keys. +Provider keys live in the **agent backend's** environment, not the app — set `OPENAI_API_KEY` (Probe + healthcare/devops) and/or `GOOGLE_API_KEY` (Orbit) in your shell or in `demo/agent-server/.env` before starting the backends. HexKit never holds your model keys. #### Terminal 2 — frontend diff --git a/README.md b/README.md index 32dd97c..092dd0e 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@
-# HexUI +# HexKit
A **UI/UX-first multi-agent chat platform**. Developers bring their own -streaming agent backend (any framework); HexaUI provides the chat experience — +streaming agent backend (any framework); HexKit provides the chat experience — a configurable, YAML-driven UI, conversation history, folders, file attachments — and a thin proxy that normalizes any framework's event stream into one schema the UI renders.

- HexaUI — the DevOps agent: a YAML-driven dashboard (service metrics + table) above a streaming chat, themed by the active agent's accent color. + HexKit — the DevOps agent: a YAML-driven dashboard (service metrics + table) above a streaming chat, themed by the active agent's accent color.

- CI + CI License: MIT Python 3.11+ Node 18+ @@ -67,7 +67,7 @@ events; the **proxy translates** and the **UI renders from YAML**. See | Path | Purpose | |---|---| | [custom-UI/](custom-UI/) | The product's heart: a React + TS library that renders a configurable agent UI from YAML (`` + 12 built-in widgets). Theme bridge, streaming chat, the actions/`data_source` system. | -| [front-app/](front-app/) | The HexaUI shell that consumes `custom-UI` and talks to the proxy. | +| [front-app/](front-app/) | The HexKit shell that consumes `custom-UI` and talks to the proxy. | | [proxy-server/](proxy-server/) | The platform backend (FastAPI): JWT auth, conversations, folders, files, and the per-framework translators that normalize native events into the hexa SSE schema. Import package stays `platform_backend`. | | [packages/hexa-events/](packages/hexa-events/) | The internal event schema package consumed by the proxy (a local path dependency). | | [demo/](demo/) | The runnable reference backends: [`agent-server/`](demo/agent-server/) (a contract-conformant developer backend with 6 sample agents), [`hexgate-agent/`](demo/hexgate-agent/) (a standalone hexgate-wrapped backend), [`starter-agent/`](demo/starter-agent/) (a minimal **copy-me** backend — the whole contract in one file), and [`scripts/`](demo/scripts/) (run + smoke checks, incl. the `verify_backend.py` conformance CLI). | @@ -103,8 +103,8 @@ To get real model replies rather than the deterministic echo/canned fallback, put your provider keys in the **agent backend's environment** (`OPENAI_API_KEY` for Probe + the healthcare/devops agents, `GOOGLE_API_KEY` for Orbit) and start it with `AGENT_ENABLE_LLM=1` — see [`demo/agent-server/.env.sample`](demo/agent-server/.env.sample). -HexUI never holds your model keys. The **Settings** page carries only your -display name and a free-text `role`; if you point HexUI at a `hexgate`-wrapped +HexKit never holds your model keys. The **Settings** page carries only your +display name and a free-text `role`; if you point HexKit at a `hexgate`-wrapped agent, that role is forwarded to the agent and drives hexgate's per-tool policy + audit pipeline. diff --git a/custom-UI/src/lib/context-card.tsx b/custom-UI/src/lib/context-card.tsx index 556536c..9bc1375 100644 --- a/custom-UI/src/lib/context-card.tsx +++ b/custom-UI/src/lib/context-card.tsx @@ -3,7 +3,7 @@ import { useAgentUIContext } from "../runtime/context.js"; /** * Frame for a display widget (table / markdown) that can toggle its content - * into the conversation's model context. Ported from the HexaUI "Context Toggle" + * into the conversation's model context. Ported from the HexKit "Context Toggle" * design: a header (icon + caption + the pill switch) over the widget body; when * on, the card lights to the agent accent with a one-shot scan/glow. * diff --git a/custom-UI/src/registry/builtin.ts b/custom-UI/src/registry/builtin.ts index 0611efc..92763af 100644 --- a/custom-UI/src/registry/builtin.ts +++ b/custom-UI/src/registry/builtin.ts @@ -68,7 +68,7 @@ export const builtinWidgets: AnyWidgetDefinition[] = [ schema: AiChatInputWidgetSchema, component: AiChatInputWidgetComponent, chromeless: true, - // HexaUI: the composer is constant chrome pinned to the bottom of the chat + // HexKit: the composer is constant chrome pinned to the bottom of the chat // area (the transcript scrolls above it), not a widget in the content flow. slot: "footer", }), diff --git a/custom-UI/src/schema/page.ts b/custom-UI/src/schema/page.ts index 32f232c..1307dd0 100644 --- a/custom-UI/src/schema/page.ts +++ b/custom-UI/src/schema/page.ts @@ -27,7 +27,7 @@ export const PageSchema = { layout_type: { enum: ["grid", "flex"] }, /** * The active agent's signature color — the ONE variable that recolors the - * whole page (HexaUI's core principle). Bridges to shadcn `--primary` / + * whole page (HexKit's core principle). Bridges to shadcn `--primary` / * `--ring` (and the legacy `--accent` agent usage). Takes precedence over * `theme.accent`. Hex (`#RGB`, `#RRGGBB`, `#RRGGBBAA`). */ diff --git a/custom-UI/src/shadcn.css b/custom-UI/src/shadcn.css index 3408ea5..38af3ba 100644 --- a/custom-UI/src/shadcn.css +++ b/custom-UI/src/shadcn.css @@ -1,5 +1,5 @@ /* - * agent-ui shadcn base layer — themed to HexaUI. + * agent-ui shadcn base layer — themed to HexKit. * * Consumer usage (from your app's CSS entry): * @import "agent-ui/shadcn.css"; @@ -7,8 +7,8 @@ * Pair with the Tailwind preset: * presets: [require("agent-ui/tailwind-preset")] * - * The shadcn HSL tokens are mapped onto the HexaUI neutral scale (Spec §2), so - * every native widget inherits the HexaUI look automatically. The ONE color in + * The shadcn HSL tokens are mapped onto the HexKit neutral scale (Spec §2), so + * every native widget inherits the HexKit look automatically. The ONE color in * the product is the active agent's hue: `page.main_color` → `--primary` / * `--ring` (set inline at the page root by the theme bridge) and a raw hex * `--accent-color` for links / carets / status dots. Chrome stays monochrome — @@ -20,7 +20,7 @@ @layer base { :root { - /* ----- HexaUI light neutral scale (Spec §2) ----- */ + /* ----- HexKit light neutral scale (Spec §2) ----- */ --background: 0 0% 100%; /* --bg #ffffff */ --foreground: 216 14% 11%; /* --text #191c21 */ @@ -52,7 +52,7 @@ --radius: 0.6875rem; /* --r-md 11px */ - /* ----- HexaUI raw tokens (for widget chrome that needs them) ----- */ + /* ----- HexKit raw tokens (for widget chrome that needs them) ----- */ --hx-bg: #ffffff; --hx-bg-2: #f5f6f7; --hx-surface: #ffffff; @@ -78,7 +78,7 @@ } .dark { - /* ----- HexaUI dark neutral scale (Spec §2) ----- */ + /* ----- HexKit dark neutral scale (Spec §2) ----- */ --background: 240 2% 12%; /* --bg #1e1e1f */ --foreground: 220 9% 93%; /* --text #ecedef */ @@ -106,7 +106,7 @@ --input: 240 3% 22%; --ring: 174 43% 47%; - /* ----- HexaUI raw tokens (dark) ----- */ + /* ----- HexKit raw tokens (dark) ----- */ --hx-bg: #1e1e1f; --hx-bg-2: #181819; --hx-surface: #282829; diff --git a/custom-UI/src/styles.css b/custom-UI/src/styles.css index 9560662..5fb1b06 100644 --- a/custom-UI/src/styles.css +++ b/custom-UI/src/styles.css @@ -281,7 +281,7 @@ } /* ============================================================ - * HexaUI chat — metaball thinking loader, streaming caret, status shimmer. + * HexKit chat — metaball thinking loader, streaming caret, status shimmer. * All tint from the agent color via --accent-color (set by the theme bridge), * falling back to the shadcn primary. * ============================================================ */ @@ -386,7 +386,7 @@ /* ============================================================ File handling — composer attach popover + attached pills. - Ported from the HexaUI design handoff; tokens scoped to `.hxf` + Ported from the HexKit design handoff; tokens scoped to `.hxf` and mapped onto the shadcn palette + the active agent accent. The agent stays the only color; glyphs are neutral. ============================================================ */ diff --git a/custom-UI/src/widgets/ai-chat-input.tsx b/custom-UI/src/widgets/ai-chat-input.tsx index 9a0de01..0f52aad 100644 --- a/custom-UI/src/widgets/ai-chat-input.tsx +++ b/custom-UI/src/widgets/ai-chat-input.tsx @@ -25,7 +25,7 @@ const SHORTCUT_LABEL = : "Ctrl K"; /** - * The constant HexaUI composer: one quiet field on a surface card — attach on + * The constant HexKit composer: one quiet field on a surface card — attach on * the left, send on the right. When the bridge exposes a file capability, the * attach button opens a menu to upload a new file or reuse one from the * library; attached files persist on the conversation and show as a tray of diff --git a/custom-UI/src/widgets/tool-calls.tsx b/custom-UI/src/widgets/tool-calls.tsx index 2e7b2fa..a812b9f 100644 --- a/custom-UI/src/widgets/tool-calls.tsx +++ b/custom-UI/src/widgets/tool-calls.tsx @@ -156,7 +156,7 @@ function StatusDot({ }: { status: FoldedEntry["status"]; }): JSX.Element { - // HexaUI: amber pulsing (running) → agent accent (done) → rose (error). + // HexKit: amber pulsing (running) → agent accent (done) → rose (error). // `bg-primary` is the agent color via the theme bridge (page.main_color). const tone = status === "running" diff --git a/demo-users.yaml b/demo-users.yaml index 82c8d3f..754fa24 100644 --- a/demo-users.yaml +++ b/demo-users.yaml @@ -1,4 +1,4 @@ -# Demo users for HexUI. Loaded at startup when PLATFORM_DEMO_USERS_FILE +# Demo users for HexKit. Loaded at startup when PLATFORM_DEMO_USERS_FILE # points at this file (`make dev` sets that env var by default). # # Idempotent: existing rows (matched by email) are LEFT ALONE — changing a @@ -9,7 +9,7 @@ # throwaway accounts. # # `role` is optional and opaque: hexgate-wrapped agents read it via -# `User(role=...)`. HexUI itself never interprets the string — every team +# `User(role=...)`. HexKit itself never interprets the string — every team # defines their own role vocabulary in their hexgate policy. A role only # means something to the agent whose policy defines it; talking to the other # agent falls through to that policy's fail-closed `default` (deny). diff --git a/demo/agent-server/pyproject.toml b/demo/agent-server/pyproject.toml index 9e1ad36..513796e 100644 --- a/demo/agent-server/pyproject.toml +++ b/demo/agent-server/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "agent-server" version = "0.1.0" -description = "Reference developer backend for the HexaUI streaming contract" +description = "Reference developer backend for the HexKit streaming contract" requires-python = ">=3.11" dependencies = [ "fastapi>=0.115", @@ -43,4 +43,4 @@ build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/agent_server"] -# Ruff config is shared at the repo root (HexUI/ruff.toml). +# Ruff config is shared at the repo root (HexKit/ruff.toml). diff --git a/demo/agent-server/src/agent_server/__init__.py b/demo/agent-server/src/agent_server/__init__.py index 16ef2b6..8525a4b 100644 --- a/demo/agent-server/src/agent_server/__init__.py +++ b/demo/agent-server/src/agent_server/__init__.py @@ -1,4 +1,4 @@ -"""Reference developer backend — the executable spec for the HexaUI contract.""" +"""Reference developer backend — the executable spec for the HexKit contract.""" import os diff --git a/demo/agent-server/src/agent_server/agents/base.py b/demo/agent-server/src/agent_server/agents/base.py index 9d5d491..60f608e 100644 --- a/demo/agent-server/src/agent_server/agents/base.py +++ b/demo/agent-server/src/agent_server/agents/base.py @@ -3,7 +3,7 @@ An agent declares the `framework` whose native events it emits, and its `run` is an async generator yielding those native events (already JSON-able). The server route wraps each as `{"framework": ..., "event": ...}` and frames it to -SSE; the HexaUI proxy selects the matching translator and normalizes the stream. +SSE; the HexKit proxy selects the matching translator and normalizes the stream. `framework="native"` means the agent emits the minimal already-normalized events (see `agent_server.protocol`) — the zero-translation escape hatch. diff --git a/demo/agent-server/src/agent_server/agents/devops.py b/demo/agent-server/src/agent_server/agents/devops.py index d662403..542c6f8 100644 --- a/demo/agent-server/src/agent_server/agents/devops.py +++ b/demo/agent-server/src/agent_server/agents/devops.py @@ -1,4 +1,4 @@ -"""HexaUI contract wrapper for the devops agent. +"""HexKit contract wrapper for the devops agent. The agent runs on Google ADK, but its model is OpenAI via LiteLLM — which reads ``OPENAI_API_KEY`` from the environment. This resolves that key, picks the plain @@ -45,12 +45,12 @@ async def run( text = protocol.last_user_text(input) # HexGate-gated path whenever HexGate is configured; plain ADK otherwise. if os.getenv("HEXGATE_KEY"): - # Scope policy decisions to the signed-in HexUI user. `id` / `role` + # Scope policy decisions to the signed-in HexKit user. `id` / `role` # ride in `context.user` (CONTRACT.md §5); fall back to the static # demo identity and HEXGATE_ROLE for standalone runs that send no # user block. caller = protocol.caller(context) - user_id = caller.get("id") or "hexui-demo" + user_id = caller.get("id") or "hexkit-demo" role = caller.get("role") or os.getenv("HEXGATE_ROLE", "default") if role not in _DEVOPS_ROLES: role = "default" diff --git a/demo/agent-server/src/agent_server/agents/devops_agent.py b/demo/agent-server/src/agent_server/agents/devops_agent.py index 70fefc6..0bb2b0a 100644 --- a/demo/agent-server/src/agent_server/agents/devops_agent.py +++ b/demo/agent-server/src/agent_server/agents/devops_agent.py @@ -2,7 +2,7 @@ The tools + ``agent``, and how to invoke it: ``stream`` (plain ADK runner) and ``stream_as`` (the same agent gated by HexGate policy). Vendored from -``hexgate/examples/devops_agent.py``. The HexaUI contract wrapper that the +``hexgate/examples/devops_agent.py``. The HexKit contract wrapper that the server runs lives in ``devops.py``; the ADK ``Event`` → native projection lives in ``google_adk``. @@ -97,8 +97,8 @@ def delete_resource(name: str, env: str) -> str: # ── Invocation ─────────────────────────────────────────────────────────────── _APP_NAME = "devops_agent" -_USER_ID = "hexui-demo" -_SESSION_ID = "hexui-demo-devops" +_USER_ID = "hexkit-demo" +_SESSION_ID = "hexkit-demo-devops" def _message(text: str) -> types.Content: @@ -124,7 +124,7 @@ async def stream_as(text: str, *, user_id: str, role: str) -> AsyncIterator[Any] ``role`` (viewer < operator < admin) is what flips each decision. ``HexgateRunner`` reads ``HEXGATE_KEY`` from the environment. - ``user_id`` and ``role`` come from the HexUI caller (``context.user``); the + ``user_id`` and ``role`` come from the HexKit caller (``context.user``); the wrapper in ``devops.py`` resolves them. """ from hexgate.adapters.google import HexgateRunner diff --git a/demo/agent-server/src/agent_server/agents/healthcare.py b/demo/agent-server/src/agent_server/agents/healthcare.py index 2034ad2..65ddb9f 100644 --- a/demo/agent-server/src/agent_server/agents/healthcare.py +++ b/demo/agent-server/src/agent_server/agents/healthcare.py @@ -1,4 +1,4 @@ -"""HexaUI contract wrapper for the healthcare agent. +"""HexKit contract wrapper for the healthcare agent. Resolves the OpenAI key, picks the plain or HexGate-gated path, and forwards each SDK event as a native event. The agent itself lives in ``healthcare_agent``; @@ -39,12 +39,12 @@ async def run( # HexGate-gated path whenever HexGate is configured; plain SDK otherwise. if os.getenv("HEXGATE_KEY"): - # Scope policy decisions to the signed-in HexUI user. `id` / `role` + # Scope policy decisions to the signed-in HexKit user. `id` / `role` # ride in `context.user` (CONTRACT.md §5); fall back to the static # demo identity and HEXGATE_ROLE for standalone runs that send no # user block. caller = protocol.caller(context) - user_id = caller.get("id") or "hexui-demo" + user_id = caller.get("id") or "hexkit-demo" role = caller.get("role") or os.getenv("HEXGATE_ROLE", "nurse") events = healthcare_agent.stream_as( agent_input(input), user_id=user_id, role=role diff --git a/demo/agent-server/src/agent_server/agents/healthcare_agent.py b/demo/agent-server/src/agent_server/agents/healthcare_agent.py index ed85993..63c6691 100644 --- a/demo/agent-server/src/agent_server/agents/healthcare_agent.py +++ b/demo/agent-server/src/agent_server/agents/healthcare_agent.py @@ -2,7 +2,7 @@ The tools + ``agent``, and how to invoke it: ``stream`` (plain SDK) and ``stream_as`` (the same agent gated by HexGate policy). Vendored from -``hexgate/examples/healthcare_agent.py``. The HexaUI contract wrapper that the +``hexgate/examples/healthcare_agent.py``. The HexKit contract wrapper that the server runs lives in ``healthcare.py``. """ @@ -112,14 +112,14 @@ async def stream_as(input: Any, *, user_id: str, role: str) -> AsyncIterator[Any """Same as :func:`stream`, but through HexGate as ``user_id`` / ``role`` — every tool call is policy-gated against the calling user. - ``user_id`` and ``role`` come from the HexUI caller (``context.user``); the + ``user_id`` and ``role`` come from the HexKit caller (``context.user``); the wrapper in ``healthcare.py`` resolves them. Policy decisions and audit events are tagged with this identity. """ from hexgate.adapters.openai import HexgateRunner from hexgate.runtime import User - user = User(user_id=user_id, session_id="hexui-demo-healthcare", role=role) + user = User(user_id=user_id, session_id="hexkit-demo-healthcare", role=role) result = HexgateRunner().run_streamed(agent, input, user=user) async for event in result.stream_events(): yield event diff --git a/demo/agent-server/src/agent_server/agents/hr.py b/demo/agent-server/src/agent_server/agents/hr.py index 47f9af3..da7d0cb 100644 --- a/demo/agent-server/src/agent_server/agents/hr.py +++ b/demo/agent-server/src/agent_server/agents/hr.py @@ -1,4 +1,4 @@ -"""HexaUI contract wrapper for the HR (RH) agent. +"""HexKit contract wrapper for the HR (RH) agent. Resolves the OpenAI key, picks the plain or HexGate-gated path, and projects each LangChain event into a native event. The agent lives in ``hr_agent``; the caller's @@ -46,7 +46,7 @@ async def run( # `name` / `role` ride in `context.user` (CONTRACT.md §5); fall back to # a static identity for standalone runs that send no user block. caller = protocol.caller(context) - identity = caller.get("name") or "hexui-demo" + identity = caller.get("name") or "hexkit-demo" role = caller.get("role") or os.getenv("HEXGATE_ROLE", "default") if role not in _HR_ROLES: role = "default" diff --git a/demo/agent-server/src/agent_server/agents/hr_agent.py b/demo/agent-server/src/agent_server/agents/hr_agent.py index 0c85a79..f1b4d67 100644 --- a/demo/agent-server/src/agent_server/agents/hr_agent.py +++ b/demo/agent-server/src/agent_server/agents/hr_agent.py @@ -1,6 +1,6 @@ """HR (RH) assistant agent — RBAC with field-level scoping (LangChain). -Vendored from ``hexgate/examples/hr_agent.py``; the HexaUI wrapper is ``hr.py``. +Vendored from ``hexgate/examples/hr_agent.py``; the HexKit wrapper is ``hr.py``. One agent definition — the caller's ROLE flips every decision via the platform policy (resolved by agent name ``hr_agent``; source in ``hexgate/examples/hr_policy.yaml``). The escalation ladder, least → most @@ -47,7 +47,7 @@ def _actor() -> str: from hexgate.runtime import get_current_user user = get_current_user() - return user.user_id if user is not None else "hexui-demo" + return user.user_id if user is not None else "hexkit-demo" # --------------------------------------------------------------------------- @@ -287,7 +287,7 @@ async def stream_as(input: Any, *, user_id: str, role: str) -> AsyncIterator[Any (default < manager < gestionnaire_rh) flips each decision.""" from hexgate.runtime import User - user = User(user_id=user_id, role=role, session_id="hexui-demo-hr") + user = User(user_id=user_id, role=role, session_id="hexkit-demo-hr") async for event in _enforced_agent().astream_events( messages_input(input), user=user ): diff --git a/demo/agent-server/src/agent_server/agents/itsm.py b/demo/agent-server/src/agent_server/agents/itsm.py index 2675c9c..acdcdae 100644 --- a/demo/agent-server/src/agent_server/agents/itsm.py +++ b/demo/agent-server/src/agent_server/agents/itsm.py @@ -1,8 +1,8 @@ -"""HexaUI contract wrapper for the ITSM change-request agent. +"""HexKit contract wrapper for the ITSM change-request agent. Resolves the OpenAI key, picks the plain or HexGate-gated path, and projects each LangChain event into a native event. The agent lives in ``itsm_agent``; ownership -keys off the caller's **name** (HexUI never forwards email — see ``itsm_db``). +keys off the caller's **name** (HexKit never forwards email — see ``itsm_db``). """ from __future__ import annotations @@ -41,7 +41,7 @@ async def run( # `name` / `role` ride in `context.user` (CONTRACT.md §5); fall back to # a static identity for standalone runs that send no user block. caller = protocol.caller(context) - identity = caller.get("name") or "hexui-demo" + identity = caller.get("name") or "hexkit-demo" role = caller.get("role") or os.getenv("HEXGATE_ROLE", "requester") events = itsm_agent.stream_as(input, user_id=identity, role=role) else: diff --git a/demo/agent-server/src/agent_server/agents/itsm_agent.py b/demo/agent-server/src/agent_server/agents/itsm_agent.py index 9907296..6a66f58 100644 --- a/demo/agent-server/src/agent_server/agents/itsm_agent.py +++ b/demo/agent-server/src/agent_server/agents/itsm_agent.py @@ -1,12 +1,12 @@ """ITSM Change-Request agent — RBAC + state-machine guard (deepagents/LangChain). -Vendored from ``hexgate/examples/itsm_agent.py``; the HexaUI wrapper is ``itsm.py``. +Vendored from ``hexgate/examples/itsm_agent.py``; the HexKit wrapper is ``itsm.py``. Two checks per action: the policy answers "does the ROLE grant this tool?" (each transition is its own tool, so separation of duties is structural); the tool body answers "is the transition valid from the current state, and does the actor own the record?" — keyed off the trusted ``User`` the policy can't see. -Identity = the caller's NAME (HexUI never forwards email — see ``itsm_db``), so +Identity = the caller's NAME (HexKit never forwards email — see ``itsm_db``), so ownership compares against ``requester_name`` / ``implementer_name``. new ──(requester)──▶ Assess ──(change_manager)──▶ Authorize ──(cab_manager)──▶ Schedule @@ -323,7 +323,7 @@ async def stream_as(input: Any, *, user_id: str, role: str) -> AsyncIterator[Any / scope); ``role`` is the opaque role from ``context.user``.""" from hexgate.runtime import User - user = User(user_id=user_id, role=role, session_id="hexui-demo-itsm") + user = User(user_id=user_id, role=role, session_id="hexkit-demo-itsm") async for event in _enforced_agent().astream_events( messages_input(input), user=user ): diff --git a/demo/agent-server/src/agent_server/agents/itsm_db.py b/demo/agent-server/src/agent_server/agents/itsm_db.py index d0801d0..7423fc6 100644 --- a/demo/agent-server/src/agent_server/agents/itsm_db.py +++ b/demo/agent-server/src/agent_server/agents/itsm_db.py @@ -1,7 +1,7 @@ """Minimal ITSM datastore for the change-request agent. Vendored from ``hexgate/examples/itsm_db.py``, but keyed off the caller's **name** -(``requester_name`` / ``implementer_name``) rather than email, since HexUI's proxy +(``requester_name`` / ``implementer_name``) rather than email, since HexKit's proxy never forwards email. Plain CRUD over an in-memory stdlib ``sqlite3`` DB plus a local audit trail (UC-10); the tools enforce state/ownership. Process-global, like ``devops_state``. diff --git a/demo/agent-server/src/agent_server/agents/openai_agents.py b/demo/agent-server/src/agent_server/agents/openai_agents.py index d7b66fc..e59dff0 100644 --- a/demo/agent-server/src/agent_server/agents/openai_agents.py +++ b/demo/agent-server/src/agent_server/agents/openai_agents.py @@ -1,8 +1,8 @@ -"""Project OpenAI Agents SDK stream events into HexaUI native events. +"""Project OpenAI Agents SDK stream events into HexKit native events. Reusable for any ``agents.Agent``: ``to_native_event`` maps one ``stream_events()`` item to the native JSON event the proxy's -``OpenAIAgentsTranslator`` reads; ``agent_input`` shapes HexaUI input for the SDK. +``OpenAIAgentsTranslator`` reads; ``agent_input`` shapes HexKit input for the SDK. """ from __future__ import annotations @@ -13,7 +13,7 @@ def agent_input(input: dict[str, Any]) -> Any: - """HexaUI ``{"messages": [...]}`` → SDK input (full transcript, or last user text).""" + """HexKit ``{"messages": [...]}`` → SDK input (full transcript, or last user text).""" messages = (input or {}).get("messages") if isinstance(messages, list) and messages: return messages diff --git a/demo/agent-server/src/agent_server/protocol.py b/demo/agent-server/src/agent_server/protocol.py index c0d2f96..6bf483c 100644 --- a/demo/agent-server/src/agent_server/protocol.py +++ b/demo/agent-server/src/agent_server/protocol.py @@ -2,7 +2,7 @@ This is the entire surface a developer's backend has to emit. Each event is one SSE frame — ``data: {compact-json}\\n\\n`` — on a ``text/event-stream`` response. -The HexaUI proxy normalizes these into the rich internal event schema, +The HexKit proxy normalizes these into the rich internal event schema, synthesizing run ids, sequence numbers, block lifecycle, and the ``run_start`` / ``run_end`` envelope. Developers never construct any of that. diff --git a/demo/agent-server/src/agent_server/roster.py b/demo/agent-server/src/agent_server/roster.py index e4fc67e..6925189 100644 --- a/demo/agent-server/src/agent_server/roster.py +++ b/demo/agent-server/src/agent_server/roster.py @@ -1,7 +1,7 @@ """The agent roster + per-agent ``ui.yaml`` loading. The roster is the ``GET /agents`` payload: one entry per agent with the -fields the HexaUI proxy/shell needs to render a picker and theme the chrome. +fields the HexKit proxy/shell needs to render a picker and theme the chrome. ``main_color`` is the single color that drives the active agent's accent. """ diff --git a/demo/agent-server/src/agent_server/routes/agents.py b/demo/agent-server/src/agent_server/routes/agents.py index 8ab39d0..f026b65 100644 --- a/demo/agent-server/src/agent_server/routes/agents.py +++ b/demo/agent-server/src/agent_server/routes/agents.py @@ -1,4 +1,4 @@ -"""The contract endpoints the HexaUI proxy calls. +"""The contract endpoints the HexKit proxy calls. GET /agents roster GET /agents/{id}/ui per-agent ui.yaml (text/yaml) diff --git a/demo/agent-server/src/agent_server/server/app.py b/demo/agent-server/src/agent_server/server/app.py index e7d65d3..7f3c843 100644 --- a/demo/agent-server/src/agent_server/server/app.py +++ b/demo/agent-server/src/agent_server/server/app.py @@ -11,8 +11,8 @@ def create_app() -> FastAPI: app = FastAPI( - title="HexaUI Reference Agent Server", - description="Executable spec for the HexaUI streaming contract", + title="HexKit Reference Agent Server", + description="Executable spec for the HexKit streaming contract", version="0.1.0", ) # In-memory run registry: run_id -> cancel Event, populated by the stream diff --git a/demo/hexgate-agent/README.md b/demo/hexgate-agent/README.md index 9c782c1..46e3bc9 100644 --- a/demo/hexgate-agent/README.md +++ b/demo/hexgate-agent/README.md @@ -1,19 +1,19 @@ -# hexgate-agent — a hexgate-wrapped agent on the HexaUI contract +# hexgate-agent — a hexgate-wrapped agent on the HexKit contract A developer backend that serves an agent wrapped with **hexgate** (the authorization-infrastructure SDK from the security-platform team) over the five [CONTRACT.md](../CONTRACT.md) endpoints. It exists to demonstrate two things: 1. **Schema compatibility.** Hexgate emits its own normalized event stream; - HexaUI's internal schema is a near-twin. This backend forwards hexgate's + HexKit's internal schema is a near-twin. This backend forwards hexgate's events verbatim and the proxy's `HexgateTranslator` maps them onto the shared `RunEmitter`. The round-trip proves the "same events" decision between the two products holds on the wire. -2. **End-to-end user identity.** When the HexUI proxy sends +2. **End-to-end user identity.** When the HexKit proxy sends `context.user = {id, name, role}` (CONTRACT.md §5), this backend opens an `async with hexgate.User(user_id=..., role=...)` block around the run. The role drives hexgate's per-tool policy decisions, biscuit attenuation, and - audit emission to the hexgate cloud — so the demo's HexUI users show up + audit emission to the hexgate cloud — so the demo's HexKit users show up in the cloud dashboard tagged with whatever role you set in **Settings**. ## The events @@ -37,9 +37,9 @@ hexgate's own envelope events and re-drives the emitter from the content events 3.11). The venv below must use a 3.13+ interpreter. - **`HEXGATE_KEY`** (optional, for cloud audit) — the dev/admin key that authenticates this backend to your hexgate cloud project. Per-request biscuit - attenuation scopes each call down to the HexUI user, so one key serves all - HexUI users. -- **`OPENAI_API_KEY`** — read from this backend's process env. HexUI does not + attenuation scopes each call down to the HexKit user, so one key serves all + HexKit users. +- **`OPENAI_API_KEY`** — read from this backend's process env. HexKit does not send provider keys. ## Run it @@ -57,7 +57,7 @@ demo/hexgate-agent/.venv/bin/python -m hexgate_agent # serves on :8080 The agent registers as `guard` with `framework: "hexgate"`. Sending it a "what time is it?" message exercises the tool-call path: the call comes through as hexgate `tool_start`/`tool_end` and lands in the **tool-calls** -widget in HexUI's chat surface. +widget in HexKit's chat surface. ## Verify the contract @@ -73,7 +73,7 @@ demo/hexgate-agent/.venv/bin/python demo/scripts/verify_backend.py http://127.0. `context.user.role` and opens `async with hexgate.User(...)` around `stream_agent(...)`. From there, hexgate's policy enforcement picks the role's rules from your `policy.yaml` (or your registered cloud policy) and audit events -stream to the cloud, tagged with the HexUI user. **Policy enforcement** is +stream to the cloud, tagged with the HexKit user. **Policy enforcement** is opt-in — add `agent = agent.enforce_policy("policy.yaml")` after `create_agent(...)` once you want denials to flow through too; a blocked tool surfaces as a hexgate `error` event, which the translator already handles. diff --git a/demo/hexgate-agent/pyproject.toml b/demo/hexgate-agent/pyproject.toml index d4459b3..8651667 100644 --- a/demo/hexgate-agent/pyproject.toml +++ b/demo/hexgate-agent/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "hexgate-agent" version = "0.1.0" -description = "HexaUI backend serving a hexgate-wrapped agent — forwards hexgate's normalized events tagged framework='hexgate'" +description = "HexKit backend serving a hexgate-wrapped agent — forwards hexgate's normalized events tagged framework='hexgate'" # hexgate requires >=3.13; this backend inherits that floor (the other demo # backends only need 3.11). Create this venv with a 3.13+ interpreter. requires-python = ">=3.13" diff --git a/demo/hexgate-agent/src/hexgate_agent/__init__.py b/demo/hexgate-agent/src/hexgate_agent/__init__.py index aafb8cc..3f0ffc6 100644 --- a/demo/hexgate-agent/src/hexgate_agent/__init__.py +++ b/demo/hexgate-agent/src/hexgate_agent/__init__.py @@ -1 +1 @@ -"""A HexaUI developer backend serving a hexgate-wrapped agent.""" +"""A HexKit developer backend serving a hexgate-wrapped agent.""" diff --git a/demo/hexgate-agent/src/hexgate_agent/agent.py b/demo/hexgate-agent/src/hexgate_agent/agent.py index a4e7146..304fe6d 100644 --- a/demo/hexgate-agent/src/hexgate_agent/agent.py +++ b/demo/hexgate-agent/src/hexgate_agent/agent.py @@ -5,23 +5,23 @@ 1. **What it forwards.** A hexgate agent exposes a normalized event stream via ``hexgate.stream_agent(...)`` — hexgate's own unified schema (``run_start`` / ``block_delta`` / ``tool_start`` / ...). We do **not** reshape those events - into HexaUI's minimal `native` vocabulary; we forward them verbatim, tagged + into HexKit's minimal `native` vocabulary; we forward them verbatim, tagged ``framework: "hexgate"``, and the proxy's ``HexgateTranslator`` maps them onto the rich internal schema. That round-trip is the whole point: it proves the two products' "same events" decision actually holds on the wire. -2. **The user identity it carries.** When the HexUI proxy sends +2. **The user identity it carries.** When the HexKit proxy sends ``context.user = {id, name, role}`` (CONTRACT.md §5), this backend opens an ``async with hexgate.User(user_id=..., role=...)`` block around the run. That ContextVar drives: - per-tool policy decisions (``enforce_policy(role, tool, args)``); - per-request biscuit attenuation by ``HexgateClient``; - - audit events POSTed to the hexgate cloud, tagged with the HexUI user. + - audit events POSTed to the hexgate cloud, tagged with the HexKit user. To see those audit events on the cloud dashboard, set ``HEXGATE_KEY`` in this process's env (it's the dev/admin key — biscuits attenuate per request - to scope back down to the HexUI user). + to scope back down to the HexKit user). Wrapping vs. enforcement: ``create_agent`` already returns a hexgate-wrapped agent (the runtime wrap whose event stream we test here). Policy enforcement is @@ -133,7 +133,7 @@ async def run_hexgate_agent( exact shape the proxy's HexgateTranslator reads. The caller tags every frame with ``framework: "hexgate"``. """ - # The OpenAI key comes from this backend's own environment — HexUI does not + # The OpenAI key comes from this backend's own environment — HexKit does not # send provider keys. Read it per run; never persist or log it. api_key = os.getenv("OPENAI_API_KEY") if not api_key: @@ -153,7 +153,7 @@ async def run_hexgate_agent( agent, handler = _get_agent(api_key) messages = _messages_with_files(input, context) - # Bind the run to the HexUI caller's identity. hexgate reads the ContextVar + # Bind the run to the HexKit caller's identity. hexgate reads the ContextVar # set by `async with User(...)` for policy decisions, biscuit attenuation, # and audit emission. Missing user block = no scoping (the SDK still runs; # decisions just won't be tagged with a user). diff --git a/demo/hexgate-agent/src/hexgate_agent/app.py b/demo/hexgate-agent/src/hexgate_agent/app.py index a20da14..a6765d1 100644 --- a/demo/hexgate-agent/src/hexgate_agent/app.py +++ b/demo/hexgate-agent/src/hexgate_agent/app.py @@ -1,4 +1,4 @@ -"""The five HexaUI contract endpoints for a hexgate-wrapped agent. +"""The five HexKit contract endpoints for a hexgate-wrapped agent. Structurally identical to demo/starter-agent/ — same five endpoints, same SSE framing — with two differences: @@ -121,7 +121,7 @@ async def invoke_action( def create_app() -> FastAPI: - app = FastAPI(title="HexaUI Hexgate Agent", version="0.1.0") + app = FastAPI(title="HexKit Hexgate Agent", version="0.1.0") # run_id -> cancel Event. Process-local; a multi-worker deploy needs a # shared store. Created here so it exists before any lifespan runs. app.state.runs = {} diff --git a/demo/scripts/README.md b/demo/scripts/README.md index dbc779b..a9bb7bc 100644 --- a/demo/scripts/README.md +++ b/demo/scripts/README.md @@ -1,6 +1,6 @@ # M1 smoke checks -Executable verification of the HexaUI streaming contract (M1). Both run against +Executable verification of the HexKit streaming contract (M1). Both run against the real code — no mocks of the contract itself. First-time setup (creates the venvs from the pyprojects; needs [`uv`](https://docs.astral.sh/uv/)): diff --git a/demo/scripts/run-backends.sh b/demo/scripts/run-backends.sh index 19bcefe..c0b1b85 100644 --- a/demo/scripts/run-backends.sh +++ b/demo/scripts/run-backends.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Launch the HexaUI backends for local dev — agent-server (:8880) + proxy (:8800) +# Launch the HexKit backends for local dev — agent-server (:8880) + proxy (:8800) # on a throwaway SQLite DB (no Postgres needed). Run from the repo root under WSL: # # bash demo/scripts/run-backends.sh @@ -27,7 +27,7 @@ trap cleanup EXIT INT TERM export AGENT_ENABLE_LLM="${AGENT_ENABLE_LLM:-0}" # Export agent-server secrets (OPENAI_API_KEY, GOOGLE_API_KEY, HEXGATE_KEY) from -# its .env. The agent backend reads its provider keys from this env — HexUI +# its .env. The agent backend reads its provider keys from this env — HexKit # never sends them. if [ -f demo/agent-server/.env ]; then set -o allexport diff --git a/demo/scripts/verify_backend.py b/demo/scripts/verify_backend.py index 783b3d0..cedfbd1 100644 --- a/demo/scripts/verify_backend.py +++ b/demo/scripts/verify_backend.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -"""Contract-conformance checker for a HexaUI developer backend. +"""Contract-conformance checker for a HexKit developer backend. Point it at *your own* running backend URL and it validates the CONTRACT.md §8 -checklist the way the HexaUI proxy would — assigning a run_id, reading the SSE +checklist the way the HexKit proxy would — assigning a run_id, reading the SSE stream over a real socket, cancelling mid-run, and inspecting every frame's shape. Each check prints PASS / FAIL / SKIP; the process exits non-zero if any required check fails, so it doubles as a CI gate. @@ -289,13 +289,13 @@ async def check_actions(c: httpx.AsyncClient, r: Report, agent_id: str, ui_text: async def main() -> int: - ap = argparse.ArgumentParser(description="Validate a HexaUI backend against CONTRACT.md §8.") + ap = argparse.ArgumentParser(description="Validate a HexKit backend against CONTRACT.md §8.") ap.add_argument("base_url", help="Base URL of the running backend, e.g. http://127.0.0.1:8880") ap.add_argument("--agent", help="Agent id to exercise (default: first in the roster)") ap.add_argument("--timeout", type=float, default=30.0, help="Per-request timeout seconds") args = ap.parse_args() - print(f"HexaUI contract conformance — {args.base_url}") + print(f"HexKit contract conformance — {args.base_url}") r = Report() async with httpx.AsyncClient(base_url=args.base_url.rstrip("/"), timeout=args.timeout) as c: roster = await check_roster(c, r) diff --git a/demo/starter-agent/pyproject.toml b/demo/starter-agent/pyproject.toml index f2fa95a..92f4516 100644 --- a/demo/starter-agent/pyproject.toml +++ b/demo/starter-agent/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "starter-agent" version = "0.1.0" -description = "Minimal copy-me backend for the HexaUI streaming contract" +description = "Minimal copy-me backend for the HexKit streaming contract" requires-python = ">=3.11" dependencies = [ "fastapi>=0.115", diff --git a/demo/starter-agent/src/starter_agent/app.py b/demo/starter-agent/src/starter_agent/app.py index ba2e327..f4d39e9 100644 --- a/demo/starter-agent/src/starter_agent/app.py +++ b/demo/starter-agent/src/starter_agent/app.py @@ -1,6 +1,6 @@ -"""The entire HexaUI developer contract, in one file. +"""The entire HexKit developer contract, in one file. -This is a **copy-me template**: the smallest backend the HexaUI proxy will talk +This is a **copy-me template**: the smallest backend the HexKit proxy will talk to. It implements the five endpoints from CONTRACT.md with a single `native` echo agent, and nothing else. Read it top to bottom — every endpoint is annotated with the contract section it satisfies. To build your own agent, copy @@ -177,7 +177,7 @@ def _last_user_text(input: dict[str, Any]) -> str: def create_app() -> FastAPI: - app = FastAPI(title="HexaUI Starter Agent", version="0.1.0") + app = FastAPI(title="HexKit Starter Agent", version="0.1.0") # run_id -> cancel Event. Process-local; a multi-worker deploy needs a # shared store. Created here so it exists before any lifespan runs. app.state.runs = {} diff --git a/front-app/README.md b/front-app/README.md index 51fcfd1..075492e 100644 --- a/front-app/README.md +++ b/front-app/README.md @@ -1,6 +1,6 @@ # front-app -The **HexaUI shell** — the user-facing web app. It wraps the +The **HexKit shell** — the user-facing web app. It wraps the [`agent-ui`](../custom-UI/) library (``, rendered from each agent's `ui.yaml`) in constant chrome and talks to the [proxy](../proxy-server/) over HTTP + SSE through a single origin (`/api/*`). diff --git a/front-app/src/api/agents.ts b/front-app/src/api/agents.ts index e2a1232..aeb2d8c 100644 --- a/front-app/src/api/agents.ts +++ b/front-app/src/api/agents.ts @@ -1,7 +1,7 @@ import { authedFetch, getJson, postJson } from "./client"; /** - * Roster entry from the proxy's `GET /agents` (HexaUI contract). `main_color` + * Roster entry from the proxy's `GET /agents` (HexKit contract). `main_color` * is the agent's signature hue — the one color that recolors the page. */ export interface AgentSummary { diff --git a/front-app/src/layout/AppShell.tsx b/front-app/src/layout/AppShell.tsx index faf9974..3d4b93d 100644 --- a/front-app/src/layout/AppShell.tsx +++ b/front-app/src/layout/AppShell.tsx @@ -7,7 +7,7 @@ import { Header } from "./Header"; import { Sidebar } from "./Sidebar"; /** - * The constant HexaUI chrome: a folding sidebar + top bar wrapping the MAIN + * The constant HexKit chrome: a folding sidebar + top bar wrapping the MAIN * region (``, rendered by ChatPage via the Outlet). The active agent's * `main_color` sets the accent CSS vars at the shell root, so the whole product * — sidebar glyphs, picker, composer send — tints from that one variable. diff --git a/front-app/src/lib/fileFx.tsx b/front-app/src/lib/fileFx.tsx index aaea9b5..7bc97cd 100644 --- a/front-app/src/lib/fileFx.tsx +++ b/front-app/src/lib/fileFx.tsx @@ -2,7 +2,7 @@ import { Code2, FileText, Sheet } from "lucide-react"; /** * File-presentation helpers + the shared monochrome glyph, ported from the - * HexaUI file-handling design handoff. The agent stays the only color, so + * HexKit file-handling design handoff. The agent stays the only color, so * glyphs are neutral and only distinguish by icon (doc / sheet / code). */ diff --git a/front-app/src/main.tsx b/front-app/src/main.tsx index 072ecb0..ccfac03 100644 --- a/front-app/src/main.tsx +++ b/front-app/src/main.tsx @@ -5,7 +5,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { AuthProvider } from "./auth/AuthContext"; import { AppRouter } from "./router"; -// HexaUI fonts: Hanken Grotesk (UI), Source Serif 4 (display), IBM Plex Mono +// HexKit fonts: Hanken Grotesk (UI), Source Serif 4 (display), IBM Plex Mono // (data). Loaded here so the whole app — chrome + AgentUI widgets — picks them // up via the --font-* tokens in agent-ui/shadcn.css. import "@fontsource/hanken-grotesk/400.css"; diff --git a/front-app/src/pages/FilesPage.tsx b/front-app/src/pages/FilesPage.tsx index 5867e33..52437d0 100644 --- a/front-app/src/pages/FilesPage.tsx +++ b/front-app/src/pages/FilesPage.tsx @@ -28,7 +28,7 @@ const KINDS: { id: "all" | Kind; label: string; tag?: string }[] = [ ]; /** - * The Files library — the editorial full-screen view from the HexaUI handoff: + * The Files library — the editorial full-screen view from the HexKit handoff: * a masthead with file/byte totals, a search + kind-filter + upload toolbar, a * monochrome grid (the agent stays the only color), inline rename, and a * deferred delete with an undo toast. Files are global and reusable; attach any diff --git a/front-app/src/pages/SettingsPage.tsx b/front-app/src/pages/SettingsPage.tsx index b39f2be..6f18578 100644 --- a/front-app/src/pages/SettingsPage.tsx +++ b/front-app/src/pages/SettingsPage.tsx @@ -8,11 +8,11 @@ import { useAuth } from "../auth/AuthContext"; * Settings — display profile. * * `role` is a free-text optional string forwarded to hexgate-wrapped agents - * as `context.user.role`. HexUI never interprets it; the dev team picks the + * as `context.user.role`. HexKit never interprets it; the dev team picks the * vocabulary in their hexgate policy. * * Provider API keys are NOT configured here — the agent backend reads its own - * keys from its environment (see the backend's `.env`). HexUI never holds them. + * keys from its environment (see the backend's `.env`). HexKit never holds them. */ export function SettingsPage() { const { user, setUser } = useAuth(); @@ -40,7 +40,7 @@ export function SettingsPage() {

Settings

Your display name and optional hexgate role. Provider API keys live in - the agent backend's environment — HexUI never holds them. + the agent backend's environment — HexKit never holds them.

diff --git a/front-app/src/styles.css b/front-app/src/styles.css index 7056daf..b1eb7a1 100644 --- a/front-app/src/styles.css +++ b/front-app/src/styles.css @@ -14,7 +14,7 @@ body { font-feature-settings: "rlig" 1, "calt" 1, "ss01" 1; } -/* HexaUI shell: AgentUI fills the chat area under the 58px top bar; the +/* HexKit shell: AgentUI fills the chat area under the 58px top bar; the * transcript (main slot) scrolls while the composer (footer slot) stays pinned * to the bottom. Overrides the library's standalone `min-height:100vh` default * — scoped to this app, so other agent-ui consumers are unaffected. */ @@ -127,7 +127,7 @@ body { } /* ============================================================ - File handling — ported from the original HexaUI design handoff. + File handling — ported from the original HexKit design handoff. Tokens are scoped to `.hxf` and mapped onto the shell's shadcn theme + the active agent accent, so file UI recolors with the agent and stays the only color. diff --git a/packages/hexa-events/pyproject.toml b/packages/hexa-events/pyproject.toml index 9c0c4cd..7043336 100644 --- a/packages/hexa-events/pyproject.toml +++ b/packages/hexa-events/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "hexa-events" version = "0.1.0" -description = "HexaUI streaming event schema + emit-side helpers (the wire contract)" +description = "HexKit streaming event schema + emit-side helpers (the wire contract)" requires-python = ">=3.11" dependencies = [ "pydantic>=2.7", diff --git a/packages/hexa-events/src/hexa_events/__init__.py b/packages/hexa-events/src/hexa_events/__init__.py index 1cf5b85..1dde556 100644 --- a/packages/hexa-events/src/hexa_events/__init__.py +++ b/packages/hexa-events/src/hexa_events/__init__.py @@ -1,6 +1,6 @@ -"""HexaUI streaming event schema + emit-side helpers. +"""HexKit streaming event schema + emit-side helpers. -The wire contract between a developer's agent backend and the HexaUI proxy. +The wire contract between a developer's agent backend and the HexKit proxy. Install via ``pip install -e packages/hexa-events`` (or ``file:`` path) in both the agent-server and the proxy so the schema can't drift. """ diff --git a/packages/hexa-events/src/hexa_events/events.py b/packages/hexa-events/src/hexa_events/events.py index f88ed24..06b54ae 100644 --- a/packages/hexa-events/src/hexa_events/events.py +++ b/packages/hexa-events/src/hexa_events/events.py @@ -1,8 +1,8 @@ """ -Normalized event schema for the HexaUI streaming contract. +Normalized event schema for the HexKit streaming contract. This module is the wire contract between a developer's agent backend and the -HexaUI proxy. It is a trimmed descendant of the old unified-runtime event +HexKit proxy. It is a trimmed descendant of the old unified-runtime event schema: the core lifecycle (run / block / tool / error) is preserved verbatim so existing consumers and the proxy's SSE parser keep working unchanged, while the framework-observability and human-in-the-loop layers are dropped. diff --git a/packages/hexa-events/src/hexa_events/sse.py b/packages/hexa-events/src/hexa_events/sse.py index 601b87e..2354df8 100644 --- a/packages/hexa-events/src/hexa_events/sse.py +++ b/packages/hexa-events/src/hexa_events/sse.py @@ -1,5 +1,5 @@ """ -SSE wire serialization for the HexaUI streaming contract. +SSE wire serialization for the HexKit streaming contract. A backend serves the stream as ``text/event-stream`` and frames each :class:`~hexa_events.events.StreamEvent` with :func:`to_sse_frame`, which emits diff --git a/proxy-server/pyproject.toml b/proxy-server/pyproject.toml index a43ed7b..1172f42 100644 --- a/proxy-server/pyproject.toml +++ b/proxy-server/pyproject.toml @@ -1,7 +1,7 @@ [project] -name = "hexaui-proxy" +name = "hexkit-proxy" version = "0.1.0" -description = "HexaUI platform backend — single-user proxy: conversations, files, and per-framework SSE translation (import package stays `platform_backend`)" +description = "HexKit platform backend — single-user proxy: conversations, files, and per-framework SSE translation (import package stays `platform_backend`)" requires-python = ">=3.11" dependencies = [ "fastapi>=0.115", @@ -39,4 +39,4 @@ build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/platform_backend"] -# Ruff config is shared at the repo root (HexUI/ruff.toml). +# Ruff config is shared at the repo root (HexKit/ruff.toml). diff --git a/proxy-server/src/platform_backend/access.py b/proxy-server/src/platform_backend/access.py index 61e0c58..d24b583 100644 --- a/proxy-server/src/platform_backend/access.py +++ b/proxy-server/src/platform_backend/access.py @@ -12,7 +12,7 @@ Enforced proxy-side: the roster (`GET /agents`) is filtered to the accessible set, and the agent-scoped routes (`/ui`, `/actions`, conversation creation) -reject the rest. The agent backend never sees this — it's a HexUI concern. +reject the rest. The agent backend never sees this — it's a HexKit concern. """ from __future__ import annotations diff --git a/proxy-server/src/platform_backend/models/user.py b/proxy-server/src/platform_backend/models/user.py index eee34ec..e059476 100644 --- a/proxy-server/src/platform_backend/models/user.py +++ b/proxy-server/src/platform_backend/models/user.py @@ -26,7 +26,7 @@ class User(Base): # Display name. Optional — falls back to the email's local-part in the UI. name: Mapped[str | None] = mapped_column(String(120), nullable=True) # Opaque role string forwarded to hexgate-wrapped agents as - # `context.user.role`. HexUI never interprets it; each dev team decides + # `context.user.role`. HexKit never interprets it; each dev team decides # their own role vocabulary. role: Mapped[str | None] = mapped_column(String(64), nullable=True) # Agent allow-list: the agent ids this user may reach. `NULL` (or empty) diff --git a/proxy-server/src/platform_backend/routes/me.py b/proxy-server/src/platform_backend/routes/me.py index db954cb..674f18f 100644 --- a/proxy-server/src/platform_backend/routes/me.py +++ b/proxy-server/src/platform_backend/routes/me.py @@ -2,7 +2,7 @@ PATCH lets users set their display ``name`` and an opaque ``role`` string (which is forwarded to hexgate-wrapped agents as ``context.user.role``). -HexUI never interprets the role; it's free text per the dev team's policy +HexKit never interprets the role; it's free text per the dev team's policy vocabulary. """ diff --git a/proxy-server/src/platform_backend/runtime_client.py b/proxy-server/src/platform_backend/runtime_client.py index 1e7464b..e4e32f0 100644 --- a/proxy-server/src/platform_backend/runtime_client.py +++ b/proxy-server/src/platform_backend/runtime_client.py @@ -6,7 +6,7 @@ without standing up a real backend. The streaming method (`stream`) yields raw upstream bytes so the chat route -can pass them through the wire untouched — the SSE schema is the HexaUI +can pass them through the wire untouched — the SSE schema is the HexKit streaming contract, not the proxy's invention. """ From 840a6d804e15ad2a5bfc420bef9c65931a4799de Mon Sep 17 00:00:00 2001 From: Le Ha Quang Date: Wed, 24 Jun 2026 09:10:51 +0200 Subject: [PATCH 2/3] docs: README mark + widget gallery section - Add the hexkit mark (from the landing page) to assets/hexkit-mark.svg and display it above the README title. - Insert a Components section between the agent table and "The two things a developer configures." Eight widgets in a 2x4 HTML grid: ai-response, ai-chat-input, metrics, table, tool-calls, markdown, form, button-group. Each card shows the widget type, a one-line tag, and a real ui.yaml snippet using the canonical schema (matches the *.yaml files in demo/agent-server/src/agent_server/ui/, no toy syntax). - Closing line names the remaining widgets (dropdown, page-header, page-footer, placeholder, spacer) and links to the full catalog. --- README.md | 151 +++++++++++++++++++++++++++++++++++++++++ assets/hexkit-mark.svg | 7 ++ 2 files changed, 158 insertions(+) create mode 100644 assets/hexkit-mark.svg diff --git a/README.md b/README.md index 092dd0e..4f02a7e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@
+HexKit + # HexKit
@@ -126,6 +128,155 @@ The bundled agents demonstrate the contract end to end: --- +## Components + +Every agent UI is built out of these widgets. You compose them in a `ui.yaml` — +`type` picks the widget, `position` + `size` lay it out on the grid, +`data_source` wires it to one of your `/actions/{name}` endpoints. No React, +no CSS. + + + + + + + + + + + + + + + + + + +
+ +**`ai-response`** — streaming chat surface + +The flagship widget. Renders the assistant's turn as it streams; embeds tool calls, markdown, code blocks, files inline. + +```yaml +- name: transcript + type: ai-response + position: { horizontal: left, vertical: high } + size: { width: 8, height: 520 } + empty_text: "Ask something…" + thinking_indicator: dots +``` + + + +**`ai-chat-input`** — composer with attachments + +Text input + file attach + keyboard send. Forwards the composed turn through `POST /conversations/{id}/messages`. + +```yaml +- name: chat-input + type: ai-chat-input + position: { horizontal: left, vertical: low } + size: { width: 12, height: auto } + placeholder: "Message Hexgate Guard…" + rows: 2 +``` + +
+ +**`metrics`** — KPI strip + +A row of labeled stat tiles. Pulls its values from a `data_source` action; auto-refreshes when a button-group action lists it in `refresh:`. + +```yaml +- name: kpis + type: metrics + size: { width: 12, height: auto } + columns: 4 + data_source: { action: change_summary } + metrics: + - { id: new, label: "New", format: number } +``` + + + +**`table`** — scrollable data grid + +Header row + virtualized rows. Sourced from an action that returns rows; can be refreshed by a button. + +```yaml +- name: changes + type: table + size: { width: 12, height: auto } + data_source: { action: change_table } + has_header: true + empty_text: "No changes yet." +``` + +
+ +**`tool-calls`** — live tool log + +Shows each tool the agent calls in real time, with arguments, status, and result. Default landing surface for any unaddressed tool call. + +```yaml +- name: tools + type: tool-calls + position: { horizontal: right, vertical: high } + size: { width: 4, height: 520 } + empty_text: "Tool calls will appear here." +``` + + + +**`markdown`** — rich text + code + +Static markdown sourced from a string, or live markdown that the agent updates via a data source (e.g. a runbook the agent edits). + +```yaml +- name: runbook + type: markdown + size: { width: 8, height: auto } + data_source: { action: get_runbook } +``` + +
+ +**`form`** — structured input + +Labeled fields the user submits as one payload to an action. Each field declares its type; submit fires `POST /actions/{name}`. + +```yaml +- name: deploy + type: form + size: { width: 6, height: auto } + action: deploy_service + fields: + - { name: env, label: Environment, type: text } + - { name: replicas, label: Replicas, type: number } +``` + + + +**`button-group`** — actions row + +A row of buttons, each tied to an action. Optional `refresh:` list re-pulls the named widgets after the action completes — the basis for the lifecycle dashboards in ITSM / DevOps. + +```yaml +- name: ops + type: button-group + size: { width: 12, height: auto } + buttons: + - { label: "Refresh", action: refresh_changes, + refresh: [change-metrics, change-table] } +``` + +
+ +Five more widgets ship for layout and forms: `dropdown`, `page-header`, `page-footer`, `placeholder`, `spacer`. See [`custom-UI/src/widgets/`](custom-UI/src/widgets/) for the full catalog and [demo/agent-server/src/agent_server/ui/](demo/agent-server/src/agent_server/ui/) for complete `ui.yaml` examples (the ITSM and DevOps agents stitch most of the widgets together into a live ops dashboard). + +--- + ## The two things a developer configures 1. **`ui.yaml`** — which widgets, where, and the accent color. Placed/served by diff --git a/assets/hexkit-mark.svg b/assets/hexkit-mark.svg new file mode 100644 index 0000000..6949ed6 --- /dev/null +++ b/assets/hexkit-mark.svg @@ -0,0 +1,7 @@ + + + + + + + From 18b75cfada8f302c917d5e78c508ea7bf28b02d9 Mon Sep 17 00:00:00 2001 From: Le Ha Quang Date: Wed, 24 Jun 2026 10:08:17 +0200 Subject: [PATCH 3/3] docs: fix stale agent + widget counts surfaced during review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Agent table gains ITSM and HR rows (langchain/deepagents). Brings the table to the 9 agents actually shipped (8 in agent-server + Hexgate Guard in hexgate-agent). - README repo-layout: "6 sample agents" -> "8 sample agents" and names all eight, matching demo/agent-server/src/agent_server/ui/*.yaml. - QUICKSTART step 4: same fix — "six demo agents" -> "eight demo agents", list now includes ITSM and HR. - Components section: "5 more widgets ... placeholder" -> "4 more widgets" (placeholder is a file but not in the registry, so isn't a user-facing widget; the canonical count from custom-UI/src/registry/builtin.ts is 12, which matches the repo-layout claim). --- QUICKSTART.md | 2 +- README.md | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/QUICKSTART.md b/QUICKSTART.md index 22797af..20faa3d 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -88,7 +88,7 @@ Open . startup when `PLATFORM_DEMO_USERS_FILE` is set (the `make dev` launcher sets it for you). Or sign up a fresh account at **/signup**. 3. The chat shell loads with an empty greeting. -4. Click the agent picker in the top bar and choose **Probe** (or any of the six demo agents — Probe, Orbit, Atlas, Forge, Healthcare, DevOps). +4. Click the agent picker in the top bar and choose **Probe** (or any of the eight demo agents — Probe, Orbit, Atlas, Forge, Healthcare, DevOps, ITSM, HR). 5. Type a message and send. 6. With `AGENT_ENABLE_LLM=1` and a provider key in the agent backend's env → a real LLM reply. Without → an echo of your message (this confirms the full pipeline works). diff --git a/README.md b/README.md index 4f02a7e..a501d9d 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ events; the **proxy translates** and the **UI renders from YAML**. See | [front-app/](front-app/) | The HexKit shell that consumes `custom-UI` and talks to the proxy. | | [proxy-server/](proxy-server/) | The platform backend (FastAPI): JWT auth, conversations, folders, files, and the per-framework translators that normalize native events into the hexa SSE schema. Import package stays `platform_backend`. | | [packages/hexa-events/](packages/hexa-events/) | The internal event schema package consumed by the proxy (a local path dependency). | -| [demo/](demo/) | The runnable reference backends: [`agent-server/`](demo/agent-server/) (a contract-conformant developer backend with 6 sample agents), [`hexgate-agent/`](demo/hexgate-agent/) (a standalone hexgate-wrapped backend), [`starter-agent/`](demo/starter-agent/) (a minimal **copy-me** backend — the whole contract in one file), and [`scripts/`](demo/scripts/) (run + smoke checks, incl. the `verify_backend.py` conformance CLI). | +| [demo/](demo/) | The runnable reference backends: [`agent-server/`](demo/agent-server/) (a contract-conformant developer backend with 8 sample agents — Probe, Orbit, Atlas, Forge, Healthcare, DevOps, ITSM, HR), [`hexgate-agent/`](demo/hexgate-agent/) (a standalone hexgate-wrapped backend), [`starter-agent/`](demo/starter-agent/) (a minimal **copy-me** backend — the whole contract in one file), and [`scripts/`](demo/scripts/) (run + smoke checks, incl. the `verify_backend.py` conformance CLI). | | [legacy/](legacy/) | The dropped unified-runtime backend (`backend-runtime`), kept for reference. Not part of the live product. | | [CONTRACT.md](CONTRACT.md) | The developer contract — the one document an integrator reads. | @@ -124,6 +124,8 @@ The bundled agents demonstrate the contract end to end: | **Forge** | `openai-agents` | the OpenAI Agents translator (canned native events) | | **Healthcare** | `openai-agents` (OpenAI) | a real clinical-assistant agent; HexGate-gated when `HEXGATE_KEY` is set, scoping per-tool policy to the caller's `context.user` role | | **DevOps** | `google-adk` (OpenAI via LiteLLM) | a real infra-assistant agent; HexGate-gated when `HEXGATE_KEY` is set, scoping per-tool policy to the caller's `context.user` role | +| **ITSM** | `langchain` (deepagents) | a change-request assistant with a live lifecycle dashboard (refresh button → funnel metrics + change table updates as the agent's tools run) | +| **HR** | `langchain` (deepagents) | an internal HR assistant; demonstrates stateful per-user data (`hr_state.py`) and role-gated tools when HexGate is wired | | **Hexgate Guard** | `hexgate` | a hexgate-wrapped agent that opens `User(user_id, role)` per run and emits audit decisions to the hexgate cloud (separate backend at [`demo/hexgate-agent/`](demo/hexgate-agent/)) | --- @@ -273,7 +275,7 @@ A row of buttons, each tied to an action. Optional `refresh:` list re-pulls the -Five more widgets ship for layout and forms: `dropdown`, `page-header`, `page-footer`, `placeholder`, `spacer`. See [`custom-UI/src/widgets/`](custom-UI/src/widgets/) for the full catalog and [demo/agent-server/src/agent_server/ui/](demo/agent-server/src/agent_server/ui/) for complete `ui.yaml` examples (the ITSM and DevOps agents stitch most of the widgets together into a live ops dashboard). +Four more widgets ship for layout and inputs: `dropdown`, `page-header`, `page-footer`, `spacer`. See [`custom-UI/src/registry/builtin.ts`](custom-UI/src/registry/builtin.ts) for the canonical registry and [demo/agent-server/src/agent_server/ui/](demo/agent-server/src/agent_server/ui/) for complete `ui.yaml` examples (the ITSM and DevOps agents stitch most of the widgets together into a live ops dashboard). ---