Commit Graph

493 Commits

Author SHA1 Message Date
NCBM c06fb57e72 core/agent: return each round's reasoning in the Responses input
A request carrying `tools` must return every round's chain-of-thought — "必须完整
回传 `reasoning_content` … 即使该轮模型未实际进行工具调用" — and the API merges a
`reasoning` item into the assistant message its round forms: a missing item and
an empty `reasoning_text` are both answered with "The `reasoning_text` in the
thinking mode must be passed back to the API". Each round now goes back as its
reasoning, its text, then its calls, with a blank line standing in when the
round kept none (a `rollback_tail` carrier, a forged todo call, the seed a
compacted session starts with) — never words of the bridge's own for a round
that may genuinely have reasoned nothing. A round's calls stay contiguous ahead
of their outputs: an interleaved batch reads as a second round without
reasoning and is rejected the same way, and an output recorded after another
item moves up beside its own call.

The reasoning is read back from the item's `content` parts, the only part the
API documents for `reasoning` items (`summary` and `encrypted_content` are not
supported).
2026-10-06 23:23:18 +08:00
NCBM 932b4f0a7f core/agent: keep a rolled-back turn's reasoning with its calls
A failed turn keeps the calls that already ran as a bare pairing carrier, and
clipping the chain-of-thought off that carrier sent the call back to the API
with no reasoning at all — thinking mode refuses a call whose reasoning never
came back. The carrier keeps the reasoning and drops only the text.
2026-10-06 23:23:12 +08:00
NCBM 19e247d739 docs: describe the wrapper command-line review
`env -S "…"` / `su -c "…"` hand a command line to a wrapper instead of running
a program, so the soft confirm now covers them alongside interpreters and
detached runners, with the text under its own `env -S:` label.
2026-10-06 21:54:28 +08:00
NCBM 135c28a622 core/tools: review a wrapper option that carries a command line
`env -S "rm -rf /"` ran a command nothing looked at: the option belongs to the
wrapper, so the scan skipped it and the denylist found no program to block while
the soft confirm had no interpreter to review. Collect those values — `env
-S`/`--split-string` and `su -c`/`--command`/`--session-command`, jammed
`--opt=value` and `-Svalue` forms included — and confirm the call the way an
interpreter's `-c` one-liner is confirmed, printing the text under its own
`env -S` label. Recursing into the text for a hard denylist is left out for now:
the review asks the human, who sees the command.
2026-10-06 21:54:18 +08:00
NCBM 2b3b2073a0 core/tools: only value-taking options may swallow the program
The wrapper option table listed flags as if they consumed the next token, so
the program behind them was skipped: `exec -c git -c init.defaultBranch=main
init` resolved to `init` and the policy denied it as a denylisted basename,
while `exec -c rm -rf /`, `command -p rm -rf /` and `command -v rm` hid `rm`
from the denylist completely and `exec -c python -c …` lost the interpreter
review. Drop the entries that take no value — `exec -c`/`-l`, the whole
`command` entry, `pkexec --disable-internal-agent`, `su -p`, and `xargs -e`
(its argument is optional, and the jammed form needs no entry) — so the
resolved program is the one that really runs.
2026-10-06 21:50:21 +08:00
NCBM e05dc5127a docs: describe how a batch of tool calls keeps its rows
The note said a second call ends the open prefix as its own line; that row was
what made the first call of a batch print twice. Record the queued behaviour:
each call of a round prints one finished row, and only output that genuinely
takes the line still closes the prefix.
2026-10-06 21:38:13 +08:00
NCBM 768b310a0b cli/display: hold a batch's later prefixes until the open row is done
A round that asked for several calls printed the first one as an abandoned
half-line: the next prefix closed the still-open row (a bare newline), the
result then printed whole and repeated that prefix, and the rest of the batch
was suppressed. The model edits files in batches, so the duplicate row showed
up there most. Queue the later prefixes instead: each one opens its own row
once the row before it has taken its detail, which keeps one finished row per
call in call order and leaves the bytes identical to the non-interactive path.
Only output that genuinely takes the line — a prompt box, streamed text, an
error — still ends the open prefix as its own line. The cursor is still never
moved.
2026-10-06 21:38:03 +08:00
NCBM 66b771f87d docs: use the current DeepSeek flash id in the samples
The default catalog and the sample config still named `deepseek-v4-flash`,
which DeepSeek keeps only as a compatibility alias. Spell out the mapping
Claude-* ids get server-side (`deepseek-v4-pro` / `deepseek-flash`) instead
of the `deepseek-v4-*` glob the flash rename made stale.
2026-10-06 21:22:55 +08:00
NCBM ec5340bdce config: rename the DeepSeek flash model to deepseek-flash
DeepSeek dropped the `v4` prefix from its flash model, and the old id stays
valid only as a compatibility alias. Seed the default catalog with the current
name so a provider that omits `models` no longer offers a deprecated id, and
follow the rename in the wire fixtures and the minimal config template. An
explicit `deepseek-v4-flash` in TOML still passes through unchanged.
2026-10-06 21:22:35 +08:00
NCBM 35dbd30328 docs: describe the thinking-strength settings 2026-10-06 21:11:28 +08:00
NCBM 60bc5957a7 cli: resolve thinking settings for the chat session 2026-10-06 21:11:28 +08:00
NCBM fb8ef88d9f core/agent: send the resolved reasoning effort with each request 2026-10-06 21:11:28 +08:00
NCBM 445aba7e5f lmproto: carry thinking options on the wire 2026-10-06 21:11:28 +08:00
NCBM ffd4dbbe26 config: resolve thinking strength across agent, provider, and model layers 2026-10-06 21:11:28 +08:00
NCBM 0c9bb2e067 docs: describe merged todo batches 2026-10-06 20:51:13 +08:00
NCBM 7cd5fcc576 cli/display: merge a batch of todo calls into one line
A round that updated its todo list printed one header plus a full stack
render per call, so the same list appeared several times. When a batch only
touches todo tools, print one `* Todo x<N>: Push, Update` line and the last
result, whose text already ends with the final stack. A batch holding any
other tool keeps the per-call lines, and a todo call never prints a prefix
at call time (it would dangle when the batch is merged).
2026-10-06 20:51:07 +08:00
NCBM 49ddf1c3c1 cli: correct the auto-retry schedule in the REPL help
The help said 10s/20s/30s; the delays are 5s/10s/15s/20s, then +10s each step.
2026-10-06 20:33:36 +08:00
NCBM 7d9b979604 core/agent: record every tool result before yielding them
A caller that goes away mid-batch (cancel, display error) left the results of
tools that had already run out of history, so the retry ran them again. Append
the collected results first, then emit the events.
2026-10-06 20:33:30 +08:00
NCBM 4b1cb84256 docs: describe what a rolled-back turn keeps
A failed or cancelled turn drops unfinished assistant text, and tool calls
whose result already arrived stay in history (and in the store), so /retry
continues from real results instead of running those tools again.
2026-10-06 20:32:35 +08:00
NCBM cecd5e5ae3 core/agent: keep executed tool results when a failed turn is rolled back
A tool batch counted as committed only once every call had its result, so a
batch cut short was dropped whole and the retry ran tools that had already
had effects. Keep the calls that did report a result: their assistant row
stays as the pairing carrier (a request must answer every tool_calls id),
without the text of the unfinished turn, and the calls without a result are
absent so the retry re-issues them instead of assuming they ran. The kept
rows go to the store right away, and a failed rollback write is not allowed
to mask the failure being rolled back.
2026-10-06 20:32:09 +08:00
NCBM 1cead73320 docs: describe argument-aware command denylist entries 2026-10-06 19:55:40 +08:00
NCBM c7680491c9 core/tools: denylist power-management subcommands and privileged programs 2026-10-06 19:55:14 +08:00
NCBM f285848dd5 docs: describe wrapper-aware command review 2026-10-06 19:44:50 +08:00
NCBM 7862a555bc core/tools: review interpreters and detached runners past wrappers 2026-10-06 19:44:29 +08:00
NCBM 9501efb3d7 core/tools: block a denylisted program behind env wrappers and run launchers 2026-10-06 19:42:06 +08:00
NCBM 6453a8ac89 core/tools: resolve the program behind env wrappers and run launchers 2026-10-06 19:41:17 +08:00
NCBM 1a63327040 docs: describe ending an interrupted pretty line 2026-10-06 19:15:49 +08:00
NCBM 25b8ef3e58 core/tools: resume fetch bodies from memory instead of refetching 2026-10-06 19:14:38 +08:00
NCBM be16839d9a core/tools: use run_argv names in truncation docs 2026-10-06 19:09:07 +08:00
NCBM 1068ea0025 prompting: end an open tool line before writing a prompt 2026-10-06 19:06:22 +08:00
NCBM a81b138bf8 cli/display: close an interrupted pretty line instead of erasing it 2026-10-06 19:01:42 +08:00
NCBM 36156043ca release: plyngent 0.7.0 v0.7.0 2026-09-22 23:35:03 +08:00
NCBM 2cc5222dd3 docs: use regex_files tool name in docs 2026-09-22 23:23:11 +08:00
NCBM 0343e58dd9 core/config: point default playbook and reminder at regex_files 2026-09-22 23:22:41 +08:00
NCBM 7127190b9a cli/display: label regex_files lines with Search 2026-09-22 23:22:29 +08:00
NCBM de03e5932b core/tools: rename grep_files to regex_files (regex pattern) 2026-09-22 23:22:13 +08:00
NCBM 76933b044c docs: describe grep_files pattern and path shapes 2026-09-22 23:17:53 +08:00
NCBM 2a6130495c core/config: steer the playbook away from shell/interpreter commands 2026-09-22 23:13:41 +08:00
NCBM 9b365403d7 cli/history: print a row's reasoning before its answer
A reasoning trace was appended after the body it produced, which read as if the
answer had come first and the thinking had followed it. It now leads the row,
under its own `reasoning:` label with a blank line before the answer - the order
the live stream uses. The trace only prints where it already did: a turn's ends
(the default view) and -vv; previews stay silent.
2026-09-22 23:05:59 +08:00
NCBM 20fc493c47 tools/skills: rebase search hits from either path form
A skill root can live inside the workspace (the project-scope .claude/skills),
and grep reports those hits relative to the workspace root while outside ones
come back absolute. The attribution only stripped an absolute skill prefix, so
an in-workspace root produced alpha/alpha/SKILL.md - and, worse, a path that no
longer started with the skill name when the root itself was the workspace.
Normalizing the hit to an absolute path before relativizing to the skill covers
both, and the hit line is now matched with a pattern instead of a colon split so
a Windows drive letter cannot split it wrongly.

