Skip to content

Commit 3340e3d

Browse files
committed
fix: prevent Paperclip heartbeat spam, stable thread per task
Root cause: deployed agents had no runtimeConfig, so Paperclip's default heartbeat scheduler could fire repeatedly. Each heartbeat created a new AF thread (using runId), causing thread spam. Fixes: - Deploy now sets runtimeConfig.heartbeat.intervalSec=0 (on-demand only, no automatic timer). Configurable via --heartbeat-interval. - Paperclip connector uses issueId as threadId (not runId), so repeated triggers for the same task reuse the same AF conversation thread, preserving context instead of creating duplicates. - Added --heartbeat-interval flag to `af paperclip deploy` Verified by sub-agent: 2 triggers for same issue → same thread_id, 2 comments (not 50), conversation continuity preserved.
1 parent 79c488f commit 3340e3d

File tree

2 files changed

+12
-1
lines changed

2 files changed

+12
-1
lines changed

packages/cli/src/cli/gateway/connectors/paperclip.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,16 @@ export class PaperclipConnector implements ChannelConnector {
6161

6262
if (parts.length === 0) parts.push("Heartbeat triggered. Check your inbox for work.");
6363

64+
// Use issueId as threadId so repeated heartbeats for the same task
65+
// reuse the same AF conversation thread (continuity, not duplication)
6466
const uuidRe = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
67+
const stableThreadId = issueId && uuidRe.test(issueId) ? issueId : undefined;
6568

6669
return {
6770
afAgentId,
6871
afStreamUrl,
6972
message: parts.join("\n"),
70-
threadId: uuidRe.test(payload.runId) ? payload.runId : undefined,
73+
threadId: stableThreadId,
7174
label: (ctx.taskKey as string) ?? issueId ?? "heartbeat",
7275
replyContext: { issueId, agentId: payload.agentId },
7376
};

packages/cli/src/cli/main.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4336,6 +4336,7 @@ export function createProgram(): Command {
43364336
.option("--company-name <name>", "Create a new Paperclip company with this name")
43374337
.option("--role <role>", "Paperclip agent role", "general")
43384338
.option("--budget <cents>", "Monthly budget in cents", "0")
4339+
.option("--heartbeat-interval <seconds>", "Auto-heartbeat interval in seconds (0 = on-demand only)", "0")
43394340
.option("--reports-to <id>", "Paperclip agent ID this agent reports to")
43404341
.action(async (opts) => {
43414342
const client = buildClient(program.opts());
@@ -4416,6 +4417,13 @@ export function createProgram(): Command {
44164417
messages: [{ content: "Execute your assigned task.", role: "user" }],
44174418
},
44184419
},
4420+
runtimeConfig: {
4421+
heartbeat: {
4422+
enabled: true,
4423+
intervalSec: Number.parseInt(opts.heartbeatInterval as string, 10) || 0,
4424+
wakeOnDemand: true,
4425+
},
4426+
},
44194427
budgetMonthlyCents: Number.parseInt(opts.budget, 10) || 0,
44204428
reportsTo: opts.reportsTo,
44214429
metadata,

0 commit comments

Comments
 (0)