485 lines
28 KiB
Markdown
485 lines
28 KiB
Markdown
# DS4Server implementation plan
|
|
|
|
Bundle/application identifier: `DS4Server.rfc1437.de`
|
|
|
|
The GUI is a Rust/Iced reimplementation of the user-facing model server and
|
|
coding-agent workflows in `../ds4`. The existing engine remains the behavioral
|
|
reference: `ds4.c`/`ds4.h` define model and session behavior,
|
|
`ds4_server.c` defines the compatible API, and `ds4_agent.c` defines agent
|
|
sessions, tools, and turn orchestration.
|
|
|
|
## Current status
|
|
|
|
| Area | Status | Available now | Still open |
|
|
| --- | --- | --- | --- |
|
|
| App shell | Implemented | Native Iced window, Codex-inspired two-pane layout, dark theme, embedded SVG icons, `Command-,` Preferences panel | Functional chat content and native app packaging |
|
|
| Projects and sessions | Implemented for metadata | Native folder picker, project-name dialog, create/select/delete projects and sessions | Transcripts, KV payloads, rename/archive, and model binding |
|
|
| Persistence | Implemented for metadata and preferences | SQLite in Application Support, Diesel ORM, embedded migrations, constrained defaults and CRUD tests | Messages, downloaded-artifact metadata, and session-runtime migrations |
|
|
| Model runtime | Download workflow implemented | Persisted model choice, DSpark toggle, idle timeout, and Rust-native background main/DSpark downloads with progress, ETA, stop, restart-resume, size checks, and SHA-256 verification | Loading, inference, idle unloading, and Metal integration |
|
|
| Local endpoint | Not started | Nothing listening | OpenAI-compatible HTTP and streaming surfaces |
|
|
| Agent | UI shell only | Empty conversation pane and composer placeholder | Messages, generation, tools, approvals, compaction, and cancellation |
|
|
| A2UI | Future extension | bDS2 provides the reference structured render-tool contract | Native inline surfaces for local chat after core chat and tools are stable |
|
|
| Dev brain | Not started | No vault access | Obsidian vault selection, durable access, and agent knowledge/memory tools |
|
|
| Release | Not started | Development binary builds and tests | `.app` packaging, signing, entitlements, and notarization |
|
|
|
|
The application currently manages durable project/session metadata and model
|
|
preferences, and can download the selected model's main and optional DSpark
|
|
GGUF into managed Application Support storage without blocking the UI. It does
|
|
not yet load a model, serve HTTP, save chat messages, or run an agent.
|
|
|
|
## Phase 0 — project and session shell
|
|
|
|
Status: **implemented**.
|
|
|
|
- Show projects in a sidebar with their sessions nested underneath.
|
|
- Create projects with a native macOS folder picker and a project-name dialog.
|
|
- Create, select, and delete projects and sessions.
|
|
- Use a Codex-inspired two-pane layout with embedded, action-specific SVG icons.
|
|
- Persist projects and sessions in SQLite under
|
|
`~/Library/Application Support/DS4Server.rfc1437.de/`, using Diesel ORM
|
|
queries and embedded Diesel migrations.
|
|
- Never delete workspace contents when removing app metadata.
|
|
|
|
Exit criterion: restart the app and see the same project/session tree.
|
|
|
|
## Phase 1 — model library and on-demand loading
|
|
|
|
Status: **partially implemented**. Basic preferences and the complete
|
|
background download workflow are implemented; DS4 CLI preference parity,
|
|
loading, inference, and idle unloading remain open.
|
|
|
|
1. Complete the typed model/runtime preference contract described below before
|
|
connecting chat, the HTTP endpoint, or the engine lifecycle.
|
|
2. Port the narrow GGUF loader, tokenizer, prompt renderer, and Metal session
|
|
API behind a small Rust `Engine` surface modeled on `ds4.h`:
|
|
`open`, `close`, `create_session`, `sync`, `sample`, and KV save/load.
|
|
3. Retain the tested model restrictions from DwarfStar; reject unsupported
|
|
shapes and quantizations before allocating model state.
|
|
4. Reuse the existing `.metal` kernels and preserve mmap-backed resident
|
|
loading plus the explicit SSD-streaming path. Keep Objective-C only at the
|
|
Metal interop boundary.
|
|
5. Keep one engine resident at most, matching DwarfStar's instance-lock and
|
|
memory assumptions.
|
|
6. Move engine work off the UI thread and support cooperative cancellation at
|
|
the safe session boundaries already defined by `ds4_session_sync`.
|
|
|
|
### DS4 KV-cache port and shared session core
|
|
|
|
KV-cache behavior is part of the DS4 engine contract, not a new application
|
|
cache to redesign. Port the existing `ds4_session` and `ds4_kvstore` behavior
|
|
to Rust while preserving its semantics and on-disk compatibility:
|
|
|
|
- A live engine session owns one mutable inference timeline: exact rendered
|
|
tokens, logits, and the DS4-specific KV graph state. Callers provide the full
|
|
token prefix and the Rust port of `ds4_session_sync` must retain the longest
|
|
compatible prefix, evaluate only its suffix, or safely rewind, invalidate,
|
|
and rebuild exactly when DS4 does.
|
|
- Carry over DS4's safe cancellation/checkpoint boundaries, common-prefix
|
|
matching, canonical rewrite and replay, snapshots, payload staging,
|
|
save/load, strip-to-transcript behavior, and atomic replacement. The engine
|
|
continues to own the opaque KV payload format; UI, HTTP, and persistence code
|
|
must not reinterpret tensor state.
|
|
- Port `ds4_kvstore` policy rather than replacing it with a generic cache:
|
|
exact token and rendered-text prefix lookup, cold and continued aligned
|
|
checkpoints, model/quantization/context/payload-ABI compatibility checks,
|
|
tool-call replay metadata, disk-budget enforcement, hit tracking, and
|
|
eviction behavior.
|
|
- Use one process-wide Rust session registry and KV checkpoint store for both
|
|
local chat and the HTTP server. A remote request bound to an application
|
|
session resolves to the same logical DS4 session as the GUI and mutations are
|
|
serialized so two callers never write one live timeline concurrently.
|
|
Stateless HTTP requests still participate in the same compatible-prefix
|
|
checkpoint pool, so a prefix produced locally can be reused remotely and
|
|
vice versa.
|
|
- Store that shared checkpoint pool under Application Support in
|
|
`kv-cache/`, using the DS4 key/header/payload rules. Session rows hold only an
|
|
optional reference to their current checkpoint; the large opaque payload is
|
|
not copied into separate GUI and HTTP caches.
|
|
- Sharing does not merge unrelated conversations or expose one session's
|
|
transcript to another. It shares the DS4 implementation, checkpoint pool, and
|
|
explicitly bound logical session; each unrelated live conversation keeps its
|
|
own mutable session state.
|
|
- Engine unload must first leave every reusable live timeline in a valid
|
|
persisted checkpoint. Reload restores a compatible checkpoint immediately;
|
|
if model identity, quantization, context size, payload ABI, or rendered
|
|
history is incompatible, rebuild from the transcript and replace the stale
|
|
checkpoint only after the new state is valid.
|
|
|
|
### Lazy lifecycle
|
|
|
|
- Start the application and the local HTTP endpoint with no model loaded.
|
|
- Acquire the configured model only when generation starts, whether initiated
|
|
by a local chat or an OpenAI-compatible endpoint request. Concurrent first
|
|
requests share the same load instead of opening the model more than once.
|
|
- Expose `Unloaded → Downloading → Loading → Ready → Unloading` plus failure
|
|
states and progress in the GUI. A request that triggered loading waits for
|
|
the shared load and receives a clear error if download or initialization
|
|
fails.
|
|
- Treat active local generations, endpoint requests, prefills, and tool turns
|
|
as model activity. Start the idle timer only when all activity has stopped.
|
|
- Unload the engine after the configured idle timeout. New work cancels a
|
|
pending unload; work arriving after unload transparently loads the model
|
|
again. Persisted transcripts and KV files remain available when model memory
|
|
is released.
|
|
- Changing the selected model prevents new work from using the old model and
|
|
unloads it as soon as current work reaches a safe boundary.
|
|
|
|
### Preferences foundation (implemented)
|
|
|
|
- Provide a Preferences panel from the sidebar and the standard
|
|
macOS `Command-,` shortcut.
|
|
- Let the user choose the active model. Default to `deepseek-v4-flash`.
|
|
- Let the user enable or disable DSpark for the selected model. Disable the
|
|
control for models that do not support DSpark.
|
|
- Let the user configure the inactivity timeout; default to 10 minutes.
|
|
- Persist preferences in the application SQLite database. Changing preferences
|
|
never loads a model by itself.
|
|
|
|
### DS4 model and generation preferences (required before chat)
|
|
|
|
The Preferences panel must expose every persistent model, runtime, and
|
|
generation parameter accepted by the `ds4` command line. `../ds4/ds4_cli.c`,
|
|
`ds4.h`, and the shared GPU/distributed parsers are the source of truth; use the
|
|
same defaults, ranges, units, dependencies, and model-family overrides rather
|
|
than inventing application-specific behavior.
|
|
|
|
- **Model and capacity:** selected main GGUF (`--model`), optional MTP/DSpark
|
|
support GGUF (`--mtp`), context tokens (`--ctx`), maximum generated tokens
|
|
(`--tokens`), and system prompt (`--system`). Managed catalog selections map
|
|
to their installed files instead of requiring users to type paths.
|
|
- **Sampling and reasoning:** temperature (`--temp`), top-p, min-p, optional
|
|
seed, and one reasoning mode representing `--think`, `--think-max`, or
|
|
`--nothink`. Preserve DS4's explicit-vs-default distinction because GLM
|
|
applies model-family sampling defaults only when the user has not overridden
|
|
them.
|
|
- **Backend and execution:** backend (`--backend` and its aliases), CPU helper
|
|
threads, GPU power percentage, prefill chunk, exact/quality kernels, and warm
|
|
weights. Only offer backend/device choices supported by the current build.
|
|
- **Speculative decoding:** MTP draft-token count and margin, GLM MTP, GLM MTP
|
|
timing, DSpark enablement, DSpark confidence threshold, and DSpark strict
|
|
target-only decode. Enabling a dependent control must enable or require its
|
|
support artifact exactly as the CLI does.
|
|
- **SSD streaming:** enablement, cold start, expert count or GiB cache budget,
|
|
fully resident GLM layers, and explicit expert preload count. Retain the
|
|
distinction between unset/automatic and an explicit zero where DS4 does.
|
|
- **GPU placement:** per-device VRAM budgets, device indices, and CUDA tensor
|
|
parallelism when available. Hide or disable these controls in a Metal-only or
|
|
CPU-only build rather than accepting values the engine cannot honor.
|
|
- **Directional steering:** direction-vector file, FFN scale, and attention
|
|
scale, including the CLI rule that a file with no explicit scale defaults the
|
|
FFN scale to 1.
|
|
- **Advanced diagnostics that change model execution:** simulated used memory
|
|
and routed expert profile output. Keep these in an Advanced section with
|
|
clear diagnostic labels, but persist and pass them through like their CLI
|
|
equivalents.
|
|
|
|
Prompt sources, raw one-shot mode, inspect/dump/perplexity/imatrix/self-test
|
|
actions, and distributed coordinator/worker network topology are CLI workflows,
|
|
not persistent model parameters; they belong to their corresponding chat,
|
|
diagnostic, or deployment surfaces rather than Preferences. Any future DS4 CLI
|
|
option must be classified explicitly as either a preference or one of these
|
|
non-preference actions.
|
|
|
|
Implement this before chat as one typed settings path shared by the local GUI,
|
|
the lazy engine lifecycle, and HTTP defaults:
|
|
|
|
- Persist unset/automatic values separately from explicit values and provide a
|
|
Reset to DS4 defaults action. Validate before saving with the same accepted
|
|
ranges and cross-field rules as the CLI.
|
|
- Mark settings as load-time or turn-time. A load-time change unloads/reloads at
|
|
the next safe boundary; sampling, seed, token budget, and reasoning changes
|
|
apply to the next turn without duplicating the engine.
|
|
- Local chat uses these values directly. HTTP requests use them as defaults and
|
|
may override only request-scoped generation fields supported by the API; both
|
|
paths still resolve through the same effective-settings builder.
|
|
- Add a focused parity test that inventories every option branch in the DS4 CLI
|
|
model/runtime, sampling, and steering groups and fails until each option is
|
|
mapped to a typed preference or explicitly classified as a non-preference
|
|
action.
|
|
|
|
Exit criterion: save, restart, and recover every supported DS4 model/runtime
|
|
and generation value; show the same effective defaults and validation as the
|
|
CLI; and construct one engine configuration plus one turn configuration without
|
|
chat or HTTP code re-parsing preference fields.
|
|
|
|
### Targeted downloads and storage
|
|
|
|
- The Preferences panel can download the selected model's main GGUF and the
|
|
DSpark support GGUF when enabled. A dedicated worker thread performs HTTP and
|
|
verification work so Preferences and the rest of the application stay
|
|
interactive.
|
|
- Use an in-process Rust HTTP client with Rustls rather than invoking a system
|
|
downloader. Stream response chunks directly into a `.part` file and use a
|
|
Rust SHA-256 implementation for verification.
|
|
- Report aggregate bytes present, total bytes, bytes missing, percentage,
|
|
smoothed transfer rate, current artifact/verification phase, and estimated
|
|
time remaining. Keep the detailed display in Preferences and a persistent
|
|
status bar with a Stop action while the transfer runs.
|
|
- Stop is non-destructive: close the active transfer and retain its `.part`
|
|
file. Starting the download again in the same process or after quitting and
|
|
relaunching must derive progress from that file and issue an HTTP range
|
|
request from its exact byte length. If the server ignores the range request,
|
|
safely restart that artifact from byte zero rather than appending corrupt
|
|
data.
|
|
- Promote a `.part` file only after its exact size and SHA-256 are verified. A
|
|
stopped verification keeps the complete partial file so the next run can
|
|
verify and promote it without downloading it again.
|
|
- Store managed model artifacts under
|
|
`~/Library/Application Support/DS4Server.rfc1437.de/models/<model-id>/` and
|
|
mmap/load them from there. Do not place managed models in the app bundle or a
|
|
project directory.
|
|
- Download only the selected model's main artifact. Download its DSpark
|
|
artifact only when DSpark is enabled; never prefetch other catalog models or
|
|
optional artifacts.
|
|
- Remove checksum-invalid partial files without touching a valid model. Keep
|
|
partial files after cancellation, application exit, network failure, or an
|
|
interrupted verification so they remain restart-resumable.
|
|
- When the selected model changes or DSpark is disabled, offer removal of the
|
|
now-unused artifact; do not delete large existing downloads without explicit
|
|
confirmation.
|
|
|
|
Exit criterion: select a supported DeepSeek V4 or GLM 5.2 GGUF, load it without
|
|
blocking the UI only when a chat begins, run a deterministic prompt, unload it
|
|
after the configured idle timeout, and pass the matching `../ds4` token-output
|
|
fixture. Repeat through the local endpoint and verify both paths share the same
|
|
engine lifecycle.
|
|
|
|
## Phase 2 — OpenAI-compatible local endpoint
|
|
|
|
Status: **open; not started**.
|
|
|
|
1. Add a localhost-only HTTP service whose lifecycle is independent of the
|
|
engine. It can listen while the model is unloaded and acquires the configured
|
|
model only for inference. Start and stop it from the GUI; never expose a LAN
|
|
listener without an explicit setting.
|
|
2. Implement the DwarfStar compatibility surface in this order:
|
|
- `GET /v1/models`
|
|
- `POST /v1/chat/completions`
|
|
- `POST /v1/responses`
|
|
- `POST /v1/completions`
|
|
`GET /v1/models` reports the configured model without forcing it to load.
|
|
3. Support streaming SSE, reasoning output, usage accounting, cancellation,
|
|
sampling parameters, tool schemas, and tool choice.
|
|
4. Port exact sampled tool-call replay and deterministic canonicalization from
|
|
`ds4_server.c` so a client's normalized JSON does not destroy KV-prefix
|
|
reuse.
|
|
5. Route API conversations through the shared session registry and KV store
|
|
defined in Phase 1. Responses `conversation` bindings and any other
|
|
persistent request identity map to the same application session used by the
|
|
GUI; stateless requests use shared DS4 prefix lookup. Persist/restore only
|
|
through the engine-owned serialization format. Add resident batching only
|
|
after single-session and cross-surface correctness are established.
|
|
6. Display endpoint address, model, active requests, token rates, and errors in
|
|
the GUI.
|
|
|
|
Exit criterion: the upstream DwarfStar server tests pass against the app for
|
|
non-streaming and streaming Chat Completions and Responses calls, including a
|
|
multi-turn tool call. A compatible prefix created by local chat must register a
|
|
remote cache hit, a remote checkpoint must be reusable by local chat, and a
|
|
GUI/HTTP race on one bound session must serialize without corrupting its token
|
|
or KV frontier.
|
|
|
|
## Phase 3 — durable agent sessions
|
|
|
|
Status: **partially open**. Project/session metadata rows exist; transcripts,
|
|
model binding, and KV payload persistence are not implemented.
|
|
|
|
Extend each metadata-only session with transcript and shared-checkpoint
|
|
metadata:
|
|
|
|
```text
|
|
Application Support/DS4Server.rfc1437.de/
|
|
data.sqlite3
|
|
models/<model-id>/
|
|
main.gguf
|
|
dspark.gguf # only when enabled
|
|
kv-cache/
|
|
<ds4-cache-key>.kv
|
|
```
|
|
|
|
- Add migrated message/transcript tables and an optional current-checkpoint key
|
|
to SQLite. Keep large engine-owned KV payloads only in the process-wide Phase
|
|
1 store, written with atomic replacement; do not introduce separate
|
|
agent-only or HTTP-only cache formats.
|
|
- Record model identity, context size, rendered token history, title,
|
|
timestamps, and working directory.
|
|
- Restore compatible KV immediately. If KV is absent or incompatible, rebuild
|
|
from the transcript and show prefill progress.
|
|
- Add strip/archive behavior equivalent to the native agent: retain the
|
|
transcript and clear its checkpoint reference. Remove the cache file only
|
|
when it is not reusable by another live/session prefix; otherwise normal DS4
|
|
disk-budget eviction reclaims it.
|
|
- Version formats before the first release and add migrations only when a real
|
|
format change exists.
|
|
|
|
Exit criterion: quit during normal use, relaunch, select a session, and resume
|
|
the same conversation without prefill when its KV payload is compatible.
|
|
|
|
## Phase 4 — agent chat and tools
|
|
|
|
Status: **UI shell only**. The conversation area, composer, and icons are
|
|
visual placeholders with no message or agent runtime behind them.
|
|
|
|
1. Build the classic chat surface: transcript, reasoning disclosure, tool-call
|
|
cards, composer, queued input, stop button, prefill progress, and generation
|
|
statistics. Local turns must call the same session registry and KV path used
|
|
by the HTTP endpoint.
|
|
2. Port the native agent turn loop from `ds4_agent.c`, including model-specific
|
|
system prompts and DeepSeek DSML/GLM tool-call parsing.
|
|
3. Implement the local tool set with the project directory as its boundary:
|
|
- shell command execution
|
|
- file read and continuation
|
|
- file write
|
|
- anchored edit
|
|
- text/file search
|
|
- opt-in Dev Brain knowledge lookup and memory storage
|
|
4. Stream assistant tokens and partial tool calls into Iced while inference and
|
|
tools run on workers. Preserve cooperative interruption and a valid KV
|
|
prefix at every stop point.
|
|
5. Require confirmation for commands or writes outside the project boundary,
|
|
destructive actions, and network tools. Add web search/page visiting only
|
|
after the local tool loop is stable.
|
|
6. Port context compaction and system-prompt reinjection after ordinary
|
|
multi-turn operation is correct.
|
|
|
|
### Native macOS menus (required with chat)
|
|
|
|
The application must install and maintain a complete native macOS menu bar;
|
|
the application-name menu alone is not sufficient. Use platform menu roles,
|
|
ordering, selectors, and standard key equivalents rather than drawing menus
|
|
inside the Iced window.
|
|
|
|
- Provide the standard **Application**, **File**, **Edit**, **View**,
|
|
**Window**, and **Help** menus. Include the normal macOS Application actions
|
|
(About, Settings, Services, Hide, Hide Others, Show All, and Quit) and Window
|
|
actions (Minimize, Zoom, Bring All to Front) with native behavior.
|
|
- Make File actions operate on real application concepts: New Session, Add/Open
|
|
Project, and Close Window. Make View actions cover actual available views,
|
|
including sidebar visibility and Enter Full Screen. Help opens the local help
|
|
or documentation surface. Do not add permanently inert placeholder items.
|
|
- The Edit menu is part of the chat acceptance criteria. Undo, Redo, Cut, Copy,
|
|
Paste, Paste and Match Style where supported, Delete, and Select All must act
|
|
on the current first responder. They must work in the chat composer and every
|
|
other editable text field; Copy and Select All must also work for selectable
|
|
transcript text.
|
|
- Prefer native first-responder selectors for native controls. Where an Iced
|
|
widget owns focus, bridge the same menu command into that focused widget so
|
|
menu clicks and `Command-Z`, `Shift-Command-Z`, `Command-X`, `Command-C`,
|
|
`Command-V`, and `Command-A` behave identically.
|
|
- Validate menu enabled state whenever focus or application state changes:
|
|
editing commands reflect the focused selection/clipboard and session/project
|
|
commands reflect whether their action is currently possible. Menu actions
|
|
must use the same application messages as toolbar/sidebar actions instead of
|
|
duplicating business logic.
|
|
- Preserve conventional macOS labels, grouping, keyboard shortcuts, and
|
|
accessibility metadata. Keep platform-specific menu integration behind the
|
|
macOS application shell so the chat and session core remain platform-neutral.
|
|
|
|
Exit criterion: with the composer focused, every standard Edit command works
|
|
from both the menu and its keyboard shortcut, including undo/redo across
|
|
multiple edits; transcript text can be copied; and Application, File, View,
|
|
Window, and Help expose functional, correctly enabled native actions.
|
|
|
|
### Dev Brain — Obsidian knowledge and memory
|
|
|
|
- Add an optional Dev Brain setting in Preferences. Use the native macOS folder
|
|
picker to select an existing Obsidian vault, allow the vault to be changed or
|
|
disconnected, and persist its canonical path plus a security-scoped bookmark
|
|
in SQLite so sandboxed builds can regain access after restart.
|
|
- Keep the vault global to the application rather than tied to one project or
|
|
session. The selected vault remains in its original location; never copy it
|
|
into Application Support or a project directory.
|
|
- Add one local `dev_brain` agent tool with the minimum useful operations:
|
|
search Markdown notes, read a selected note, and create or append a memory
|
|
note. Return vault-relative paths with results so the agent can cite where
|
|
knowledge came from.
|
|
- Restrict every operation to the explicitly selected vault. Resolve and check
|
|
paths before access, ignore `.obsidian` and hidden files, and do not provide
|
|
deletion or arbitrary overwrite operations initially.
|
|
- Let the agent retrieve relevant global knowledge during a turn and record
|
|
durable conclusions after a turn. Vault access is opt-in, does not preload the
|
|
model, and must not block sessions when no vault is configured or available.
|
|
- Reuse the existing local file/search implementation underneath the new vault
|
|
boundary instead of building a second filesystem stack.
|
|
|
|
Exit criterion: create a project session, ask the model to inspect and edit a
|
|
small fixture repository, review each tool result in the GUI, restart, and
|
|
continue from the persisted session. With Dev Brain enabled, store a memory in
|
|
one session and retrieve it with a cited vault-relative note path from a session
|
|
in another project after restarting the app.
|
|
|
|
## Phase 5 — A2UI rich local-chat surfaces
|
|
|
|
Status: **future extension; not part of the core milestone**. Start only after
|
|
ordinary local chat, structured tool calls, transcript persistence, and
|
|
cancellation are stable. Use the A2UI implementation in `../bDS2` as the
|
|
behavioral reference, especially its render-tool schemas, typed surface
|
|
normalization, inline message placement, chart geometry, and interaction state.
|
|
|
|
- Expose typed `render_card`, `render_chart`, `render_form`, `render_list`,
|
|
`render_metric`, `render_mindmap`, `render_table`, and `render_tabs` tools to
|
|
the local agent. Keep these tools presentation-only; they return structured
|
|
data and do not perform project mutations themselves.
|
|
- Support the bDS2 chart set initially: bar, stacked bar, line, area, pie,
|
|
donut, and heatmap. Render charts and mind maps with native Iced primitives
|
|
and SVG geometry inside the assistant message rather than adding a web view.
|
|
- Treat tool arguments as untrusted data. Validate type, nesting depth, row and
|
|
series counts, numeric values, labels, action names, and payload size before
|
|
rendering. Never accept model-authored HTML, JavaScript, styles, file URLs, or
|
|
arbitrary commands.
|
|
- Attach each validated surface to the assistant message/tool call that created
|
|
it and persist the versioned structured payload with the transcript. A
|
|
restarted session must reconstruct the same surface without asking the model
|
|
to emit it again.
|
|
- Build a surface only after its tool arguments are complete and valid while
|
|
allowing ordinary assistant text to continue streaming. Malformed or unknown
|
|
render payloads fall back to a bounded JSON/text representation and must not
|
|
fail the surrounding chat turn.
|
|
- Preserve local interaction state for forms and tabs. Dispatch form submits
|
|
and card actions through a small allowlist of application actions; any action
|
|
that mutates files, settings, or external state still follows the normal
|
|
approval path.
|
|
- Provide keyboard navigation, readable labels, theme-aware colors, and a text
|
|
or tabular fallback for chart data so the information remains accessible and
|
|
copyable.
|
|
- Keep A2UI local-chat-only initially. Do not extend the OpenAI-compatible HTTP
|
|
surface or invent a general plugin/component protocol until a real client
|
|
requires it.
|
|
|
|
Exit criterion: ask the local agent to present fixture data as each supported
|
|
surface type; verify a chart and nested tab surface render correctly, an
|
|
interactive form returns validated values, malformed payloads degrade safely,
|
|
and all surfaces survive application restart with their message history.
|
|
|
|
## Verification and packaging
|
|
|
|
Status: **partially implemented**. Formatting, Clippy, build, and unit-test
|
|
commit gates are documented in `AGENTS.md`; database migration/CRUD constraints
|
|
and the preferences shortcut have unit coverage. Model fixtures, integration
|
|
tests, and release packaging remain open.
|
|
|
|
- Keep unit coverage narrow: persistence round trips, format compatibility,
|
|
DS4 KV prefix/rewrite/store/load parity, cross-surface session binding,
|
|
request parsing, and tool-boundary checks.
|
|
- Reuse `../ds4` fixtures for prompt rendering, sampling, server streaming, and
|
|
KV correctness; run live Metal tests only when a supported GGUF is available.
|
|
- Preserve the DwarfStar/llama.cpp notices required by `../ds4/LICENSE` for
|
|
reused or adapted source and kernels.
|
|
- Produce a signed `.app` with the exact identifier above, then add hardened
|
|
runtime, entitlements, notarization, and update delivery as release work.
|
|
|
|
## Recommended next milestones
|
|
|
|
1. Complete DS4 CLI model/runtime/generation preference parity and its shared
|
|
typed effective-settings builder.
|
|
2. Implement the single-engine lifecycle and local generation path: lazy load,
|
|
shared concurrent acquisition, activity tracking, and idle unload.
|
|
3. Put the OpenAI-compatible endpoint on that same engine lifecycle so local
|
|
chats and HTTP requests cannot load duplicate engines.
|
|
4. Add transcript/KV persistence, then connect the existing conversation UI and
|
|
finally port the agent tools.
|
|
5. Add the opt-in Dev Brain tool after local file/search boundaries and agent
|
|
approvals are stable.
|
|
6. Add bDS2-style A2UI render tools and native inline surfaces after the core
|
|
local chat/tool loop is complete.
|