Files
zk-data-agent/docs/architecture.md
T
2026-07-26 17:40:51 +08:00

87 lines
4.0 KiB
Markdown

# Architecture
## Product modes
Chat and Work share the same authenticated user, conversation history, and
workspace, but not the same Agent loop.
| Concern | Chat | Work |
| --- | --- | --- |
| Primary purpose | Fast conversation | Multi-step deliverables |
| Loop owner | Open WebUI native loop | K1412 Agent Runtime |
| Tools | Workspace Gateway through OpenAPI | Workspace Gateway through Runtime |
| Visible history | Open WebUI | Open WebUI |
| Run events | Open WebUI | Runtime event store |
| Context and memory | Open WebUI defaults are disabled by policy | Runtime policy and store |
| Workspace files | Authenticated K1412 file browser | Same file browser and volume |
Selecting Work atomically upgrades `(user_id, chat_id)` in the Runtime store.
Subsequent Chat requests for that conversation are rejected even if a client
tries to bypass the disabled UI control.
## Work loop
The first strategy is intentionally modular:
- `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 modes, events, plans, and durable Work memory.
- `ExecutionProvider` owns local or SSH Docker execution.
Every run records its model tier, 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.
The light, medium, and high tiers use the internal K1412 model endpoint. The
extreme tier uses DeepSeek V4 Pro with thinking enabled and maximum reasoning
effort. Provider selection and credentials remain server-side. Thinking state
is preserved across tool turns because DeepSeek requires the assistant's
`reasoning_content` to be returned with the following tool results; Work never
publishes that hidden state as its own user-facing reasoning.
Work 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.
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.
## Execution providers
`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.
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.
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.
## Workspace file path
```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
```
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.