docs: publish architecture and experiment portal
This commit is contained in:
+164
-53
@@ -1,74 +1,185 @@
|
||||
# Architecture
|
||||
|
||||
## Single Agent path
|
||||
## Design objective
|
||||
|
||||
Open WebUI owns authenticated users, conversation history, and rendering.
|
||||
Every normal model request is delegated to the K1412 Runtime. There is no
|
||||
second Chat loop and no per-conversation mode state.
|
||||
K1412 Agent is a multi-user web coding Agent whose loop can be changed
|
||||
independently of its account system and user interface. The architecture keeps
|
||||
the high-cost experimental surface small: researchers should be able to change
|
||||
context, memory, scheduling, tools, delegation, or completion policy without
|
||||
forking authentication, chat history, Docker lifecycle, or the whole frontend.
|
||||
|
||||
## Agent loop
|
||||
The system deliberately has one Agent path. The earlier idea of a lightweight
|
||||
Chat loop beside a custom Work loop was removed because it duplicated product
|
||||
behavior, confused model selection, and increased the amount of frontend and
|
||||
backend code that had to remain compatible.
|
||||
|
||||
The first strategy is intentionally modular:
|
||||
## System context
|
||||
|
||||
- `ModelProvider` owns provider transport.
|
||||
- `ContextPolicy` owns visible-message cleanup and compaction.
|
||||
- `ToolRegistry` owns tool schemas and dispatch.
|
||||
- `AgentLoop` owns iteration, safe parallel scheduling, and delegation.
|
||||
- `RuntimeStore` owns events, plans, and durable Agent memory.
|
||||
- `ExecutionProvider` owns local or SSH Docker execution.
|
||||
```mermaid
|
||||
flowchart LR
|
||||
U["Browser user"] --> P["DNS, TLS and Nginx Proxy Manager"]
|
||||
P --> W["Open WebUI<br/>auth, RBAC, history, UI"]
|
||||
W --> R["Agent Runtime<br/>loop, context, memory, model routing"]
|
||||
R --> M["Model providers<br/>K1412 API or DeepSeek"]
|
||||
R --> G["Workspace Gateway<br/>identity and execution policy"]
|
||||
G -->|Tailscale + SSH Docker| X["Per-user workspace container<br/>home-node-itx"]
|
||||
W --> DB["PostgreSQL<br/>users and chats"]
|
||||
R --> DB
|
||||
W --> Q["Redis<br/>coordination"]
|
||||
```
|
||||
|
||||
Every run records its model ID, strategy version, scheduler version, context
|
||||
policy, model/tool events, failures, and completion. This event stream is the
|
||||
foundation for replay, evaluation, and future experiment assignment.
|
||||
Only Web is publicly reachable. Runtime, Gateway, PostgreSQL, and Redis live on
|
||||
private Compose networks. Workspace containers run on a separate physical
|
||||
Docker host, receive no application secrets, and expose no host ports.
|
||||
|
||||
Luna, Terra, and Sol are three independent Ollama models. Each advertises
|
||||
boolean thinking support, but none advertises adjustable reasoning effort.
|
||||
DeepSeek V4 Pro is a fourth model configured with thinking enabled and maximum
|
||||
reasoning effort. Provider selection and credentials remain server-side.
|
||||
Thinking state is preserved across tool turns when the provider requires the
|
||||
assistant's `reasoning_content` to be returned with following tool results.
|
||||
The Agent never publishes hidden reasoning as its own user-facing output.
|
||||
## Responsibility boundaries
|
||||
|
||||
Completion is evidence-gated. Requests for scripts, reports, code, or
|
||||
other concrete artifacts are not accepted as complete until a file mutation
|
||||
has succeeded and a later read, diff, or command has verified the latest
|
||||
mutation. Bare interactive shell commands are rejected. If the iteration
|
||||
budget is exhausted without evidence, Runtime returns an explicit incomplete
|
||||
checkpoint instead of repeating an unverified model claim.
|
||||
| Layer | Owns | Must not own |
|
||||
| --- | --- | --- |
|
||||
| Open WebUI | Registration, login, sessions, admin approval, RBAC, chat persistence, rendering | Agent scheduling, provider secrets, Docker access |
|
||||
| Agent Runtime | Model catalog, context policy, Agent loop, tools, scheduling, delegation, memory, plans, run events, evidence gates | Browser sessions, Docker socket |
|
||||
| Workspace Gateway | Signed identity enforcement, workspace path policy, per-user locks, Docker lifecycle, file delivery | Model calls, public authentication UI |
|
||||
| Workspace container | User code, dependencies, generated files, command execution | Other users' data, service credentials, Docker socket |
|
||||
| PostgreSQL | Open WebUI durable state plus Runtime events, plans, and memories | Execution |
|
||||
| Shared infrastructure | TLS, registry, source hosting, private routing, model serving | Agent behavior |
|
||||
|
||||
Read-only tools and read-only child Agents may run concurrently. Workspace
|
||||
mutations are serialized. A child Agent cannot delegate again, and read-only
|
||||
children receive only read-only tools.
|
||||
This separation lets the Web UI be upgraded on its own schedule while the
|
||||
Agent loop can iterate frequently.
|
||||
|
||||
## Execution providers
|
||||
## Request lifecycle
|
||||
|
||||
`local-docker` connects the Workspace Gateway to the local Docker daemon.
|
||||
`ssh-docker` connects the same Docker SDK operations to a remote physical
|
||||
machine through SSH. Both create the same workspace image, persistent per-user
|
||||
volume, and dedicated per-user bridge network, so moving execution off the web
|
||||
host changes configuration rather than Agent behavior.
|
||||
### Agent request
|
||||
|
||||
For SSH mode, layer `compose.ssh.yaml` over the development Compose file, or
|
||||
`deploy/docker-compose.ssh.yml` over the two production Compose files. The
|
||||
override removes the local Docker socket and mounts only the selected SSH
|
||||
configuration directory read-only.
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant B as Browser
|
||||
participant W as Open WebUI
|
||||
participant R as Runtime
|
||||
participant M as Model provider
|
||||
participant G as Gateway
|
||||
participant X as User workspace
|
||||
|
||||
Only Open WebUI publishes a host port. Runtime, Gateway, Postgres, and Redis
|
||||
remain unpublishing services. Runtime and Gateway also join an egress-only
|
||||
bridge so the model API and a future SSH Docker host are reachable without
|
||||
exposing either service on the host.
|
||||
B->>W: Authenticated chat request
|
||||
W->>R: OpenAI-compatible request + service key + signed user identity
|
||||
R->>R: Verify identity, build context, record run.created
|
||||
loop Until evidence-backed completion or budget exhausted
|
||||
R->>M: Recent context + tools + provider policy
|
||||
M-->>R: Assistant content and/or tool calls
|
||||
R->>R: Normalize, validate, limit, and schedule calls
|
||||
R->>G: Tool request + service key + freshly signed identity
|
||||
G->>G: Verify identity and bind user workspace
|
||||
G->>X: Execute with resource and path constraints
|
||||
X-->>G: Exit code, output, or file result
|
||||
G-->>R: Structured tool result
|
||||
R->>R: Persist events and evaluate completion evidence
|
||||
end
|
||||
R-->>W: SSE answer and completed tool detail blocks
|
||||
W-->>B: Rendered Agent response
|
||||
```
|
||||
|
||||
## Workspace file path
|
||||
The identity sent by Open WebUI is verified once when Runtime accepts the
|
||||
request. Runtime then signs the already verified identity again for every
|
||||
Gateway call. This prevents a long Agent run from reusing an identity token
|
||||
that expired while the model or a tool was working.
|
||||
|
||||
### Workspace file request
|
||||
|
||||
```text
|
||||
browser with Open WebUI session
|
||||
-> /api/v1/k1412/workspace/*
|
||||
-> Open WebUI backend verifies the user
|
||||
-> backend mints a short-lived signed identity JWT
|
||||
-> Workspace Gateway verifies service key + user JWT
|
||||
-> provider selects only that user's hashed container and volume
|
||||
-> Open WebUI verifies the logged-in user
|
||||
-> Web signs a short-lived user identity
|
||||
-> Gateway verifies service key + signed identity
|
||||
-> Gateway selects only the hashed container and volume for that user
|
||||
-> browse, download, or streamed archive response
|
||||
```
|
||||
|
||||
The file API exposes read-only browse, file download, and streamed directory
|
||||
archive operations. Paths pass through the same `/workspace` normalization as
|
||||
Agent tools. The browser never talks to Gateway or Docker directly.
|
||||
The browser never receives a Gateway service key and never connects to Docker.
|
||||
|
||||
## Runtime internals
|
||||
|
||||
Runtime is an OpenAI-compatible provider from Open WebUI's point of view, but
|
||||
normal chat completions are implemented by the K1412 loop:
|
||||
|
||||
- `ModelProvider` translates the internal model spec to a provider request and
|
||||
normalizes streamed completion responses.
|
||||
- `ContextPolicy` removes rendered tool-detail markup, prepends the system
|
||||
contract and durable memories, and keeps the newest visible messages within
|
||||
a per-model character budget.
|
||||
- `ToolRegistry` declares tool schemas and routes workspace tools to Gateway or
|
||||
state tools to `RuntimeStore`.
|
||||
- `AgentLoop` owns iteration, tool normalization, validation, scheduling,
|
||||
recovery, delegation, and evidence-gated completion.
|
||||
- `RuntimeStore` persists run events, per-chat plans, and user memories.
|
||||
|
||||
More detail is in [agent-loop.md](agent-loop.md).
|
||||
|
||||
## Workspace architecture
|
||||
|
||||
`local-docker` and `ssh-docker` implement the same `ExecutionProvider`
|
||||
contract. Production uses `ssh-docker`: Gateway talks to Docker on
|
||||
`home-node-itx` through a dedicated SSH configuration mounted read-only.
|
||||
|
||||
Each immutable Open WebUI user ID maps to a SHA-256-derived workspace ID and
|
||||
therefore to exactly one:
|
||||
|
||||
- container named `k1412-ws-<workspace-id>`;
|
||||
- named volume `k1412-ws-data-<workspace-id>`;
|
||||
- bridge network `k1412-ws-net-<workspace-id>`.
|
||||
|
||||
Containers run as UID/GID 1000 with a read-only root filesystem, all Linux
|
||||
capabilities dropped, `no-new-privileges`, PID/CPU/memory limits, no Docker
|
||||
socket, and no published ports. `/workspace` is the only persistent writable
|
||||
filesystem. `/tmp` is writable but mounted `noexec`.
|
||||
|
||||
Python environments live at `/workspace/.venv`. User-level home and package
|
||||
caches live below `/workspace/.agent`. The image puts the virtual environment
|
||||
and user binary directories first on `PATH`. Commands run under Bash with
|
||||
`pipefail`, so a failed install cannot be hidden by a successful `tail` or
|
||||
similar pipeline stage.
|
||||
|
||||
When `WORKSPACE_IMAGE` changes to a new immutable tag, Gateway replaces a stale
|
||||
container on its next access but reattaches the existing named volume. Image
|
||||
upgrades therefore change the execution environment without deleting user
|
||||
files.
|
||||
|
||||
## Networks and deployment
|
||||
|
||||
Production runs as one Unraid Compose Manager project:
|
||||
|
||||
- `public`: Web ingress;
|
||||
- `internal`: private service-to-service traffic;
|
||||
- `egress`: Runtime provider access and Gateway SSH access.
|
||||
|
||||
Only Web publishes NAS port `12004`. Nginx Proxy Manager on the VPS terminates
|
||||
TLS for `agent.k1412.top` and forwards over Tailscale. Images are built for
|
||||
`linux/amd64`, pushed to `docker.k1412.top/wuyang/*` with immutable
|
||||
timestamp-and-commit tags, and deployed by updating only the relevant service.
|
||||
|
||||
The documentation portal is packaged inside the Web image at `/doc/`. It does
|
||||
not add a public service, port, database, or proxy rule.
|
||||
|
||||
## Stable and experimental surfaces
|
||||
|
||||
Stable platform contracts:
|
||||
|
||||
- authenticated Web-to-Runtime request;
|
||||
- signed Runtime/Web-to-Gateway identity;
|
||||
- `ExecutionProvider` workspace semantics;
|
||||
- per-user volume isolation;
|
||||
- run-event persistence;
|
||||
- public model IDs;
|
||||
- workspace file API.
|
||||
|
||||
Expected experiment surfaces:
|
||||
|
||||
- prompt and context policy;
|
||||
- memory selection;
|
||||
- tool catalog and intent routing;
|
||||
- scheduler and parallelism;
|
||||
- delegation;
|
||||
- recovery and evidence rules;
|
||||
- model budgets and routing.
|
||||
|
||||
Version experiment-sensitive behavior in `run.created` so results remain
|
||||
comparable after the implementation changes.
|
||||
|
||||
Reference in New Issue
Block a user