feat(server): wire slide.setImageModel + revertToLastGenerated + resolveContext + bg.extractTheme #53

Merged
mik-tf merged 1 commit from development_mik into development 2026-05-10 12:47:31 +00:00
Owner

Bucket B of #51 — 4 of 15 undispatched OpenRPC methods. Sibling of PR #52 (bucket A — wizard.* + deckjobs.*).

Summary

Adds 4 dispatch arms in crates/hero_slides_server/src/rpc.rs plus the backing handler functions. Each method is advertised in openrpc.json but had no match arm, so calls returned -32000 "Method not found".

Method Backing lib Notes
slide.setImageModel hero_slides_lib::slide_set_image_model Per-slide image-model override; empty/missing model clears the override and reverts to deck default. JS dashboard's pro-toggle (onSlideImageModelChange, dashboard.js:2352) was hitting -32000.
slide.revertToLastGenerated composes slide_list_versions + slide_restore_version + slide_get_content Mirrors the existing Rhai binding at hero_slides_rhai/src/slide_module.rs:421. Returns {restored_version, content}.
slide.resolveContext hero_slides_lib::resolve_context Returns entries with byte_count instead of raw bytes (Vec would bloat the wire by megabytes per resolve). Maps ResolvedContext → JSON manually since ResolvedContextEntry isn't Serialize. Includes the deterministic fingerprint.
bg.extractTheme extract_theme_from_image / extract_theme_from_pdf Three input shapes — {data, mime_type} (browser upload), {folder, file} (under <deck>/content/background/<folder>/<file>), or {file} (root-level) — auto-detects PDF vs image by mime / extension, runs through ai_util::ai_client() (uses OPENROUTER_API_KEY from hero_proc secrets), and persists the result to theme.md via deck_save_theme.

