@clwnt/clawnet 0.7.8 → 0.7.10
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/package.json +1 -1
- package/src/cli.ts +4 -0
- package/src/config.ts +6 -0
- package/src/service.ts +22 -27
- package/src/tools.ts +6 -0
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -154,6 +154,10 @@ export function buildStatusText(api: any): string {
|
|
|
154
154
|
lines.push("Polling: **PAUSED** (run /clawnet resume to restart)");
|
|
155
155
|
}
|
|
156
156
|
lines.push(`Poll interval: ${pluginCfg.pollEverySeconds ?? "?"}s`);
|
|
157
|
+
const notifyOn = pluginCfg.notifyOnNew ?? true;
|
|
158
|
+
const remindH = pluginCfg.remindAfterHours ?? null;
|
|
159
|
+
lines.push(`Notify on new: ${notifyOn ? "on" : "off"}`);
|
|
160
|
+
lines.push(`Reminder interval: ${remindH ? `${remindH}h` : "never"}`);
|
|
157
161
|
|
|
158
162
|
const accounts: any[] = pluginCfg.accounts ?? [];
|
|
159
163
|
const agentList: any[] = currentConfig?.agents?.list ?? [];
|
package/src/config.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface ClawnetConfig {
|
|
|
19
19
|
maxSnippetChars: number;
|
|
20
20
|
setupVersion: number;
|
|
21
21
|
paused: boolean;
|
|
22
|
+
notifyOnNew: boolean;
|
|
23
|
+
remindAfterHours: number | null;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
const DEFAULTS: ClawnetConfig = {
|
|
@@ -32,6 +34,8 @@ const DEFAULTS: ClawnetConfig = {
|
|
|
32
34
|
maxSnippetChars: 500,
|
|
33
35
|
setupVersion: 0,
|
|
34
36
|
paused: false,
|
|
37
|
+
notifyOnNew: true,
|
|
38
|
+
remindAfterHours: 4,
|
|
35
39
|
};
|
|
36
40
|
|
|
37
41
|
export function parseConfig(raw: Record<string, unknown>): ClawnetConfig {
|
|
@@ -67,6 +71,8 @@ export function parseConfig(raw: Record<string, unknown>): ClawnetConfig {
|
|
|
67
71
|
deliveryMethod:
|
|
68
72
|
raw.deliveryMethod === "agent" ? "agent" : DEFAULTS.deliveryMethod,
|
|
69
73
|
paused: raw.paused === true,
|
|
74
|
+
notifyOnNew: raw.notifyOnNew !== false,
|
|
75
|
+
remindAfterHours: typeof raw.remindAfterHours === "number" ? raw.remindAfterHours : null,
|
|
70
76
|
};
|
|
71
77
|
}
|
|
72
78
|
|
package/src/service.ts
CHANGED
|
@@ -73,7 +73,7 @@ async function reloadOnboardingMessage(): Promise<void> {
|
|
|
73
73
|
|
|
74
74
|
const SKILL_UPDATE_INTERVAL_MS = 6 * 60 * 60 * 1000; // 6 hours
|
|
75
75
|
const SKILL_FILES = ["skill.json", "api-reference.md", "inbox-handler.md", "capabilities.json", "hook-template.txt", "tool-descriptions.json", "onboarding-message.txt", "inbox-protocol.md"];
|
|
76
|
-
export const PLUGIN_VERSION = "0.7.
|
|
76
|
+
export const PLUGIN_VERSION = "0.7.10"; // Reported to server via PATCH /me every 6h
|
|
77
77
|
|
|
78
78
|
function loadFreshConfig(api: any): ClawnetConfig {
|
|
79
79
|
const raw = api.runtime?.config?.loadConfig?.()?.plugins?.entries?.clawnet?.config ?? {};
|
|
@@ -177,7 +177,7 @@ export function createClawnetService(params: { api: any; cfg: ClawnetConfig }) {
|
|
|
177
177
|
// Mark notified (non-fatal)
|
|
178
178
|
if (emailIds.length > 0 || taskIds.length > 0) {
|
|
179
179
|
try {
|
|
180
|
-
await fetch(`${auth.baseUrl}/inbox/mark-notified`, {
|
|
180
|
+
const markRes = await fetch(`${auth.baseUrl}/inbox/mark-notified`, {
|
|
181
181
|
method: "POST",
|
|
182
182
|
headers: { Authorization: `Bearer ${auth.token}`, "Content-Type": "application/json" },
|
|
183
183
|
body: JSON.stringify({
|
|
@@ -185,31 +185,18 @@ export function createClawnetService(params: { api: any; cfg: ClawnetConfig }) {
|
|
|
185
185
|
...(taskIds.length > 0 ? { task_ids: taskIds } : {}),
|
|
186
186
|
}),
|
|
187
187
|
});
|
|
188
|
-
|
|
188
|
+
if (markRes.ok) {
|
|
189
|
+
const markData = await markRes.json().catch(() => ({})) as Record<string, unknown>;
|
|
190
|
+
api.logger.info(`[clawnet] ${accountId}: marked notified (${markData.marked_messages ?? 0} msgs, ${markData.marked_tasks ?? 0} tasks)`);
|
|
191
|
+
} else {
|
|
192
|
+
const errText = await markRes.text().catch(() => "");
|
|
193
|
+
api.logger.warn(`[clawnet] ${accountId}: mark-notified returned ${markRes.status}: ${errText}`);
|
|
194
|
+
}
|
|
189
195
|
} catch (err: any) {
|
|
190
196
|
api.logger.warn(`[clawnet] ${accountId}: mark-notified failed (non-fatal): ${err.message}`);
|
|
191
197
|
}
|
|
192
198
|
}
|
|
193
199
|
|
|
194
|
-
// Mark incoming A2A tasks as 'working' (protocol semantics, separate from notification tracking)
|
|
195
|
-
for (const msg of messages) {
|
|
196
|
-
if (msg.type === "task" && msg.content.startsWith("[A2A Task ")) {
|
|
197
|
-
try {
|
|
198
|
-
await fetch(`${auth.baseUrl}/a2a`, {
|
|
199
|
-
method: "POST",
|
|
200
|
-
headers: { Authorization: `Bearer ${auth.token}`, "Content-Type": "application/json" },
|
|
201
|
-
body: JSON.stringify({
|
|
202
|
-
jsonrpc: "2.0",
|
|
203
|
-
id: `ack-${msg.id}`,
|
|
204
|
-
method: "tasks/respond",
|
|
205
|
-
params: { id: msg.id, state: "working" },
|
|
206
|
-
}),
|
|
207
|
-
});
|
|
208
|
-
} catch {
|
|
209
|
-
// Non-fatal — task may get re-delivered next cycle
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
200
|
}
|
|
214
201
|
} catch (err: any) {
|
|
215
202
|
state.lastError = { message: err.message, at: new Date() };
|
|
@@ -389,8 +376,16 @@ export function createClawnetService(params: { api: any; cfg: ClawnetConfig }) {
|
|
|
389
376
|
cfg.deliver.channel = pc.deliver_channel;
|
|
390
377
|
changed = true;
|
|
391
378
|
}
|
|
379
|
+
if (pc.notify_on_new !== undefined && pc.notify_on_new !== cfg.notifyOnNew) {
|
|
380
|
+
cfg.notifyOnNew = pc.notify_on_new;
|
|
381
|
+
changed = true;
|
|
382
|
+
}
|
|
383
|
+
if (pc.remind_after_hours !== undefined && pc.remind_after_hours !== cfg.remindAfterHours) {
|
|
384
|
+
cfg.remindAfterHours = pc.remind_after_hours;
|
|
385
|
+
changed = true;
|
|
386
|
+
}
|
|
392
387
|
if (changed) {
|
|
393
|
-
api.logger.info(`[clawnet] Config updated from server: poll=${cfg.pollEverySeconds}s debounce=${cfg.debounceSeconds}s batch=${cfg.maxBatchSize}`);
|
|
388
|
+
api.logger.info(`[clawnet] Config updated from server: poll=${cfg.pollEverySeconds}s debounce=${cfg.debounceSeconds}s batch=${cfg.maxBatchSize} notify=${cfg.notifyOnNew} remind=${cfg.remindAfterHours ?? "never"}`);
|
|
394
389
|
}
|
|
395
390
|
}
|
|
396
391
|
|
|
@@ -489,7 +484,7 @@ export function createClawnetService(params: { api: any; cfg: ClawnetConfig }) {
|
|
|
489
484
|
api.logger.info(`[clawnet] ${account.id}: ${tasks.length} A2A task(s) to deliver`);
|
|
490
485
|
|
|
491
486
|
// Convert A2A tasks to the message format for delivery
|
|
492
|
-
//
|
|
487
|
+
// mark-notified happens post-delivery in deliverBatch
|
|
493
488
|
const messages: InboxMessage[] = tasks.map((task) => {
|
|
494
489
|
const history = task.history as Array<{ role: string; parts: Array<{ text?: string }> }> ?? [];
|
|
495
490
|
const lastMsg = history[history.length - 1];
|
|
@@ -607,10 +602,10 @@ export function createClawnetService(params: { api: any; cfg: ClawnetConfig }) {
|
|
|
607
602
|
let hadError = false;
|
|
608
603
|
for (const account of enabledAccounts) {
|
|
609
604
|
try {
|
|
610
|
-
const { a2aDmCount, sentTaskUpdates } = await pollAccount(account);
|
|
605
|
+
const { a2aDmCount, sentTaskUpdates, notifyCount } = await pollAccount(account);
|
|
611
606
|
|
|
612
607
|
// Also poll for A2A DMs if any pending
|
|
613
|
-
if (a2aDmCount > 0) {
|
|
608
|
+
if (a2aDmCount > 0 && notifyCount > 0) {
|
|
614
609
|
try {
|
|
615
610
|
await pollAccountA2A(account, a2aDmCount);
|
|
616
611
|
} catch (a2aErr: any) {
|
|
@@ -619,7 +614,7 @@ export function createClawnetService(params: { api: any; cfg: ClawnetConfig }) {
|
|
|
619
614
|
}
|
|
620
615
|
|
|
621
616
|
// Poll for sent task updates (tasks I sent that got a response)
|
|
622
|
-
if (sentTaskUpdates > 0) {
|
|
617
|
+
if (sentTaskUpdates > 0 && notifyCount > 0) {
|
|
623
618
|
try {
|
|
624
619
|
await pollSentTaskUpdates(account);
|
|
625
620
|
} catch (err: any) {
|
package/src/tools.ts
CHANGED
|
@@ -203,6 +203,12 @@ const BUILTIN_OPERATIONS: CapabilityOp[] = [
|
|
|
203
203
|
{ operation: "profile.capabilities", method: "PATCH", path: "/me/capabilities", description: "Set agent capabilities list", params: {
|
|
204
204
|
capabilities: { type: "array", description: "List of capability strings (replaces all)", required: true },
|
|
205
205
|
}},
|
|
206
|
+
// Notification settings
|
|
207
|
+
{ operation: "notifications.get", method: "GET", path: "/me/notifications", description: "Get notification preferences (notify_on_new, remind_after_hours)" },
|
|
208
|
+
{ operation: "notifications.update", method: "PATCH", path: "/me/notifications", description: "Update notification preferences", params: {
|
|
209
|
+
notify_on_new: { type: "boolean", description: "Notify when new messages/tasks arrive (default: true)" },
|
|
210
|
+
remind_after_hours: { type: "number", description: "Re-notify about unresolved items every N hours (1-168), or null to disable reminders" },
|
|
211
|
+
}},
|
|
206
212
|
// Contacts
|
|
207
213
|
{ operation: "contacts.list", method: "GET", path: "/contacts", description: "List your contacts", params: {
|
|
208
214
|
type: { type: "string", description: "'email' or 'agent'" },
|