@holon-run/agentinbox 1.0.4 → 1.0.5
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/README.md +13 -6
- package/dist/src/adapters.js +12 -0
- package/dist/src/cli.js +87 -17
- package/dist/src/http.js +58 -1
- package/dist/src/service.js +17 -3
- package/dist/src/source_hosts.js +2 -4
- package/dist/src/source_schema.js +1 -3
- package/dist/src/sources/feishu.js +1030 -31
- package/dist/src/sources/remote.js +24 -0
- package/dist/src/sources/remote_modules.js +15 -3
- package/package.json +2 -1
- package/skills/README.md +2 -2
- package/skills/agentinbox/SKILL.md +59 -14
package/README.md
CHANGED
|
@@ -13,8 +13,9 @@ In practice, that means `AgentInbox` can:
|
|
|
13
13
|
|
|
14
14
|
- share one GitHub or Feishu source across multiple local agents
|
|
15
15
|
- materialize those events into durable inboxes
|
|
16
|
-
-
|
|
17
|
-
|
|
16
|
+
- activate terminal-backed sessions in `tmux` or `iTerm2`, or Holon agents
|
|
17
|
+
through runtime-provided webhook triggers, without embedding connector logic
|
|
18
|
+
in the agent runtime
|
|
18
19
|
|
|
19
20
|
## Event Flow
|
|
20
21
|
|
|
@@ -111,7 +112,7 @@ node dist/src/cli.js --help
|
|
|
111
112
|
|
|
112
113
|
## Recommended Onboarding
|
|
113
114
|
|
|
114
|
-
If you are using Codex
|
|
115
|
+
If you are using Codex, Claude Code, or Holon, start with the bundled AgentInbox skill:
|
|
115
116
|
|
|
116
117
|
- repo copy: [`skills/agentinbox/SKILL.md`](./skills/agentinbox/SKILL.md)
|
|
117
118
|
- docs site copy: `https://agentinbox.holon.run/skills/agentinbox/SKILL`
|
|
@@ -120,7 +121,7 @@ If you use the community `skills` installer, you can install the bundled skill
|
|
|
120
121
|
directly:
|
|
121
122
|
|
|
122
123
|
```bash
|
|
123
|
-
npx skills add holon-run/agentinbox --skill agentinbox -a codex -a claude-code
|
|
124
|
+
npx skills add holon-run/agentinbox --skill agentinbox -a codex -a claude-code -a holon
|
|
124
125
|
```
|
|
125
126
|
|
|
126
127
|
That skill is the recommended onboarding path. It can guide the agent through:
|
|
@@ -128,7 +129,8 @@ That skill is the recommended onboarding path. It can guide the agent through:
|
|
|
128
129
|
- checking or installing `agentinbox`
|
|
129
130
|
- checking or installing `uxc`
|
|
130
131
|
- importing GitHub auth from the local `gh` CLI via `uxc auth credential import github --from gh`
|
|
131
|
-
- registering the current
|
|
132
|
+
- registering the current runtime/session as an agent, including Holon webhook
|
|
133
|
+
activation when running in Holon
|
|
132
134
|
- adding GitHub sources and standing subscriptions using the docs-site examples
|
|
133
135
|
|
|
134
136
|
## Quick Start
|
|
@@ -139,15 +141,20 @@ Start the local daemon:
|
|
|
139
141
|
agentinbox daemon start
|
|
140
142
|
```
|
|
141
143
|
|
|
142
|
-
Register the current
|
|
144
|
+
Register the current runtime/session:
|
|
143
145
|
|
|
144
146
|
```bash
|
|
145
147
|
agentinbox agent register
|
|
146
148
|
agentinbox agent register --agent-id agent-alpha
|
|
149
|
+
agentinbox agent register --agent-id agent-alpha --webhook-url <external-trigger-url>
|
|
147
150
|
agentinbox agent register --notify-lease-ms 600000 --min-unacked-items 5
|
|
148
151
|
agentinbox agent current
|
|
149
152
|
```
|
|
150
153
|
|
|
154
|
+
Terminal-backed runtimes attach a terminal activation target. In Holon, the
|
|
155
|
+
no-arg form uses `HOLON_AGENT_ID` and `HOLON_EXTERNAL_TRIGGER_URL` when present;
|
|
156
|
+
otherwise pass `--webhook-url` explicitly.
|
|
157
|
+
|
|
151
158
|
`notifyLeaseMs` and `minUnackedItems` are target-facing notification policy:
|
|
152
159
|
they control how often a target may be reminded and how many unacked items must
|
|
153
160
|
accumulate before AgentInbox notifies it. Service-wide activation batching
|
package/dist/src/adapters.js
CHANGED
|
@@ -208,6 +208,18 @@ class AdapterRegistry {
|
|
|
208
208
|
}
|
|
209
209
|
return module.invokeDeliveryOperation({ handle, operation, input, attempt, source });
|
|
210
210
|
}
|
|
211
|
+
async listSourceOperations(source) {
|
|
212
|
+
if (source.sourceType === "local_event") {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
return this.remoteSource.listSourceOperations(source);
|
|
216
|
+
}
|
|
217
|
+
async invokeSourceOperation(source, operation, input) {
|
|
218
|
+
if (source.sourceType === "local_event") {
|
|
219
|
+
throw new Error(`source operations are not supported for source type ${source.sourceType}`);
|
|
220
|
+
}
|
|
221
|
+
return this.remoteSource.invokeSourceOperation(source, operation, input);
|
|
222
|
+
}
|
|
211
223
|
status() {
|
|
212
224
|
return {
|
|
213
225
|
remote: this.remoteSource.status?.() ?? {},
|
package/dist/src/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const commander_1 = require("commander");
|
|
9
10
|
const adapters_1 = require("./adapters");
|
|
10
11
|
const client_1 = require("./client");
|
|
11
12
|
const control_server_1 = require("./control_server");
|
|
@@ -24,11 +25,16 @@ async function main() {
|
|
|
24
25
|
const normalized = shouldTreatJsonFlagAsNoop(detectedArgs)
|
|
25
26
|
? stripNoopJsonFlag(detectedArgs)
|
|
26
27
|
: detectedArgs;
|
|
28
|
+
const shell = parseCommanderShell(normalized);
|
|
27
29
|
const command = normalized[0];
|
|
28
30
|
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
29
31
|
printHelp(normalized.slice(1));
|
|
30
32
|
return;
|
|
31
33
|
}
|
|
34
|
+
if (shell.isBareGroup) {
|
|
35
|
+
printHelp([command]);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
32
38
|
if (command === "version" || command === "--version" || command === "-v") {
|
|
33
39
|
if (hasHelpFlag(normalized.slice(1))) {
|
|
34
40
|
printHelp(["version"]);
|
|
@@ -343,6 +349,27 @@ async function main() {
|
|
|
343
349
|
await printRemote(client, `/sources/${encodeURIComponent(sourceRef)}/schema`, undefined, "GET");
|
|
344
350
|
return;
|
|
345
351
|
}
|
|
352
|
+
if (command === "source" && normalized[1] === "actions") {
|
|
353
|
+
const sourceId = normalized[2];
|
|
354
|
+
if (!sourceId) {
|
|
355
|
+
throw new Error("usage: agentinbox source actions <sourceId>");
|
|
356
|
+
}
|
|
357
|
+
await printRemote(client, `/sources/${encodeURIComponent(sourceId)}/actions`, undefined, "GET");
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
if (command === "source" && normalized[1] === "invoke") {
|
|
361
|
+
const sourceId = normalized[2];
|
|
362
|
+
const operation = takeFlagValue(normalized, "--operation");
|
|
363
|
+
const inputJson = takeFlagValue(normalized, "--input-json");
|
|
364
|
+
if (!sourceId || !operation || !inputJson) {
|
|
365
|
+
throw new Error("usage: agentinbox source invoke <sourceId> --operation NAME --input-json JSON");
|
|
366
|
+
}
|
|
367
|
+
await printRemote(client, `/sources/${encodeURIComponent(sourceId)}/invoke`, {
|
|
368
|
+
operation,
|
|
369
|
+
input: (0, util_1.parseJsonArg)(inputJson, "--input-json"),
|
|
370
|
+
});
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
346
373
|
if (command === "source" && normalized[1] === "poll") {
|
|
347
374
|
const sourceId = normalized[2];
|
|
348
375
|
if (!sourceId) {
|
|
@@ -878,6 +905,53 @@ async function main() {
|
|
|
878
905
|
}
|
|
879
906
|
throw new Error(`unknown command: ${normalized.join(" ")}`);
|
|
880
907
|
}
|
|
908
|
+
const COMMAND_SHELL_SPECS = [
|
|
909
|
+
{ name: "serve", group: false, summary: "Run the AgentInbox control server." },
|
|
910
|
+
{ name: "daemon", group: true, summary: "Manage the local AgentInbox daemon." },
|
|
911
|
+
{ name: "host", group: true, summary: "Manage source hosts." },
|
|
912
|
+
{ name: "stream", group: true, summary: "Manage source streams." },
|
|
913
|
+
{ name: "follow", group: true, summary: "Create high-level source subscriptions." },
|
|
914
|
+
{ name: "source", group: true, summary: "Manage source streams through the source alias." },
|
|
915
|
+
{ name: "agent", group: true, summary: "Manage local agent registrations and activation targets." },
|
|
916
|
+
{ name: "timer", group: true, summary: "Manage agent reminder timers." },
|
|
917
|
+
{ name: "subscription", group: true, summary: "Manage source subscriptions." },
|
|
918
|
+
{ name: "inbox", group: true, summary: "Read and manage agent inboxes." },
|
|
919
|
+
{ name: "gc", group: false, summary: "Run garbage collection." },
|
|
920
|
+
{ name: "deliver", group: true, summary: "Send outbound delivery actions." },
|
|
921
|
+
{ name: "status", group: false, summary: "Show daemon status." },
|
|
922
|
+
{ name: "version", group: false, summary: "Show CLI version." },
|
|
923
|
+
];
|
|
924
|
+
const COMMANDER_SHELL = createCommanderShell();
|
|
925
|
+
function createCommanderShell() {
|
|
926
|
+
const program = new commander_1.Command();
|
|
927
|
+
program
|
|
928
|
+
.name("agentinbox")
|
|
929
|
+
.allowUnknownOption(true)
|
|
930
|
+
.allowExcessArguments(true)
|
|
931
|
+
.exitOverride()
|
|
932
|
+
.configureOutput({
|
|
933
|
+
writeOut: () => { },
|
|
934
|
+
writeErr: () => { },
|
|
935
|
+
});
|
|
936
|
+
for (const spec of COMMAND_SHELL_SPECS) {
|
|
937
|
+
program
|
|
938
|
+
.command(`${spec.name} [args...]`)
|
|
939
|
+
.description(spec.summary)
|
|
940
|
+
.allowUnknownOption(true)
|
|
941
|
+
.allowExcessArguments(true);
|
|
942
|
+
}
|
|
943
|
+
return program;
|
|
944
|
+
}
|
|
945
|
+
function parseCommanderShell(args) {
|
|
946
|
+
const command = args[0] ?? null;
|
|
947
|
+
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
948
|
+
return { isBareGroup: false };
|
|
949
|
+
}
|
|
950
|
+
const spec = COMMANDER_SHELL.commands.find((item) => item.name() === command);
|
|
951
|
+
return {
|
|
952
|
+
isBareGroup: Boolean(COMMAND_SHELL_SPECS.find((item) => item.name === spec?.name())?.group && args.length === 1),
|
|
953
|
+
};
|
|
954
|
+
}
|
|
881
955
|
async function runServe(args) {
|
|
882
956
|
const port = parseOptionalNumber(takeFlagValue(args, "--port"));
|
|
883
957
|
const homeOverride = takeFlagValue(args, "--home");
|
|
@@ -1345,10 +1419,9 @@ function unexpectedFlags(args, allowedFlags) {
|
|
|
1345
1419
|
const allowed = new Set(allowedFlags);
|
|
1346
1420
|
return args.filter((token) => token.startsWith("--") && !allowed.has(token));
|
|
1347
1421
|
}
|
|
1348
|
-
function
|
|
1349
|
-
const
|
|
1350
|
-
|
|
1351
|
-
root: `agentinbox
|
|
1422
|
+
function renderRootHelp() {
|
|
1423
|
+
const commands = COMMAND_SHELL_SPECS.map((spec) => ` ${spec.name}`).join("\n");
|
|
1424
|
+
return `agentinbox
|
|
1352
1425
|
|
|
1353
1426
|
Usage:
|
|
1354
1427
|
agentinbox <command> [options]
|
|
@@ -1357,19 +1430,13 @@ Usage:
|
|
|
1357
1430
|
agentinbox --version, -v
|
|
1358
1431
|
|
|
1359
1432
|
Commands:
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
inbox
|
|
1368
|
-
gc
|
|
1369
|
-
deliver
|
|
1370
|
-
status
|
|
1371
|
-
version
|
|
1372
|
-
`,
|
|
1433
|
+
${commands}
|
|
1434
|
+
`;
|
|
1435
|
+
}
|
|
1436
|
+
function printHelp(path = []) {
|
|
1437
|
+
const key = path[0] ?? "root";
|
|
1438
|
+
const helpByKey = {
|
|
1439
|
+
root: renderRootHelp(),
|
|
1373
1440
|
serve: `agentinbox serve
|
|
1374
1441
|
|
|
1375
1442
|
Usage:
|
|
@@ -1415,6 +1482,7 @@ Examples:
|
|
|
1415
1482
|
agentinbox follow github repo --agent-id <agentId> --arg owner=holon-run --arg repo=agentinbox
|
|
1416
1483
|
agentinbox follow github pr --agent-id <agentId> --arg owner=holon-run --arg repo=agentinbox --arg number=87 --arg withCi=true
|
|
1417
1484
|
agentinbox follow github issue --agent-id <agentId> --arg owner=holon-run --arg repo=agentinbox --arg number=180
|
|
1485
|
+
agentinbox follow feishu mentions --agent-id <agentId> --config-json '{"uxcAuth":"feishu-default"}'
|
|
1418
1486
|
`,
|
|
1419
1487
|
source: `agentinbox source
|
|
1420
1488
|
|
|
@@ -1427,6 +1495,8 @@ Usage:
|
|
|
1427
1495
|
agentinbox source pause <remoteSourceId>
|
|
1428
1496
|
agentinbox source resume <remoteSourceId>
|
|
1429
1497
|
agentinbox source schema <sourceId>
|
|
1498
|
+
agentinbox source actions <sourceId>
|
|
1499
|
+
agentinbox source invoke <sourceId> --operation NAME --input-json JSON
|
|
1430
1500
|
agentinbox source poll <sourceId>
|
|
1431
1501
|
agentinbox source event <sourceId> --native-id ID --event EVENT [--occurred-at ISO8601] [--metadata-json JSON] [--payload-json JSON]
|
|
1432
1502
|
`,
|
package/dist/src/http.js
CHANGED
|
@@ -381,6 +381,60 @@ function buildFastifyServer(service) {
|
|
|
381
381
|
const params = request.params;
|
|
382
382
|
return service.getResolvedSourceSchema(decodeURIComponent(params.sourceId));
|
|
383
383
|
});
|
|
384
|
+
app.get("/sources/:sourceId/actions", {
|
|
385
|
+
schema: {
|
|
386
|
+
tags: ["sources"],
|
|
387
|
+
params: {
|
|
388
|
+
type: "object",
|
|
389
|
+
required: ["sourceId"],
|
|
390
|
+
properties: {
|
|
391
|
+
sourceId: { type: "string", minLength: 1 },
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
response: {
|
|
395
|
+
200: jsonObjectSchema,
|
|
396
|
+
400: errorResponseSchema,
|
|
397
|
+
404: errorResponseSchema,
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
}, async (request) => {
|
|
401
|
+
const params = request.params;
|
|
402
|
+
return service.listSourceOperations(decodeURIComponent(params.sourceId));
|
|
403
|
+
});
|
|
404
|
+
app.post("/sources/:sourceId/invoke", {
|
|
405
|
+
schema: {
|
|
406
|
+
tags: ["sources"],
|
|
407
|
+
params: {
|
|
408
|
+
type: "object",
|
|
409
|
+
required: ["sourceId"],
|
|
410
|
+
properties: {
|
|
411
|
+
sourceId: { type: "string", minLength: 1 },
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
body: {
|
|
415
|
+
type: "object",
|
|
416
|
+
additionalProperties: false,
|
|
417
|
+
required: ["operation", "input"],
|
|
418
|
+
properties: {
|
|
419
|
+
operation: { type: "string", minLength: 1 },
|
|
420
|
+
input: jsonObjectSchema,
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
response: {
|
|
424
|
+
200: jsonObjectSchema,
|
|
425
|
+
400: errorResponseSchema,
|
|
426
|
+
404: errorResponseSchema,
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
}, async (request) => {
|
|
430
|
+
const params = request.params;
|
|
431
|
+
const body = request.body;
|
|
432
|
+
return service.invokeSourceOperation({
|
|
433
|
+
sourceId: decodeURIComponent(params.sourceId),
|
|
434
|
+
operation: body.operation,
|
|
435
|
+
input: body.input,
|
|
436
|
+
});
|
|
437
|
+
});
|
|
384
438
|
app.patch("/streams/:streamId", {
|
|
385
439
|
schema: {
|
|
386
440
|
tags: ["sources"],
|
|
@@ -1816,10 +1870,13 @@ function isBadRequestError(message) {
|
|
|
1816
1870
|
message.startsWith("deliver send is not supported") ||
|
|
1817
1871
|
message.startsWith("deliveryHandle requires") ||
|
|
1818
1872
|
message.startsWith("delivery operations are not supported") ||
|
|
1873
|
+
message.startsWith("source operations are not supported") ||
|
|
1819
1874
|
message.startsWith("unknown GitHub delivery operation") ||
|
|
1820
1875
|
message.startsWith("unknown Feishu delivery operation") ||
|
|
1876
|
+
message.startsWith("unknown Feishu source operation") ||
|
|
1821
1877
|
message.startsWith("invalid GitHub targetRef") ||
|
|
1822
|
-
message.
|
|
1878
|
+
message.startsWith("get_message_context requires") ||
|
|
1879
|
+
message.includes("requires input.") ||
|
|
1823
1880
|
message.includes("requires input.body") ||
|
|
1824
1881
|
message.startsWith("subscriptions/reset requires") ||
|
|
1825
1882
|
message.startsWith("agents requires") ||
|
package/dist/src/service.js
CHANGED
|
@@ -282,6 +282,22 @@ class AgentInboxService {
|
|
|
282
282
|
const source = this.getSource(sourceId);
|
|
283
283
|
return this.adapters.resolveSourceSchema(source);
|
|
284
284
|
}
|
|
285
|
+
async listSourceOperations(sourceId) {
|
|
286
|
+
const source = this.getSource(sourceId);
|
|
287
|
+
return {
|
|
288
|
+
sourceId: source.sourceId,
|
|
289
|
+
operations: await this.adapters.listSourceOperations(source),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
async invokeSourceOperation(request) {
|
|
293
|
+
const source = this.getSource(request.sourceId);
|
|
294
|
+
const data = await this.adapters.invokeSourceOperation(source, request.operation, request.input);
|
|
295
|
+
return {
|
|
296
|
+
sourceId: source.sourceId,
|
|
297
|
+
operation: request.operation,
|
|
298
|
+
data,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
285
301
|
async previewSourceSchema(input) {
|
|
286
302
|
try {
|
|
287
303
|
const source = buildPreviewSource(input);
|
|
@@ -3877,9 +3893,7 @@ function getHostConfigFields(hostType) {
|
|
|
3877
3893
|
];
|
|
3878
3894
|
case "feishu":
|
|
3879
3895
|
return [
|
|
3880
|
-
{ name: "
|
|
3881
|
-
{ name: "appSecret", type: "string", description: "Feishu app secret.", required: true },
|
|
3882
|
-
{ name: "uxcAuth", type: "string", description: "Optional shared Feishu auth/runtime profile.", required: false },
|
|
3896
|
+
{ name: "uxcAuth", type: "string", description: "Optional shared Feishu/Lark UXC auth profile.", required: false },
|
|
3883
3897
|
];
|
|
3884
3898
|
case "local_event":
|
|
3885
3899
|
return [];
|
package/dist/src/source_hosts.js
CHANGED
|
@@ -32,13 +32,11 @@ function resolveSourceRegistration(input) {
|
|
|
32
32
|
if (input.sourceType === "feishu_bot") {
|
|
33
33
|
return {
|
|
34
34
|
hostType: "feishu",
|
|
35
|
-
hostKey: `
|
|
35
|
+
hostKey: `uxcAuth:${stringOrDefault(config.uxcAuth, input.configRef ?? input.sourceKey)}`,
|
|
36
36
|
hostConfig: {
|
|
37
|
-
...(valueOrUndefined(config.
|
|
38
|
-
...(valueOrUndefined(config.appSecret) ? { appSecret: config.appSecret } : {}),
|
|
37
|
+
...(valueOrUndefined(config.uxcAuth) ? { uxcAuth: config.uxcAuth } : {}),
|
|
39
38
|
...(valueOrUndefined(config.schemaUrl) ? { schemaUrl: config.schemaUrl } : {}),
|
|
40
39
|
...(valueOrUndefined(config.replyInThread) ? { replyInThread: config.replyInThread } : {}),
|
|
41
|
-
...(valueOrUndefined(config.uxcAuth) ? { uxcAuth: config.uxcAuth } : {}),
|
|
42
40
|
},
|
|
43
41
|
streamKind: "message_events",
|
|
44
42
|
streamKey: input.sourceKey,
|
|
@@ -146,13 +146,11 @@ const SOURCE_SCHEMAS = {
|
|
|
146
146
|
],
|
|
147
147
|
eventVariantExamples: ["im.message.receive_v1.text"],
|
|
148
148
|
configFields: [
|
|
149
|
-
{ name: "
|
|
150
|
-
{ name: "appSecret", type: "string", required: true, description: "Feishu app secret." },
|
|
149
|
+
{ name: "uxcAuth", type: "string", required: false, description: "Optional UXC auth profile for the Feishu/Lark app." },
|
|
151
150
|
{ name: "eventTypes", type: "string[]", required: false, description: "Optional Feishu event type allowlist." },
|
|
152
151
|
{ name: "chatIds", type: "string[]", required: false, description: "Optional Feishu chat allowlist." },
|
|
153
152
|
{ name: "schemaUrl", type: "string", required: false, description: "Optional Feishu OpenAPI schema URL." },
|
|
154
153
|
{ name: "replyInThread", type: "boolean", required: false, description: "Reply in thread when sending outbound messages." },
|
|
155
|
-
{ name: "uxcAuth", type: "string", required: false, description: "Optional uxc auth profile." },
|
|
156
154
|
],
|
|
157
155
|
},
|
|
158
156
|
};
|