feat(tui): wire AI jobs to PluginBridge for prompt enhance & tags #104

Merged
claude-desktop merged 2 commits from tui/ai-wire-94 into main 2026-04-12 15:43:36 +00:00
Collaborator

Summary

  • Wire PluginBridge.enhance_prompt() and PluginBridge.generate_tags() to the TUI generate screen via async tokio tasks
  • Add AppAction::AiResult variant and Screen::handle_ai_result trait method to route AI job completions back to the active screen
  • Ctrl+E dispatches prompt enhancement, Ctrl+T dispatches tag generation (requires a preview image)
  • AiJobTracker guards against duplicate in-flight jobs; results apply to prompt fields via existing apply_prompt_enhance / apply_tag_generation helpers

Closes charles/loom#94

Test plan

  • cargo clippy -p loom-tui -- -D warnings clean
  • cargo test -p loom-tui passes (113 tests)
  • just qa passes (full workspace fmt + lint + test)
  • Manual: launch TUI with a running backend, type a prompt, press Ctrl+E — verify enhanced prompt replaces the field
  • Manual: generate an image (F5), then press Ctrl+T — verify tags are appended to prompt without duplicates
  • Manual: press Ctrl+E with empty prompt — verify warning notification
  • Manual: press Ctrl+T without preview — verify "no preview image" notification

🤖 Generated with Claude Code

## Summary - Wire `PluginBridge.enhance_prompt()` and `PluginBridge.generate_tags()` to the TUI generate screen via async tokio tasks - Add `AppAction::AiResult` variant and `Screen::handle_ai_result` trait method to route AI job completions back to the active screen - Ctrl+E dispatches prompt enhancement, Ctrl+T dispatches tag generation (requires a preview image) - `AiJobTracker` guards against duplicate in-flight jobs; results apply to prompt fields via existing `apply_prompt_enhance` / `apply_tag_generation` helpers Closes charles/loom#94 ## Test plan - [x] `cargo clippy -p loom-tui -- -D warnings` clean - [x] `cargo test -p loom-tui` passes (113 tests) - [x] `just qa` passes (full workspace fmt + lint + test) - [ ] Manual: launch TUI with a running backend, type a prompt, press Ctrl+E — verify enhanced prompt replaces the field - [ ] Manual: generate an image (F5), then press Ctrl+T — verify tags are appended to prompt without duplicates - [ ] Manual: press Ctrl+E with empty prompt — verify warning notification - [ ] Manual: press Ctrl+T without preview — verify "no preview image" notification 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add AiResult variant to AppAction and route completions to the current
screen via a new Screen::handle_ai_result trait method. The generate
screen handles Ctrl+E (prompt enhance) and Ctrl+T (tag generation) by
dispatching async jobs through PluginBridge and applying results back
to the prompt fields on completion.

- ai.rs: dispatch_prompt_enhance / dispatch_tag_generate spawn tokio
  tasks that call PluginBridge and send AiResult back via AppHandle
- generate.rs: Ctrl+E enhances the current prompt text, Ctrl+T reads
  the preview image as base64 and generates tags
- AiJobTracker guards against duplicate in-flight jobs per kind
- Hint row updated with C-E / C-T shortcuts

Closes charles/loom#94

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Collaborator

Review — PR #104: AI jobs wired to PluginBridge for prompt enhance & tags

Clean dispatch pattern. The AiResult enum + handle_ai_result trait method is a good design.

Concern: synchronous file read in dispatch_tags

dispatch_tags calls std::fs::read(path) on the main thread to load the preview image for base64 encoding. For a large image (e.g. 4K, ~10MB), this blocks the event loop noticeably. Consider spawning the read + encode into the same tokio::spawn as the bridge call:

tokio::spawn(async move {
    let bytes = tokio::fs::read(path).await?;
    let image_b64 = base64::encode(&bytes);
    bridge.generate_tags(...).await;
});

Nit

  • imagination: 0.5 is hardcoded in dispatch_prompt_enhance. Should this be configurable or derived from a setting?
  • prompt_style: "tags" is also hardcoded. The user might want prose-style enhancement. Consider reading from settings or the screen's mode.
  • notify_no_bridge is a free function taking &AppHandle — it works, but AppCtx::notify is the pattern everywhere else. Minor inconsistency.
## Review — PR #104: AI jobs wired to PluginBridge for prompt enhance & tags **Clean dispatch pattern.** The `AiResult` enum + `handle_ai_result` trait method is a good design. ### Concern: synchronous file read in `dispatch_tags` `dispatch_tags` calls `std::fs::read(path)` on the main thread to load the preview image for base64 encoding. For a large image (e.g. 4K, ~10MB), this blocks the event loop noticeably. Consider spawning the read + encode into the same `tokio::spawn` as the bridge call: ```rust tokio::spawn(async move { let bytes = tokio::fs::read(path).await?; let image_b64 = base64::encode(&bytes); bridge.generate_tags(...).await; }); ``` ### Nit - `imagination: 0.5` is hardcoded in `dispatch_prompt_enhance`. Should this be configurable or derived from a setting? - `prompt_style: "tags"` is also hardcoded. The user might want prose-style enhancement. Consider reading from settings or the screen's mode. - `notify_no_bridge` is a free function taking `&AppHandle` — it works, but `AppCtx::notify` is the pattern everywhere else. Minor inconsistency.
charles force-pushed tui/ai-wire-94 from 00059bd1ab to a68faa4ef3 2026-04-12 14:47:30 +00:00 Compare
claude-desktop changed target branch from tui/image-ctx-85 to main 2026-04-12 15:36:29 +00:00
charles force-pushed tui/ai-wire-94 from a68faa4ef3 to b0b75c3e41
All checks were successful
QA / qa (pull_request) Successful in 27m18s
2026-04-12 15:42:51 +00:00
Compare
claude-desktop deleted branch tui/ai-wire-94 2026-04-12 15:43:37 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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
charles/loom!104
No description provided.