Conversation
…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
|
|
||
| let expiresAt: string | null = null; | ||
| if (mode === 'queue' && options?.ttlSeconds != null) { | ||
| expiresAt = new Date(Date.now() + options.ttlSeconds * 1000).toISOString(); |
There was a problem hiding this comment.
WARNING: TTL timestamps are stored in a format that SQLite won't compare correctly
expires_at is written with toISOString() (2026-03-12T10:00:00.000Z), but the pending/expiry queries compare it to datetime('now') (2026-03-12 10:00:00). On the same day, the T vs space mismatch makes expired nudges still sort as future rows, so queued nudges can survive long past their TTL. Store the timestamp with the same SQLite format you query against, or compare via strftime(...)/unix epoch instead.
| WHERE ${agent_nudges.agent_bead_id} = ? | ||
| AND ${agent_nudges.source} = 'witness' | ||
| AND ${agent_nudges.message} LIKE '%GUPP_ESCALATION%' | ||
| AND ${agent_nudges.delivered_at} IS NULL |
There was a problem hiding this comment.
WARNING: Successful immediate nudges will be re-sent on every patrol tick
This dedupe check only looks for rows where delivered_at IS NULL, but both GUPP paths call queueNudge(..., { mode: 'immediate' }), which marks a successful send as delivered immediately. After the first successful nudge, the next 5s alarm tick won't find any matching row here and will enqueue/deliver the same GUPP escalation again. The same problem exists in the GUPP_CHECK query below.
| + '<div class="nudge-meta">source: ' + esc(n.source) + ' | mode: ' + esc(n.mode) + ' | priority: ' + esc(n.priority) + ' | ' + esc(n.created_at ?? '') + '</div>' | ||
| + '<div class="nudge-msg">' + esc(preview) + '</div>' | ||
| + '<div style="margin-top:4px">' | ||
| + '<button class="primary" style="font-size:11px;padding:2px 8px" onclick="deliverNudgeNow(\\'' + agentId + '\\', ' + JSON.stringify(n.message).replace(/</g, '\\\\u003c') + ')">Deliver Now</button>' |
There was a problem hiding this comment.
WARNING: This generates invalid HTML for the Deliver Now button
JSON.stringify(n.message) produces a raw double-quoted JS string, so the final markup looks like onclick="deliverNudgeNow('agent', "message")" and the attribute terminates early. As written, the button won't be reliably clickable. Put the message in a data-* attribute or escape it for HTML before interpolating it into the handler.
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)Issues found in unchanged code that cannot receive inline comments:
Files Reviewed (13 files)
Reviewed by gpt-5.4-20260305 · 1,368,071 tokens |
Summary
agent_nudgestable and TownDO nudge queue methods (queueNudge,getPendingNudges,acknowledgeNudge) for reliable message delivery to agentssession.idle, agents now check for pending nudges before exiting — if nudges are pending, they inject the next nudge as a follow-up prompt and stay alive ("idle-but-available" state)gt_nudgetool for inter-agent messaging withwait-idle,immediate, andqueuedelivery modesnudge()client method andhandleNudgeworker endpoint for the container→worker nudge pathsendMailwithqueueNudgein patrol functions for time-sensitive messages (GUPP warnings, rework requests, merge-ready notifications)Closes #1032
Verification
origin/maingt_nudgetool registrationVisual Changes
N/A (pending nudge counts on dashboard added but not visually verified)
Reviewer Notes
process-manager.tswheresession.idleno longer terminates non-mayor agents unconditionallyagent_nudgestable is in TownDO SQLite; ensure the schema migration runs on existing townspatrol.ts) now usequeueNudgeinstead ofsendMail— this changes the delivery semantics from "push and hope" to "queue and deliver on next idle"