Repository navigation
fix(raven-design): deck lane on the engine's modules, defaults first, one .pptx delivered - #451
Conversation
gloryfromca
left a comment
There was a problem hiding this comment.
Blocking: two portability and routed-readiness defects must be fixed before merge.
I reviewed the full diff and relevant surrounding code, callers, route architecture, and commit history. I also checked the repository rules and domain terminology, backward compatibility, and whether tests were weakened; I found no weakened tests or separate rule violations worth raising. The two concrete failures are marked inline.
Verification: the directly affected Python suite passed (958 passed, 1 skipped); the broader provider, capability, plugin, publish, and materials suite passed (233 passed); the workspace UI test passed (31 passed) and TypeScript checking passed. Ruff, diff whitespace, source-language, and large-file checks also passed. The skipped Python test requires LibreOffice.
gloryfromca
left a comment
There was a problem hiding this comment.
Blocking: the two existing review findings remain unaddressed.
I reviewed the new commit and rechecked the full diff, relevant callers, history, route architecture, repository rules and domain terms, backward compatibility, and test changes. The new tool-filtering entries and regenerated TUI catalogue are consistent and add no new finding, but neither existing blocked code path changed, so both open threads still apply to this revision. No tests were weakened.
Verification: the affected launcher, routing, and web-tool regression set passed (314 passed); TUI i18n tests passed (8 passed), the generated-catalogue check passed, and TUI TypeScript checking passed. Ruff, diff whitespace, source-language, and large-file checks also passed. An initial direct Vitest invocation collected no tests because it bypassed the package's required pretest build; rerunning through the declared npm test script built the dependency and passed.
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
Both prior findings are fixed in debc00c, I accepted the author's answers, and I resolved both threads. For this revision I reviewed the five-file fix delta and its callers, relevant history, repository rules and domain terms, backward compatibility on POSIX and Windows, route architecture, and test changes; I found no new issue and no weakened test.
Verification on the exact PR head: 184 affected launcher, routing, and web-tool tests passed. Ruff, diff whitespace, source-language, and large-file checks also passed.
… third of a clone The whitespace reading groups words into a line by vertical overlap, not by a 4pt top, so a unit beside a figure is no longer an orphan. A full-width panel that runs off the bottom edge is the page's ground and not body reaching the boundary, so the trailing field of a cloned page is read again; a centred body is exempt from it. Cloned pages skip only the header reading, borrowed pages only the group gaps, and pages built on the template's own cover, index, divider or closing skip the gate. Data-source lines count as captions for the type floor. layout_picture is said once per run. The review ledger refuses an ownership-only reason on a page the template does not own, counts a reason that made room as a fix, and names the underfilled reason it refuses. tidy returns a line whose solid fill names no colour to no line at all, which is what reading shape.line.color through python-pptx leaves behind. The build reply folds Python warnings into warned.json, keeps the type_floor and title_row detail internal, and exempts drafts from the evidence finding. The script runner notes a SLIDE banner that heads two blocks. Template compose cuts a cover-fit picture in pixels before filling a shape with it, since LibreOffice ignores srcRect on shape fills, drops the scale a template baked into normAutofit, and lets the template tool read borrowed pages. The outline refuses one repeated page but leaves a run of three alike pages alone as a series. Prepare, materials and state guidance say where the figures of a cited paper are and which file a figure id names.
…earch vendor A picture search tool beside web_search: one call takes every picture the deck needs as queries, and each hit carries the direct image URL, its pixel size, the domain and the page it came from; anything under 640px wide is dropped. The tool is offered only when the vendor with an image surface has a key, following the host's selected search vendor where that vendor has one and Serper otherwise, and the capability table swaps in that vendor's config path. The routed design lane registers it under the same gate, so a host on a vendor that searches pages only does not open a lane that needs pictures. The ppt lane keeps its own ppt_image_search and holds the host tool out. The oversized-picture refusal in the loop says only that the pictures came out.
…ration tiers The launcher writes <state root>/bin/raven-python, a shell wrapper on its own interpreter, and appends that directory to tools.exec.pathAppend, so the deck skill can name one interpreter that has python-pptx and raven_ppt on a uv tool install, an editable install and a wheel alike. A wrapper and not a symlink: CPython resolves a symlinked venv python back to the base interpreter. Two runs spent five and seven exec calls hunting for the interpreter and one built a venv of its own. The deck skill reads deck-to-pptx before the first page, searches pictures through image_search where the deployment has it, crops a paper's figures out of the PDF with PyMuPDF and renders formulas with mathtext rather than typing them, then renders the page and looks. The route note says the same. All three tiers run 400 tool iterations; medium keeps low reasoning effort. The baseline cap leaves the fork's 150, which the launcher test records.
Tabler draws every icon with a 2-unit stroke on a 24-unit grid, so the weight is a twelfth of whatever side the icon is drawn at. add_icon's fixed 1.75pt pen kept that proportion only at 0.29in; at the 0.7in a card carries it was a third of the designed weight, and the delivered decks' icons read as hairlines beside the type. The default is now side / 12 in the engine helper, the route note and the deck skill's reference alike, and a caller who wants a fixed pen still passes width_pt. The dot a round cap leaves is sized to the same pen.
With no PDF in hand the skill first has the deck find and download one, from the publisher or arXiv, and crop from that; image_search for the published figure is the last resort, when no PDF can be had.
…owed page numbers The whitespace gate's list of borrowed pages was added under the name the template gates already used for the list of borrowed template files, and the later definition won: placeholder_copy, placeholder_marks, template_picture and same_mark received page numbers, raised on Path(4), and check_deck swallowed the error, so on a deck with a borrowed page none of the four reported anything. The page list is _borrowed_pages now, and the registry test asserts that _borrowed still answers with files. The review tool's house-page reading catches an unreadable template the way the gate registry does, the made-room refusal branch is covered by a reason that names ownership and the room made, and a test docstring stops quoting the icon pen's old default.
…d-built deck lane raven_ppt.services.assets.formulas gives the deck lane below the top tier what ppt_layout.formula gives the engine's own scripts: add_formula renders TeX with mathtext to a transparent PNG in the deck's ink and places it at true size, with \frac promoted to display style and STIX scaled to stand level with body copy; math_runs sets a sentence that carries symbols as text runs with real sub- and superscripts, italic variables and upright words. CJK inside an expression and constructs mathtext does not know are refused with the way round. The ppt_layout template promotes \frac the same way.
…s rules only The raven-python shim is written with the interpreter path shell-quoted and replaced atomically. The deck skill, its assets reference and the route note lose every sentence of rationale and keep the rules: light ground by default, recommended when asking; a paper's figures come from its PDF, a downloaded one before an image search; add_formula for anything that stacks, math_runs for symbols in a sentence, no _A or ^2 left as characters; the pen follows the icon's side.
The lane asked the user for language, audience, length and ground on most decks. The skill, the route note and the product description now take each of those from the request, then from what memory recalled about the user, then from fixed defaults (the request's language, a general audience, about 20 pages, a light ground), and ask at most once, only for what none of those settles. The lane's memory slice hardcoded the stock everos address, so a host serving everos elsewhere gave the lane an empty recall every time. The launcher now copies the host's everos base_url into the slice. The interpreter shim is written through a staged file and os.replace.
The engine lane delivered the PDF render beside the deck and named it in the reply, so a max deck arrived as two files where a medium or high deck arrived as one. The render under out/ stays the engine's own preview and is no longer delivered or handed over; the build tool's reply, its description and the authoring skill say one file lands. Recorded as D64 in the design ledger.
…d keeps no ledger Five recorded deck runs each wrote their own python-pptx kit -- text box with CJK font, rectangle, rule, connector, icon, header, footer, source note -- 48 helpers in all, with the previous deck's palette baked in. The engine already writes the same kit beside a build script (ppt_layout, ppt_theme, ppt_icons, ppt_shapes, ppt_charts), measured and themed; the route note and the deck skill now say to write those modules once and import from them, and the icon-drawing snippet they used to copy is gone. Nine audited runs wrote the anti-pattern ledger 18 times and read it back never, wrote no contract, and used the task state as progress ticks that leaked across sessions; every real fix came from reading a render. On this route the note and the skill now say: no ledger, no contract, no task state, and every page read back from a render at 90 dpi or more before the file is handed over. Verified on a live medium run (21 pages, 21 minutes, no question asked): no task-state call, no ledger, no hand-written helper, renders at 90 dpi, 32 page reads.
… every page's picture The first live run under the no-ledger rule read only deck-to-pptx: the model took "no ledger, no contract, no task state on this route" as leave to skip the engine skills, and design-editorial-and-presentations is where the content order and the editorial judgement come from. The deck came out at 8 picture pages of 21 with one search for application photos. The route note and the skill now name both skills to read, say the ledger rule excuses nothing else, and add the picture rules: every page is named with the picture it carries before the build, type-and-card pages are at most a third of the deck, a model, method, dataset or milestone page carries its own figure whatever the audience, the first search covers every page and a page left without one gets a second, count 8 per query. Second live run, same eight-character request: both skills read, 18 picture pages of 20, paper figures for AlexNet, CNN, CLIP, YOLO, segmentation, Imagen and the adversarial panda, 26 minutes including one upstream timeout the host resumed.
…the templates' compositions Under "helpers are packaged; do not write your own" two live runs drew nothing by hand: 305 lines of build script, zero shapes, pictures placed bare, ten of twenty pages the same two-column card layout. The rule now splits the page: furniture (text, points, cards, rules, heading, footer, table, icon, chart, formula, the grid) comes from the engine's modules and is not rewritten; what makes a page its own -- a diagram, a polygon, a map, a custom arrow, a gradient, a hero number, a cover or section composition, and the treatment of every placed picture (frame, shadow, scrim, crop, full-bleed ground) -- is drawn by hand with python-pptx. The picture rule added in the previous commit is withdrawn: its numbers were not measured. The editorial skill stays required. layouts.md gains twenty compositions read off the 54 template pages the deck engine keeps as reference layouts, each with its shares of the canvas and the template pages it comes from, so a hand-built deck has the same menu of shapes a template-bound one does.
…rks are searched The engine table draws the ordinary grid; merged cells, spanning headers, icons or colour inside a cell and over-wide tables are drawn by hand. Generic marks come from the packaged icon set; a company's logo, a product's icon or a framework's badge is searched, downloaded and placed as a picture.
…inside its box Two rules with the engine gates' own numbers: content runs to within 0.5in of the footer, no gap over 0.75in between groups, no card under 35% full, a short run centred with holding() or given its picture; copy measured before drawing and never shrunk to fit. The engine's whitespace gate read 15 gaps and 3 sparse panels on one delivered medium deck and 14 overflowing boxes on the next; the hand-built lane never runs that gate.
…the page's edges The previous commit stated the gates' inch thresholds; the rules now say what a page is made of: every component full, components in a hierarchy of size, weight and tint with groups told apart by the space between them, and the page composed to its edges.
…ld shim a .cmd twin The deck route's readiness probe took the host's selected search vendor as the one the target lane would search pictures with. Raven-PPT holds the host image_search out and searches through its own plugin, which speaks Serper, so a Tavily host on Tavily's key alone opened a lane that could not search. The probe now asks the target first: a product whose config holds image_search out is read on its own tools.web.search.provider, Serper when it names none. The design lane's raven-python shim was a POSIX shell script only; cmd.exe cannot run one, so a medium or high deck on native Windows failed at its first interpreter call. A raven-python.cmd twin is written beside it and resolves through PATHEXT.
The picture search registered in every loop that held a search key, so the research, code and oncall lanes grew a tool their faces never listed. The tool now sits behind tools.web.search.images, off by default; the design launcher switches it on in the config it renders, on top of the host's web slot it inherits, and the ppt lane keeps holding the host tool out in favour of its own. A loop that did not ask has no image_search at all, keyed or not.
debc00c to
6995b78
Compare
gloryfromca
left a comment
There was a problem hiding this comment.
Blocking: make the new image-search opt-in agree with capability reporting and its invariant tests.
I reviewed the actual ten-file change after separating it from the branch rebase, then rechecked the full PR diff, relevant callers and history, project rules and domain terms, backward compatibility, route/tool architecture, and test changes. The prior two fixes remain valid and their threads remain resolved. I found no other issue.
This meets the late-round blocking bar: commit 6995b78 introduces it; an ordinary default config with a search key reaches it; and an operator who sees the green capability result but lacks the tool is given no accurate state or repair path, while the repository's invariant suite has no passing path until the contract is reconciled.
Verification: the unaffected launcher, routing, web-tool, runtime, and subagent regression set passed (292 passed). The capability suite failed (42 passed, 2 failed), both on the image_search registry/reporting mismatch. Ruff, diff whitespace, source-language, and large-file checks passed.
| """The Serper key on the pre-vendor layout. Still honoured, read after | ||
| ``tools.web.providers.serper.apiKey``; new writes go to the vendor slot.""" | ||
| max_results: int = 5 | ||
| images: bool = False |
There was a problem hiding this comment.
Blocking: make the new image-search opt-in part of the capability contract.
With the new default images=false and a valid Serper key, the runtime does not register image_search, but raven.agent.tools.capabilities.is_configured and is_offered still return true because they only inspect the key. As a result, raven doctor prints a green check for a tool the agent does not have, and the extension setup surface suppresses its missing-capability guidance. The existing contract tests catch the same concrete divergence: tests/test_tool_capabilities.py now has 2 failures (42 pass). Please make the capability predicates/reporting account for this opt-in and preserve the registry invariant rather than weakening those tests.
This is introduced here, occurs in an ordinary keyed default config, and leaves the operator with neither a truthful diagnostic nor a repair path from that surface.
…ads (#463) ## Summary `main` is red on three jobs (`python lint`, `unit 2/4`, `unit 3/4`), and has been since #451 merged. All of it is fallout from one arrival: `image_search` came with a second switch beside its credential. `tools.web.search.images` decides whether the tool is registered at all (`raven/agent/loop/wiring.py`), so a lane that never places a picture keeps the tool face it had. The capability table was not told. `is_configured` answers on the vendor key alone, so with a Serper key and the switch left off the table ticked a capability the agent does not hold, and the two tests that drive a real `AgentLoop` caught exactly the disagreement that module exists to prevent. The switch belongs on `is_disabled`, not `is_configured`. That function's own docstring already names the reason: a switched-off tool usually has its credential set, and calling it unconfigured sends the deployer to set a key that is already there. `tools.disabledTools` and this flag are the same kind of answer, so `is_offered` needs no change and the doctor row reads "off" rather than "missing a key". The test configs that mean "everything supplied" now turn the switch on, the way `raven/core/runtime.py` passes it from the config, and a new case pins the combination that was wrong: key present, pictures off, nothing offered, table saying off. Two more pieces of the same arrival: - `ImageSearchTool` copied `WebSearchTool`'s key resolution without its two attribute annotations, so the untyped lambda `wiring.py` hands it left the `api_key` property returning `~AlwaysFalsy | str` against a declared `str`. The type checker pinned in #416 reports it; the annotations are the fix. - `WebSearchConfig` gained the `images` field, so the writer's validated subtree now carries it and two `test_config_update_tools` expectations that pin the written section by value went stale. Not changed here: `get_web_search` still reports `{provider, api_key, max_results}` and does not surface `images`, though `set_web_search` can write it. That is a gap in the read side of the config API, not a CI failure, and it wants its own change. ## Type - [x] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification Run on Windows 11 in a clean worktree cut from `main` (`5a29ea22`): - `uv run pytest tests/test_tool_capabilities.py tests/test_config_update_tools.py -q`: 71 passed. All four tests failing on `main` now pass, plus the new case. - `uv run --frozen --python 3.12 --all-extras ty check raven evolver agents plugins-dist scripts`: the `web.py:516` diagnostic is gone. The diagnostics that remain locally are unresolved imports for optional packages absent from this machine's environment (`boxlite`, `nio`); CI reported exactly one diagnostic before this change, the one fixed here. - `uv run --frozen --python 3.12 --extra dev ruff check raven tests`: all checks passed. - `ruff format --check` on the four changed files: already formatted. - `uv run pytest tests/test_cli_doctor_commands.py tests/test_rpc_console.py -q`, which consume `is_disabled`: the failing-test set is byte-identical before and after this change (8 pre-existing Windows-only failures around file modes and an absent browser package, none of them in the set CI reports). ## Risk `is_disabled` gains a second reason to answer true, so a deployment with a search key and `tools.web.search.images` off now reads as "switched off" in `raven doctor` and the console capability report, where it previously read as offered. That is the state the loop was already in; only the description changes. Nothing about registration, gating, or the tool's runtime behaviour moves. The other two changes are an annotation and two test expectations, with no runtime effect. Rollback is reverting this commit; it touches nothing that other work builds on. ## Related Issues N/A --------- Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
…ked again (#467) ## Summary Two regressions in the hand-built deck lanes (medium and high on Raven-Design), and the stream failure that made every run of them a coin toss. **The deck lane draws its own pages again.** PR #451 pointed the hand-built lane at the engine's helper modules (`ppt_layout`, `ppt_theme`, `ppt_shapes`), which were written for the max lane's script backend. Their defaults became the deck: `heading()` put a white surface band bled across every page, `card()` became the way anything was placed, text frames were top-anchored with the lower third empty, and a build script named three colours. Measured on the same request, the accent colour appeared 8 times across 20 pages. The skill, route note and assets reference go back to the pre-#451 text: the lane draws with python-pptx and takes only the icon set, `add_formula` and `math_runs` from the engine. On the reverted lane the accent appears 54 times, the deck carries 12 real pictures and the layouts differ page to page. **Colour is named beside the type sizes.** The skill listed sizes for every role and said nothing about colour, so a lane with the right palette still drew in one colour. One paragraph now says what colour is for; the layouts note no longer reads as one accent per page, which a lane took as a ceiling. Where `image_search` is not offered, the fallback no longer tells the lane to give the pictures up: `web_search` for the page, `web_fetch` it, and download where the fetch backend keeps image links. **A stall in a silent think is asked again.** Across two measured runs the lane's turn failed 28 times on `Upstream idle timeout exceeded`, every time in the one round that writes the whole build script into a tool argument. `stream_llm_call` refuses to retry after output a watcher has seen, and counted reasoning deltas and half-built tool-call fragments as that output, though neither is ever shown as the reply. So the configured retry ladder was never reached. `rendered()` now asks what a watcher could have seen; every retry path resets the buffers first (a slot left standing merged with the next attempt into a call the model never made); a stall handed back as an error response carries the usage it spent. The in-process builtin backend, whose comment claimed a retry ladder and passed none, now receives the deployment's `llmErrorRetryDelays` and `llmRetryAfterOutput` through the SubagentManager. No packaged product takes that path; all five run as ACP agents on the loop's own call site. **Two bundled templates edited in place**, by the maintainer's word. `beige_geometric_general_report` loses its page 20, a dark photograph cut by a circle under pale rounded cards; 23 pages become 22 and the two reference pages the lane borrows from it (17, 19) keep their numbers. `black_circuit_tech_launch` loses the 27 percent circuit texture on its master and the photograph on its Section Header layout, so its body and section pages sit on the master's plain `#000000`; cover and closing are unchanged. `templates.manifest.json` is repinned; `fetch_templates.py --verify` holds all ten pins. The registry archive was not re-cut. No configuration default changes. The only behaviour every lane sees: a stream that fails before any reply text reached a watcher is retried on the configured ladder instead of failing the turn. ## Type - [x] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification ``` uv run --frozen pytest tests/test_agent_loop_llm_error_patience.py tests/test_agent_loop_stream.py \ tests/test_subagent_manager.py tests/test_subagent_routing_backend.py -q 265 passed in 6.85s (after rebase onto main) uv run --frozen pytest tests/test_litellm_provider_stream.py tests/test_litellm_provider_stream_end.py \ tests/test_provider_stream_fallback.py tests/test_providers_stream_idle_budget.py -q 102 passed uv run --frozen ruff check raven/agent/loop/main.py raven/agent/subagent/backends/raven_loop.py \ raven/agent/subagent/manager.py raven/providers/streaming.py All checks passed! grep -nP "[^\x00-\x7F]" agents/raven-design/route-raven-ppt.md -> no matches (the note is pinned ASCII) ``` Both new tests were checked against the unfixed code: `test_a_stall_during_a_silent_think_is_asked_again` fails with the old `emitted` test, and `test_what_the_failed_attempt_left_behind_is_dropped` fails with the buffer resets removed. The failure itself was reproduced outside the runtime: the same 37-message history, six pictures and tool table, sent through litellm 1.101.0 to the same vendor, succeeds on a short answer every time and fails mid-stream one time in three when asked to write the full build script; healthy long streams show a maximum inter-chunk gap of 1.9s over 234s, so the cut is a dropped connection, not a slow model. Decks built on the changed lane, same request as the #451 acceptance run (glm-5.3-flash via OpenRouter): medium 21 pages with 12 pictures and 7 text colours, 48 gate findings (4 `excessive_whitespace`, down from 18); high 13 pages with 13 pictures and 9 text colours, 37 findings. The high run's page count came from the host agent's forwarded brief, which stated 10-14 pages the user never asked for; that is a separate issue. Template edits: `tests/test_ppt_engine_templates.py tests/test_ppt_engine_default_templates.py tests/test_ppt_engine_template_bands.py tests/test_ppt_engine_template_theme.py tests/test_ppt_engine_measure_geometry.py` -> 152 passed, 1 skipped; `make check-large-files` -> clean; both templates rendered and read page by page. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [ ] User-facing docs or screenshots are updated when needed ## Risk - [ ] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes User-visible: on every lane, a streamed call that fails during reasoning or mid tool-call, with no reply text yet shown, waits out the configured ladder (default 15/30/60s) and asks again instead of ending the turn. A call that already streamed reply text behaves as before. Reasoning tokens of the abandoned attempt are spent again and are now recorded in usage. Rollback: revert the `providers` commit alone to restore the old failure; the skill text and the builtin-backend plumbing are independent of it. ## Related Issues N/A
## Summary `refactor/ui_web_architecture` last shared a commit with `main` at `5a29ea22` (#451). This merges `main` (`dbe259f6`) into it so the conflicts get settled once, now, instead of all at once under #475, and so CI runs on the merged tree rather than on a branch GitHub already reports as `CONFLICTING`. Seven paths conflicted. How each was settled: - `ui-web/src/features/settings/SettingsPage.tsx`, its test, and `ui-web/src/live/120-settings.js` -- deleted on this branch, edited on `main` (modify/delete, so git leaves `main`'s copy in the tree). The rebuilt settings surface replaces all three; the deletions stand. - `i18n/messages.json` and `ui-tui/src/i18n/messages.generated.ts` -- `main`'s only change to either since the merge base is #506 dropping `gui.set.chn.cron_to` and `cron_ph` (8 and 4 lines, no additions). This branch already drops the whole `gui.set.chn.*` group, so its side is the superset and wins. - `raven/skill_hub/hub.py` -- each side added one import from `skill_hub.audit`. `write_install_meta` is called at line 621, `INSTALL_META` at line 699, and both exist in the merged `audit.py`, so both are imported. - `ui-web/build.py` -- `main` rewrote the `newline=""` comment, this branch added `flush=True` to the print under it. Both kept. What came in quietly and is worth knowing: #506's cron timezone fix auto-merged into `raven/rpc/methods/console.py` and brought its five cases in `tests/test_rpc_settings.py` with it. The rebuilt settings pages have no cron section at all, so on this branch the backend can now write `cron.defaultTimezone` correctly and nothing on the page does it. Whether that control gets ported, and in which PR, is a separate decision. ## Type - [ ] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [x] Other (catch-up merge) ## Verification Run in a worktree on the merged commit: - `uv run pytest tests/test_rpc_settings.py tests/test_skill_hub_client.py tests/test_skill_hub_policy.py tests/test_skill_hub_source.py tests/test_skill_hub_tools.py tests/test_i18n_boundary.py -q` -- 174 passed. - `npm test` in `ui-web` -- 181 files, 2513 tests, all passed. - `node ui-tui/scripts/gen-i18n.mjs` -- regenerating the TUI catalogue leaves `messages.generated.ts` byte-identical to the resolved file, so the two i18n artifacts agree. - `make lint-python` -- 1986 files already formatted, clean. - `make lint-imports` -- 10 contracts kept, 0 broken. - `make build-ui` -- page built, `boot-snapshot: OK` on both snapshots. - `scripts/check_source_language.py` and `scripts/check_large_files.py` over `bc74bf73..HEAD` -- both exit 0. The full suite was left to CI. `commit messages` is red, and will be red on any PR that merges `main` into a branch. Commitlint runs over `<base>..HEAD`, which here includes every commit `main` gained since the merge base. One of them, `b01534d0` (#471, merged 09-18), carries a `Co-authored-by` trailer with a non-ASCII name, which `scripts/check_commit_messages.py` rejects. That is history on `main`; this branch neither introduced it nor can rewrite it. Nothing in the ruleset makes that check blocking. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [ ] User-facing docs or screenshots are updated when needed ## Risk This branch is squash-only, so merging this PR flattens the merge commit and the merge base stays at `5a29ea22`. The contents line up either way, but git will not know `main` was taken in, and the next catch-up will re-raise the content conflicts in the two large i18n files. Landing it as a real merge commit instead would move the merge base and avoid that; that needs someone who can bypass the ruleset. Rollback is resetting the branch to `bc74bf73`; nothing here is a source change of its own beyond the four resolutions above. - [x] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes ## Related Issues N/A. Unblocks #475. --------- Co-authored-by: xfng-sd <xufang@shanda.com> Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com> Co-authored-by: KT <74288668+0xKT@users.noreply.github.com> Co-authored-by: Handsome-wzw <68996445+Handsome-wzw@users.noreply.github.com> Co-authored-by: Dizhan Xue <dizhan.xue@evermind.ai> Co-authored-by: Kevin Hu <kevinhu.sh@gmail.com> Co-authored-by: admin <admin@SH-HuKai.local> Co-authored-by: 江国庆/Forrest <mr.jianggq@163.com> Co-authored-by: 江国庆 <guoqingjiang@deepglint.com> Co-authored-by: Codex <noreply@openai.com> Co-authored-by: ypflll <ypflll@163.com> Co-authored-by: yao pengfei <yaopengfei@shanda.com> Co-authored-by: Zuyi Zhou <144661423+ZuyiZhou@users.noreply.github.com> Co-authored-by: Tong Li <litong02@shanda.com> Co-authored-by: litong <238663200+TongLi31@users.noreply.github.com> Co-authored-by: Tchen-data <176354753+Tchen-data@users.noreply.github.com> Co-authored-by: gloryfromca <23442919+gloryfromca@users.noreply.github.com> Co-authored-by: Dizhan Xue <xuedizhan17@mails.ucas.ac.cn>
… one .pptx delivered (#451) ## Summary The hand-built deck lane (Raven-Design at medium and high) and the deck engine lane (Raven-PPT at max) as one product, measured on live runs. - image_search for the deck lanes sits behind tools.web.search.images, off by default and switched on by the design launcher; the readiness probe for the deck route reads the target lane's own picture vendor; the build-interpreter shim has a .cmd twin for native Windows. - Deck route on Raven-Design: page furniture comes from the engine's helper modules (ppt_layout, ppt_theme, ppt_icons, ppt_shapes, ppt_charts) written beside the build script; diagrams, picture treatment and cover/section compositions are drawn by hand. Five recorded runs had each rewritten the same 48 helpers. - Deck route keeps no anti-pattern ledger, contract or task state: nine audited runs wrote the ledger 18 times and read it back never, and every real fix came from reading a render. The editorial skill is read alongside the deck skill; every page is read back from a render at 90 dpi or more before delivery. - Defaults before questions: language of the request, general audience, about 20 pages, light ground, memory first; ask at most once. Two of three ask_user calls in the audit timed out unanswered. - Formulas as pictures (matplotlib mathtext, dfrac promotion, serif scale) and inline sub/superscript runs, shared by both lanes; image_search for both lanes keyed by the selected search vendor; the raven-python interpreter shim (sh wrapper, not a symlink); all three tiers at 400 iterations. - layouts.md gains nine compositions measured off the packaged templates' reference pages; three rules ask for full components, a hierarchy among them, and the whole page used. - The max lane delivers the .pptx alone (D64); the PDF render stays the engine's own preview. - ppt-engine: template gates silenced on template pages, borrowed template files kept apart from borrowed page numbers, the icon pen follows the icon's side. ## Type - [x] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification ``` uv run --frozen pytest -q -x tests/test_agents_design_launcher.py tests/test_subagent_routing_backend.py tests/test_ppt_engine_build_tool.py tests/test_ppt_engine_build_stage.py tests/test_ppt_engine_assets_formulas.py tests/test_ppt_engine_gates_registry.py # 299 passed ``` Live runs on a test stack (medium tier, glm-5.3-flash, the eight-character request "make a deck introducing computer vision"): with the editorial skill read, 20 pages, 18 of them carrying a searched picture or a paper figure, delivered in 26 minutes with no question asked, no task-state call, no ledger, no hand-written helper, renders at 90 dpi. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [ ] User-facing docs or screenshots are updated when needed ## Risk User-visible: the max lane no longer delivers a PDF beside the deck; the design lane asks fewer questions; the host loop offers image_search only where tools.web.search.images is on. Rollback: revert the commits touching agents/raven-design, raven/agent and plugins-dist/ppt-engine/raven_ppt/stages/build.py; no data migration is involved. - [x] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes ## Related Issues N/A
…ads (#463) ## Summary `main` is red on three jobs (`python lint`, `unit 2/4`, `unit 3/4`), and has been since #451 merged. All of it is fallout from one arrival: `image_search` came with a second switch beside its credential. `tools.web.search.images` decides whether the tool is registered at all (`raven/agent/loop/wiring.py`), so a lane that never places a picture keeps the tool face it had. The capability table was not told. `is_configured` answers on the vendor key alone, so with a Serper key and the switch left off the table ticked a capability the agent does not hold, and the two tests that drive a real `AgentLoop` caught exactly the disagreement that module exists to prevent. The switch belongs on `is_disabled`, not `is_configured`. That function's own docstring already names the reason: a switched-off tool usually has its credential set, and calling it unconfigured sends the deployer to set a key that is already there. `tools.disabledTools` and this flag are the same kind of answer, so `is_offered` needs no change and the doctor row reads "off" rather than "missing a key". The test configs that mean "everything supplied" now turn the switch on, the way `raven/core/runtime.py` passes it from the config, and a new case pins the combination that was wrong: key present, pictures off, nothing offered, table saying off. Two more pieces of the same arrival: - `ImageSearchTool` copied `WebSearchTool`'s key resolution without its two attribute annotations, so the untyped lambda `wiring.py` hands it left the `api_key` property returning `~AlwaysFalsy | str` against a declared `str`. The type checker pinned in #416 reports it; the annotations are the fix. - `WebSearchConfig` gained the `images` field, so the writer's validated subtree now carries it and two `test_config_update_tools` expectations that pin the written section by value went stale. Not changed here: `get_web_search` still reports `{provider, api_key, max_results}` and does not surface `images`, though `set_web_search` can write it. That is a gap in the read side of the config API, not a CI failure, and it wants its own change. ## Type - [x] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification Run on Windows 11 in a clean worktree cut from `main` (`5a29ea22`): - `uv run pytest tests/test_tool_capabilities.py tests/test_config_update_tools.py -q`: 71 passed. All four tests failing on `main` now pass, plus the new case. - `uv run --frozen --python 3.12 --all-extras ty check raven evolver agents plugins-dist scripts`: the `web.py:516` diagnostic is gone. The diagnostics that remain locally are unresolved imports for optional packages absent from this machine's environment (`boxlite`, `nio`); CI reported exactly one diagnostic before this change, the one fixed here. - `uv run --frozen --python 3.12 --extra dev ruff check raven tests`: all checks passed. - `ruff format --check` on the four changed files: already formatted. - `uv run pytest tests/test_cli_doctor_commands.py tests/test_rpc_console.py -q`, which consume `is_disabled`: the failing-test set is byte-identical before and after this change (8 pre-existing Windows-only failures around file modes and an absent browser package, none of them in the set CI reports). ## Risk `is_disabled` gains a second reason to answer true, so a deployment with a search key and `tools.web.search.images` off now reads as "switched off" in `raven doctor` and the console capability report, where it previously read as offered. That is the state the loop was already in; only the description changes. Nothing about registration, gating, or the tool's runtime behaviour moves. The other two changes are an annotation and two test expectations, with no runtime effect. Rollback is reverting this commit; it touches nothing that other work builds on. ## Related Issues N/A --------- Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
…ked again (#467) ## Summary Two regressions in the hand-built deck lanes (medium and high on Raven-Design), and the stream failure that made every run of them a coin toss. **The deck lane draws its own pages again.** PR #451 pointed the hand-built lane at the engine's helper modules (`ppt_layout`, `ppt_theme`, `ppt_shapes`), which were written for the max lane's script backend. Their defaults became the deck: `heading()` put a white surface band bled across every page, `card()` became the way anything was placed, text frames were top-anchored with the lower third empty, and a build script named three colours. Measured on the same request, the accent colour appeared 8 times across 20 pages. The skill, route note and assets reference go back to the pre-#451 text: the lane draws with python-pptx and takes only the icon set, `add_formula` and `math_runs` from the engine. On the reverted lane the accent appears 54 times, the deck carries 12 real pictures and the layouts differ page to page. **Colour is named beside the type sizes.** The skill listed sizes for every role and said nothing about colour, so a lane with the right palette still drew in one colour. One paragraph now says what colour is for; the layouts note no longer reads as one accent per page, which a lane took as a ceiling. Where `image_search` is not offered, the fallback no longer tells the lane to give the pictures up: `web_search` for the page, `web_fetch` it, and download where the fetch backend keeps image links. **A stall in a silent think is asked again.** Across two measured runs the lane's turn failed 28 times on `Upstream idle timeout exceeded`, every time in the one round that writes the whole build script into a tool argument. `stream_llm_call` refuses to retry after output a watcher has seen, and counted reasoning deltas and half-built tool-call fragments as that output, though neither is ever shown as the reply. So the configured retry ladder was never reached. `rendered()` now asks what a watcher could have seen; every retry path resets the buffers first (a slot left standing merged with the next attempt into a call the model never made); a stall handed back as an error response carries the usage it spent. The in-process builtin backend, whose comment claimed a retry ladder and passed none, now receives the deployment's `llmErrorRetryDelays` and `llmRetryAfterOutput` through the SubagentManager. No packaged product takes that path; all five run as ACP agents on the loop's own call site. **Two bundled templates edited in place**, by the maintainer's word. `beige_geometric_general_report` loses its page 20, a dark photograph cut by a circle under pale rounded cards; 23 pages become 22 and the two reference pages the lane borrows from it (17, 19) keep their numbers. `black_circuit_tech_launch` loses the 27 percent circuit texture on its master and the photograph on its Section Header layout, so its body and section pages sit on the master's plain `#000000`; cover and closing are unchanged. `templates.manifest.json` is repinned; `fetch_templates.py --verify` holds all ten pins. The registry archive was not re-cut. No configuration default changes. The only behaviour every lane sees: a stream that fails before any reply text reached a watcher is retried on the configured ladder instead of failing the turn. ## Type - [x] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification ``` uv run --frozen pytest tests/test_agent_loop_llm_error_patience.py tests/test_agent_loop_stream.py \ tests/test_subagent_manager.py tests/test_subagent_routing_backend.py -q 265 passed in 6.85s (after rebase onto main) uv run --frozen pytest tests/test_litellm_provider_stream.py tests/test_litellm_provider_stream_end.py \ tests/test_provider_stream_fallback.py tests/test_providers_stream_idle_budget.py -q 102 passed uv run --frozen ruff check raven/agent/loop/main.py raven/agent/subagent/backends/raven_loop.py \ raven/agent/subagent/manager.py raven/providers/streaming.py All checks passed! grep -nP "[^\x00-\x7F]" agents/raven-design/route-raven-ppt.md -> no matches (the note is pinned ASCII) ``` Both new tests were checked against the unfixed code: `test_a_stall_during_a_silent_think_is_asked_again` fails with the old `emitted` test, and `test_what_the_failed_attempt_left_behind_is_dropped` fails with the buffer resets removed. The failure itself was reproduced outside the runtime: the same 37-message history, six pictures and tool table, sent through litellm 1.101.0 to the same vendor, succeeds on a short answer every time and fails mid-stream one time in three when asked to write the full build script; healthy long streams show a maximum inter-chunk gap of 1.9s over 234s, so the cut is a dropped connection, not a slow model. Decks built on the changed lane, same request as the #451 acceptance run (glm-5.3-flash via OpenRouter): medium 21 pages with 12 pictures and 7 text colours, 48 gate findings (4 `excessive_whitespace`, down from 18); high 13 pages with 13 pictures and 9 text colours, 37 findings. The high run's page count came from the host agent's forwarded brief, which stated 10-14 pages the user never asked for; that is a separate issue. Template edits: `tests/test_ppt_engine_templates.py tests/test_ppt_engine_default_templates.py tests/test_ppt_engine_template_bands.py tests/test_ppt_engine_template_theme.py tests/test_ppt_engine_measure_geometry.py` -> 152 passed, 1 skipped; `make check-large-files` -> clean; both templates rendered and read page by page. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [ ] User-facing docs or screenshots are updated when needed ## Risk - [ ] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes User-visible: on every lane, a streamed call that fails during reasoning or mid tool-call, with no reply text yet shown, waits out the configured ladder (default 15/30/60s) and asks again instead of ending the turn. A call that already streamed reply text behaves as before. Reasoning tokens of the abandoned attempt are spent again and are now recorded in usage. Rollback: revert the `providers` commit alone to restore the old failure; the skill text and the builtin-backend plumbing are independent of it. ## Related Issues N/A
Summary
The hand-built deck lane (Raven-Design at medium and high) and the deck engine lane (Raven-PPT at max) as one product, measured on live runs.
Type
Verification
Live runs on a test stack (medium tier, glm-5.3-flash, the eight-character request "make a deck introducing computer vision"): with the editorial skill read, 20 pages, 18 of them carrying a searched picture or a paper figure, delivered in 26 minutes with no question asked, no task-state call, no ledger, no hand-written helper, renders at 90 dpi.
Risk
User-visible: the max lane no longer delivers a PDF beside the deck; the design lane asks fewer questions; the host loop offers image_search only where tools.web.search.images is on. Rollback: revert the commits touching agents/raven-design, raven/agent and plugins-dist/ppt-engine/raven_ppt/stages/build.py; no data migration is involved.
Related Issues
N/A