516 Commits
Author SHA1 Message Date
yhh 07d2d4bdd0 Show the cache hit rate after the cold start, and the output ratio
The session's first executor request pays for the prefix every later one
reuses, so the session-wide hit rate mixes "did the cache work once warm"
with "how much a cold start could reuse". usagereport already records the
cold start, but nothing a live session reads projected it.

The live figures come from the serve ledger, which restarts on /new,
/resume and /fork; usageTally does not, so its ColdStart can belong to an
earlier conversation in the same process. The broadcaster therefore takes
the cold start from the ledger's own population: the first request the
ledger files under the executor (pricing.LedgerSource, the rule Add
already used), split by the same CacheSplit the ledger applies, and reset
with it. SessionUsage carries it as coldStart.

- /status (TUI): "warm cache" row, ledger hit rate with the cold start
  taken out of hit, miss and unknown; "out/in" row, output ÷ input.
- Desktop session overview behind the cache meter: the same two figures,
  computed in state/overview beside cacheRate.
- wire-parity: ColdStartUsage mirrored in port/session.ts.
2026-11-07 09:06:37 +00:00
yhh 83bdeb81f0 feat(studio): the workbench gets a terminal of your own, as the Terminal board draws it
A fourth kind of tab opens a real shell (ConPTY on Windows, a pty elsewhere) in
the project folder, outside the model's permissions and sandbox and with the
host's provider keys left out of its environment. The kernel keeps each shell's
output, so a tab left or a window reloaded comes back as it was; a tab is named
for the command submitted while the shell is busy and carries a blue dot, and
closing a busy one asks first.

Also: the composer's note stack no longer clips to a few pixels when it holds
two notes, which left the second one overlapping the input.
2026-11-06 04:44:41 -08:00
yhh 3bf7491840 refactor(studio): the settings window loses its enlarge mode and keeps one close button
The sheet already fills the window, so enlarging only took it over the title bar and added three window buttons beside its own two. The control, the stored preference, the window buttons it summoned and the drag-region rules that went with it are removed; the board draws no buttons in that corner besides closing.
2026-11-05 19:13:20 -08:00
yhh 1b8b56aa65 feat(studio): compaction archives earlier turns to a file instead of summarizing; a skipped ask ends the turn as finished; chat overlays follow the design board
Compaction moves the folded span into <session>.outputs/fold-<hash>.md and leaves a pointer the model reads back with read_file. The summarizer path, its retries, bounds and tests are removed.

Answering an ask with no selection ends the turn normally instead of reporting a failure.

Find bar, overview and context cards, compact dialog, image preview, root-missing banner, toasts, side panel and prompt refine are aligned to the Chat-Tools board; the agent preset picker follows the Agent-Picker board.
2026-11-05 16:25:25 -08:00
esengine c93eabbe4c feat(studio): starter chips in the empty conversation and a changed-settings card on the common page 2026-11-05 10:41:00 +00:00
esengine 53cd9a0ac3 refactor(studio): keyframes converge to the six spec 07 shared ones plus the ones a board draws, registered in a test 2026-11-05 10:20:01 +00:00
esengine cf4ed6d7c6 fix(studio): motion follows spec 07: entrance animations play again, spec durations and one global reduced-motion rule 2026-11-05 09:58:51 +00:00
esengine 8472468039 refactor(studio): remove the delivery-receipt chain and the completion-standard row; light remember and guardian cards 2026-11-05 08:16:07 +00:00
esengine c370090b8b feat(desktop): the message rail spreads over the column and shows where you are, as the Msg-Rail board draws it
Marks sit at each message's place in the whole conversation (a mounted
message by its own box, an unmounted one by its block), filling the column
instead of a compact cluster in the middle. A grey band follows the viewport
and the marks inside it draw darker; a message that changed files draws
longer; stars are orange. Hovering grows the pointed line and two neighbours
each side (22/16/12px) and opens a card: "你的第n条 · 改了n个文件", two lines of
the message, and the click/right-click hint. Marks closer than 5px join into
segments of at most 56px; hovering one lists its messages with their numbers
and stars, and a press on bare track lands on the mark at that height.
Unloaded earlier messages show as a count pill at the top with a tooltip.
Ctrl+Up/Down rings the mark it walks to and shows its card. A landing on a
mounted message glides over 300ms and the message flashes. The rail needs
three of your messages, is hidden in the folded narrow layout, and reduced
motion switches without animating.

