Commit 7ec4ad7
authored
feat: Glob pagination, read-only tools in side questions, and MCP structured results (#303)
## Related Issue
None — routine maintenance batch.
## Problem
Eight independent gaps across the agent engine, CLI and telemetry:
- Glob capped every search at 100 matches with no way to reach the rest.
- MCP tools that return both a text summary and a structured payload
lost the structured half whenever the text was non-empty, so the agent
never saw the records.
- Side questions started with `/btw` vetoed every tool call, so a
question about the codebase could only be answered from memory.
- The subagent model list annotated `primary` with its alias only when
the caller's model happened to be in the pool — that is, it stayed
anonymous exactly when the annotation was needed — and
`AgentDynamicWorkflow` repeated the whole block.
- A `[models]` entry written without a `model` field (most often an
unquoted dotted alias that TOML parsed as a nested table) failed
silently.
- `turn_ended` never carried the error code, session attribution keys
were dropped by payload flattening, and properties a sink could not
accept vanished with no report.
- Tower missions carried only the tower's paraphrase to workers and
reviewers, spawned tasks ignored the configured subagent timeout, and
`/tasks` did not show which model a background agent runs on.
- Sessions could not be deleted from the session picker.
## What changed
Per commit:
- **`bc6abb3` MCP structured results + malformed `[models]` warning.**
The structured payload is dropped only when a text block parses to the
identical JSON value — compared with `isDeepStrictEqual` behind a
reviver that refuses any number `JSON.parse` would round, so a summary,
a media block or a rounded copy never suppresses it. Serialized extras
now escape `<` instead of stripping literal closing tags, which
preserves the values. Config sections gained a `collectDiagnostics` hook
(mirroring the existing deprecations contribution); the models section
uses it to warn on an entry with no `model`, with a hint naming the
quoted table when an unquoted dotted alias produced a nested table. Also
scrubs every ambient `PYTHINKER_CODE_*` variable in the engine and
gateway test setups, and gives the SDK, client and extension projects an
explicit integration-test timeout.
- **`2e3f6d7` `/btw` read-only tools + subagent model disclosure.**
`BTW_READONLY_TOOLS` (Read, Grep, Glob) passes the veto listener; every
write and execute tool still returns the deny message. Mirrored into the
v1 engine — `DenyAllPermissionPolicy` takes an allowlist — because the
v1↔v2 parity suite compares both side-question contexts. `primary` now
always renders as `primary (= <alias>)`, the duplicate `[main model]`
marker is gone, a closing line states that pool entries do not inherit
the caller's thinking level, and `AgentDynamicWorkflow` renders a
one-line summary.
- **`6e89460` Glob pagination.** `offset` and `head_limit` (default 100,
`0` lifts the match-count limit). Every page still fits the output
character limit, ends on a complete path, reports the range it covers
and gives the next offset when matches remain; a page that cannot fit
one complete path plus its diagnostics returns an error instead of a
partial path. The tool card counts only paths and marks a page that is
not the last.
- **`434e97d` telemetry attributes.** `turn_ended` carries the engine
error code; session attribution keys emit empty strings so they survive
flattening; a new `onUnexpectedError` hook reports properties the sink
could not accept. Properties are sanitized when the sink accepts the
event, so drops on events queued before initialization are reported once
a handler is installed, and the hook runs behind a guard so a faulty
host handler cannot abort `track()`.
- **`c84f5df` tower.** Missions take a `context` field holding the
user's own sentences verbatim, rendered into the mission file and every
briefing. Reviewer briefings embed the mission text and the author's own
review-request behind an intent-first checklist; workers escalate
substantive ambiguity with a `clarify-request` instead of guessing, and
reconcile completion reports task by task. `TowerSpawnTool` resolves the
timeout through the `[subagent]` config instead of a hardcoded two
hours, and reports the bound model and effective thinking effort in the
task info, which `/tasks` renders.
- **`38ac69f` session deletion.** `Ctrl+X` on a picker row asks for
confirmation and deletes. The picker stays mounted and holds the input
lock until the replacement session is ready, so no prompt races the
swap; deleting the current session closes it first (no events from a
dying session reach the UI) and starts a fresh one; a failed delete
reattaches to the session the engine kept, falling back to a new session
only if it is gone.
- **`4aee74c`** changesets, **`90e3495`** docs.
Scope deliberately excluded: the gateway-side half of session deletion
(`event.session.deleted` over WS and the serialized cleanup route) is
not in this PR — the CLI half stands alone on the existing
`harness.deleteSession`.
## Risk
Medium. Three behaviour changes are visible to the model rather than to
the user: MCP results now carry more content, the subagent model prose
changed, and `/btw` can read files. The `/btw` change widens what a
side-question agent may do — it is limited to three read-only tools, and
the deny path is unchanged for everything else.
The telemetry change alters emitted values (`''` instead of `null`); the
`pfc_` event prefix and ingest hosts are untouched.
## Verification
Each exit code captured separately, all 0 unless noted:
- `pnpm run typecheck`, `pnpm run lint`, `pnpm run sherif`, `pnpm run
build`, `pnpm run check:web`, `pnpm -C apps/vscode run typecheck`, `pnpm
-C apps/vscode test`, `node scripts/check-nix-workspace.mjs`, `nix build
.#pythinker-code`.
- `pnpm test`: 1241 files, 21,526 passed / 2 failed / 3 expected fail /
79 skipped / 2 todo. Both failures are
`packages/agent-gateway/test/fs-watch.e2e.test.ts` under load — a
temp-dir `rename` ENOENT in `instanceRegistry.writeFileAtomic` plus its
10s `afterEach` timeout. That file passes 10/10 in isolation and is
untouched by this diff.
Tests added or updated: 5 config-diagnostics cases, 15 MCP output cases
(including a 6-way difference matrix), 2 `/btw` cases plus 3 v1
parity/prompt assertions, 6 subagent-description assertions, 4 Glob chip
cases and the engine glob suite, 1 `turn_ended` error-code case plus
telemetry/SDK fixture updates, tower spawn timeout and metadata cases,
and the session-picker delete flow.
Three guards were proven by mutation rather than by passing: removing
the `collectDiagnostics` registration fails 4 tests, an unconditional
btw veto fails 1, and the pre-change `hasUsableContent` rule fails 15.
## Rollback and review
Every commit is independent and revertible on its own. Residual risk is
the model-facing prose and the wider MCP payload; both are covered by
tests that assert the exact rendered text.
Human review wanted on the `/btw` read-only allowance — it is the one
change that widens what an agent may do.
## Checklist
- [x] I have read the CONTRIBUTING document.
- [ ] I have linked a related issue — none; routine maintenance batch.
- [x] I have added tests that prove my feature works.
- [x] Ran `gen-changesets` skill.
- [x] Ran `gen-docs` — `docs/customization/mcp.md`,
`docs/reference/tools.md`, `docs/guides/sessions.md`,
`docs/reference/slash-commands.md` and
`docs/configuration/config-files.md` updated.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- `/btw` side questions can use read-only `Read`, `Grep`, and `Glob`
tools.
- Delete sessions with `Ctrl+X`, including confirmation and
active-session replacement.
- Glob supports paginated results with offsets and configurable limits.
- Background task lists display agent model names.
- Tower missions preserve context, enforce worker timeouts, and require
tasks for build missions.
- MCP structured results remain available alongside text and media
output.
- **Bug Fixes**
- Added warnings for malformed model configuration entries, with
refreshed diagnostics after settings changes.
- Improved telemetry reporting for dropped properties and turn errors.
- Improved Glob result counts and empty-result handling.
- Addressed a TOML parser denial-of-service issue.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->1 parent 0ae4200 commit 7ec4ad7
94 files changed
Lines changed: 2592 additions & 329 deletions
File tree
- .changeset
- apps
- pythinker-code
- dist-web
- src
- cli
- tui
- components
- dialogs
- messages/tool-renderers
- controllers
- test
- cli
- tui
- components
- dialogs
- messages/tool-renderers
- vscode
- test
- docs
- configuration
- customization
- guides
- reference
- release-notes
- packages
- agent-core-v2
- src
- agent
- loop
- mcp
- tools
- agent
- os/glob
- app
- config
- kosongConfig
- telemetry
- features
- btw
- dynamic_workflow/tools/agent-dynamic_workflow
- tower
- injection
- protocol
- tools
- plan
- spawn
- session/subagent
- test
- agent
- fullCompaction
- loop
- mcp
- app
- config
- sessionIndex
- features
- btw
- dynamic_workflow
- tower
- tools
- os/backends/node-local/tools
- tool
- agent-core
- src
- agent/permission/policies
- session
- test/session
- agent-gateway
- test
- klient
- node-sdk
- src
- test
- telemetry
- src
- test
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
0 commit comments