@rubytech/taskmaster 1.16.3 → 1.17.0
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.
- package/dist/agents/tools/logs-read-tool.js +9 -0
- package/dist/agents/tools/memory-tool.js +1 -0
- package/dist/auto-reply/group-activation.js +2 -0
- package/dist/auto-reply/reply/commands-session.js +28 -11
- package/dist/build-info.json +3 -3
- package/dist/config/group-policy.js +16 -0
- package/dist/config/zod-schema.providers-whatsapp.js +2 -0
- package/dist/control-ui/assets/{index-Bd75cI7J.js → index-Beuhzjy_.js} +525 -492
- package/dist/control-ui/assets/index-Beuhzjy_.js.map +1 -0
- package/dist/control-ui/assets/index-XqRo9tNW.css +1 -0
- package/dist/control-ui/index.html +2 -2
- package/dist/cron/preloaded.js +27 -23
- package/dist/gateway/protocol/index.js +7 -2
- package/dist/gateway/protocol/schema/logs-chat.js +6 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +6 -0
- package/dist/gateway/protocol/schema/sessions-transcript.js +1 -0
- package/dist/gateway/protocol/schema/sessions.js +6 -1
- package/dist/gateway/protocol/schema/whatsapp.js +24 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/public-chat/session-token.js +52 -0
- package/dist/gateway/public-chat-api.js +40 -13
- package/dist/gateway/server-methods/logs.js +17 -1
- package/dist/gateway/server-methods/public-chat.js +5 -0
- package/dist/gateway/server-methods/sessions-transcript.js +30 -6
- package/dist/gateway/server-methods/whatsapp-conversations.js +387 -0
- package/dist/gateway/server-methods-list.js +6 -0
- package/dist/gateway/server-methods.js +7 -0
- package/dist/gateway/server.impl.js +3 -1
- package/dist/gateway/sessions-patch.js +1 -1
- package/dist/hooks/bundled/ride-dispatch/HOOK.md +7 -6
- package/dist/hooks/bundled/ride-dispatch/handler.js +75 -30
- package/dist/memory/manager.js +3 -3
- package/dist/tui/tui-command-handlers.js +1 -1
- package/dist/web/auto-reply/monitor/group-activation.js +12 -10
- package/dist/web/auto-reply/monitor/group-gating.js +23 -2
- package/dist/web/auto-reply/monitor/on-message.js +27 -5
- package/dist/web/auto-reply/monitor/process-message.js +64 -53
- package/dist/web/inbound/monitor.js +30 -0
- package/extensions/whatsapp/src/channel.ts +1 -1
- package/package.json +1 -1
- package/skills/log-review/SKILL.md +17 -4
- package/skills/log-review/references/review-protocol.md +4 -4
- package/taskmaster-docs/USER-GUIDE.md +14 -0
- package/dist/control-ui/assets/index-Bd75cI7J.js.map +0 -1
- package/dist/control-ui/assets/index-BkymP95Y.css +0 -1
|
@@ -182,10 +182,10 @@ export async function processMessage(params) {
|
|
|
182
182
|
// ── End opening hours gate ──────────────────────────────────────────
|
|
183
183
|
// Send ack reaction immediately upon message receipt (post-gating).
|
|
184
184
|
// Suppress when running silently on un-mentioned group messages.
|
|
185
|
-
if (params.
|
|
185
|
+
if (params.contextOnly) {
|
|
186
186
|
shouldClearGroupHistory = false;
|
|
187
187
|
}
|
|
188
|
-
if (!params.
|
|
188
|
+
if (!params.contextOnly)
|
|
189
189
|
maybeSendAckReaction({
|
|
190
190
|
cfg: params.cfg,
|
|
191
191
|
msg: params.msg,
|
|
@@ -315,6 +315,21 @@ export async function processMessage(params) {
|
|
|
315
315
|
}, "failed updating session meta");
|
|
316
316
|
});
|
|
317
317
|
trackBackgroundTask(params.backgroundTasks, metaTask);
|
|
318
|
+
// contextOnly mode: accumulate user message in transcript but skip LLM.
|
|
319
|
+
// This prevents phantom assistant messages that corrupt conversation history.
|
|
320
|
+
if (params.contextOnly) {
|
|
321
|
+
// Store user message in transcript so context accumulates for the next mentioned reply
|
|
322
|
+
void appendUserMessageToSessionTranscript({
|
|
323
|
+
agentId: params.route.agentId,
|
|
324
|
+
sessionKey: params.route.sessionKey,
|
|
325
|
+
text: combinedBody,
|
|
326
|
+
storePath,
|
|
327
|
+
}).catch((err) => {
|
|
328
|
+
params.replyLogger.warn({ error: formatError(err) }, "contextOnly: failed to store user turn");
|
|
329
|
+
});
|
|
330
|
+
params.replyLogger.info({ correlationId, from: fromDisplay }, "context-only mode: user message stored, LLM skipped");
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
318
333
|
const { queuedFinal } = await dispatchReplyWithBufferedBlockDispatcher({
|
|
319
334
|
ctx: ctxPayload,
|
|
320
335
|
cfg: params.cfg,
|
|
@@ -328,60 +343,56 @@ export async function processMessage(params) {
|
|
|
328
343
|
logVerbose("Stripped stray HEARTBEAT_OK token from web reply");
|
|
329
344
|
}
|
|
330
345
|
},
|
|
331
|
-
deliver:
|
|
332
|
-
|
|
333
|
-
|
|
346
|
+
deliver: async (payload, info) => {
|
|
347
|
+
await deliverWebReply({
|
|
348
|
+
replyResult: payload,
|
|
349
|
+
msg: params.msg,
|
|
350
|
+
maxMediaBytes: params.maxMediaBytes,
|
|
351
|
+
textLimit,
|
|
352
|
+
chunkMode,
|
|
353
|
+
replyLogger: params.replyLogger,
|
|
354
|
+
connectionId: params.connectionId,
|
|
355
|
+
// Tool + block updates are noisy; skip their log lines.
|
|
356
|
+
skipLog: info.kind !== "final",
|
|
357
|
+
tableMode,
|
|
358
|
+
});
|
|
359
|
+
didSendReply = true;
|
|
360
|
+
if (info.kind === "tool") {
|
|
361
|
+
params.rememberSentText(payload.text, {});
|
|
362
|
+
return;
|
|
334
363
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
didSendReply = true;
|
|
349
|
-
if (info.kind === "tool") {
|
|
350
|
-
params.rememberSentText(payload.text, {});
|
|
351
|
-
return;
|
|
364
|
+
const shouldLog = info.kind === "final" && payload.text ? true : undefined;
|
|
365
|
+
params.rememberSentText(payload.text, {
|
|
366
|
+
combinedBody,
|
|
367
|
+
combinedBodySessionKey: params.route.sessionKey,
|
|
368
|
+
logVerboseMessage: shouldLog,
|
|
369
|
+
});
|
|
370
|
+
if (info.kind === "final") {
|
|
371
|
+
const fromDisplay = params.msg.chatType === "group" ? conversationId : (params.msg.from ?? "unknown");
|
|
372
|
+
const hasMedia = Boolean(payload.mediaUrl || payload.mediaUrls?.length);
|
|
373
|
+
whatsappOutboundLog.info(`Auto-replied to ${fromDisplay}${hasMedia ? " (media)" : ""}`);
|
|
374
|
+
if (shouldLogVerbose()) {
|
|
375
|
+
const preview = payload.text != null ? elide(payload.text, 400) : "<media>";
|
|
376
|
+
whatsappOutboundLog.debug(`Reply body: ${preview}${hasMedia ? " (media)" : ""}`);
|
|
352
377
|
}
|
|
353
|
-
|
|
354
|
-
params.
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
378
|
+
// Fire message:outbound hook for conversation archiving
|
|
379
|
+
const outboundHookEvent = createInternalHookEvent("message", "outbound", params.route.sessionKey, {
|
|
380
|
+
from: params.msg.to, // Agent is sending
|
|
381
|
+
to: params.msg.senderE164 ?? params.msg.from, // To the user
|
|
382
|
+
text: payload.text,
|
|
383
|
+
timestamp: Date.now(),
|
|
384
|
+
chatType: params.msg.chatType,
|
|
385
|
+
agentId: params.route.agentId,
|
|
386
|
+
channel: "whatsapp",
|
|
387
|
+
hasMedia,
|
|
388
|
+
senderE164: params.msg.senderE164,
|
|
389
|
+
groupSubject: params.msg.groupSubject,
|
|
390
|
+
conversationId,
|
|
391
|
+
cfg: params.cfg,
|
|
358
392
|
});
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
whatsappOutboundLog.info(`Auto-replied to ${fromDisplay}${hasMedia ? " (media)" : ""}`);
|
|
363
|
-
if (shouldLogVerbose()) {
|
|
364
|
-
const preview = payload.text != null ? elide(payload.text, 400) : "<media>";
|
|
365
|
-
whatsappOutboundLog.debug(`Reply body: ${preview}${hasMedia ? " (media)" : ""}`);
|
|
366
|
-
}
|
|
367
|
-
// Fire message:outbound hook for conversation archiving
|
|
368
|
-
const outboundHookEvent = createInternalHookEvent("message", "outbound", params.route.sessionKey, {
|
|
369
|
-
from: params.msg.to, // Agent is sending
|
|
370
|
-
to: params.msg.senderE164 ?? params.msg.from, // To the user
|
|
371
|
-
text: payload.text,
|
|
372
|
-
timestamp: Date.now(),
|
|
373
|
-
chatType: params.msg.chatType,
|
|
374
|
-
agentId: params.route.agentId,
|
|
375
|
-
channel: "whatsapp",
|
|
376
|
-
hasMedia,
|
|
377
|
-
senderE164: params.msg.senderE164,
|
|
378
|
-
groupSubject: params.msg.groupSubject,
|
|
379
|
-
conversationId,
|
|
380
|
-
cfg: params.cfg,
|
|
381
|
-
});
|
|
382
|
-
void triggerInternalHook(outboundHookEvent);
|
|
383
|
-
}
|
|
384
|
-
},
|
|
393
|
+
void triggerInternalHook(outboundHookEvent);
|
|
394
|
+
}
|
|
395
|
+
},
|
|
385
396
|
onError: (err, info) => {
|
|
386
397
|
const label = info.kind === "tool"
|
|
387
398
|
? "tool update"
|
|
@@ -395,5 +395,35 @@ export async function monitorWebInbox(options) {
|
|
|
395
395
|
},
|
|
396
396
|
// IPC surface (sendMessage/sendPoll/sendReaction/sendComposingTo)
|
|
397
397
|
...sendApi,
|
|
398
|
+
// Conversation browser methods
|
|
399
|
+
listConversations: async () => {
|
|
400
|
+
const entries = [];
|
|
401
|
+
for (const [jid, cached] of groupMetaCache) {
|
|
402
|
+
entries.push({
|
|
403
|
+
jid,
|
|
404
|
+
type: "group",
|
|
405
|
+
name: cached.subject ?? jid,
|
|
406
|
+
lastMessageTimestamp: undefined,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
return entries;
|
|
410
|
+
},
|
|
411
|
+
getMessages: async (_jid, _limit) => {
|
|
412
|
+
// No in-memory message store — Baileys makeInMemoryStore is not used.
|
|
413
|
+
return [];
|
|
414
|
+
},
|
|
415
|
+
getGroupMetadata: async (jid) => {
|
|
416
|
+
const meta = await sock.groupMetadata(jid);
|
|
417
|
+
return {
|
|
418
|
+
subject: meta.subject,
|
|
419
|
+
participants: (meta.participants ?? []).map((p) => ({
|
|
420
|
+
jid: p.id,
|
|
421
|
+
name: p.name ?? undefined,
|
|
422
|
+
admin: p.admin === "admin" || p.admin === "superadmin",
|
|
423
|
+
})),
|
|
424
|
+
creation: meta.creation,
|
|
425
|
+
desc: meta.desc ?? undefined,
|
|
426
|
+
};
|
|
427
|
+
},
|
|
398
428
|
};
|
|
399
429
|
}
|
|
@@ -56,7 +56,7 @@ export const whatsappPlugin: ChannelPlugin<ResolvedWhatsAppAccount> = {
|
|
|
56
56
|
reactions: true,
|
|
57
57
|
media: true,
|
|
58
58
|
},
|
|
59
|
-
reload: { configPrefixes: ["web"
|
|
59
|
+
reload: { configPrefixes: ["web", "channels.whatsapp"], noopPrefixes: [] },
|
|
60
60
|
gatewayMethods: ["web.login.start", "web.login.wait"],
|
|
61
61
|
configSchema: buildChannelConfigSchema(WhatsAppConfigSchema),
|
|
62
62
|
config: {
|
package/package.json
CHANGED
|
@@ -20,12 +20,13 @@ Load `references/review-protocol.md` for the full review and analysis protocol.
|
|
|
20
20
|
|
|
21
21
|
### Rules
|
|
22
22
|
|
|
23
|
-
1. **Scan system logs** — use `logs_read(action: "system")`
|
|
23
|
+
1. **Scan system logs** — use `logs_read(action: "system", minLevel: "warn")` to retrieve only warnings and errors. Do not call without `minLevel` — full logs will overflow context.
|
|
24
24
|
2. **Scan session logs** — use `logs_read(action: "sessions")` across all agents for tool failures and agent errors
|
|
25
25
|
3. **Triage by severity** — critical, warning, info. Deduplicate repeated errors.
|
|
26
|
-
4. **
|
|
27
|
-
5. **
|
|
28
|
-
6. **
|
|
26
|
+
4. **Deduplicate** — group identical messages from repeated occurrences and report as "N× [message]" rather than listing each separately.
|
|
27
|
+
5. **Analyse each issue** — plain-language explanation, likely root cause, suggested admin action
|
|
28
|
+
6. **Escalation guidance** — for issues beyond local resolution, advise forwarding this report to the Taskmaster public agent on WhatsApp for support
|
|
29
|
+
7. **All-clear confirmation** — if no issues found, confirm briefly so admins know the review ran
|
|
29
30
|
|
|
30
31
|
### Output Format
|
|
31
32
|
|
|
@@ -37,8 +38,20 @@ The report should follow this structure:
|
|
|
37
38
|
- **Escalation** — if any issues warrant Taskmaster support, advise forwarding this report
|
|
38
39
|
- **Summary** — issue count or all-clear confirmation
|
|
39
40
|
|
|
41
|
+
Each individual issue entry must be formatted exactly as:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
**N. Title** _(HH:MM or HH:MM–HH:MM Nx)_
|
|
45
|
+
- What: ...
|
|
46
|
+
- Why: ...
|
|
47
|
+
- Action: ...
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The time in parentheses is mandatory. Extract it from the log line's `time` field (UTC ISO format, e.g. `2026-03-05T10:35:22.000Z`) — take the `HH:MM` part, which is characters 11–15 of the string (e.g. `10:35`). For repeated occurrences show the first–last range and count: `08:36–09:48 (3×)`. Never omit the time — if the log line has no `time` field, write `(?:??)` as a placeholder.
|
|
51
|
+
|
|
40
52
|
### Constraints
|
|
41
53
|
|
|
54
|
+
- **Only report what is directly evidenced in the log data returned by the tools.** Do not infer, extrapolate, or report issues that do not appear verbatim in the log lines. Every issue in the report must be traceable to a specific log entry you received.
|
|
42
55
|
- Keep total execution under 2 minutes
|
|
43
56
|
- Be honest — if nothing surfaced, say "all clear" rather than padding the report
|
|
44
57
|
- Use plain language — the admin is not a developer
|
|
@@ -4,9 +4,7 @@ Run this protocol on schedule or when triggered by an admin. Be thorough in anal
|
|
|
4
4
|
|
|
5
5
|
## Step 1: System Log Scan
|
|
6
6
|
|
|
7
|
-
Use `logs_read
|
|
8
|
-
|
|
9
|
-
Focus on entries containing `[ERROR]` and `[WARN]`. Ignore routine info-level entries unless they reveal a pattern (e.g. repeated restarts, auth refresh cycles).
|
|
7
|
+
Use `logs_read(action: "system", minLevel: "warn")` to pull only warnings and errors. **Never call without `minLevel`** — the full log will overflow context.
|
|
10
8
|
|
|
11
9
|
Look for:
|
|
12
10
|
- Service crashes or unexpected restarts
|
|
@@ -18,7 +16,7 @@ Look for:
|
|
|
18
16
|
|
|
19
17
|
## Step 2: Session Log Scan
|
|
20
18
|
|
|
21
|
-
Use `logs_read
|
|
19
|
+
Use `logs_read(action: "sessions")` to pull recent error entries across all agents. Only error-type entries are returned — tool failures, agent exceptions, and crashed sessions.
|
|
22
20
|
|
|
23
21
|
Look for:
|
|
24
22
|
- Tool call failures or errors
|
|
@@ -46,6 +44,8 @@ For each issue provide:
|
|
|
46
44
|
|
|
47
45
|
Be specific with actions. "Check the logs" is not a useful suggestion — the whole point of this skill is that the admin doesn't have to.
|
|
48
46
|
|
|
47
|
+
**CRITICAL: Only report issues present in the log data you received.** Do not draw on your knowledge of the codebase, providers, or past conversations to invent or infer issues. If a provider name, error code, or warning does not appear in a log line you read, it must not appear in the report. Fabricating issues destroys trust.
|
|
48
|
+
|
|
49
49
|
## Step 5: Escalation Guidance
|
|
50
50
|
|
|
51
51
|
If any issue meets these criteria, advise the admin to escalate to Taskmaster support:
|
|
@@ -1166,6 +1166,20 @@ Occasionally, AI providers like Claude experience temporary outages or slowdowns
|
|
|
1166
1166
|
2. **Check your logs** — If replies are failing, open **Advanced → Logs → Session Logs** and filter by "errors" to see what's happening.
|
|
1167
1167
|
3. **Wait it out** — Most AI service outages resolve within minutes to hours. Your assistant will automatically use the primary provider again once it's back.
|
|
1168
1168
|
|
|
1169
|
+
### Sharing logs with support
|
|
1170
|
+
|
|
1171
|
+
If you're still stuck after trying the steps above, export your logs and send them to Taskmaster support on WhatsApp. Logs give the support team exact error messages and timing, which speeds up diagnosis.
|
|
1172
|
+
|
|
1173
|
+
1. Go to the **Advanced** tab in the Control Panel and tap **Logs**
|
|
1174
|
+
2. Select the view that covers your issue:
|
|
1175
|
+
- **Session Logs** — for problems with replies, conversations, or tool errors
|
|
1176
|
+
- **System Logs** — for connection, startup, or gateway issues
|
|
1177
|
+
3. Tap **Filters** to open the filter panel
|
|
1178
|
+
4. Tap **Export** — the browser downloads a log file to your device
|
|
1179
|
+
5. Send the file to Taskmaster support on WhatsApp
|
|
1180
|
+
|
|
1181
|
+
> **Tip:** If you're not sure which view to use, export both — Session Logs and System Logs — and send them together.
|
|
1182
|
+
|
|
1169
1183
|
### "sudo: unable to resolve host taskmaster" warning?
|
|
1170
1184
|
|
|
1171
1185
|
This harmless warning appears when the Pi's hostname isn't listed in `/etc/hosts`. Every `sudo` command still works — it's just a cosmetic message. To fix it, open a terminal on the Pi and run:
|