The test for BackgroundJob imported Tool from the port, which does not
export it; it comes from the wire module.
2026-11-04 11:31:51 +00:00
esengine 24a506d553 chore(repolint): lower the budgets the deleted account row freed 2026-11-04 08:32:30 +00:00
esengine ca167b6c47 feat(desktop): the workbench and the command palette follow their boards
Workbench (WB-Frame, WB-Parts): a raised panel with the float shadow; a 42px tab strip on the page tone with the file-tree tab first, the active tab a raised folder tab of 35px that sits into the panel, others 34px and quiet; a 40px path bar whose segments are faint 12px mono with the file name in semibold text; the read/edit/diff choice as a 24px segmented control; Save as the 32px primary button, outlined while there is nothing to save. The editor sits on the raised surface. Its default width is 520 and the drag starts at 360 with a 900 ordinary limit, as the board's width rule states.

Command palette (Cmd-Palette): 14px corners, a 52px search row at 15px with an Esc key, 11.5px section labels, 36px rows that light with the float highlight, and a 36px footer on the page tone.
2026-11-04 06:12:20 +00:00
esengine 9937a1cb4a feat(desktop): delivered files are the board's one-column file cards, and the empty conversation is flat
A delivered file is one row in a single column: 16px file icon, 13px semibold name, 12px faint description, an Open pill and a 28px more button, 10px/12px padding in a 10px bordered card; the one open in the workbench takes the accent border. The two-column grid and the 22px badged icons are gone, and the more button keeps its "More actions: name" label.

The empty conversation drops the grid and glow it painted under the hero and sits on the plain surface, as both editor boards draw it.
2026-11-04 05:34:38 +00:00
esengine 6734594790 feat(desktop): the turn and its execution card follow the Chat-Reply and Think-Exec boards
Your message is a 15px overlay bubble at 14px/1.6 and at most 78% of the column; the reply head is a 20px accent R tile beside the 13px semibold name. The execution process is one card with a hair border and 10px radius: a 30px header carrying the running pill and the step count, then 28px rows of kind glyph, the board's verb (读取, 编辑, 运行命令…), the target in 12px mono, the reading, and the status mark at the right end. The raw tool id stays on the verb's title, where it is still one hover away.

The legacy !important rules on .activity-body, .activity-group and .call[data-call] > .c are deleted so the design layer can draw them; src/design/turn.css holds the replacements.
2026-11-04 05:31:43 +00:00
esengine 04ad0e3c25 feat(desktop): the composer follows the Chat-Composer board
One 15px box with the composer's only shadow; a top row that exists only while a turn runs or files have changed, holding the run pill and the changed-files pill; 14px/1.6 input with 10px/16px padding; a toolbar of 28px borderless pills in the 12px meta size; the model name in 13px semibold text beside its effort; 32px round send and stop, stop drawn as a danger ring. Under 590px of conversation the pickers tighten and under 420px the effort reading folds into the model button, as the narrow-window state shows. The status line keeps 11px faint labels with muted semibold values.

The legacy !important rules on .compose, the pickers and the attach buttons are deleted, since an important declaration in the legacy layer outranks every design-layer rule; the replacements live in src/design/composer.css.
2026-11-04 05:26:10 +00:00
esengine fe55132d55 feat(desktop): the window bar, empty state and sidebar foot follow the editor board
The window bar is 48 high on the surface with a hair line under it; the breadcrumb is 13px and the four icon buttons are 28px, ordered find, device access, theme, workbench. The sidebar foot is the Rail-Foot board's single toolbar row: usage, files, tools, extensions, memory and remote as 28px icons whose names carry their reading, settings at the right end, and feedback as its own 30px row with the unread count. The account entry leaves the rail for settings, as the board says. The empty state's mark sits in a 44px accent tile above a 22px title.

