You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: web domain allowlist and markdown report rendering (#15)
* feat(wire): add ToolExecutionStarted and ToolOutputPart events for live tool feedback
Introduces two new wire protocol events so the UI can distinguish the approval/hooks
phase from actual tool execution, and stream incremental shell output before the final
ToolResult arrives.
- ToolExecutionStarted: emitted once per tool call after approval completes, before
the tool body runs; file/MCP/external tools emit from the approval path while Shell
and RunAgents emit it themselves at the right moment
- ToolOutputPart: streamed from the Shell tool as stdout/stderr lines arrive
TUI blocks now hold the execution-started spinner until ToolExecutionStarted lands
(showing a calm "preparing" row before that), render streamed output as a live tail
preview, and the Bash card shows "running" status when partial output is present.
The composing _ContentBlock also gains a live Markdown preview while the model writes.
* fix(agents): guard against out-of-policy lint findings in explore/plan agents; pad markdown code blocks
explore.yaml: require supplemental ruff checks (e.g. --select C901) to be
labeled "outside project lint policy" so callers can distinguish enforced
violations from advisory findings.
plan.yaml: add context-gate rule to verify any lint/complexity finding is in
the project's active select list before proposing a refactor — prevents plans
driven by rules the project intentionally does not enforce.
markdown.py: yield a blank_row() above and below each bordered code block so
panels read as distinct sections rather than crowding surrounding prose.
Test added to assert the blank-row framing is present.
* docs: add agent live tool stream design spec
* docs: add agent live tool stream implementation plan
* feat(blocks): add subagent output tracking state and methods to _ToolCallBlock
Add three new state fields (_subagent_output_parts, _subagent_output_had_stderr,
_subagent_execution_started), two new public methods (mark_sub_execution_started,
append_sub_output_part), and cleanup in finish_sub_tool_call for the new fields.
Also update append_sub_tool_call and append_sub_tool_call_part to recompose after
mutations, readying the block for live subagent tool streaming in Task 2.
* test: sync default agent-spec snapshot with explore.yaml lint policy
The committed explore.yaml carries lint/complexity-policy guidance (do not
flag rules such as C901 that are absent from the project's configured rule
set) that its inline snapshot in test_agent_spec.py never received, so the
test failed on a clean checkout. Regenerate the snapshot to match HEAD.
* fix(tui): refine markdown report rendering
- Frame fenced code blocks with a blank row above and below so they read as
a distinct section instead of crowding surrounding prose.
- Add a conservative pre-parse normalizer that repairs malformed GFM tables
the model sometimes emits (header glued to prose, a blank line before the
|---| delimiter, data rows crammed onto the delimiter line) which
markdown-it would otherwise render as raw text. Anchored on the delimiter
row, it rebuilds only regions whose header and data cell counts validate,
preserves column alignment, and leaves ambiguous or fenced content
untouched.
* feat(agent): guide output formatting and anchor date awareness
- Add an Output Formatting section to the default system prompt: emit
well-formed Markdown tables, reserve code fences for actual code (never
wrap prose reports, finding lists, or ASCII boxes in a fence), and use
status icons sparingly. This stops the model from producing the malformed
tables and emoji-laden boxes that rendered poorly in the TUI.
- Reword the Date and Time section so the injected ${PYTHINKER_NOW} is
framed as the authoritative present, anchoring the agent's sense of 'now',
recency, and 'latest' to it instead of a training-era year.
- Refresh the prompt snapshot and add coverage for both.
* refactor(blocks): align subagent output methods with peer guards, add cap test
* feat(web): add fetch/search domain allowlist
* test(web): add domain-allowlist fetch tests and tool-description/config docs
* fix(typos): unparseable -> unparsable in tasks/todo.md to satisfy spell-check gate
* fix: address CodeRabbit review findings on web allowlist and markdown
- config.py: reject `allowed_domains` entries that are dots-only (would
normalize to empty → silently unrestricted) and any entry containing
whitespace (newlines previously slipped past the space/tab check).
- tools/web/_allowlist.py: strip trailing dots when normalizing entries so
`example.com.` matches `example.com` hosts.
- tools/web/search.py + ui/shell/tool_renderers/web.py: emit a structured
`returned_results=0` signal on the all-filtered path and have the search
renderer prefer it, so an all-filtered result reports "0 results" instead of
misreading the prose notice as one result.
- ui/shell/components/markdown.py: prefix rebuilt table rows with the captured
delimiter-line indent so normalization never promotes an indented table to
top level (defensive; the guard already bails on non-empty indent today).
- agents/default/system.md: reword the code-fence guidance to use inline code
spans for language names (markdownlint MD038).
- Tests: reject `.`/whitespace allowlist entries, trailing-dot entry matching,
and an all-results-filtered renderer regression; refresh the default-agent
system-prompt snapshot.
@@ -199,6 +202,16 @@ Configures web fetch service. When enabled, the `FetchURL` tool prioritizes usin
199
202
When configuring the Pythinker platform using the `/login` command, search and fetch services are automatically configured.
200
203
:::
201
204
205
+
### `web`
206
+
207
+
`web` configures policy shared by the `FetchURL` and `SearchWeb` tools.
208
+
209
+
| Field | Type | Default | Description |
210
+
| --- | --- | --- | --- |
211
+
|`allowed_domains`|`array<string>`|_unset_| When set, web fetch and search may only touch these domains and their subdomains. `FetchURL` rejects URLs on other hosts before making any request — including redirect targets, which are re-validated on every hop — and `SearchWeb` drops results from other domains. Unset or empty means unrestricted. Entries must be bare hostnames (e.g. `example.com`), not URLs, paths, or `host:port`. |
212
+
213
+
This is a coarse governance control layered on top of the existing SSRF protections (which always block private, loopback, link-local, multicast, and reserved addresses); it does not replace them. Matching is label-aware: `example.com` matches `example.com` and `docs.example.com`, but not `notexample.com`.
Copy file name to clipboardExpand all lines: src/pythinker_code/agents/default/system.md
+10-1Lines changed: 10 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -188,7 +188,7 @@ The operating environment is not in a sandbox. Any actions you do will immediate
188
188
189
189
## Date and Time
190
190
191
-
The current date and time in ISO format is `${PYTHINKER_NOW}`. This is only a reference for you when searching the web, or checking file modification time, etc. If you need the exact time, use Shell tool with proper command.
191
+
The current date and time in ISO format is `${PYTHINKER_NOW}`. Treat this as the authoritative present — it reflects the real "now", which is later than your training data suggests. Anchor all reasoning about the current date, the year, recency, and what counts as the "latest" version or release to `${PYTHINKER_NOW}`; do not fall back on an earlier year you might assume from training. Use it as your reference when searching the web or checking file modification times. If you need the exact time, use the Shell tool with a proper command.
192
192
193
193
## Working Directory
194
194
@@ -261,6 +261,15 @@ Identify the skills that are likely to be useful for the tasks you are currently
261
261
262
262
Only read skill details when needed to conserve the context window.
263
263
264
+
# Output Formatting
265
+
266
+
Your responses are rendered as Markdown in a terminal. Emit well-formed Markdown so it renders cleanly:
267
+
268
+
-**Tables:** put the header row on its own line, the `|---|---|` delimiter row on the immediately following line (no blank line between them), and one row per line. Never glue a table onto adjacent prose (e.g. `Findings| Col |`) and never cram multiple rows onto one line. Leave a blank line before and after the table.
269
+
- Prefer a short bullet list over a table when there are only a few items or any cell is long; reserve tables for genuinely tabular data with short cells.
270
+
-**Code fences are for code only.** Use triple-backtick blocks tagged with a language (for example, `python` or `toml`) solely for source, config, or commands — one snippet per block. Never wrap a prose report, finding list, checklist, or ASCII box in a fence to align or frame it; write it as normal Markdown (headings, bullets, tables) so it renders cleanly.
271
+
-**Status icons sparingly.** A check/cross/dot can mark a single headline result, but do not prefix every line with one. Use plain words for severity and outcomes (e.g. `High`, `PASS`, `0 findings`). The terminal renders icons as calm monochrome glyphs only outside code fences — another reason not to box reports.
272
+
264
273
# Ultimate Reminders
265
274
266
275
At any time, you should be HELPFUL, CONCISE, and ACCURATE. Be thorough in your actions — test what you build, verify what you change — not in your explanations.
Fetch a web page from a URL and extract main text content from it.
1
+
Fetch a web page from a URL and extract main text content from it. Requests may be restricted to a configured set of allowed domains; fetching a disallowed host (including via a redirect) returns an error.
WebSearch tool allows you to search on the internet to get latest information, including news, documents, release notes, blog posts, papers, etc.
1
+
WebSearch tool allows you to search on the internet to get latest information, including news, documents, release notes, blog posts, papers, etc. Results may be limited to a configured set of allowed domains.
0 commit comments