Found by running the REPL against a workspace-local skill root; the tool tests
only covered roots outside the workspace, so they get that case now.
2026-09-22 22:59:57 +08:00
NCBM b967a000dc docs: document skills
README and the example config cover the [skills] section, the five tools, and
the read/write split; AGENTS.md gains the skills/ package, the tool family, the
config fields, and the /skills + /status surface; architecture.md lists the
package. doc/skills.md is the author guide: layout, the frontmatter subset and
how a broken one degrades, roots and shadowing, what the agent sees, the
grant story for reads and writes, and the warning that a skill is data —
third-party skill directories are untrusted input.
2026-09-22 22:58:09 +08:00
NCBM 90174340d7 cli/skills: expose skills to the session
ReplState builds the store from [skills] against the current workspace and
publishes its roots as static read-only roots, so read_file/grep_files see a
skill directory while writing stays denied; the roots are rebuilt when the
workspace changes, since the project-scope directories hang off it. Discovered
skills are folded into the system prompt the way MCP instructions are, with the
catalog cap and its 'use skill_search' hint, and only when tools are on and
injection is not switched off; [skills].enabled = false drops the tools from the
registry entirely.

The write policy is installed with the CLI confirm: once, session, or no, timed
with a default of no and independent of YOLO, because a skill directory is not a
grant. A library host that installs no hook keeps the deny default. /skills
lists, searches, reads, and reloads; /status counts what was found.
2026-09-22 22:55:24 +08:00
NCBM c7441d4a43 tools/skills: create and modify skills behind a grant
skill_create writes a SKILL.md (name, description, body) plus whatever bundled
files the model lists, and skill_edit changes one file of an existing skill
either by literal replacement, by appending, or by rewriting it. Both resolve
every path inside the skill directory first, so a bad argument is answered
before anything is written and before the human is asked anything; a rewritten
SKILL.md is re-parsed so a skill that lost its description (or its frontmatter)
says so instead of failing quietly. The store is reloaded after a write, which
makes a new skill visible to the very next skill_list.