The legacy .chrome, .railfoot, quick-nav, wallet, user-foot and hero rules are deleted rather than overridden; the replacements live in src/design/shell.css in the design layer.
2026-11-04 05:14:26 +00:00
esengine 9d18948916 chore(repolint): a release-note item is no longer held to a column limit, only to naming its change 2026-11-03 17:27:21 -08:00
YHH 055b60bc0c Merge pull request #14948 from chuiwenwei/fix/acp-lease-refusal-carries-a-code
fix(acp): a lease refusal says which refusal it is
2026-11-02 21:16:57 -08:00
esengine 863f66cb7e test: update the compact ratio default the CLI reports 2026-11-02 15:57:06 -08:00
esengine ad2c963475 refactor(delegation): replace the task family with spawn_agents
Rewrite internal/runtime/delegation around one Runner and one tool.
spawn_agents runs 1 to 8 independent tasks in parallel, each in its own
session with three base tools (read_file, write_file, bash); plan mode and
read-only skills keep a read-only child. A child's full answer is archived;
the caller gets the opening, a reference, and the files the child read and
wrote, and pages the rest through read_subagent_result.

Removed with it: task, read_only_task, parallel_tasks, fleet,
list_subagents, background sub-tasks, steering and its limits and settings
UI, continue_from, write_paths claims, isolated worktrees, best-of-n, the
run graph and the runtime-resume benchmark. Stale writes by children stay
refused through the per-agent file views.

The use_capability description no longer names task:fleet, so the stable
prefix and its golden files change once.
2026-11-02 08:52:45 -08:00
esengine 0bb0f44785 refactor(delegation): sub-agents return prose, not a structured completion report
complete_subtask, the host adjudication of its criteria and the 'lowered by the
host' note are gone, with the handoff audit channel and its metrics, trajectory
field and benchmark columns. A delegated child ends the way any turn does and
the parent reads its last reply.

The host's own receipts appended to a child's reply and the write-scope check
stay: they need a record of what the child changed, which is replaced with the
evidence ledger later.
2026-11-02 07:16:52 -08:00
esengine 5766a8ebeb refactor(tools,plan): complete_step takes no evidence; drop conclude_blocked and plan criteria
complete_step now only says a step is done: it names the step and what is now
true, and the host advances the task list as before. It no longer asks for
commands, files or criteria to cite and no longer checks them against the
session's receipts.

conclude_blocked existed to let the readiness gate through and goes with it;
the prompts that pointed at it now ask for a sentence in the reply. Plan steps
lose their acceptance and verification fields: the submit_plan schema, the
planner and executor prompts, the rendering and the re-approval rule all
stop mentioning them, and plans saved with them still load.

The executor's no-action nudge now keys on a plan naming files only.
2026-11-02 06:33:28 -08:00
esengine 3d0fe85e7e refactor(event): remove the readiness and audit channels nothing sends to
With the final-readiness gate gone, FinalReadinessError, the readiness audit
and the structured readiness on TurnDone have no producer, and neither do the
contract-shadow, completion-report, evidence-bundle, outcome-progress,
protocol-recovery, verification-drift and project-check-probe audits. Removes
the types, the sink capabilities and their forwarding in every wrapper, the
trajectory and metrics fields, the final_readiness outcome and notice code,
and the delivery-recovery submit port.

The ACP status shape and the desktop reader of old sessions keep their
readiness fields: external editors and recorded sessions still carry them.
2026-11-02 05:59:36 -08:00
esengine 8c785fa4b0 refactor(cli,config): remove --fail-on-unverified and agent.host_verification
Both only steered the final-readiness gate, which no longer exists: the flag
chose exit 3 for an unmet readiness verdict and the setting chose whether a
changed turn was held for a check, a review and a sign-off. Neither can do
anything now.

