@2en/clawly-plugins 1.22.2 → 1.22.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -274,14 +274,27 @@ describe('shouldSkipPushForMessage', () => {
|
|
|
274
274
|
expect(shouldSkipPushForMessage(' NO_REPLY ')).toBe('silent reply')
|
|
275
275
|
})
|
|
276
276
|
|
|
277
|
-
test('skips
|
|
277
|
+
test('skips heartbeat ack when HEARTBEAT_OK is the only content', () => {
|
|
278
278
|
expect(shouldSkipPushForMessage('HEARTBEAT_OK')).toBe('heartbeat ack')
|
|
279
|
-
expect(shouldSkipPushForMessage('
|
|
279
|
+
expect(shouldSkipPushForMessage('HEARTBEAT_OK.')).toBe('heartbeat ack')
|
|
280
|
+
expect(shouldSkipPushForMessage('HEARTBEAT_OK\n')).toBe('heartbeat ack')
|
|
280
281
|
})
|
|
281
282
|
|
|
282
|
-
test('does
|
|
283
|
-
|
|
284
|
-
expect(shouldSkipPushForMessage(
|
|
283
|
+
test('does NOT skip meaningful content ending with HEARTBEAT_OK', () => {
|
|
284
|
+
expect(shouldSkipPushForMessage('All good. HEARTBEAT_OK')).toBeNull()
|
|
285
|
+
expect(shouldSkipPushForMessage('Nothing to report. HEARTBEAT_OK。')).toBeNull()
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
test('does NOT skip verbose heartbeat response with content before HEARTBEAT_OK', () => {
|
|
289
|
+
const verbose =
|
|
290
|
+
'The user said hello recently. Looking at HEARTBEAT.md checklist: nothing needs attention. HEARTBEAT_OK'
|
|
291
|
+
expect(shouldSkipPushForMessage(verbose)).toBeNull()
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
test('does not skip message mentioning HEARTBEAT_OK mid-text', () => {
|
|
295
|
+
expect(
|
|
296
|
+
shouldSkipPushForMessage('HEARTBEAT_OK is a status code I output after each check.'),
|
|
297
|
+
).toBeNull()
|
|
285
298
|
})
|
|
286
299
|
|
|
287
300
|
test('skips system prompt leak', () => {
|
|
@@ -345,6 +358,29 @@ describe('offline-push with filtered messages', () => {
|
|
|
345
358
|
})
|
|
346
359
|
})
|
|
347
360
|
|
|
361
|
+
test('sends push for meaningful heartbeat response and strips HEARTBEAT_OK from body', async () => {
|
|
362
|
+
const {api, logs, handlers} = createMockApi()
|
|
363
|
+
registerOfflinePush(api)
|
|
364
|
+
|
|
365
|
+
await handlers.get('agent_end')!(
|
|
366
|
+
{
|
|
367
|
+
messages: [
|
|
368
|
+
{
|
|
369
|
+
role: 'assistant',
|
|
370
|
+
content: 'Hey! Just checking in — saw some interesting news today.\n\nHEARTBEAT_OK',
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
},
|
|
374
|
+
{sessionKey: 'agent:clawly:main'},
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
expect(logs).toContainEqual({
|
|
378
|
+
level: 'info',
|
|
379
|
+
msg: expect.stringContaining('notified (session=agent:clawly:main)'),
|
|
380
|
+
})
|
|
381
|
+
expect(lastPushOpts?.body).toBe('Hey! Just checking in — saw some interesting news today.')
|
|
382
|
+
})
|
|
383
|
+
|
|
348
384
|
test('sends push for normal message text', async () => {
|
|
349
385
|
const {api, logs, handlers} = createMockApi()
|
|
350
386
|
registerOfflinePush(api)
|
package/gateway/offline-push.ts
CHANGED
|
@@ -79,8 +79,11 @@ export function shouldSkipPushForMessage(text: string): string | null {
|
|
|
79
79
|
// Agent sentinel "nothing to say" — mobile hides as "silentReply"
|
|
80
80
|
if (trimmed === 'NO_REPLY') return 'silent reply'
|
|
81
81
|
|
|
82
|
-
//
|
|
83
|
-
if (
|
|
82
|
+
// Heartbeat acknowledgment (HEARTBEAT_OK as ending sentinel) — only skip if no substantial content before it
|
|
83
|
+
if (/HEARTBEAT_OK[\p{P}\s]*$/u.test(text)) {
|
|
84
|
+
const stripped = text.replace(/HEARTBEAT_OK[\p{P}\s]*$/u, '').trim()
|
|
85
|
+
if (stripped.length === 0) return 'heartbeat ack'
|
|
86
|
+
}
|
|
84
87
|
|
|
85
88
|
// Agent echoed system prompt metadata — mobile hides as "systemPromptLeak"
|
|
86
89
|
if (text.includes('Conversation info (untrusted metadata)')) return 'system prompt leak'
|
|
@@ -118,8 +121,9 @@ export function registerOfflinePush(api: PluginApi) {
|
|
|
118
121
|
return
|
|
119
122
|
}
|
|
120
123
|
|
|
121
|
-
const
|
|
122
|
-
const
|
|
124
|
+
const cleaned = fullText?.replace(/HEARTBEAT_OK[\p{P}\s]*$/u, '').trim() ?? null
|
|
125
|
+
const preview = cleaned && cleaned.length > 140 ? `${cleaned.slice(0, 140)}…` : cleaned
|
|
126
|
+
const body = preview || 'Your response is ready'
|
|
123
127
|
|
|
124
128
|
const sent = await sendPushNotification(
|
|
125
129
|
{
|