Verification

  • cargo check -p hero_slides_server clean (no new warnings — 11 pre-existing warnings are bucket-C param_* helpers from PR #50).
  • Combined with PR #52, scripts/smoke_openrpc.py METHOD_MISSING expected to drop from 15 → 5 (only bucket C left: slide.setLink, slide.clearLink, slide.getStaleness, deck.staleness, folder.pick).
  • Hero Browser MCP smoke (post-merge): the per-slide "Pro" toggle on the slide editor (uses slide.setImageModel) stops failing silently.

Why these 4, not all 5 originally in bucket B

The original sizing folded slide.clearLink into bucket B because the lib helper exists (deck_slide_link_clear returns Ok(())). On second read, that helper is a no-op stub — wiring it up would let the dispatcher succeed but nothing would actually clear, hiding the missing implementation. Since slide.setLink is also a stub (Err("slide linking not yet implemented")) and the two methods are paired, both move to the bucket-C follow-up issue together with the link-persistence design call.

Out of scope

Bucket C (5 methods, all blocked on missing lib code or a missing crate dep) — fresh issue at session end.

Signed-off-by: mik-tf

Bucket B of https://forge.ourworld.tf/lhumina_code/hero_slides/issues/51 — 4 of 15 undispatched OpenRPC methods. Sibling of [PR #52](https://forge.ourworld.tf/lhumina_code/hero_slides/pulls/52) (bucket A — wizard.* + deckjobs.*). ## Summary Adds 4 dispatch arms in `crates/hero_slides_server/src/rpc.rs` plus the backing handler functions. Each method is advertised in `openrpc.json` but had no `match` arm, so calls returned `-32000 "Method not found"`. | Method | Backing lib | Notes | |---|---|---| | `slide.setImageModel` | `hero_slides_lib::slide_set_image_model` | Per-slide image-model override; empty/missing `model` clears the override and reverts to deck default. JS dashboard's pro-toggle (`onSlideImageModelChange`, `dashboard.js:2352`) was hitting -32000. | | `slide.revertToLastGenerated` | composes `slide_list_versions` + `slide_restore_version` + `slide_get_content` | Mirrors the existing Rhai binding at `hero_slides_rhai/src/slide_module.rs:421`. Returns `{restored_version, content}`. | | `slide.resolveContext` | `hero_slides_lib::resolve_context` | Returns entries with `byte_count` instead of raw `bytes` (Vec<u8> would bloat the wire by megabytes per resolve). Maps `ResolvedContext` → JSON manually since `ResolvedContextEntry` isn't `Serialize`. Includes the deterministic `fingerprint`. | | `bg.extractTheme` | `extract_theme_from_image` / `extract_theme_from_pdf` | Three input shapes — `{data, mime_type}` (browser upload), `{folder, file}` (under `<deck>/content/background/<folder>/<file>`), or `{file}` (root-level) — auto-detects PDF vs image by mime / extension, runs through `ai_util::ai_client()` (uses `OPENROUTER_API_KEY` from hero_proc secrets), and persists the result to `theme.md` via `deck_save_theme`. | ## Verification - `cargo check -p hero_slides_server` clean (no new warnings — 11 pre-existing warnings are bucket-C `param_*` helpers from PR #50). - Combined with [PR #52](https://forge.ourworld.tf/lhumina_code/hero_slides/pulls/52), `scripts/smoke_openrpc.py` METHOD_MISSING expected to drop from 15 → 5 (only bucket C left: `slide.setLink`, `slide.clearLink`, `slide.getStaleness`, `deck.staleness`, `folder.pick`). - Hero Browser MCP smoke (post-merge): the per-slide "Pro" toggle on the slide editor (uses `slide.setImageModel`) stops failing silently. ## Why these 4, not all 5 originally in bucket B The original sizing folded `slide.clearLink` into bucket B because the lib helper exists (`deck_slide_link_clear` returns `Ok(())`). On second read, that helper is a no-op stub — wiring it up would let the dispatcher succeed but nothing would actually clear, hiding the missing implementation. Since `slide.setLink` is also a stub (`Err("slide linking not yet implemented")`) and the two methods are paired, both move to the bucket-C follow-up issue together with the link-persistence design call. ## Out of scope Bucket C (5 methods, all blocked on missing lib code or a missing crate dep) — fresh issue at session end. Signed-off-by: mik-tf
feat(server): wire slide.setImageModel + revertToLastGenerated + resolveContext + bg.extractTheme
Some checks failed
Test / test (push) Failing after 30s
Test / test (pull_request) Failing after 25s
42dd31dcc6
Adds 4 dispatch arms in `crates/hero_slides_server/src/rpc.rs` and the
backing handler functions. Each method is advertised in `openrpc.json`
but had no `match` arm, so calls returned -32000 "Method not found".

| Method | Handler | Notes |
|---|---|---|
| `slide.setImageModel` | `slide_set_image_model()` | Per-slide image-model override; empty/missing model clears it back to deck default. JS dashboard's pro-toggle (`onSlideImageModelChange`, dashboard.js:2352) was hitting -32000. |
| `slide.revertToLastGenerated` | composes `slide_list_versions` + `slide_restore_version` + `slide_get_content` | Mirrors the existing Rhai binding at hero_slides_rhai/src/slide_module.rs:421. |
| `slide.resolveContext` | `resolve_context()` | Returns entries with `byte_count` instead of raw `bytes` (Vec<u8> would bloat the wire by megabytes per resolve). Maps `ResolvedContext` → JSON manually since the entry type isn't `Serialize`. |
| `bg.extractTheme` | `extract_theme_from_image()` / `extract_theme_from_pdf()` | Three input shapes — `{data, mime_type}` (browser upload), `{folder, file}`, or `{file}` — auto-detects PDF vs image by mime, runs through `ai_util::ai_client()`, persists result to `theme.md`. |

Bucket B of #51
(4 of 15 undispatched methods). Bucket A (wizard.* + deckjobs.*) landed
in PR #52 (commit 1c4391e). Bucket C (slide.setLink / slide.clearLink /
slide.getStaleness / deck.staleness / folder.pick — all blocked on
missing lib code or a missing crate dep) gets a fresh issue at session
end.

Verified `cargo check -p hero_slides_server` clean (no new warnings —
the 11 pre-existing warnings are bucket-C param helpers from PR #50).

Signed-off-by: mik-tf
mik-tf merged commit c8979388f5 into development 2026-05-10 12:47:31 +00:00
mik-tf deleted branch development_mik 2026-05-10 12:47:32 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_slides!53
No description provided.