Writing is a host policy, not a directory-access grant: the denylist wins
first, then a session grant, then [skills].allow_write, then the host's confirm
hook — asked once per skill directory, so one answer covers its files. A host
without a hook denies, which keeps the library default safe; the confirm can
also answer 'session' to cover the rest of the chat.
2026-09-22 22:46:21 +08:00
NCBM 1d05da62c2 tools/skills: list, read, and search skills
skill_list shows what was discovered (name, source root, directory, description)
together with the copies a name collision shadowed and the notes from repaired
frontmatter, so a third-party skill never disappears quietly. skill_read
addresses a skill by name and defaults to its SKILL.md, reusing read_file for
ranges, line numbers, and the continuation token; a bundled file is resolved
inside the skill directory only, symlinks included. skill_search greps every
visible skill (or one) and rebases each hit on its skill, which makes a match
attributable without absolute paths.

Reads need no grant: the host registers the roots as static read-only roots on
the workspace policy, so read_file/grep_files see skill directories too while
write access stays denied — skill writes will go through their own confirm.
Grep used to drop every file outside the primary workspace root, which also hid
hits under a granted directory; those now come back as absolute paths.
2026-09-22 22:42:45 +08:00
NCBM a9f58428bf skills: discover roots and parse SKILL.md frontmatter
A skill is a directory with a SKILL.md; roots are ordered by priority (an
explicit path, then our own user directory, then the directories other
harnesses install into, with the project-scope one behind its own switch). The
first copy of a name wins and the ones it shadows stay listed for reporting
instead of vanishing.

