|
Hey this is Isaac, This week I was fixing some basic and classic async problems: a "processing" pill that never updated to "complete." Blech. The goal is to prevent long-running tasks from freezing the user interface. If something takes a second, it’s fine to expect the user to stay on the page until it completes. But if it takes 5 minutes? Users will want to be able to do other things while it’s processing. So we have background tasks that run independently of the UI the user sees. But the user will still expect to see updates and watch the job though! For a project I am working on, Devrelifier, the updates were not working for this processing pipeline:
For a 90-minute video, that can take quite a while! I needed a clean and simple way to update the UI after a background job finished.. The Build: Choosing Simplicity Over InfrastructureThe user clicks “Generate” to start background jobs that generate content. It can take a while, especially if it’s processing a long video, and the user may want to navigate to other pages or wait and watch the job in the UI until it completes. Once the background job is running, there are two main options to deliver updates to the UI:
I chose simplicity of logic. A 1-second delay in the UI updating for a long-running background task is inconsequential for what I was doing. For many things, like a chat application, the real-time updates SSE gives are really important. SSE requires managing active connections, which is typically implemented using something like the HTMX SSE extension. The extension allows you to keep code very light, but I think regular HTTP requests with fewer dependencies make for easier testing, debugging, and maintenance. The Learn: The "Self-Polling Pill"Here’s the pattern I used. It's a self-contained component that polls every second and then stops itself. Here’s how it works:
The Refactor: From 4x Duplication to 1 ConfigThe self-polling pill worked quite well, but after a while I realized that I had almost the same logic in 4 places! blog_actions, newsletter_actions, twitter_actions, and linkedin_actions. The old way: Each content type had its own duplicated logic for the "Generate" button and the completion button ("Edit" vs. "View"). This logic was mirrored in the main view and in the status endpoint. It was a headache-in-waiting. The new way: I refactored all of it into a single, config-driven helper: build_content_actions(project, task_type). This function uses a small config dictionary that maps a task_type (like "blog") to:
This simple refactor replaced about 100 lines of duplicated code. More importantly, adding a new content type is much easier (and I plan on adding many more!) Until next week, Isaac |
Every post comes from something I've done on a real project. AI tools, development approaches, how I actually build things. You're getting a curation of my taste, not takes on stuff I don't use. Subscribers also get extras: things that went wrong, how my thinking about AI is changing, hacky workflows I use every day, and the occasional personal update. Stuff I share with subscribers because it's a little too personal or unpolished to blast across the internet.
Today's post is about a project that I will take concepts from to improve my own work. So I studied the OSS prototype of it to understand how it works. Point and Talk: How Clicky’s AI Interface Works Clicky is an AI buddy made by Farza that lives on your Mac. You press a key, talk, and a glowing blue triangle flies across your screen, points at whatever you asked about, and talks you through the answer. Most apps with an agent should have something like this. Point and talk is closer to how...
Last week I shared my knowledge base tool, agentkb. This week I am OSSing my pi harness that uses it, Harpy. The most interesting part of the harness is that knowledge base <-> harness integration so that's what this week post dives into. It covers what RLM is, how it drives a python loop with state, how Pi (typscript) extension talks to python, and how that allows for smart delegation and fan-out to smaller models to give more accurate search results. How My RLM Tool Works An LLM writes...
Hey, This was a week of context switching 😅. Product release weeks are always odd. The goal is super specific, and yet the work is scattered small tasks (testing, polish, docs, marketing copy, etc.). We shipped the stoa beta, and I kept wishing my agents could remember more. That's why I'm open sourcing `agentkb`, my work-in-progress knowledge base framework today. The Pi harness built around it will be open sourced next. AgentKB: A Local Knowledge Base for Agents My agent should learn from...