`run` still exits 4 when an untrusted folder refused its edits. A user config
that still carries host_verification loads unchanged; the key is ignored.
Removes the HoldOwedChecks and WaiveOwedChecks plumbing behind them.
2026-11-02 05:27:28 -08:00
esengine b364c1693c refactor(agent): remove the final-readiness gate, review gate and baseline checks
A turn that ends with its answer is done. The agent no longer asks, at the
point of stopping, whether a check ran after the last write, whether a
high-risk change was reviewed, or whether captured test criteria still hold;
it no longer ends a run with a readiness error, and the controller no longer
re-runs the turn to satisfy one.

Goal keeps its update_goal report and the evaluator, and still holds a
complete claim while the task list is unfinished; it no longer reads a
readiness result or freezes a verification contract. Review sub-agents are
ordinary sub-agents: nothing requires them to file a typed report.

Removes the readiness, owed-review, baseline-criteria, carried-proof and
review-report code, the delivery checkpoint, the readiness continuation, the
orphaned helpers they left in evidence, and the tests that asserted the removed
behaviour.
2026-11-02 05:15:57 -08:00
Will e5a6c3ae93 fix(acp): a lease refusal says which refusal it is
A session method refused because another runtime owns the transcript answered
-32600 and prose, the code a malformed frame gets; an ownership probe that could
not decide answered -32603, the same as a disk that would not write. A client
could not tell "held" from "unreadable" from "your request was broken", so it
could not decide whether to ask the person to close a window or retry.

session/new, session/load and session/resume now answer -32022 with data.code
busy.session_in_use for a held lease and -32023 with data.code
session.lease_unprovable when the store's probe cannot prove ownership either
way; -32600 is left to a genuinely malformed request. The human message stays.
The HTTP frontend, the kernel, the lease and the inbox are untouched.

docs/ACP.md states the table and what a client does with each answer. repolint's
family-vs-writer check is now parameterised by family; it reads the lease
sentinels beside the inbox ones, so a lease sentinel added without a coded case
fails by name against the ACP writer.
2026-11-02 21:00:01 +08:00
esengine fb02f44834 refactor(agent): stop sealing, shadowing and receipting each turn
A turn no longer builds a shadow task contract, a completion report or a
sealed evidence bundle, takes a workspace snapshot, or hands the host a
completion receipt. Removes the agent-side producers and their wiring in boot,
the observation and verdict packages that only they used, and the
write-protection and unconfined-launch probes that only boot read.

The receipt and audit shapes on the event wire, the terminal and the desktop
settings stay for a later cleanup; nothing sends them now.
2026-11-02 04:01:03 -08:00
esengine be5c98c744 refactor(agent): remove missing-tool-call-reasoning detection and recovery
The loop no longer classifies a tool-call turn that arrived without
reasoning, retries it, or keeps a file-backed cooldown for it. Removes the
watch and the cooldown state, the deferred stream sink they needed, the
provider policy interfaces and their implementations, the descriptor field on
the extension wire (schema and SDK regenerated), the state-dir path, the
run-metrics counters and the protocol-recovery kinds.

The protocol-recovery audit channel itself stays for now.
2026-11-02 03:26:03 -08:00
SivanCola 4cef3671b3 Merge studio into feature/model-health-ui-upstream
Problem: upstream studio changes made the model-health UI PR conflict in Composer.

Root cause: studio added WorkspaceInfo while the health hook removed the former
inline ModelEntry loading state in the same import declaration.

Fix: retain studio's workspace information, running-message intent and composer
hint behavior alongside the consent-gated health hook. Remove the unused
ModelEntry import. The grouped picker, default-off setting and old-server hints
remain unchanged; the feature diff remains 514 additions across 22 files.

Verification: production frontend build, frontend tests and census; go vet,
pinned lint and repository checks; HTTP health authorization/settings tests,
builtin tests and inventory-reconciled boot partitions.
2026-10-30 10:58:58 +08:00
YHH c58b1242c8 Merge pull request #14729 from chuiwenwei/fix/register-the-unguarded-wire-mirrors
fix(repolint): register the wire mirrors that had no guard
2026-10-28 21:34:37 -07:00
Will c1079d99ba fix(repolint): register the wire mirrors that had no guard
The registry declares 324 pairs now: the 202 it already had and 122 page
copies that agree field for field with the struct their handler writes. The
table moved to a second file, wireparity_table.go, rather than taking
wireparity.go past the 800-line ceiling; the checker still reads one list.