The frontmatter reader covers the subset those files actually use — scalars,
booleans, ints, inline and block lists, | and > blocks, folded plain scalars —
so no YAML dependency is needed; a nested mapping is skipped and a structurally
broken block degrades to "no metadata" with a note, keeping a third-party skill
listable rather than dropping it. Metadata is cached against the directory list
and its SKILL.md timestamps, so a listing is cheap yet notices an edit.
2026-09-22 22:37:42 +08:00
NCBM bbda658eab skills/config: add the [skills] section
Skills are discovered from user-level directories by default: an explicit
``paths`` list wins, then the built-in sources (our own user config dir, and
other harnesses' skill dirs) with the project-scope dirs behind their own
switch. A name found twice shadows the lower-priority copy without hiding it.

``inject_catalog`` / ``max_catalog_skills`` bound what reaches the system
prompt, ``enabled = false`` registers nothing, and ``allow_write`` is the
standing grant for editing skills (default: ask every time). A malformed
section degrades to the defaults, like [agent] and [mcp].
2026-09-22 22:26:50 +08:00
NCBM ec228e9219 docs: document the full pretty-tool coverage
Every builtin tool now prints the in-progress prefix (previously only the ones
with a renderer were named), MCP tools share one generic line, and plugin tools
keep the [tool] fallback. The parallel-batch fallback erases only its own line,
so the streamed line above it survives.
2026-09-22 22:25:43 +08:00
NCBM d6c4aa0d4f cli/display: prettify the remaining tools
PTY, human-prompt, temp-dir, truncate, and the rest of the VCS/todo family still
printed raw "[tool] name(args)" lines while every other tool had a syntax. Each
one now has a prefix that appears as the call starts and an outcome parsed from
its own result shape: session ids and alive/exit state for PTY, answered/
selected/count for the ask family, granted or denied for access requests, the
new path for a temp dir, changed files with line counts for vcs_diff, and the
rendered stack for the remaining todo commands. ask_into_pty reports only that
the answer was written.

Resolution is no longer a dict lookup: namespaced MCP tools are built from
their ``mcp__<server>__<tool>`` name so a newly connected server gets the same
line without registration, and the resolved renderer is carried from call to
result instead of being looked up twice. Plugin tools and custom calls keep the
whole-line fallback. The shared key=value parser and the ranged-read detail are
reused by run_argv, fetch, read_file, and get_truncated rather than copied.

Tests cover every added line (including the error paths), the MCP naming rule,
and an invariant that each builtin tool resolves to a renderer.
2026-09-22 22:25:34 +08:00
NCBM 221d5d5b68 cli/display: keep the line above an erased tool prefix
Erasing the in-flight prefix reused a helper that cleared one row more than
requested, so a parallel tool batch also erased the line above the prefix -
the streamed reasoning text that sits there when a model reasons and then
calls tools. The helper now clears exactly the requested rows and takes
explicit control of where the cursor lands; the parallel fallback erases its
own line and lets the leading newline of the whole-line write reuse it.

Row counts are computed from physical terminal rows instead of logical
newlines, so an assistant segment wider than the terminal is fully erased
before the markdown re-render rather than leaving a stray copy behind.

Tests: a byte-level regression for reasoning before a parallel batch, unit
coverage for the row-counting and erase primitives, and a wrapped-line flush.
2026-09-22 22:13:24 +08:00
NCBM d697ecdaf6 docs: note that /history keeps a turn's ends expanded
The user message and the final answer print in full at every verbosity level;
only --preview collapses them.
2026-09-22 21:15:31 +08:00