This commit is contained in:
2026-02-21 15:02:10 -05:00
parent 4b4c4d96ad
commit 47c581d037
6 changed files with 457 additions and 68 deletions

View File

@@ -1,4 +1,4 @@
**manual_slop** is a local GUI tool for manually curating and sending context to AI APIs. It aggregates files, screenshots, and discussion history into a structured markdown file and sends it to a chosen AI provider with a user-written message.
**manual_slop** is a local GUI tool for manually curating and sending context to AI APIs. It aggregates files, screenshots, and discussion history into a structured markdown file and sends it to a chosen AI provider with a user-written message. The AI can also execute PowerShell scripts within the project directory, with user confirmation required before each execution.
**Stack:**
- `dearpygui` - GUI with docking/floating/resizable panels
@@ -8,9 +8,10 @@
- `uv` - package/env management
**Files:**
- `gui.py` - main GUI, `App` class, all panels, all callbacks
- `ai_client.py` - unified provider wrapper, model listing, session management, send
- `aggregate.py` - reads config, collects files/screenshots/discussion, writes numbered `.md` files to `output_dir/md_gen/`
- `gui.py` - main GUI, `App` class, all panels, all callbacks, confirmation dialog
- `ai_client.py` - unified provider wrapper, model listing, session management, send, tool/function-call loop
- `aggregate.py` - reads config, collects files/screenshots/discussion, writes numbered `.md` files to `output_dir`
- `shell_runner.py` - subprocess wrapper that runs PowerShell scripts sandboxed to `base_dir`, returns stdout/stderr/exit code as a string
- `config.toml` - namespace, output_dir, files paths+base_dir, screenshots paths+base_dir, discussion history array, ai provider+model
- `credentials.toml` - gemini api_key, anthropic api_key
@@ -22,21 +23,41 @@
- **Provider** - provider combo (gemini/anthropic), model listbox populated from API, fetch models button, status line
- **Message** - multiline input, Gen+Send button, MD Only button, Reset session button
- **Response** - readonly multiline displaying last AI response
- **Tool Calls** - scrollable log of every PowerShell tool call the AI made, showing script and result; Clear button
**AI Tool Use (PowerShell):**
- Both Gemini and Anthropic are configured with a `run_powershell` tool/function declaration
- When the AI wants to edit or create files it emits a tool call with a `script` string
- `ai_client` runs a loop (max `MAX_TOOL_ROUNDS = 5`) feeding tool results back until the AI stops calling tools
- Before any script runs, `gui.py` shows a modal `ConfirmDialog` on the main thread; the background send thread blocks on a `threading.Event` until the user clicks Approve or Reject
- The dialog displays `base_dir`, shows the script in an editable text box (allowing last-second tweaks), and has Approve & Run / Reject buttons
- On approval the (possibly edited) script is passed to `shell_runner.run_powershell()` which prepends `Set-Location -LiteralPath '<base_dir>'` and runs it via `powershell -NoProfile -NonInteractive -Command`
- stdout, stderr, and exit code are returned to the AI as the tool result
- Rejections return `"USER REJECTED: command was not executed"` to the AI
- All tool calls (script + result/rejection) are appended to `_tool_log` and displayed in the Tool Calls panel
**Data flow:**
1. GUI edits are held in `App` state lists (`self.files`, `self.screenshots`, `self.history`) and dpg widget values
2. `_flush_to_config()` pulls all widget values into `self.config` dict
3. `_do_generate()` calls `_flush_to_config()`, saves `config.toml`, calls `aggregate.run(config)` which writes the md and returns `(markdown_str, path)`
4. `cb_generate_send()` calls `_do_generate()` then threads a call to `ai_client.send(md, message)`
4. `cb_generate_send()` calls `_do_generate()` then threads a call to `ai_client.send(md, message, base_dir)`
5. `ai_client.send()` prepends the md as a `<context>` block to the user message and sends via the active provider chat session
6. Sessions are stateful within a run (chat history maintained), `Reset` clears them
6. If the AI responds with tool calls, the loop handles them (with GUI confirmation) before returning the final text response
7. Sessions are stateful within a run (chat history maintained), `Reset` clears them and the tool log
**Config persistence:**
- Every send and save writes `config.toml` with current state including selected provider and model under `[ai]`
- Discussion history is stored as a TOML array of strings in `[discussion] history`
- File and screenshot paths are stored as TOML arrays, support absolute paths, relative paths from base_dir, and `**/*` wildcards
**Threading model:**
- DPG render loop runs on the main thread
- AI sends and model fetches run on daemon background threads
- `_pending_dialog` (guarded by a `threading.Lock`) is set by the background thread and consumed by the render loop each frame, calling `dialog.show()` on the main thread
- `dialog.wait()` blocks the background thread on a `threading.Event` until the user acts
**Known extension points:**
- Add more providers by adding a section to `credentials.toml`, a `_list_*` and `_send_*` function in `ai_client.py`, and the provider name to the `PROVIDERS` list in `gui.py`
- System prompt support could be added as a field in `config.toml` and passed in `ai_client.send()`
- Discussion history excerpts could be individually toggleable for inclusion in the generated md
- `MAX_TOOL_ROUNDS` in `ai_client.py` caps agentic loops at 5 rounds; adjustable