Left out on purpose, because the writer is not a named struct and a guard
over the lookalike struct would not see the response drift:
account.DeviceGrant (/account/login assembles a map), market.Page
(/market/packages assembles a map) and control's McpDraft (/mcp/parse
assembles a map). host.ts's Refusal and ViewRect are the Electron preload's
bridge, not kernel wire; workspace.ts's WorkspaceEntry has no writer.

Tests: the added half resolves, is exact today and is unique per reader; a
dropped field on createBackupRequest -> BackupCreateRequest names the field.
2026-10-28 13:55:00 +08:00
Will 6c1f68df48 fix(tui): a restored image-only turn is still a turn
The terminal's hand-written HistoryMessage dropped images, via and modelRef.
A turn that was only an image has empty text, so Restore saw nothing to draw
and dropped it from the transcript, and every reload lost the device and the
model of turns it did keep. Carry the fields that decide that a turn exists
and what it was, restore the image-only row with an honest line, and register
the pair in repolint so a dropped field fails make check.
2026-10-28 13:43:20 +08:00
SivanCola 7142f95dba feat(studio): add opt-in health chips to grouped model picker
Problem: Saved connections lack health evidence when selecting a model, while
automatic credential-bearing checks require an explicit user opt-in.
Root cause: The previous UI slice also redesigned the disabled picker, hiding
account endpoint headings and reducing density outside the requested scope.
Fix: Preserve the original grouped rows, hosts, ordering and modelLabel behavior.
Add only short accessible health chips after reading backend consent. Put the
global switch outside the service editor, and explain unsupported older servers
and settings-read failures without enabling probes. Rebase onto current studio.
Verification: 640 frontend tests, production build, census fixtures, vet, pinned
lint, repository checks, HTTP authorization/route tests and builtin tests pass.
All 849 boot cases accounted for: 846 pass, 3 skip. Negative controls fail the
group-layout and old-server regressions. Native Electron light/dark wide/narrow
captures and 390px browser inspection verify retained row density and hosts.
Native disable/reopen issues no new requests; no generation requests occur.
2026-10-28 10:36:23 +08:00
YHH cd9c8723de Merge pull request #14551 from chuiwenwei/fix/acp-inbox-refusals-carry-codes
fix(acp): an inbox refusal says which refusal it is
2026-10-27 11:22:28 -07:00
Will d7d0c8aeef fix(acp): an inbox refusal says which refusal it is
Every inbox handler answered a store refusal with -32600 and prose, so a client
could not tell "gone" from "wrong state" from "may already have run" — and one
that retried on any error re-sent work the kernel refuses precisely because the
turn may already have run. The HTTP frontend already names 14 conditions; ACP
now answers the same names, with -32020 for "the queue refused this call" and
-32021 for "the work may already have run", and leaves -32600 to a malformed
frame alone.

docs/ACP.md states the table and each refusal's class (terminal,
retry-after-repair, do not retry). repolint's family-vs-writer check now reads
both writers, so a sentinel added to the store cannot reach ACP unnamed.
2026-10-27 18:01:52 +08:00
Lancy 4a28c20aad feat(theme): add per-scheme backdrop surface opacity 2026-10-27 02:39:02 +08:00
xxoingr 8c42340ea4 test(netclient): pin the stream dialer's proxy boundary
NewStreamDialer is how SSH reaches a remote host under the user's proxy
(remote/attach), and none of dialer.go was exercised: netclient sat at
47% against a 47.2% floor on a declared-sensitive path.

Four tests drive it against fake proxies on loopback:
- an http proxy gets CONNECT to the target with Proxy-Authorization, and
  the credentials never also travel as Authorization;
- a proxy that answers 407 yields an error, not an open stream;
- an https proxy sees a TLS handshake first, so CONNECT and credentials
  never cross in cleartext;
