@holon-run/agentinbox 1.0.2 → 1.0.4
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/src/cli.js +164 -49
- package/dist/src/current_agent.js +31 -0
- package/dist/src/http.js +69 -15
- package/dist/src/service.js +22 -27
- package/dist/src/sources/github.js +15 -6
- package/dist/src/sources/remote.js +1 -0
- package/dist/src/sources/remote_modules.js +15 -3
- package/dist/src/store.js +92 -30
- package/drizzle/migrations/0004_provider_raw_payload.sql +3 -0
- package/drizzle/schema.ts +2 -0
- package/package.json +3 -2
- package/skills/README.md +18 -0
- package/skills/agentinbox/SKILL.md +239 -0
- package/skills/agentinbox/agents/openai.yaml +3 -0
package/dist/src/store.js
CHANGED
|
@@ -288,8 +288,10 @@ class AgentInboxStore {
|
|
|
288
288
|
]);
|
|
289
289
|
this.persist();
|
|
290
290
|
}
|
|
291
|
-
listSourceHosts() {
|
|
292
|
-
const rows =
|
|
291
|
+
listSourceHosts(limit) {
|
|
292
|
+
const rows = typeof limit === "number"
|
|
293
|
+
? this.getAll("select * from source_hosts order by created_at asc, host_id asc limit ?", [limit])
|
|
294
|
+
: this.getAll("select * from source_hosts order by created_at asc, host_id asc");
|
|
293
295
|
return rows.map((row) => this.mapSourceHost(row));
|
|
294
296
|
}
|
|
295
297
|
updateSourceHostDefinition(hostId, input) {
|
|
@@ -362,8 +364,10 @@ class AgentInboxStore {
|
|
|
362
364
|
});
|
|
363
365
|
this.persist();
|
|
364
366
|
}
|
|
365
|
-
listSources() {
|
|
366
|
-
const rows =
|
|
367
|
+
listSources(limit) {
|
|
368
|
+
const rows = typeof limit === "number"
|
|
369
|
+
? this.getAll("select * from sources order by created_at asc, source_id asc limit ?", [limit])
|
|
370
|
+
: this.getAll("select * from sources order by created_at asc, source_id asc");
|
|
367
371
|
return rows.map((row) => this.mapSource(row));
|
|
368
372
|
}
|
|
369
373
|
getSourceIdleState(sourceId) {
|
|
@@ -505,8 +509,10 @@ class AgentInboxStore {
|
|
|
505
509
|
this.persist();
|
|
506
510
|
return this.getAgent(agentId);
|
|
507
511
|
}
|
|
508
|
-
listAgents() {
|
|
509
|
-
const rows =
|
|
512
|
+
listAgents(limit) {
|
|
513
|
+
const rows = typeof limit === "number"
|
|
514
|
+
? this.getAll("select * from agents order by created_at asc, agent_id asc limit ?", [limit])
|
|
515
|
+
: this.getAll("select * from agents order by created_at asc, agent_id asc");
|
|
510
516
|
return rows.map((row) => this.mapAgent(row));
|
|
511
517
|
}
|
|
512
518
|
getInbox(inboxId) {
|
|
@@ -556,8 +562,10 @@ class AgentInboxStore {
|
|
|
556
562
|
this.persist();
|
|
557
563
|
return this.getInbox(inboxId);
|
|
558
564
|
}
|
|
559
|
-
listInboxes() {
|
|
560
|
-
const rows =
|
|
565
|
+
listInboxes(limit) {
|
|
566
|
+
const rows = typeof limit === "number"
|
|
567
|
+
? this.getAll("select * from inboxes order by created_at asc, inbox_id asc limit ?", [limit])
|
|
568
|
+
: this.getAll("select * from inboxes order by created_at asc, inbox_id asc");
|
|
561
569
|
return rows.map((row) => this.mapInbox(row));
|
|
562
570
|
}
|
|
563
571
|
getSubscription(subscriptionId) {
|
|
@@ -583,16 +591,41 @@ class AgentInboxStore {
|
|
|
583
591
|
]);
|
|
584
592
|
this.persist();
|
|
585
593
|
}
|
|
586
|
-
listSubscriptions() {
|
|
587
|
-
const rows =
|
|
594
|
+
listSubscriptions(limit) {
|
|
595
|
+
const rows = typeof limit === "number"
|
|
596
|
+
? this.getAll("select * from subscriptions order by created_at asc, subscription_id asc limit ?", [limit])
|
|
597
|
+
: this.getAll("select * from subscriptions order by created_at asc, subscription_id asc");
|
|
588
598
|
return rows.map((row) => this.mapSubscription(row));
|
|
589
599
|
}
|
|
590
|
-
|
|
591
|
-
const
|
|
600
|
+
listSubscriptionsFiltered(filters) {
|
|
601
|
+
const clauses = [];
|
|
602
|
+
const params = [];
|
|
603
|
+
if (filters?.sourceId) {
|
|
604
|
+
clauses.push("source_id = ?");
|
|
605
|
+
params.push(filters.sourceId);
|
|
606
|
+
}
|
|
607
|
+
if (filters?.agentId) {
|
|
608
|
+
clauses.push("agent_id = ?");
|
|
609
|
+
params.push(filters.agentId);
|
|
610
|
+
}
|
|
611
|
+
const where = clauses.length > 0 ? ` where ${clauses.join(" and ")}` : "";
|
|
612
|
+
const limitClause = typeof filters?.limit === "number" ? " limit ?" : "";
|
|
613
|
+
if (typeof filters?.limit === "number") {
|
|
614
|
+
params.push(filters.limit);
|
|
615
|
+
}
|
|
616
|
+
const rows = this.getAll(`select * from subscriptions${where} order by created_at asc, subscription_id asc${limitClause}`, params);
|
|
617
|
+
return rows.map((row) => this.mapSubscription(row));
|
|
618
|
+
}
|
|
619
|
+
listSubscriptionsForSource(sourceId, limit) {
|
|
620
|
+
const rows = typeof limit === "number"
|
|
621
|
+
? this.getAll("select * from subscriptions where source_id = ? order by created_at asc, subscription_id asc limit ?", [sourceId, limit])
|
|
622
|
+
: this.getAll("select * from subscriptions where source_id = ? order by created_at asc, subscription_id asc", [sourceId]);
|
|
592
623
|
return rows.map((row) => this.mapSubscription(row));
|
|
593
624
|
}
|
|
594
|
-
listSubscriptionsForAgent(agentId) {
|
|
595
|
-
const rows =
|
|
625
|
+
listSubscriptionsForAgent(agentId, limit) {
|
|
626
|
+
const rows = typeof limit === "number"
|
|
627
|
+
? this.getAll("select * from subscriptions where agent_id = ? order by created_at asc, subscription_id asc limit ?", [agentId, limit])
|
|
628
|
+
: this.getAll("select * from subscriptions where agent_id = ? order by created_at asc, subscription_id asc", [agentId]);
|
|
596
629
|
return rows.map((row) => this.mapSubscription(row));
|
|
597
630
|
}
|
|
598
631
|
listSubscriptionsForHostTrackedResourceRef(hostId, trackedResourceRef) {
|
|
@@ -821,12 +854,16 @@ class AgentInboxStore {
|
|
|
821
854
|
this.persist();
|
|
822
855
|
return this.getActivationTarget(targetId);
|
|
823
856
|
}
|
|
824
|
-
listActivationTargets() {
|
|
825
|
-
const rows =
|
|
857
|
+
listActivationTargets(limit) {
|
|
858
|
+
const rows = typeof limit === "number"
|
|
859
|
+
? this.getAll("select * from activation_targets order by created_at asc, target_id asc limit ?", [limit])
|
|
860
|
+
: this.getAll("select * from activation_targets order by created_at asc, target_id asc");
|
|
826
861
|
return rows.map((row) => this.mapActivationTarget(row));
|
|
827
862
|
}
|
|
828
|
-
listActivationTargetsForAgent(agentId) {
|
|
829
|
-
const rows =
|
|
863
|
+
listActivationTargetsForAgent(agentId, limit) {
|
|
864
|
+
const rows = typeof limit === "number"
|
|
865
|
+
? this.getAll("select * from activation_targets where agent_id = ? order by created_at asc, target_id asc limit ?", [agentId, limit])
|
|
866
|
+
: this.getAll("select * from activation_targets where agent_id = ? order by created_at asc, target_id asc", [agentId]);
|
|
830
867
|
return rows.map((row) => this.mapActivationTarget(row));
|
|
831
868
|
}
|
|
832
869
|
deleteActivationTarget(agentId, targetId) {
|
|
@@ -902,12 +939,16 @@ class AgentInboxStore {
|
|
|
902
939
|
const row = this.getOne("select * from timers where schedule_id = ?", [scheduleId]);
|
|
903
940
|
return row ? this.mapTimer(row) : null;
|
|
904
941
|
}
|
|
905
|
-
listTimers() {
|
|
906
|
-
const rows =
|
|
942
|
+
listTimers(limit) {
|
|
943
|
+
const rows = typeof limit === "number"
|
|
944
|
+
? this.getAll("select * from timers order by created_at asc, schedule_id asc limit ?", [limit])
|
|
945
|
+
: this.getAll("select * from timers order by created_at asc, schedule_id asc");
|
|
907
946
|
return rows.map((row) => this.mapTimer(row));
|
|
908
947
|
}
|
|
909
|
-
listTimersForAgent(agentId) {
|
|
910
|
-
const rows =
|
|
948
|
+
listTimersForAgent(agentId, limit) {
|
|
949
|
+
const rows = typeof limit === "number"
|
|
950
|
+
? this.getAll("select * from timers where agent_id = ? order by created_at asc, schedule_id asc limit ?", [agentId, limit])
|
|
951
|
+
: this.getAll("select * from timers where agent_id = ? order by created_at asc, schedule_id asc", [agentId]);
|
|
911
952
|
return rows.map((row) => this.mapTimer(row));
|
|
912
953
|
}
|
|
913
954
|
listDueTimers(cutoffIso) {
|
|
@@ -1015,8 +1056,8 @@ class AgentInboxStore {
|
|
|
1015
1056
|
this.db.run(`
|
|
1016
1057
|
insert or ignore into inbox_items (
|
|
1017
1058
|
item_id, source_id, source_native_id, event_variant, inbox_id, occurred_at,
|
|
1018
|
-
metadata_json, raw_payload_json, delivery_handle_json, acked_at
|
|
1019
|
-
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1059
|
+
metadata_json, raw_payload_json, provider_raw_payload_json, delivery_handle_json, acked_at
|
|
1060
|
+
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1020
1061
|
`, [
|
|
1021
1062
|
item.itemId,
|
|
1022
1063
|
item.sourceId,
|
|
@@ -1026,6 +1067,7 @@ class AgentInboxStore {
|
|
|
1026
1067
|
item.occurredAt,
|
|
1027
1068
|
JSON.stringify(item.metadata),
|
|
1028
1069
|
JSON.stringify(item.rawPayload),
|
|
1070
|
+
item.providerRawPayload ? JSON.stringify(item.providerRawPayload) : null,
|
|
1029
1071
|
item.deliveryHandle ? JSON.stringify(item.deliveryHandle) : null,
|
|
1030
1072
|
item.ackedAt ?? null,
|
|
1031
1073
|
]);
|
|
@@ -1059,6 +1101,7 @@ class AgentInboxStore {
|
|
|
1059
1101
|
occurredAt: item.occurredAt,
|
|
1060
1102
|
metadata: item.metadata,
|
|
1061
1103
|
rawPayload: item.rawPayload,
|
|
1104
|
+
providerRawPayload: item.providerRawPayload,
|
|
1062
1105
|
deliveryHandle: item.deliveryHandle ?? null,
|
|
1063
1106
|
}),
|
|
1064
1107
|
count: 1,
|
|
@@ -1092,7 +1135,11 @@ class AgentInboxStore {
|
|
|
1092
1135
|
filters.push("sequence > ?");
|
|
1093
1136
|
params.push(Number(anchor.sequence));
|
|
1094
1137
|
}
|
|
1095
|
-
const
|
|
1138
|
+
const sql = `select * from inbox_entries where ${filters.join(" and ")} order by sequence asc${typeof options?.limit === "number" ? " limit ?" : ""}`;
|
|
1139
|
+
if (typeof options?.limit === "number") {
|
|
1140
|
+
params.push(options.limit);
|
|
1141
|
+
}
|
|
1142
|
+
const rows = this.getAll(sql, params);
|
|
1096
1143
|
return this.mapInboxEntries(rows);
|
|
1097
1144
|
}
|
|
1098
1145
|
getInboxEntry(entryId) {
|
|
@@ -1273,7 +1320,11 @@ class AgentInboxStore {
|
|
|
1273
1320
|
if (!includeAcked) {
|
|
1274
1321
|
filters.push("acked_at is null");
|
|
1275
1322
|
}
|
|
1276
|
-
const
|
|
1323
|
+
const sql = `select * from inbox_items where ${filters.join(" and ")} order by coalesce(inbox_sequence, rowid) asc${typeof options?.limit === "number" ? " limit ?" : ""}`;
|
|
1324
|
+
if (typeof options?.limit === "number") {
|
|
1325
|
+
params.push(options.limit);
|
|
1326
|
+
}
|
|
1327
|
+
const rows = this.getAll(sql, params);
|
|
1277
1328
|
return rows.map((row) => this.mapInboxItem(row));
|
|
1278
1329
|
}
|
|
1279
1330
|
ackItems(inboxId, itemIds, ackedAt) {
|
|
@@ -1406,8 +1457,10 @@ class AgentInboxStore {
|
|
|
1406
1457
|
const row = this.getOne("select * from streams where stream_id = ?", [streamId]);
|
|
1407
1458
|
return row ? this.mapStream(row) : null;
|
|
1408
1459
|
}
|
|
1409
|
-
listStreams() {
|
|
1410
|
-
const rows =
|
|
1460
|
+
listStreams(limit) {
|
|
1461
|
+
const rows = typeof limit === "number"
|
|
1462
|
+
? this.getAll("select * from streams order by created_at asc, stream_id asc limit ?", [limit])
|
|
1463
|
+
: this.getAll("select * from streams order by created_at asc, stream_id asc");
|
|
1411
1464
|
return rows.map((row) => this.mapStream(row));
|
|
1412
1465
|
}
|
|
1413
1466
|
getStreamBySourceId(sourceId) {
|
|
@@ -1418,14 +1471,15 @@ class AgentInboxStore {
|
|
|
1418
1471
|
const occurredAt = event.occurredAt ?? (0, util_1.nowIso)();
|
|
1419
1472
|
const metadataJson = JSON.stringify(event.metadata ?? {});
|
|
1420
1473
|
const rawPayloadJson = JSON.stringify(event.rawPayload ?? {});
|
|
1474
|
+
const providerRawPayloadJson = event.providerRawPayload ? JSON.stringify(event.providerRawPayload) : null;
|
|
1421
1475
|
const deliveryHandleJson = event.deliveryHandle ? JSON.stringify(event.deliveryHandle) : null;
|
|
1422
1476
|
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
1423
1477
|
const before = this.changes();
|
|
1424
1478
|
this.db.run(`
|
|
1425
1479
|
insert or ignore into stream_events (
|
|
1426
1480
|
stream_event_id, stream_id, source_id, source_native_id, event_variant,
|
|
1427
|
-
occurred_at, metadata_json, raw_payload_json, delivery_handle_json, created_at
|
|
1428
|
-
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1481
|
+
occurred_at, metadata_json, raw_payload_json, provider_raw_payload_json, delivery_handle_json, created_at
|
|
1482
|
+
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1429
1483
|
`, [
|
|
1430
1484
|
(0, util_1.generateCanonicalId)("evt"),
|
|
1431
1485
|
streamId,
|
|
@@ -1435,6 +1489,7 @@ class AgentInboxStore {
|
|
|
1435
1489
|
occurredAt,
|
|
1436
1490
|
metadataJson,
|
|
1437
1491
|
rawPayloadJson,
|
|
1492
|
+
providerRawPayloadJson,
|
|
1438
1493
|
deliveryHandleJson,
|
|
1439
1494
|
(0, util_1.nowIso)(),
|
|
1440
1495
|
]);
|
|
@@ -1821,6 +1876,9 @@ class AgentInboxStore {
|
|
|
1821
1876
|
occurredAt: String(row.occurred_at),
|
|
1822
1877
|
metadata: parseJson(row.metadata_json),
|
|
1823
1878
|
rawPayload: parseJson(row.raw_payload_json),
|
|
1879
|
+
providerRawPayload: row.provider_raw_payload_json
|
|
1880
|
+
? parseJson(row.provider_raw_payload_json)
|
|
1881
|
+
: undefined,
|
|
1824
1882
|
deliveryHandle: row.delivery_handle_json
|
|
1825
1883
|
? parseJson(row.delivery_handle_json)
|
|
1826
1884
|
: null,
|
|
@@ -1858,6 +1916,7 @@ class AgentInboxStore {
|
|
|
1858
1916
|
occurredAt: item.occurredAt,
|
|
1859
1917
|
metadata: item.metadata,
|
|
1860
1918
|
rawPayload: item.rawPayload,
|
|
1919
|
+
providerRawPayload: item.providerRawPayload,
|
|
1861
1920
|
item,
|
|
1862
1921
|
};
|
|
1863
1922
|
}
|
|
@@ -2130,6 +2189,9 @@ class AgentInboxStore {
|
|
|
2130
2189
|
occurredAt: String(row.occurred_at),
|
|
2131
2190
|
metadata: parseJson(row.metadata_json),
|
|
2132
2191
|
rawPayload: parseJson(row.raw_payload_json),
|
|
2192
|
+
providerRawPayload: row.provider_raw_payload_json
|
|
2193
|
+
? parseJson(row.provider_raw_payload_json)
|
|
2194
|
+
: undefined,
|
|
2133
2195
|
deliveryHandle: row.delivery_handle_json
|
|
2134
2196
|
? parseJson(row.delivery_handle_json)
|
|
2135
2197
|
: null,
|
package/drizzle/schema.ts
CHANGED
|
@@ -173,6 +173,7 @@ export const inboxItems = sqliteTable("inbox_items", {
|
|
|
173
173
|
occurredAt: text("occurred_at").notNull(),
|
|
174
174
|
metadataJson: text("metadata_json").notNull(),
|
|
175
175
|
rawPayloadJson: text("raw_payload_json").notNull(),
|
|
176
|
+
providerRawPayloadJson: text("provider_raw_payload_json"),
|
|
176
177
|
deliveryHandleJson: text("delivery_handle_json"),
|
|
177
178
|
ackedAt: text("acked_at"),
|
|
178
179
|
}, (table) => ({
|
|
@@ -302,6 +303,7 @@ export const streamEvents = sqliteTable("stream_events", {
|
|
|
302
303
|
occurredAt: text("occurred_at").notNull(),
|
|
303
304
|
metadataJson: text("metadata_json").notNull(),
|
|
304
305
|
rawPayloadJson: text("raw_payload_json").notNull(),
|
|
306
|
+
providerRawPayloadJson: text("provider_raw_payload_json"),
|
|
305
307
|
deliveryHandleJson: text("delivery_handle_json"),
|
|
306
308
|
createdAt: text("created_at").notNull(),
|
|
307
309
|
}, (table) => ({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holon-run/agentinbox",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Local event subscription and delivery service for agents.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"files": [
|
|
21
21
|
"dist/src/",
|
|
22
22
|
"scripts/",
|
|
23
|
+
"skills/",
|
|
23
24
|
"drizzle/",
|
|
24
25
|
"README.md",
|
|
25
26
|
"LICENSE"
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
},
|
|
44
45
|
"dependencies": {
|
|
45
46
|
"@fastify/swagger": "^9.5.2",
|
|
46
|
-
"@holon-run/uxc-daemon-client": "^0.15.
|
|
47
|
+
"@holon-run/uxc-daemon-client": "^0.15.4",
|
|
47
48
|
"fastify": "^5.6.1",
|
|
48
49
|
"jexl": "^2.3.0",
|
|
49
50
|
"sql.js": "^1.13.0"
|
package/skills/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Skills
|
|
2
|
+
|
|
3
|
+
The docs site exposes selected repository skills so they can be handed directly
|
|
4
|
+
to another agent.
|
|
5
|
+
|
|
6
|
+
For `AgentInbox`, the preferred first-run path is skill-first onboarding:
|
|
7
|
+
|
|
8
|
+
- hand the bundled `AgentInbox` skill to the agent
|
|
9
|
+
- let the agent verify `agentinbox`, `uxc`, and GitHub auth
|
|
10
|
+
- let the agent register the current session and set up standing subscriptions
|
|
11
|
+
|
|
12
|
+
<!-- INDEX:START -->
|
|
13
|
+
|
|
14
|
+
- [agentinbox](./agentinbox/)
|
|
15
|
+
Use the local AgentInbox service to onboard the current session, connect GitHub through UXC, and operate sources, subscriptions, and the agent inbox.
|
|
16
|
+
<!-- mdorigin:index kind=article -->
|
|
17
|
+
|
|
18
|
+
<!-- INDEX:END -->
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentinbox
|
|
3
|
+
description: Use the local AgentInbox service to onboard the current session, manage shared sources and subscriptions, connect external providers such as GitHub through UXC, and operate the agent inbox.
|
|
4
|
+
metadata:
|
|
5
|
+
short-description: Operate AgentInbox sources and subscriptions
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# AgentInbox Skill
|
|
9
|
+
|
|
10
|
+
Use this skill when the current agent should set up or use the local
|
|
11
|
+
`agentinbox` daemon.
|
|
12
|
+
|
|
13
|
+
Primary docs:
|
|
14
|
+
|
|
15
|
+
- `https://agentinbox.holon.run/guides/onboarding-with-agent-skill`
|
|
16
|
+
- `https://agentinbox.holon.run/guides/getting-started`
|
|
17
|
+
- `https://agentinbox.holon.run/guides/review-workflows`
|
|
18
|
+
- `https://agentinbox.holon.run/reference/cli`
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
Install `agentinbox` if it is not already available:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g @holon-run/agentinbox
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Install `uxc` if GitHub or Feishu adapters are needed:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
brew tap holon-run/homebrew-tap
|
|
32
|
+
brew install uxc
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
UXC repository:
|
|
36
|
+
|
|
37
|
+
- `https://github.com/holon-run/uxc`
|
|
38
|
+
|
|
39
|
+
## First-Run Onboarding
|
|
40
|
+
|
|
41
|
+
Recommended first-run sequence:
|
|
42
|
+
|
|
43
|
+
1. if GitHub access is needed and `gh` is already authenticated, import that auth into `uxc`
|
|
44
|
+
2. register the current terminal session
|
|
45
|
+
3. follow the required sources or resources using the docs examples
|
|
46
|
+
|
|
47
|
+
If GitHub-backed adapters are needed:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
gh auth status
|
|
51
|
+
uxc auth credential import github --from gh
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This `gh` import path requires `uxc` 0.15.3 or newer.
|
|
55
|
+
|
|
56
|
+
Register the current terminal/runtime session:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
agentinbox agent register
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Treat the returned `agentId` as the stable identity for later commands.
|
|
63
|
+
|
|
64
|
+
## Usage Discipline
|
|
65
|
+
|
|
66
|
+
Defaults:
|
|
67
|
+
|
|
68
|
+
- do not create one GitHub source per PR unless the source itself must be PR-
|
|
69
|
+
scoped
|
|
70
|
+
- prefer shared repo/repo-CI sources plus narrow follows or subscriptions
|
|
71
|
+
- prefer `agentinbox follow` over manual `subscription add` when a follow
|
|
72
|
+
template exists
|
|
73
|
+
- if a source exposes only subscription shortcuts, prefer the shortcut over
|
|
74
|
+
manually reconstructing the same filter and lifecycle fields
|
|
75
|
+
- treat unused task-specific subscriptions as cleanup debt
|
|
76
|
+
- if GitHub polling volume looks high, inspect old subscriptions and duplicate
|
|
77
|
+
temporary sources before adding more
|
|
78
|
+
|
|
79
|
+
This matches the AgentInbox model: sources are shared hosting units, while
|
|
80
|
+
subscriptions carry agent-specific filtering and delivery intent.
|
|
81
|
+
|
|
82
|
+
## Default Async Lifecycle
|
|
83
|
+
|
|
84
|
+
Default to AgentInbox when the work is not purely synchronous in the current
|
|
85
|
+
session.
|
|
86
|
+
|
|
87
|
+
Typical cases:
|
|
88
|
+
|
|
89
|
+
- delayed follow-up that should happen after you stop actively looking at the
|
|
90
|
+
terminal
|
|
91
|
+
- waiting for PR review, CI completion, issue replies, or other external
|
|
92
|
+
events
|
|
93
|
+
- anything that must survive session boundaries instead of living only in chat
|
|
94
|
+
memory
|
|
95
|
+
- reminders that should fire at a specific time or on a recurring schedule
|
|
96
|
+
|
|
97
|
+
Important boundary:
|
|
98
|
+
|
|
99
|
+
- inbox items, subscriptions, and timers can outlive the current terminal
|
|
100
|
+
session
|
|
101
|
+
- terminal delivery does not automatically survive session boundaries just
|
|
102
|
+
because the inbox state does
|
|
103
|
+
- if the original runtime/terminal disappears, items may keep accumulating in
|
|
104
|
+
the inbox while notifications stop reaching you
|
|
105
|
+
- if a later session should resume the same logical agent, re-register or
|
|
106
|
+
explicitly rebind that agent to the current terminal before assuming prompt
|
|
107
|
+
delivery is live again
|
|
108
|
+
|
|
109
|
+
Lifecycle:
|
|
110
|
+
|
|
111
|
+
1. register once per live terminal/runtime session
|
|
112
|
+
2. reuse broad shared sources
|
|
113
|
+
3. add narrow task-scoped follows, subscriptions, or timers
|
|
114
|
+
4. read inbox items in bounded batches and ack only the reviewed batch
|
|
115
|
+
5. clean up task-scoped subscriptions/timers after merge, closure, or abandonment
|
|
116
|
+
|
|
117
|
+
For PR and review workflows, prefer `follow` templates. They reuse shared
|
|
118
|
+
sources, expand the source-specific filters, and attach cleanup behavior:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
agentinbox agent register
|
|
122
|
+
agentinbox follow github pr --agent-id <agentId> --arg owner=holon-run --arg repo=agentinbox --arg number=87 --arg withCi=true
|
|
123
|
+
agentinbox inbox read --agent-id <agentId>
|
|
124
|
+
agentinbox inbox ack --agent-id <agentId> --through <lastEntryId>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Ack discipline:
|
|
128
|
+
|
|
129
|
+
- prefer `agentinbox inbox ack --agent-id <agentId> --through <lastEntryId>`
|
|
130
|
+
after reading a reviewed batch
|
|
131
|
+
- avoid `ack --all` unless you explicitly verified that every current item
|
|
132
|
+
should be cleared
|
|
133
|
+
- do not ack speculative future work just because the current terminal message
|
|
134
|
+
was seen
|
|
135
|
+
|
|
136
|
+
Timer intent:
|
|
137
|
+
|
|
138
|
+
- use `agentinbox timer add` when the trigger is time-based rather than source-based
|
|
139
|
+
- prefer timers over inventing fake local events for reminders like "check CI
|
|
140
|
+
in 30 minutes" or "revisit this PR tomorrow morning"
|
|
141
|
+
|
|
142
|
+
## Core Commands
|
|
143
|
+
|
|
144
|
+
Follow high-level templates:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
agentinbox follow github repo --agent-id <agentId> --arg owner=holon-run --arg repo=agentinbox
|
|
148
|
+
agentinbox follow github pr --agent-id <agentId> --arg owner=holon-run --arg repo=agentinbox --arg number=87 --arg withCi=true
|
|
149
|
+
agentinbox follow github issue --agent-id <agentId> --arg owner=holon-run --arg repo=agentinbox --arg number=180
|
|
150
|
+
agentinbox follow github pr --agent-id <agentId> --args-json '{"owner":"holon-run","repo":"agentinbox","number":87,"withCi":true}'
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Use `follow` as the default path for GitHub repo, PR, and issue tracking. Drop
|
|
154
|
+
to `source schema` plus `subscription add` only when you need a custom filter or
|
|
155
|
+
the source has no follow template.
|
|
156
|
+
|
|
157
|
+
Advanced source/subscription commands:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
agentinbox source list
|
|
161
|
+
agentinbox source show <sourceId>
|
|
162
|
+
agentinbox source schema <sourceId>
|
|
163
|
+
agentinbox source add <hostId> repo_events <owner>/<repo> --config-json '{"owner":"holon-run","repo":"agentinbox"}'
|
|
164
|
+
agentinbox source add <hostId> ci_runs <owner>/<repo> --config-json '{"owner":"holon-run","repo":"agentinbox","pollIntervalSecs":30}'
|
|
165
|
+
agentinbox subscription add <sourceId> --shortcut pr --shortcut-args-json '{"number":87}'
|
|
166
|
+
agentinbox subscription add <sourceId> --filter-json '{"metadata":{"headBranch":"main","conclusion":"failure"}}'
|
|
167
|
+
agentinbox subscription list --agent-id <agentId>
|
|
168
|
+
agentinbox subscription remove <subscriptionId>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Use manual subscriptions for advanced filters, custom source kinds, or when
|
|
172
|
+
debugging template expansion. If `subscriptionSchema.shortcuts` is non-empty
|
|
173
|
+
but no follow template is available, prefer those shortcut entries first.
|
|
174
|
+
|
|
175
|
+
Read and ack the inbox:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
agentinbox inbox read --agent-id <agentId>
|
|
179
|
+
agentinbox inbox ack --agent-id <agentId> --through <lastEntryId>
|
|
180
|
+
agentinbox inbox send --agent-id <agentId> --message "Please review PR #87"
|
|
181
|
+
agentinbox inbox watch --agent-id <agentId>
|
|
182
|
+
agentinbox inbox ack --agent-id <agentId> --all
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Default to a batch-bounded ack flow:
|
|
186
|
+
|
|
187
|
+
1. read the inbox items you intend to process
|
|
188
|
+
2. identify the last item you actually reviewed in that batch
|
|
189
|
+
3. ack with `--through <lastEntryId>`
|
|
190
|
+
|
|
191
|
+
Use `ack --all` only after explicitly verifying every current item should be
|
|
192
|
+
cleared. Use `inbox send` for local operator/direct text ingress.
|
|
193
|
+
|
|
194
|
+
Manage timers:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
agentinbox timer add --agent-id <agentId> --at <RFC3339_TIMESTAMP> --message "Check the morning build"
|
|
198
|
+
agentinbox timer add --agent-id <agentId> --every 24h --message "Review today's open PRs"
|
|
199
|
+
agentinbox timer add --agent-id <agentId> --cron "0 8 * * *" --timezone Asia/Shanghai --message "Daily triage"
|
|
200
|
+
agentinbox timer list
|
|
201
|
+
agentinbox timer list --agent-id <agentId>
|
|
202
|
+
agentinbox timer pause <scheduleId>
|
|
203
|
+
agentinbox timer resume <scheduleId>
|
|
204
|
+
agentinbox timer remove <scheduleId>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Activation targets:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
agentinbox agent target list <agentId>
|
|
211
|
+
agentinbox agent target add webhook <agentId> --url http://127.0.0.1:8787/webhook
|
|
212
|
+
agentinbox agent target remove <agentId> <targetId>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
For filtering strategy and review workflow setup, follow the docs links above
|
|
216
|
+
instead of re-explaining the full architecture here.
|
|
217
|
+
|
|
218
|
+
## Troubleshooting
|
|
219
|
+
|
|
220
|
+
Do not start every task by checking daemon status; normal CLI commands should
|
|
221
|
+
auto-connect or surface actionable errors. Use these checks after the first
|
|
222
|
+
AgentInbox command fails, notifications stop arriving, or you suspect a stale
|
|
223
|
+
terminal binding:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
agentinbox --version
|
|
227
|
+
agentinbox daemon status
|
|
228
|
+
agentinbox daemon start
|
|
229
|
+
agentinbox agent register --agent-id <agentId> --force-rebind
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
If GitHub-backed sources fail, verify UXC and imported GitHub auth only after
|
|
233
|
+
the failure points there:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
uxc --version
|
|
237
|
+
gh auth status
|
|
238
|
+
uxc auth credential import github --from gh
|
|
239
|
+
```
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
display_name: AgentInbox
|
|
2
|
+
short_description: Operate the local AgentInbox service for shared sources, subscriptions, inbox workflows, activation targets, and external providers such as GitHub.
|
|
3
|
+
default_prompt: Use AgentInbox to register the current session, inspect sources and subscriptions, prefer broad reusable sources with subscription-side filtering, remove stale subscriptions when they are no longer needed, and read or watch the agent inbox.
|