5.0 KiB
5.0 KiB
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 panelsgoogle-genai- Gemini APIanthropic- Anthropic APItomli-w- TOML writinguv- package/env management
Files:
gui.py- main GUI,Appclass, all panels, all callbacks, confirmation dialogai_client.py- unified provider wrapper, model listing, session management, send, tool/function-call loopaggregate.py- reads config, collects files/screenshots/discussion, writes numbered.mdfiles tooutput_dirshell_runner.py- subprocess wrapper that runs PowerShell scripts sandboxed tobase_dir, returns stdout/stderr/exit code as a stringconfig.toml- namespace, output_dir, files paths+base_dir, screenshots paths+base_dir, discussion history array, ai provider+modelcredentials.toml- gemini api_key, anthropic api_key
GUI Panels:
- Config - namespace, output dir, save
- Files - base_dir, scrollable path list with remove, add file(s), add wildcard
- Screenshots - base_dir, scrollable path list with remove, add screenshot(s)
- Discussion History - multiline text box,
---as separator between excerpts, save splits on---back into toml array - 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_powershelltool/function declaration - When the AI wants to edit or create files it emits a tool call with a
scriptstring ai_clientruns a loop (maxMAX_TOOL_ROUNDS = 5) feeding tool results back until the AI stops calling tools- Before any script runs,
gui.pyshows a modalConfirmDialogon the main thread; the background send thread blocks on athreading.Eventuntil 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 prependsSet-Location -LiteralPath '<base_dir>'and runs it viapowershell -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_logand displayed in the Tool Calls panel
Data flow:
- GUI edits are held in
Appstate lists (self.files,self.screenshots,self.history) and dpg widget values _flush_to_config()pulls all widget values intoself.configdict_do_generate()calls_flush_to_config(), savesconfig.toml, callsaggregate.run(config)which writes the md and returns(markdown_str, path)cb_generate_send()calls_do_generate()then threads a call toai_client.send(md, message, base_dir)ai_client.send()prepends the md as a<context>block to the user message and sends via the active provider chat session- If the AI responds with tool calls, the loop handles them (with GUI confirmation) before returning the final text response
- Sessions are stateful within a run (chat history maintained),
Resetclears them and the tool log
Config persistence:
- Every send and save writes
config.tomlwith 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 athreading.Lock) is set by the background thread and consumed by the render loop each frame, callingdialog.show()on the main threaddialog.wait()blocks the background thread on athreading.Eventuntil the user acts
Known extension points:
- Add more providers by adding a section to
credentials.toml, a_list_*and_send_*function inai_client.py, and the provider name to thePROVIDERSlist ingui.py - System prompt support could be added as a field in
config.tomland passed inai_client.send() - Discussion history excerpts could be individually toggleable for inclusion in the generated md
MAX_TOOL_ROUNDSinai_client.pycaps agentic loops at 5 rounds; adjustable