- a SOCKS5 proxy gets username/password auth and the target by name.

Each fails when the matching guard in dialer.go is removed. The
netclient floor rises from 47.2 to 65.8.
2026-10-25 23:54:17 +08:00
Will aeeff97700 fix(tui): keep the arguments a restored tool call actually had
The terminal's copy of /history's tool call had no argumentNormalization
field, so a restored transcript rebuilt the card from Arguments alone —
the proxy's effective text — and drew it as what the model wrote. The
original was not merely hidden; it never left the decoder.

Carry the host's normalization through HistoryToolCall into the
eventwire.Tool the restored transcript draws and inspects, following the
serve payload and the desktop copy that already do. The card still draws
only the effective arguments: showing the original is a UI decision for a
later change, and changing the card would also change a live call.

Register the pair as a declared subset of the serve historyToolCall in
wireparity, naming the six fields the terminal decides from. The exact
table is the desktop's and is read as a TypeScript interface, so a Go
reader belongs in the partial table, which compares both ways over the
declared names.
2026-10-25 14:41:21 +08:00
SivanCola 591aac54e9 feat(history): expose bounded cursor paging independently of the UI
Problem: full transcript projection and transfer scale with conversation length. The session store now owns stable page snapshots and cross-page context, exposed through optional controller reads and an additive HTTP route. Existing full-history clients are unchanged. Validate through real Boot/resume, full-projection equivalence, cursor invalidation and append stability, request authority and foreground preemption. Focused history tests, race checks, Go lint and release-note tests pass; broad suites are recorded in the PR.
2026-10-24 22:13:10 +08:00
dependabot[bot] c6ba3522b9 build(deps-dev): bump fast-uri in /tools/acp-conformance
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.8 to 3.1.9.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.8...v3.1.9)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-10-24 09:50:36 +00:00
YHH 6e97bf257a Merge branch 'studio' into codex/present-files-settings 2026-10-23 05:39:43 -07:00
Will 216ea245fd fix(tui): a runtime continuation is not the person's message
The terminal counted and drew a host-authored inbox entry as the person's
own pending line, so `d d` on it reached DELETE /inbox/items/<id> and the
kernel dropped the runtime's continuation. The desktop has always filtered
these out; the terminal never decoded the field it filters on.

The mirror now carries origin, readonly and capacity, and a declared-subset
wire-parity check holds it (and the page's copy) to the fields a decision
reads, so dropping one is a `make check` failure instead of a silent zero.

A host continuation is out of the pending rows and out of the count, except
where it is blocked or uncertain and needs a decision only the person can
make; there it is drawn marked as the runtime's. A read-only snapshot offers
no mutation key and says why.
2026-10-23 11:59:16 +08:00
esengine 872031925d fix(schedule): offer the open project for trust on the scheduled runs page 2026-10-22 19:24:56 -07:00
Lancy 788cf7e18f fix(studio): stream progress for side questions 2026-10-22 19:58:32 +08:00
esengine 42c398aa6e feat(loopmetrics): session inputs note, truncation sidecar, and usage dedupe that survives resumed sessions 2026-10-22 01:19:37 -07:00
esengine b98bad7509 fix(loopmetrics): drive.py refuses a foreign reasonix.toml, and the report states analysed and excluded blocks 2026-10-22 00:46:57 -07:00
esengine d5916445b2 feat(loopmetrics): phase 1 harness, scripted turns and first results 2026-10-22 00:44:44 -07:00
esengine 17bb7dd92c feat(loopmetrics): a run may be several legs of one session 2026-10-22 00:41:29 -07:00
esengine f4fe395407 test(loopmetrics): a duplicated tool_result event counts one call 2026-10-21 23:49:43 -07:00
esengine eebf779b7c docs(loopmetrics): add the metadata header and split the long paragraphs 2026-10-21 23:47:17 -07:00
esengine 9d3a8958e1 feat(loopmetrics): read the flat wire-log envelope and fall back to message-level reasoning 2026-10-21 23:46:40 -07:00