Skip to content

Latest commit

 

History

History
86 lines (50 loc) · 41.2 KB

work.md

File metadata and controls

86 lines (50 loc) · 41.2 KB

Chat and Agent

← Docs · 中文

The folder decides

Chat and Agent aren't two entry points; the only difference is whether a chat is bound to a working folder. If the Folder tag above the welcome page's input box is empty, the sheet is Chat (言 · 对谈); fill in a path (or click Choose… to pick one in the system dialog — on Windows the modern Explorer-style dialog with an address bar and search; recent folders aren't remembered, you choose each time, and a deleted folder still listed is bound again if you click it and recreated when you send) and it's Agent (行 · 执事). The seal in the sidebar only shows the current mode; change modes from the folder tag. A folder can be bound midway through a chat — Bind folder in the chat's ⋯ menu in the sidebar — after which the tools and prompts change accordingly, with not a word of history lost: good for talking an idea through first and then acting with the context. Change folder in the same place changes or unbinds it; unbinding returns to Chat. The sidebar history is a timeline (pinned / today / past seven days / earlier). Chats bound to the same folder gather in a group marked with a 工 seal, groups ordered by their most recently active chat (one chat stirring lifts the whole group) and sorted by time within. Chats without a folder sit among them by their own time. Click a group header to collapse / expand it (the open chat stays visible when collapsed); the + on the right of the header starts a new sheet in that folder.

File tools

The file tools differ between the two modes in where they work, their style and their approval. Agent mode gets six (including exact replacement and code search); Chat mode gets the four needed to produce files (run_command / write_file / read_file / list_files) with short descriptions. To have it look at your computer, it checks directly with run_command; the sandbox's folder constraint only covers changes, not viewing. Agent mode works in the working folder, and its system prompt is the agent's way of working (locate before reading, state the plan first, minimal changes, verify after changing). Chat mode works in the Files folder and uses file tools only when the user wants a deliverable file, unless explicitly asked to inspect the computer. The agent is a lightweight coding-only agent with six file tools:

  • list_files: lists the folder tree (folders end with /, files followed by their byte size); with pattern it finds files by glob (*.ts, src/**/*.js), skipping node_modules, .git and the like
  • search_files: searches text files line by line by regex (or literal text), returning file:line:content, optionally limited to a subfolder (a single file searches only it) and a glob; for locating code. An invalid regex is searched literally, with a note at the top of the results. A regex that backtracks for more than two seconds on one file is aborted and the model is told to rewrite it, so a bad regex can't hang the bridge
  • read_file: reads a text file with line numbers, in chunks by offset / limit; understands UTF-8 (with BOM), UTF-16 (what Windows PowerShell 5.1's > and Out-File write) and GBK, telling the model when the encoding isn't UTF-8
  • edit_file: replaces one exact passage; old must match the file verbatim and be unique (or set replace_all explicitly). CRLF files keep their line endings, UTF-16 and BOM files are written back in their original encoding (GBK files aren't edited in place; the model is asked to rewrite the whole file or convert it first). Files not read or written in this chat can't be edited, so the model must edit against real content. When old doesn't match, the error includes the most similar passage in the file (as it is now, with line numbers), so the model can retry without rereading first. The step card shows the change as before and after snippets
  • write_file: creates or rewrites a whole file
  • run_command: runs one command in the working folder (on Windows, PowerShell 7 if installed, otherwise the system's built-in 5.1; sh elsewhere. Input and output are UTF-8; commands are parsed separately, unaffected by command-line quoting rules, so mistakes give readable parse errors; terminal color codes are stripped from output), returning the exit code, duration and output. timeout is how long to wait in the foreground (default 120 seconds, at most 600); if it's not done by then it isn't killed but moves to the background, returning an id and the output so far, and wakes the model when it ends like a background command. When the user sends a follow-up or the main model messages a subagent, a running foreground command also moves to the background on the spot so the words are delivered right away. Cmdlet errors also return a non-zero exit code, with error text restored to plain text. Things that run for a while, like dev servers and long jobs, go to the background with background: it returns a few seconds of output and an id (bg1…); it wakes the model when it ends (see "Waits" below), so no polling is needed. To see output midway or end it early, use check_command. Background commands are cleaned up when the bridge exits
  • set_timer: wake yourself at a time — give at (a local time like 2026-10-31 09:00; just 09:00 means the next such time) or after (seconds), with note as what to tell yourself then; every (seconds) repeats it. Ids are t1…; check_command shows when it's due or cancels it with stop (see "Waits" below)

Paths are relative to the working folder. Settings → Tools → File tool reach defaults to Anywhere (not in effect under Ask first with the sandbox on, where everything stays inside the folder): full absolute paths can then point outside the folder (system configuration and material elsewhere can be read; the model explains before writing). Set it to Folder only and anything leaving the folder is refused (including escaping through symlinks / junctions; listing and search don't follow links, which are marked with @). The working folder must be a fully qualified absolute path (on Windows, with a drive letter). The agent API only accepts requests from this site's pages and local scripts; file:// pages can't reach the bridge. File system errors come back as readable explanations. The system prompt only describes the environment (folder, platform, shell, the sandbox's limits) and a few words for wrapping up; how to read, how to edit and what not to guess are in each tool's description (see prompts/).

After uploading a ZIP or other archive, the model receives the local original's path; it can copy it into the working folder with run_command and extract it into a separate temporary subfolder to read. The original is kept, and the extract command follows this chat's permission rules. This requires the model's local tools to be on and an unpacker for that format on the system.

Waits

Anything the model arranges to wake it later is a wait (候). It wakes on one of two conditions: a process ends (a background command) or a time arrives (set_timer). Once set, it needn't be watched; if the model has nothing left but to wait, the answer finishes. When it comes due it reaches the chat like a subagent's report: if the chat isn't answering, a new answer starts with a thin line between the two; if it is (the model set things up and kept working), it's delivered into the current answer at a round boundary, as a small "Report" step at the moment it arrived, the same size as a follow-up.

  • A background command ends: the bridge waits for it to end, then the result (exit code, duration, new output since) is delivered. The thin line reads "Background “Restart preview” finished" (the quotes hold the plain-language description given when it started, or the number such as bg1 if there was none; a non-zero exit code is shown); click it to jump back to the step that started it, which then says "Finished · exit code n". A small loop that exits only when a condition holds is a watch (checking PR comments, a training log or a web page every few minutes). When the bridge exits (restarting start.cmd, shutting down) background commands end with it and the wait can't go on: the card says "stopped when the bridge restarted" and the chat isn't woken — the restart was your own doing, and what's left running is mostly previews and servers; the model sees it stopped in the step summary of the next question and decides whether to start it again.
  • A time arrives: the time is kept by the bridge (候/约.json in the storage folder) and holds no process; after a bridge restart it's read back and missed ones fire right away, saying how late ("Timer “check PR #151 for replies” is due · 40 min late"). A repeating one is rescheduled once it fires; periods slept through aren't made up. Times that pass while the computer sleeps or the bridge is off fire once it wakes or starts. A firing first lands in 候/到点/ in the storage folder and is then handed to the page: if no page is open it waits and is delivered when one opens; with several pages open, whichever claims it (by renaming it) delivers it, and chats busy answering on another page are left to that page.

The clepsydra in the top bar lists every pending wait in two sections, Running and Scheduled: background commands show how long they've run, timers when they're due ("tomorrow 9:00 · every 1 day"); when several chats have waits, each row names its chat in small type below, the current one in red; hover for the id and full command or the set time. Stop only stops generating and leaves waits alone: background commands keep running and still wake the chat when they end, and timers stay as set — what was set up earlier has nothing to do with the answer in front of you. To drop one, tell the model and let it end or cancel it with check_command (if you removed it by hand the model wouldn't know). Regenerating or deleting removes the steps that set them, so their processes are killed and their timers canceled. With several pages open, the bridge reports a background command's end only once; one the model saw end itself with check_command doesn't wake it again. A subagent's background commands wake the subagent itself (see "Subagents" below); set_timer is for the main model only.

Ledger

A long job spanning many answers lives in the folder, not in any one chat: the model keeps a .yan/账本.md (the ledger) in the folder, maintaining it itself. It records only what keeps constraining this piece of work without being a conclusion — constraints and trade-offs decided, key points about methods and environment. Conclusions to establish, progress and dead ends go into the Intent. Outdated entries are deleted and similar ones merged; it's not a running log. It's read when each answer starts and attached after the question sent to the model (earlier questions don't carry it, so one ledger isn't repeated dozens of times; attached to the question rather than the system prompt, so changing it doesn't wipe the cache before it; the first part of this question is marked as a cache point and the ledger follows as a separate part). So after compacting earlier messages, being woken by a report or a background command into a new answer, or continuing in another chat bound to the same folder, the model sees the same copy. There's no limit on how much the ledger records — some jobs really need a lot; the limit is only on how much is attached per question, following the model's window (half the attachment budget; about 12k tokens if no window is set). If it doesn't fit, the beginning is attached with a note "n lines in total, only the first m attached; use read_file for the rest" — so the ledger works best as an index: what's needed often goes first, detailed records (experiment data, long lists, research findings) go into separate files under .yan/ with one line in the ledger pointing to them, read and searched as needed. When the full text is attached it counts as read, so the main model can edit_file it directly; a truncated attachment doesn't count, and it must read before changing, so one edit can't overwrite the half it never saw. Subagents get a read-only copy when they take a task (only the main chat writes the ledger), read fresh at that moment — set a constraint first and then delegate, and the subagent gets the one just set, so a small constraint mentioned at the start isn't lost in the delegated work. If the file doesn't exist, nothing is attached.

Intent

The ledger records constraints and trade-offs; the Intent (意) records conclusions: which points a long job must establish, what each rests on and on what evidence. The model uses update_intent to keep a .yan/意.json in the folder (the bridge is the only writer, writing with versions so simultaneous edits from several places don't overwrite each other), attached after each question just like the ledger — switching chats, compacting earlier messages, being woken into a new answer, the model always sees the same copy. The program only provides formal constraints and visibility; whether something holds is judged by the model against each item's check.

  • Structure: an item is a statement that should hold (events, features and files aren't distinguished by type), with how it counts as holding (check), which items are its premises (needs; any means any one of several routes), and on what evidence (anchors). Premises must exist and form no cycles; a batch that violates this is rejected whole. A new Intent with only one item to establish is rejected too — one item isn't a graph, and work that fits in one answer doesn't need an Intent. An item nothing else depends on is a root — the final conclusion the whole job must establish. When a root is set, the user's original question is recorded (for a root marked later, the question at the time it was marked). A root's wording changes only as the user means it; changes leave a trace, and that question is attached too.
  • Nesting: an item that breaks down into many steps is a module; sub-items point to it with in, at most two levels. A module implicitly depends on the items that close it off inside, and holds only when they do. Modules are only grouping: premises can cross modules — depend on the exact item you need (evaluation depends on a step inside training, not the whole training module); the graph is still a DAG, and the cycle check includes the links from modules to their closing items. When attached for the model, settled modules fold into one line and only unsettled ones are expanded. At most 15 items per level and 60 in total. Names are at most 24 CJK characters (48 letters or digits); spaces, colons, @ and the like are rewritten to _ by rule, with a note back to the model. When the wording changes and the old name no longer fits, rename with rename; premises and membership follow, and a rename alone, without changing the wording, keeps the item settled.
  • Propagation and regression: marking an item as holding requires its premises to hold first (marking them in the same batch counts; for a module, its closing items). An item done itself while its premises aren't is still marked in progress; otherwise the batch is rejected. If a premise later goes back to needs-recheck, the items above it no longer count as holding. When marked as holding (or assumed), each piece of evidence's fingerprint and each premise's wording version are recorded; if the evidence later changes, the wording changes or a premise is added, it goes to needs-recheck. Evidence has four kinds: file (a bare path), folder (dir:, the whole tree, additions and deletions included), probe (cmd:, a command's output, covering external state such as deployments, services and dependency versions) and test (test:, whether a command passes — only whether the exit code is 0; changed timings or line numbers in the output don't count). Probes and tests follow the chat's permission level; under Ask first only clearly read-only ones run automatically — they only compare whether something changed, not whether it's right. Within an answer, file and folder fingerprints are re-taken after each round of tools (probes and tests only run when each answer starts, on marking as holding, and before wrapping up); items newly gone to needs-recheck are reported to the model right after that round's tool results. If the same item is knocked back a third time within one answer, it's called a stalemate, listing the other items that share its evidence and were also knocked back — a reminder only, not a block. Evidence is a registry (src/19-intent/05-anchors.js); adding a kind is adding one entry.
  • Downgrades and trade-offs: borrowing an outside conclusion instead of doing it yourself is marked "assumed" (note gives the source); it counts as holding, and the items above keep a count of how many they borrowed. Stuck in someone's hands, waiting for a decision, is marked "waiting" (waiting; note says who and what), which doesn't count as holding, and stays visible across chats as to whom it's waiting on. A road taken on the main line that didn't work is marked "dropped": it doesn't count and isn't drawn, but stays as a marker, named in the Intent attached for the model so it isn't walked again. A plan that changed or an item written wrongly is marked removed and deleted whole; premises pointing to it are erased too, leaving just a trace. When the graph already has roots, an item nothing depends on and not declared a root is "orphaned" — most likely a step whose link to the item it supports was forgotten, quietly becoming another root. If items written in this batch end up orphaned, the batch is rejected, suggesting it be added to the needs of the item it supports, put into a module, or marked as a keep if it's really a boundary.
  • Check before wrapping up: if an answer touched the Intent (changed it, or evidence it hangs on changed during this answer; in an answer that acted — wrote or edited files or ran commands — probes and tests are rerun before wrapping up, and an item going to needs-recheck as a result also counts), it's stopped once when the model is about to wrap up. It's shown the current Intent (reread, probes run, each root with its original question), the items that went to needs-recheck during this answer, and files changed that no evidence in the Intent covers (at most eight), and asked to judge against the original questions whether it can wrap up, continuing whatever's unfinished. It's stopped only once, nothing is verified on its behalf, and whether to send a subagent to check is up to it. The message is recorded in Steps and reinserted in place whenever this answer is rebuilt later. If it wraps up without acting again after the check, the earlier text stays outside as the reply, the check step is drawn in actual order — after the reply and before the words it led to — and it's asked not to repeat itself, only to add what the check found.
  • Keeps (hooks): conditions set per task that must always hold ("tests must pass before wrapping up after changes; if not, keep fixing", "don't change the public API") are marked as keeps (keep, 守) in the Intent; there's no separate hook system. A keep isn't a conclusion to deliver: it isn't drawn, doesn't count toward progress, neither has nor serves as a premise, and is global only; the user's original question is recorded when it's set. Keeps come in three grades: use a hook where possible, otherwise a recheck before wrapping up, otherwise the model's own discipline. Hooks: for limits on a kind of action ("only push to the test machine", "don't publish before I approve"), the keep gets an on (a regex matched against the step about to happen: the command text, file path, URL or tool name). From then on, any step with side effects in this chat (subagents' steps included) that matches is checked before acting and before any approval request, in one of three ways. With a test: attached, that test runs first, given what's about to happen through the environment variables YAN_TOOL (tool name) and YAN_TARGET (command, path or URL); if it fails, the step isn't taken and the test's output becomes the step's result for the model. Without a test, it's a ban: a match means the step isn't taken. Marked ask, it's a gate: once the test passes (or if there is none), you're still asked to approve, at any permission level (Full auto asks too, and switching levels doesn't release it). The request shows the keep's wording and what's about to happen, with only Allow and Skip, and an approved step isn't asked about again. A blocked step shows "Blocked by keep · name" on the right of Steps; a refused one shows "Not allowed by keep · name". Use the first two for limits, and mark ask only for decisions left to you; removing on removes ask with it. Tests attached to hooks don't run otherwise, aren't fingerprinted, and aren't rechecked before wrapping up; under Ask first only clearly read-only ones run automatically and others don't, because that step needs your approval anyway. Editing the Intent itself never goes through hooks. Recheck before wrapping up: for limits on results ("tests must pass after changes"). Tell the model and it sets a keep with evidence test:npm test, recording "pass" when marked. From then on, in any answer that acted (wrote or edited files or ran commands), the keep's tests and probes are rerun before wrapping up, and if one turns to failing, it's stopped once — the step in Steps shows in vermilion on the right "name · test failing", and the model keeps fixing; after wrapping up it's taken again and the header is drawn as it actually is. If the tests still pass, it wraps up as usual, without an extra round. Display: in the card, a separate Keep section follows the item list, with rows like the goal rows, wording replaced by the reason when something's wrong; the row of marks under the title and in the header shows only goals, and a keep appears at the end, behind a thin divider with its mark, only when something's wrong. Keeps have no progress: open, doing and the like that the model adds in passing are accepted, not rejected; to remove one, have the model remove it (removed). Things that must hold across tasks and everywhere don't belong here, but in the sandbox, the permission level or a preset's prompt.
  • Viewing the Intent: a stone-blue 意 seal is always shown in the line under the title and in the header: progress and a row of marks; click it to open the card. The Intent step in Steps opens it too. The card is view-only (what needs changing is rarely just a word or two — tell the model directly), drawn by the program from the file. The page header shows progress and when it was updated; History on the right is the record of edits, drops, removals and regroupings (for reference only; click to switch it in below the graph). One graph, premises on the left and roots on the right, one level at a time; a module carries "n settled inside ›", and clicking the number drills in. Premises from other modules are drawn as faint shadows on the left of this level (with small text after the name saying where they are); click to jump there. Cross-module dependencies between items inside are lifted to a faint line between modules on the level above. Marks are symbols: a jade-green check for settled, a gold check for assumed, a gold question mark for doubtful (claims to hold while premises don't), a gold dashed circle for in progress, two plain ink strokes for waiting, a vermilion circle for needs-recheck. Below the graph is this level's item list, one line per item with its wording, replaced by the reason when something's wrong (why it needs recheck, which premise it's stuck on, the source of an assumption, who a waiting item waits on and for what). Dropped items aren't drawn; they're in the history. Click an item in the graph or a row in the list to expand its check, premises and dependents, evidence and reasons in place — these causal links are derived by the program from the graph and fingerprints, not by the model.

Steps

The previous answer's steps are condensed into one line, "[上一答的行迹]…" (the previous answer's steps), placed at the start of the next question sent to the model (not shown on the page), so it remembers which files it read and changed without exploring from scratch each round. The summary isn't appended after the assistant's own words: the model would learn it as the format of its own replies and write such a line at the end itself.

In Agent chats, Steps is a timeline: what the model says as it works and each step are interleaved in order. While running, it's expanded to show the process, the header reading "Working · n s" as it goes; when done it collapses into one line, "Steps · n s · n steps · n files changed", leaving only the final summary outside; click to review the whole process. Only two kinds of step are expanded by default: folder listings (showing the first 10 lines) and edit diffs (10 lines each side), with an "expand all" line below. Command output, reads, searches and page reads — which have clear line counts and are often long — are collapsed by default (an answer with dozens of searches would take a whole screen expanded), with the result and line count on the title line; click it to expand. Errors are collapsed too. Expanded while running and collapsed when done is the rule for both Steps and subagent timelines: when the whole answer finishes, Steps always collapses, and a subagent's small timeline collapses when it's done. In Chat mode it's still a folded footnote. Each answer ends with a change summary, "n files changed · +added −removed"; click to see the line changes per file (edit_file counted by line-level diff, write_file by full text for new files and by old and new line counts for overwrites), checkable round by round. Thinking and each step have a breathing dot while running and a check when done; later rounds' thinking sits in its own group, and while tool arguments are still being drafted it shows "Drafting Write xxx · n chars" first.

Checkpoints

Before a reply first changes files (writing, editing, running commands, downloading, generating images), Yan records how its folder looks at that moment. The reply then gets a Rewind action: it first lists what would change (revert, restore, delete), and once confirmed takes the folder back to how it was before that reply — files written by tools and files changed by commands alike, along with every later change from other replies or your own edits. The next question after a rewind tells the model so, and it won't assume its earlier writes are still there. Only Agent mode (a bound folder) records checkpoints: Chat mode writes into Files, which several chats share, so rewinding one reply would also delete what others put there since.

No git needed: the folder doesn't have to be a repository and git doesn't have to be installed. Yan stores checkpoints itself under 检查点/ in the storage folder: content is stored by hash, each distinct file once; folders are stored level by level as objects, so unchanged subfolders are shared. From the second checkpoint on, only files whose size or modification time changed are read; the first one amounts to a copy of the folder. Not recorded: folders that listing also skips (node_modules, .git, dist and the like), anything in .gitignore (and .git/info/exclude), links, and the storage folder itself when the working folder contains it. Files that can't be read are recorded as unknown and left alone on rewind. Deleting a chat deletes its replies' checkpoints and clears content nothing else uses.

Only files in the folder are covered: commands that write outside it and remote changes made through MCP (a pull request opened, a message sent) can't be rewound. It's a safety net for local files, not an undo for everything.

Subagents

When there's a large subtask that stands on its own (reading through a batch of files and summarizing, tracking down a problem in some module, implementing an independent part of a decided plan), the model can use delegate to send a subagent (帮手). A subagent uses the same model, the same working folder and the same tools (but can't delegate further or ask the user, and its memory is read-only — it can recall and search past chats, but not remember / forget), running its own tool rounds independently in a separate conversation (at most 40 rounds by default, configurable in settings), and when done sends its final report and change summary back to the main model. A subagent can't see the main chat, so the task description must spell out the background, goal, boundaries and what to report. The main model sets the subagent's thinking effort by difficulty (effort: low for routine work, medium / high for judgment calls, max for hard bugs, design and review; a level the model doesn't accept falls to the nearest); omitted, it's the same as the main answer's choice, and a continuation reuses its previous run's. The level used is shown after the card's counts ("… · thinking low"). Several subagents can be sent in the same round and start in parallel (the main model ensures, when assigning, that the files each changes don't overlap; on the bridge side, writes and edits to the same file queue in order, and edit_file's read–edit–write happens inside a lock while different files proceed in parallel; run_command takes no lock — in Chat mode every working folder is Files, and a whole-folder lock would queue every chat's commands; when a command happens to change a file edit_file is holding, the text comparison catches it). Every read, write and edit carries back a file fingerprint from the bridge, recorded on that step, and later writes and edits send the last one seen: if the file was changed by someone else since it was read (another subagent, the main model, an editor, a command), write_file won't overwrite and asks for a reread, naming who changed it; edit_file still applies if the passage to change still matches, mentioning it in the reply, and a full overwrite after that requires a reread.

On the page, each subagent is a Subagents card in Steps with a 遣 seal on a pale gold ground (vermilion is reserved for seals and deletions), showing only the title and "n steps · m files changed · seconds" (while working, "n steps · seconds", the time running), breathing while it works. Click it to open a full-screen window with the subagent's own small timeline — each round's thinking, words and steps, drawn the same way as the main Steps: expanded while running, the latest thinking and words streaming live, each round's steps folded into one line such as "Search 18 · Read web page 30 · 48 steps", expanded while that round runs and collapsed when done (anything you've opened or closed by hand stays), with its words and final report always outside, never pushed screens down by dozens of searches. While subagents work, a subagent bar sits above the input box (one line per subagent, showing the step it's on; click to open its window), and the Steps title also shows "Subagent "…" · n steps · running" — even after the answer that sent it has finished. Commands follow the chat's permission level; changes count toward this answer's change summary and "n files changed"; usage counts toward the context cost (each round is deducted from tokens left at the lower right as it returns, and the subagent panel shows that subagent's usage under the title, updating while it works); the next question's step summary also carries the files it changed. Files a subagent read don't count as read by the main model (and vice versa): whoever edits must read first. Chat mode can delegate too (subagents get the web and document tools).

Subagents work in the background and don't finish with the answer that sent them: once the main model has handed out the work and has nothing else to do, the answer finishes, and nothing sits awake waiting. When a subagent finishes, if this chat happens to be answering (the main model busy with something else, or the user just asked something), its report goes into that answer's inbox and is delivered at a round boundary, as a small step at the moment it arrived, "Report · Subagent "…" reported" (click to open its window). If not, a new answer starts with the report as its question — on the page not a user bubble but a thin line reading "Subagent "…" reported" ("did not finish" if it didn't), the name opening its window; several arriving at once are merged into one question. So a long job split across several answers leaves each part's writing visible in the text, never washed away by the next round. The new question is preceded by the previous answer's steps as usual, where subagents not yet back are recorded as running in the background. Meanwhile the input box works as usual: words typed are a new question; with the input empty the seal reads 止, and pressing it stops all background subagents (stopped ones don't report, so no new answer starts). A subagent's usage is recorded on the Tokens used of the answer that sent it, added when it finishes (tokens left was already deducted round by round). Reloading or closing the page interrupts background subagents, as their cards note. If the answer that sent it is broken off (network interruption, error), the report doesn't start a new answer — that one would most likely break too, and would leave a stub under the break that becomes debris when the broken answer is continued, splitting the main line in two. Instead the report is held on this chat, the interrupted answer continues on its own, and the report is delivered when it starts; if it's still broken, the report stays held until the next answer starts (clicking Continue, retrying, or a new question). Leftover stubs in old chats — "report + empty answer that wrote nothing" — are gathered back and delivered together when continuing.

Subagents and the main answer follow the same rule: sleep when only waiting is left, wake when mail arrives. When a subagent has started a background command (training, a long build, waiting for a condition) and, at the end of its turn, that's all it has running, it hands its current words to the main chat as progress ("Subagent "…" pauses here, waiting for background command bg1 to finish") and goes to sleep — sending no requests, its card saying Waiting on background, still counted as working (the subagent bar lists it, and 止 still stops it). The message that the command ended is sent to the subagent itself, landing in its own timeline (a step "Report · Background bg1 finished"); it wakes, continues from the output and reports again when done; the main chat receives progress and report in turn. So a long job can be handed whole to one subagent: start training → sleep → wake to evaluate → start another round if unsatisfied → report, with the main model never needing to watch. Handing in progress first, rather than saving it up, keeps the main model from waiting idle and from being hung by a dev server someone forgot to stop (the subagent's system prompt says: stop what needn't be waited for before finishing). If the command it waits on ends with a bridge restart, the subagent wakes, finds no mail and finishes there, its progress being its last words, not reported again; the main model can still wake it by messaging it through helper. On page reload, sleeping subagents are interrupted just like working ones.

The main model can message a subagent with helper, using the task name given when delegating. If it's working, the message goes into its own inbox, the same as a user's follow-up: if it's speaking, it waits for the end of the sentence before stopping that round to deliver; if it's running a tool, it's delivered when the result comes back (a running foreground command moves to the background on the spot and its result returns immediately) — never cut off. The message lands in the subagent's own timeline (a Message step, checked when delivered). If it has finished, that's a continuation: the same subagent carries on with its earlier history — it remembers the task it took last time, the report it gave and its steps — and reports back as usual. Stopping stops only that working subagent; the main answer carries on, and what it has done arrives as a "did not finish" report noting it was stopped as requested. Messaging, continuing and stopping each also get a gold card in the main Steps: continuation and message cards are marked as updated, and clicking opens that subagent — a continuation opens the new run (the task at the top of the panel is the newly assigned work; ‹ › goes back to its previous run), a message opens at the words delivered.

A report is only the subagent's conclusion. To check which commands it ran and what came out, the main model reads its trail with helper and read: the task it took, its words and its steps interleaved in order, commands with the tail of their output; all runs are listed, and one still working is shown as far as it has got. Raw tool results aren't stored, so other steps have only the words on their cards. A Read trail card appears in Steps; clicking it opens that subagent.

A subagent that breaks off doesn't report; it waits for someone to continue it. Anything not stopped by someone counts as a break (unable to reach the API — remote APIs hold on for about five minutes first — quota exhausted, or a page reload or bridge restart while it's working). When the network is down the main model most likely can't connect either, and waking it would just break too, so it neither reports nor wakes anyone. The card's status changes to the continue stroke (the same stroke as Continue on messages) and reads "Halted · reason · steps", visible even when Steps is collapsed; the work bar above the input box shows "Subagent "…" halted at step n", also ending with a continue stroke, until it's continued; the subagent panel's timeline ends, like a broken main answer, with a line saying what's done is all there and it can continue from here. Click that stroke and the subagent continues from the break: its words so far, the steps done and "please continue" are placed into its history the same way a main answer continues; it keeps the same card and reports as usual when done — it can continue even while the main model is resting, and the report starts a new answer to wake it. When the main answer is broken off, clicking its Continue continues the chat's broken subagents too. The main model sees in the next question's step summary that it halted and is waiting for the user, and can also start a fresh continuation itself with helper (the broken run is then abandoned).

Long jobs aren't wasted when the context fills up: when the tool exchanges within one answer (the main answer, a side thread, or each subagent separately) pile up close to overflowing the window, the model is first asked to condense the earlier exchanges into "work notes" (facts established, files changed, verified or not, dead ends, next steps), which replace the originals as it carries on; the latest two rounds are kept verbatim. The conversation before this answer and a subagent's task description are left untouched. If what doesn't fit is the conversation before this answer, the main answer first condenses it into a summary (the same one as compacting earlier messages, landing as a divider); side threads and subagents don't. With the model's Context window set, it condenses when the estimate before sending reaches 75%; without it, it condenses and resends when the API replies that the request doesn't fit. The steps on the page are all still there; only what's sent to the model is less. A subagent that condensed shows "compacted n times" on its card. Compacting earlier messages between answers works as before; see Chat.

Stability limits and argument repair

Stability limits: one answer allows at most 80 rounds of tool calls by default (subagents counted separately, 40 by default), configurable in Settings → Tools; beyond that the tools are withdrawn and the model is asked to wrap up directly. On stop, page reload or connection loss, running steps and steps awaiting approval are all wound up, and a running command is killed by the bridge together with the whole tree of child processes it started (taskkill /T), so nothing keeps changing files in the background. Before each send, Yan confirms the bridge is online and the working folder still exists (recreating it if it was deleted).

Tool arguments are straightened out according to the schemas in prompts/tools.js (src/15-tools/01-arguments.js): common deviations are put back in place (aliases like file_path → path and cmd → command, numbers and booleans written as strings, a single item where an array is expected, ask_user with one question laid out at the top level); only if a required field is still missing after that is it not executed, and the keys and raw text received are sent back to the model. When model output is cut off at the maximum length, the argument JSON is completed as far as possible — read-only tools (read, list, search, look up) use it as is, while those with side effects (run_command / write_file / edit_file / download_file / http_request / remember / forget / delegate) are always refused with the reason given, so a write_file whose content was cut off is never written out as an empty file. Within one answer, searches, reads, computations and requests with identical arguments reuse existing results, but only successful ones are cached, so a transient timeout or error isn't reused.