You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 5442e4f
Browse filesBrowse the repository at this point in the historyBrowse files
dev-lhl: carry P22's model-source.js (the blob the incremental push missed)
Surgical fix: the incremental push assembled every path except
model-source.js (whose delta was computed against a base the script
could not resolve locally). This commit carries the exact post-P22
content of that single path; the tree now matches wt-merge HEAD
b4fb7e2 exactly.
Copy file name to clipboardExpand all lines: docs/webui.md
+96-2Lines changed: 96 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1204,12 +1204,15 @@ one, Worktree, reads the engine since PB-3.
1204
1204
| Preferences | General (通用) | implemented |
1205
1205
| Preferences | Voice | implemented, placeholder controls — the microphone dropdown is disabled with a single 「本地版不适用」 option, and both dictation rows show 未设置 (no device enumeration, no dictation input in a browser) |
1206
1206
| Preferences | Shortcuts | implemented — 10 desktop rows, each stating what the browser can do with it: 3 rebindable and live, 1 live on macOS only, 6 blocked with the specific reason (see **Shortcuts — what the browser can intercept**) |
1207
-
| Preferences | Personalization | implemented— 自定义指令 and 关于你 persist to `localStorage`; both memory switches render off and disabled with the not-applicable marker, and 管理 opens the 记忆摘要 dialog in its permanent empty state |
1207
+
| Preferences | Personalization | implemented, and honest about what it is for — 自定义指令 and 关于你 persist to `localStorage` and each field states 「已保存于本浏览器,不会注入引擎会话」, because the engine has no channel that reads them (SB-8 / D-2; the storage is kept, the injection claim is not); both memory switches render off and disabled with the not-applicable marker, and 管理 opens the 记忆摘要 dialog in its permanent empty state |
1208
1208
| Management | Usage & models | implemented; since SB-1 the two engine sources are real (Token Plan / MiniMax API switch the engine's credential, the 「使用中」 badge reads the engine back, and the MiniMax API key can be saved and probed) — the third pill, Custom models, stays a VIEW onto the provider catalogue |
1209
1209
| Management | Connection | implemented |
1210
1210
| Management | Account | implemented as a read — the section reads `GET /api/account` on mount and renders the account name, the current plan name, the quota overview (plan-quota state plus the 5-hour and weekly remaining figures) and the account status; sign-out stays disabled (no engine method acts on it) |
1211
1211
| Coding | Code review | implemented — 自定义审查准则 persists to `localStorage`; 审查方式 is a disabled single-option dropdown showing 子会话 |
1212
1212
| Coding | Worktree | implemented as a CLEANUP page since PB-3 — see **Worktree — what the page can and cannot do** |
1213
+
1214
+
| Coding | Code review | implemented — 自定义审查准则 persists to `localStorage` and carries the same 「不会注入引擎会话」 note as the two Personalization texts (SB-8 / D-2); 审查方式 is a disabled single-option dropdown showing 子会话 |
1215
+
| Coding | Worktree | **not implemented** — the tab is a one-line panel reading 「本地版暂不支持工作树管理」 |
1213
1216
| Archived | Archived tasks | the tab renders its empty state 「暂无已归档任务」; the list and its actions need an archived-session contract that does not exist |
1214
1217
1215
1218
**Worktree — what the page can and cannot do.** The Worktree tab is a
@@ -1326,7 +1329,7 @@ between adjacent rows:
1326
1329
| Session management | enabled | one switch, persisted; gates the composer's context-window readout (see below) |
1327
1330
| Agent control | disabled furniture | the 「自动打开浏览器面板」 switch renders off and disabled (no capability behind it) |
1328
1331
| Preference settings | enabled | follow-up behaviour (disabled / queue / send now); since SB-4 the composer reads it, and a send into a running turn reaches the engine's queue or steers the running turn. Watermark and data opt-in render disabled |
1329
-
| About | mixed | upload logs and check-for-update are disabled buttons; the local URL and LAN URL are live read-only rows from `/api/settings` |
1332
+
| About | mixed | **export logs** is a live download of this server's own diagnostic trail (`GET /api/logs/export`, see below); check-for-update is still a disabled button — self-hosted update is `git pull`, and the desktop updater's semantics do not apply; the local URL and LAN URL are live read-only rows from `/api/settings` |
1330
1333
| dataDir footer | not implemented | the reference prints the app data directory at the bottom of the General page; `/api/settings` has no such field and the server routes are read-only this round, so no value exists to print |
1331
1334
1332
1335
Appearance and language behave as before: immediate effect on click; the
@@ -1864,6 +1867,96 @@ scope, and until it lands a queued follow-up is invisible until the
1864
1867
running turn ends. A steered message reports admission, not whether the
1865
1868
running agent read the text before its next step.
1866
1869
1870
+
### Export logs: a download, because there is nowhere to upload to (SB-8 / D-3)
1871
+
1872
+
**What the user sees.** The About section's first row is 导出日志 / **Export
1873
+
logs**, and its button works: the browser saves one text file named
1874
+
`mcode-webui-logs-<timestamp>.txt`. The row's description says what is in
1875
+
it — this server's error log and recent activity — and adds that nothing is
1876
+
uploaded anywhere.
1877
+
1878
+
**Why the rename.** The row used to be a permanently disabled button
1879
+
labelled 上传日志 / **Upload logs**. There is no upload service in this
1880
+
edition: no telemetry sink, no ticket intake, nothing that leaves the
1881
+
machine. A label that names a destination the product does not have is a
1882
+
promise, and a disabled control cannot keep it — the tooltip only
1883
+
contradicted the title. The alternative considered and rejected was
1884
+
keeping 上传日志 and pointing it at the download, on the argument that the
1885
+
desktop reference uses the word; a reference's word does not make its
1886
+
destination real, and the button would then say "upload" while writing to
1887
+
the user's disk.
1888
+
1889
+
**What the file contains.** Two sources, both read from the module that
1890
+
writes them, so a relocated data directory cannot make the export silently
The tail, not the head: the failure being investigated happened most
1899
+
recently, and the event log is tens of megabytes on a long-lived install.
1900
+
Every bound is printed in the file itself (`[truncated: showing the last N
1901
+
of M lines]`), so a reader can tell a bounded file from a complete one
1902
+
without trusting the tool that produced it.
1903
+
1904
+
**What the file deliberately does not contain.** `sessions.json`
1905
+
(conversation transcripts), `settings.json` (provider credentials) and
1906
+
`uploads/`. A diagnostics file users attach to a bug report must not be
1907
+
the one file on the machine carrying their API keys and their
1908
+
conversations. The source list is a closed two for that reason, and a test
1909
+
asserts the markers never appear in a bundle built next to decoy files.
1910
+
1911
+
**Why there is no failure status.** The endpoint answers `200` in every
1912
+
case, including a log file that does not exist. The client is a browser
1913
+
anchor with a `download` attribute, so a `404` would be saved into the
1914
+
user's downloads folder as `mcode-webui-logs-<timestamp>.txt` containing a
1915
+
JSON error body — a file that looks like logs and is not. Absence is
1916
+
therefore reported where the reader is: inside the body, per section.
1917
+
1918
+
**What it costs.** One read of two local files per click, synchronously on
1919
+
the server's event loop. Both are capped, so the worst case is a few MiB
1920
+
of already-warm page cache.
1921
+
1922
+
**Known debt.** The bundle is plain text with no redaction: an engine error
1923
+
line can quote a prompt fragment. Redaction is not attempted because there
1924
+
is no reliable rule for what is secret in an arbitrary log line, and a
1925
+
partial redaction would be worse than none. Until the engine's own logging
1926
+
grows a redaction hook, the operator is the one deciding what to share
1927
+
from the downloaded file.
1928
+
1929
+
### The three stored texts are storage, not instructions (SB-8 / D-2)
1930
+
1931
+
**What the user sees.** 自定义指令, 关于你 and 自定义审查准则 each keep
1932
+
their textarea and their 保存 action, and each now prints one line under
1933
+
the field: **「已保存于本浏览器,不会注入引擎会话。」** / "Saved in this
1934
+
browser only — it is not injected into engine sessions."
1935
+
1936
+
**Why.** The texts have always persisted — that part is real and stays
1937
+
real. What is not real is any claim that they reach the engine. A grep of
1938
+
the runtime source for `setConfigOption` — the option the plan had assumed
1939
+
would carry them — found nothing: the method does not exist anywhere in
1940
+
`local-runtime-v2`, so there is no config write channel to hang them on,
1941
+
and no session-creation parameter that takes them either. With no consumer,
1942
+
a saved 「自定义指令」 read as an instruction the agent follows. The field
1943
+
was making a capability claim its backend had already disproved.
1944
+
1945
+
**The decision tree this took.** The three options were: extend the engine
1946
+
contract, drop the fields, or keep the storage and stop claiming the
1947
+
effect. Extending the contract is engine work with no local caller to size
1948
+
it against; dropping the fields removes a place users keep text they own
1949
+
and can read back at any time. What remains is honest and cheap: the
1950
+
storage is a user's own local text, the field says plainly that it is not
1951
+
an instruction, and the moment the engine grows a channel, deleting one
1952
+
sentence and one `note` prop is the whole change.
1953
+
1954
+
**What this does not do.** It does not make the texts work, and it does not
1955
+
hide that they do not work — that is what the note is for. Nothing reads
1956
+
the three `localStorage` keys: a future change that wires one of them must
1957
+
remove the note in the same commit, or the field will be describing an
1958
+
effect it no longer lacks.
1959
+
1867
1960
## Main-surface elements: user menu / project context menu / home capsules (ticket 55c)
1868
1961
1869
1962
The user asked for every desktop main-surface screenshot to be copied
@@ -3079,6 +3172,7 @@ marker), not by tool name.
3079
3172
| `PUT` | `/api/model-source/api-key` | `routes/model-source.js#handlePutModelSourceApiKey` | `{apiKey, saveAndUse?}`; an absent/empty/whitespace `apiKey` is the KEEP sentinel → `200 {changed:false}` with no engine write; `400 {code:"BAD_FIELD_TYPE"\|"INVALID_API_KEY"}`; `500 {code:"engine_error"}` never carries the thrown message |
3080
3173
| `POST` | `/api/model-source/test` | `routes/model-source.js#handleTestModelSource` | `{modelId?}`; always 200 for a COMPLETED probe (`{ok, success, providerId:"minimax_api", tested:"stored_key", status}`) including `success:false`; non-200 only when the probe is refused (`503`/`501`, or the engine's `400 NO_API_KEY`) |
3081
3174
| `POST` | `/api/follow-up` | `routes/follow-up.js#handleFollowUp` | `{behavior:"queue"\|"steer", content, attachments?, requestId?}` — the engine session id comes from the server's own conversation state, never the body; `400 {code:"invalid_follow_up_behavior"\|"follow_up_empty"\|"no_active_conversation"\|"BAD_FIELD_TYPE"}`; `409 {code:"no_active_turn"\|"turn_not_owned"}` when this process does not own the running turn, and nothing is queued; `501` when the host lacks the method, `503` when no runtime is booted; 200 `{ok, behavior, itemId, position, status}` (queue) or `{ok, behavior, turnId, mode}` (steer) — the engine's own answer |
3175
+
| `GET` | `/api/logs/export` | `routes/logs.js#handleExportLogs` | always `200 text/plain` with `Content-Disposition: attachment; filename="mcode-webui-logs-<YYYYMMDDTHHMMSS>.txt"` — the crash trail (`WEBUI_DATA_DIR/.server.err`) plus the last 2000 lines / 2 MiB of the event log, each section stating its own truncation or absence. No status code for a missing or unreadable log file: that is reported inside the body, because the client is a browser anchor and a 4xx would be saved as a `.txt` file containing JSON |
0 commit comments