feat(gastown): add cloud-native nudge system for reliable agent message delivery#1079
feat(gastown): add cloud-native nudge system for reliable agent message delivery#1079
Conversation
Code Review SummaryStatus: 3 Issues Found | Recommendation: Address before merge Fix these issues in Kilo Cloud Overview
Issue Details (click to expand)WARNING
Other Observations (not in diff)N/A Files Reviewed (13 files)
Reviewed by gpt-5.4-20260305 · 1,084,093 tokens |
…ge delivery Replaces fire-and-hope mail push with a nudge queue that guarantees delivery. Adds agent_nudges table and TownDO nudge queue methods (queueNudge, getPendingNudges, acknowledgeNudge). Non-mayor agents enter idle-but-available state on session.idle instead of exiting, checking for pending nudges before terminating. Adds gt_nudge tool for inter-agent messaging, nudge() client method, and handleNudge worker endpoint. Patrol functions use queueNudge instead of sendMail for time-sensitive messages. Dashboard shows pending nudge counts. Closes #1032
71682e5 to
2193c27
Compare
| ); | ||
| const townId = c.get('townId'); | ||
| const town = getTownDOStub(c.env, townId); | ||
| const nudgeId = await town.queueNudge(parsed.data.target_agent_id, parsed.data.message, { |
There was a problem hiding this comment.
WARNING: Cross-rig nudge targeting is not blocked
handleNudge() forwards target_agent_id straight to queueNudge() without checking that the target agent exists in params.rigId. Auth only proves the caller belongs to the source rig, so an agent in rig A can hit /rigs/A/nudge and inject a message into an agent from rig B in the same town. Please load the target agent first and reject the request unless its rig_id matches the route.
| } | ||
| const townId = c.get('townId'); | ||
| const town = getTownDOStub(c.env, townId); | ||
| await town.markNudgeDelivered(parsed.data.nudge_id); |
There was a problem hiding this comment.
WARNING: Any agent can acknowledge another agent's queued nudge
This marks the row delivered by nudge_id alone and ignores params.agentId. An authenticated agent can call its own /agents/:agentId/nudge-delivered route with someone else's nudge_id, which removes that other agent's pending nudge before it is ever injected. Verify that the nudge belongs to params.agentId (and ideally the same rig) before updating it.
Summary
wait-idle(delivers at next idle moment),immediate(pushes directly via container), andqueue(with TTL expiry).agent_nudgesSQLite table in TownDO, HTTP endpoints for queueing/fetching/marking nudges, client methods for both polecat and mayor agents,gt_nudgetool for both agent types, and dashboard UI for sending/inspecting nudges.session.idleevents before deciding to exit, with a configurable idle timeout (default 2 min).Closes #1032
Verification
Visual Changes
N/A
Reviewer Notes
handleNudgeDeliveredinrig-agents.handler.tsuses_paramsto silence an unused-variable lint warning rather than using therigId/agentIdfor authorization. Thenudge_idis a UUID so the practical risk is low, but a future improvement could verify the nudge belongs to the requesting agent.sendNudge()function sends asource_agent_idfield in the request body that the API schema silently strips — the actual source is derived from the JWT. Cosmetic only.process-manager.tswheresession.idleno longer terminates non-mayor agents unconditionally. Agents now stay alive checking for nudges, consuming container resources longer — monitor container memory in production.