@holon-run/agentinbox 0.2.0 → 0.4.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/README.md +38 -0
- package/dist/src/cli.js +128 -0
- package/dist/src/current_agent.js +1 -0
- package/dist/src/daemon.js +69 -0
- package/dist/src/http.js +194 -1
- package/dist/src/runtime_gate.js +645 -0
- package/dist/src/service.js +741 -8
- package/dist/src/store.js +105 -3
- package/dist/src/terminal.js +35 -12
- package/drizzle/migrations/0005_timers.sql +22 -0
- package/drizzle/migrations/0006_terminal_runtime_pid.sql +1 -0
- package/drizzle/schema.ts +21 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -136,12 +136,40 @@ Create a local source and publish an event:
|
|
|
136
136
|
agentinbox source add local_event local-demo
|
|
137
137
|
agentinbox subscription add <source_id>
|
|
138
138
|
agentinbox subscription add <source_id> --agent-id <agent_id>
|
|
139
|
+
agentinbox source schema <source_id>
|
|
140
|
+
agentinbox subscription add <source_id> --shortcut pr --shortcut-args-json '{"number":373}'
|
|
139
141
|
agentinbox subscription add <source_id> --tracked-resource-ref pr:373 --cleanup-policy-json '{"mode":"manual"}'
|
|
140
142
|
agentinbox subscription add <source_id> --filter-file ./filter.json
|
|
141
143
|
cat filter.json | agentinbox subscription add <source_id> --filter-stdin
|
|
142
144
|
agentinbox source event <source_id> --native-id demo-1 --event local.demo
|
|
143
145
|
agentinbox inbox read
|
|
144
146
|
agentinbox inbox read --agent-id <agent_id>
|
|
147
|
+
agentinbox inbox ack --agent-id <agent_id> --through <last_item_id>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
When acking a reviewed batch, prefer `--through <last_item_id>` over `--all`.
|
|
151
|
+
That preserves the boundary of the items you actually inspected. Use
|
|
152
|
+
`ack --all` only when you have intentionally verified that every current
|
|
153
|
+
unacked item should be cleared.
|
|
154
|
+
|
|
155
|
+
Send a direct text message into an agent inbox:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
agentinbox inbox send --agent-id <agent_id> --message "Please review PR #87"
|
|
159
|
+
agentinbox inbox send --agent-id <agent_id> --message "CI failed on main" --sender operator
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Schedule reminder messages with timers:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
agentinbox timer add --agent-id <agent_id> --at <RFC3339_TIMESTAMP> --message "Check the morning build"
|
|
166
|
+
agentinbox timer add --agent-id <agent_id> --every 24h --message "Review today's open PRs"
|
|
167
|
+
agentinbox timer add --agent-id <agent_id> --cron "0 8 * * *" --timezone Asia/Shanghai --message "Daily triage"
|
|
168
|
+
agentinbox timer list
|
|
169
|
+
agentinbox timer list --agent-id <agent_id>
|
|
170
|
+
agentinbox timer pause <schedule_id>
|
|
171
|
+
agentinbox timer resume <schedule_id>
|
|
172
|
+
agentinbox timer remove <schedule_id>
|
|
145
173
|
```
|
|
146
174
|
|
|
147
175
|
Update an existing source in place:
|
|
@@ -164,6 +192,16 @@ Remove a task-specific subscription without deleting the whole agent:
|
|
|
164
192
|
agentinbox subscription remove <subscription_id>
|
|
165
193
|
```
|
|
166
194
|
|
|
195
|
+
For implementation-backed sources, inspect resolved subscription capabilities
|
|
196
|
+
before adding task-scoped subscriptions:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
agentinbox source schema <source_id>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
If the source advertises subscription shortcuts, prefer them over manually
|
|
203
|
+
repeating the equivalent filter, tracked resource ref, and cleanup policy.
|
|
204
|
+
|
|
167
205
|
## Docs
|
|
168
206
|
|
|
169
207
|
Public docs live in the mdorigin site under [`docs/site`](./docs/site).
|
package/dist/src/cli.js
CHANGED
|
@@ -180,6 +180,7 @@ async function main() {
|
|
|
180
180
|
backend: detected.backend,
|
|
181
181
|
runtimeKind: detected.runtimeKind,
|
|
182
182
|
runtimeSessionId: detected.runtimeSessionId ?? undefined,
|
|
183
|
+
runtimePid: detected.runtimePid ?? undefined,
|
|
183
184
|
tmuxPaneId: detected.tmuxPaneId ?? undefined,
|
|
184
185
|
tty: detected.tty ?? undefined,
|
|
185
186
|
termProgram: detected.termProgram ?? undefined,
|
|
@@ -212,6 +213,14 @@ async function main() {
|
|
|
212
213
|
await printRemote(client, `/agents/${encodeURIComponent(agentId)}`, undefined, "DELETE");
|
|
213
214
|
return;
|
|
214
215
|
}
|
|
216
|
+
if (command === "agent" && normalized[1] === "resume") {
|
|
217
|
+
const agentId = normalized[2];
|
|
218
|
+
if (!agentId) {
|
|
219
|
+
throw new Error("usage: agentinbox agent resume <agentId>");
|
|
220
|
+
}
|
|
221
|
+
await printRemote(client, `/agents/${encodeURIComponent(agentId)}/resume`, {});
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
215
224
|
if (command === "agent" && normalized[1] === "target" && normalized[2] === "add" && normalized[3] === "webhook") {
|
|
216
225
|
const agentId = normalized[4];
|
|
217
226
|
const url = takeFlagValue(normalized, "--url");
|
|
@@ -242,6 +251,14 @@ async function main() {
|
|
|
242
251
|
await printRemote(client, `/agents/${encodeURIComponent(agentId)}/targets/${encodeURIComponent(targetId)}`, undefined, "DELETE");
|
|
243
252
|
return;
|
|
244
253
|
}
|
|
254
|
+
if (command === "agent" && normalized[1] === "target" && normalized[2] === "resume") {
|
|
255
|
+
const [agentId, targetId] = normalized.slice(3, 5);
|
|
256
|
+
if (!agentId || !targetId) {
|
|
257
|
+
throw new Error("usage: agentinbox agent target resume <agentId> <targetId>");
|
|
258
|
+
}
|
|
259
|
+
await printRemote(client, `/agents/${encodeURIComponent(agentId)}/targets/${encodeURIComponent(targetId)}/resume`, {});
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
245
262
|
if (command === "subscription" && normalized[1] === "add") {
|
|
246
263
|
const args = normalized.slice(2);
|
|
247
264
|
const positionals = positionalArgs(args, [
|
|
@@ -344,6 +361,62 @@ async function main() {
|
|
|
344
361
|
});
|
|
345
362
|
return;
|
|
346
363
|
}
|
|
364
|
+
if (command === "timer" && normalized[1] === "add") {
|
|
365
|
+
const args = normalized.slice(2);
|
|
366
|
+
const allowedFlags = ["--agent-id", "--at", "--every", "--cron", "--timezone", "--message", "--sender"];
|
|
367
|
+
if (positionalArgs(args, ["--agent-id", "--at", "--every", "--cron", "--timezone", "--message", "--sender"]).length > 0 || unexpectedFlags(args, allowedFlags).length > 0) {
|
|
368
|
+
throw new Error("usage: agentinbox timer add --agent-id ID (--at ISO8601 | --every DURATION | --cron EXPR) --message TEXT [--timezone TZ] [--sender SENDER]");
|
|
369
|
+
}
|
|
370
|
+
const agentId = takeFlagValue(normalized, "--agent-id");
|
|
371
|
+
const message = takeFlagValue(normalized, "--message");
|
|
372
|
+
const at = takeFlagValue(normalized, "--at");
|
|
373
|
+
const every = takeFlagValue(normalized, "--every");
|
|
374
|
+
const cron = takeFlagValue(normalized, "--cron");
|
|
375
|
+
if (!agentId || !message || [at, every, cron].filter(Boolean).length !== 1) {
|
|
376
|
+
throw new Error("usage: agentinbox timer add --agent-id ID (--at ISO8601 | --every DURATION | --cron EXPR) --message TEXT [--timezone TZ] [--sender SENDER]");
|
|
377
|
+
}
|
|
378
|
+
await printRemote(client, "/timers", {
|
|
379
|
+
agentId,
|
|
380
|
+
at: at ?? undefined,
|
|
381
|
+
every: every ? parseDurationMs(every) : undefined,
|
|
382
|
+
cron: cron ?? undefined,
|
|
383
|
+
timezone: takeFlagValue(normalized, "--timezone") ?? undefined,
|
|
384
|
+
message,
|
|
385
|
+
sender: takeFlagValue(normalized, "--sender") ?? undefined,
|
|
386
|
+
});
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (command === "timer" && normalized[1] === "list") {
|
|
390
|
+
const query = buildQuery({
|
|
391
|
+
agent_id: takeFlagValue(normalized, "--agent-id"),
|
|
392
|
+
});
|
|
393
|
+
await printRemote(client, `/timers${query}`, undefined, "GET");
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
if (command === "timer" && normalized[1] === "pause") {
|
|
397
|
+
const scheduleId = normalized[2];
|
|
398
|
+
if (!scheduleId) {
|
|
399
|
+
throw new Error("usage: agentinbox timer pause <scheduleId>");
|
|
400
|
+
}
|
|
401
|
+
await printRemote(client, `/timers/${encodeURIComponent(scheduleId)}/pause`, {});
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
if (command === "timer" && normalized[1] === "resume") {
|
|
405
|
+
const scheduleId = normalized[2];
|
|
406
|
+
if (!scheduleId) {
|
|
407
|
+
throw new Error("usage: agentinbox timer resume <scheduleId>");
|
|
408
|
+
}
|
|
409
|
+
await printRemote(client, `/timers/${encodeURIComponent(scheduleId)}/resume`, {});
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
if (command === "timer" && normalized[1] === "remove") {
|
|
413
|
+
const scheduleId = normalized[2];
|
|
414
|
+
if (!scheduleId) {
|
|
415
|
+
throw new Error("usage: agentinbox timer remove <scheduleId>");
|
|
416
|
+
}
|
|
417
|
+
await printRemote(client, `/timers/${encodeURIComponent(scheduleId)}`, undefined, "DELETE");
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
347
420
|
if (command === "inbox" && normalized[1] === "list") {
|
|
348
421
|
await printRemote(client, "/agents", undefined, "GET");
|
|
349
422
|
return;
|
|
@@ -374,6 +447,23 @@ async function main() {
|
|
|
374
447
|
console.log((0, util_1.jsonResponse)(withCommandMetadata(response.data, selection)));
|
|
375
448
|
return;
|
|
376
449
|
}
|
|
450
|
+
if (command === "inbox" && normalized[1] === "send") {
|
|
451
|
+
const args = normalized.slice(2);
|
|
452
|
+
const allowedFlags = ["--agent-id", "--message", "--sender"];
|
|
453
|
+
if (positionalArgs(args, ["--agent-id", "--message", "--sender"]).length > 0 || unexpectedFlags(args, allowedFlags).length > 0) {
|
|
454
|
+
throw new Error("usage: agentinbox inbox send --agent-id ID --message TEXT [--sender SENDER]");
|
|
455
|
+
}
|
|
456
|
+
const agentId = takeFlagValue(normalized, "--agent-id");
|
|
457
|
+
const message = takeFlagValue(normalized, "--message");
|
|
458
|
+
if (!agentId || !message) {
|
|
459
|
+
throw new Error("usage: agentinbox inbox send --agent-id ID --message TEXT [--sender SENDER]");
|
|
460
|
+
}
|
|
461
|
+
await printRemote(client, `/agents/${encodeURIComponent(agentId)}/inbox/items`, {
|
|
462
|
+
message,
|
|
463
|
+
sender: takeFlagValue(normalized, "--sender") ?? undefined,
|
|
464
|
+
});
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
377
467
|
if (command === "inbox" && normalized[1] === "watch") {
|
|
378
468
|
const args = normalized.slice(2);
|
|
379
469
|
if (positionalArgs(args, ["--agent-id", "--after-item", "--heartbeat-ms"]).length > 0) {
|
|
@@ -592,6 +682,7 @@ async function selectAgentForCommand(client, options) {
|
|
|
592
682
|
backend: contextForCurrent.backend,
|
|
593
683
|
runtimeKind: contextForCurrent.runtimeKind,
|
|
594
684
|
runtimeSessionId: contextForCurrent.runtimeSessionId ?? undefined,
|
|
685
|
+
runtimePid: contextForCurrent.runtimePid ?? undefined,
|
|
595
686
|
tmuxPaneId: contextForCurrent.tmuxPaneId ?? undefined,
|
|
596
687
|
tty: contextForCurrent.tty ?? undefined,
|
|
597
688
|
termProgram: contextForCurrent.termProgram ?? undefined,
|
|
@@ -648,6 +739,30 @@ function parseOptionalNumber(value) {
|
|
|
648
739
|
}
|
|
649
740
|
return parsed;
|
|
650
741
|
}
|
|
742
|
+
function parseDurationMs(value) {
|
|
743
|
+
if (/^\d+$/.test(value)) {
|
|
744
|
+
return Number(value);
|
|
745
|
+
}
|
|
746
|
+
const match = /^(\d+)(ms|s|m|h|d)$/.exec(value);
|
|
747
|
+
if (!match) {
|
|
748
|
+
throw new Error(`invalid duration: ${value}`);
|
|
749
|
+
}
|
|
750
|
+
const amount = Number(match[1]);
|
|
751
|
+
switch (match[2]) {
|
|
752
|
+
case "ms":
|
|
753
|
+
return amount;
|
|
754
|
+
case "s":
|
|
755
|
+
return amount * 1_000;
|
|
756
|
+
case "m":
|
|
757
|
+
return amount * 60_000;
|
|
758
|
+
case "h":
|
|
759
|
+
return amount * 60 * 60_000;
|
|
760
|
+
case "d":
|
|
761
|
+
return amount * 24 * 60 * 60_000;
|
|
762
|
+
default:
|
|
763
|
+
throw new Error(`invalid duration: ${value}`);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
651
766
|
function normalizeHelpArgs(args) {
|
|
652
767
|
if (args[0] !== "help") {
|
|
653
768
|
return args;
|
|
@@ -762,6 +877,7 @@ Commands:
|
|
|
762
877
|
daemon
|
|
763
878
|
source
|
|
764
879
|
agent
|
|
880
|
+
timer
|
|
765
881
|
subscription
|
|
766
882
|
inbox
|
|
767
883
|
gc
|
|
@@ -805,9 +921,20 @@ Usage:
|
|
|
805
921
|
agentinbox agent current
|
|
806
922
|
agentinbox agent show <agentId>
|
|
807
923
|
agentinbox agent remove <agentId>
|
|
924
|
+
agentinbox agent resume <agentId>
|
|
808
925
|
agentinbox agent target add webhook <agentId> --url URL [--activation-mode MODE] [--notify-lease-ms N]
|
|
809
926
|
agentinbox agent target list <agentId>
|
|
810
927
|
agentinbox agent target remove <agentId> <targetId>
|
|
928
|
+
agentinbox agent target resume <agentId> <targetId>
|
|
929
|
+
`,
|
|
930
|
+
timer: `agentinbox timer
|
|
931
|
+
|
|
932
|
+
Usage:
|
|
933
|
+
agentinbox timer add --agent-id ID (--at ISO8601 | --every DURATION | --cron EXPR) --message TEXT [--timezone TZ] [--sender SENDER]
|
|
934
|
+
agentinbox timer list [--agent-id ID]
|
|
935
|
+
agentinbox timer pause <scheduleId>
|
|
936
|
+
agentinbox timer resume <scheduleId>
|
|
937
|
+
agentinbox timer remove <scheduleId>
|
|
811
938
|
`,
|
|
812
939
|
subscription: `agentinbox subscription
|
|
813
940
|
|
|
@@ -826,6 +953,7 @@ Usage:
|
|
|
826
953
|
agentinbox inbox list
|
|
827
954
|
agentinbox inbox show <agentId>
|
|
828
955
|
agentinbox inbox read [--agent-id ID] [--after-item ID] [--include-acked]
|
|
956
|
+
agentinbox inbox send --agent-id ID --message TEXT [--sender SENDER]
|
|
829
957
|
agentinbox inbox watch [--agent-id ID] [--after-item ID] [--include-acked] [--heartbeat-ms N]
|
|
830
958
|
agentinbox inbox ack [--agent-id ID] (--through <itemId> | --item <itemId> | --all)
|
|
831
959
|
agentinbox inbox compact <agentId>
|
package/dist/src/daemon.js
CHANGED
|
@@ -15,6 +15,7 @@ const node_child_process_1 = require("node:child_process");
|
|
|
15
15
|
const client_1 = require("./client");
|
|
16
16
|
const paths_1 = require("./paths");
|
|
17
17
|
const START_TIMEOUT_MS = 15_000;
|
|
18
|
+
const PACKAGE_VERSION = readOwnPackageVersion();
|
|
18
19
|
async function ensureDaemonForClient(options = {}) {
|
|
19
20
|
const transport = resolveDaemonClientTransport(options);
|
|
20
21
|
if (options.noAutoStart || transport.kind !== "socket") {
|
|
@@ -95,14 +96,23 @@ async function daemonStatus(options = {}) {
|
|
|
95
96
|
return {
|
|
96
97
|
running: false,
|
|
97
98
|
pid: null,
|
|
99
|
+
version: null,
|
|
100
|
+
startedAt: null,
|
|
101
|
+
command: null,
|
|
102
|
+
nodeVersion: null,
|
|
98
103
|
pidPath,
|
|
99
104
|
logPath,
|
|
100
105
|
transport,
|
|
101
106
|
};
|
|
102
107
|
}
|
|
108
|
+
const processInfo = pid == null ? null : readProcessMetadata(pid);
|
|
103
109
|
return {
|
|
104
110
|
running: await canReachHealthz(transport),
|
|
105
111
|
pid,
|
|
112
|
+
version: pid == null ? null : PACKAGE_VERSION,
|
|
113
|
+
startedAt: processInfo?.startedAt ?? null,
|
|
114
|
+
command: processInfo?.command ?? null,
|
|
115
|
+
nodeVersion: processInfo?.nodeVersion ?? null,
|
|
106
116
|
pidPath,
|
|
107
117
|
logPath,
|
|
108
118
|
transport,
|
|
@@ -179,6 +189,24 @@ async function canReachHealthz(transport) {
|
|
|
179
189
|
return false;
|
|
180
190
|
}
|
|
181
191
|
}
|
|
192
|
+
function readOwnPackageVersion() {
|
|
193
|
+
const candidatePaths = [
|
|
194
|
+
node_path_1.default.join(__dirname, "..", "package.json"),
|
|
195
|
+
node_path_1.default.join(__dirname, "..", "..", "package.json"),
|
|
196
|
+
];
|
|
197
|
+
for (const candidate of candidatePaths) {
|
|
198
|
+
try {
|
|
199
|
+
const parsed = JSON.parse(node_fs_1.default.readFileSync(candidate, "utf8"));
|
|
200
|
+
if (typeof parsed.version === "string" && parsed.version.length > 0) {
|
|
201
|
+
return parsed.version;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
182
210
|
async function waitForHealthz(transport, timeoutMs) {
|
|
183
211
|
const startedAt = Date.now();
|
|
184
212
|
while (Date.now() - startedAt < timeoutMs) {
|
|
@@ -222,6 +250,47 @@ function readPidFile(pidPath) {
|
|
|
222
250
|
return null;
|
|
223
251
|
}
|
|
224
252
|
}
|
|
253
|
+
function readProcessMetadata(pid) {
|
|
254
|
+
try {
|
|
255
|
+
const output = (0, node_child_process_1.execFileSync)("ps", ["-o", "lstart=", "-o", "command=", "-p", String(pid)], {
|
|
256
|
+
encoding: "utf8",
|
|
257
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
258
|
+
}).trimEnd();
|
|
259
|
+
if (!output) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
const firstNonSpace = output.search(/\S/);
|
|
263
|
+
if (firstNonSpace < 0) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
const trimmed = output.slice(firstNonSpace);
|
|
267
|
+
const match = trimmed.match(/^([A-Z][a-z]{2}\s+[A-Z][a-z]{2}\s+\d{1,2}\s+\d\d:\d\d:\d\d\s+\d{4})\s+(.*)$/);
|
|
268
|
+
if (!match) {
|
|
269
|
+
return {
|
|
270
|
+
startedAt: null,
|
|
271
|
+
command: trimmed,
|
|
272
|
+
nodeVersion: inferNodeVersionFromCommand(trimmed),
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
const [, startedAtRaw, command] = match;
|
|
276
|
+
const startedAtMs = Date.parse(startedAtRaw);
|
|
277
|
+
return {
|
|
278
|
+
startedAt: Number.isNaN(startedAtMs) ? null : new Date(startedAtMs).toISOString(),
|
|
279
|
+
command: command || null,
|
|
280
|
+
nodeVersion: inferNodeVersionFromCommand(command),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function inferNodeVersionFromCommand(command) {
|
|
288
|
+
if (!command) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
const match = command.match(/node\/(v\d+\.\d+\.\d+)\//);
|
|
292
|
+
return match ? match[1] : null;
|
|
293
|
+
}
|
|
225
294
|
function isProcessAlive(pid) {
|
|
226
295
|
try {
|
|
227
296
|
process.kill(pid, 0);
|
package/dist/src/http.js
CHANGED
|
@@ -419,6 +419,7 @@ function buildFastifyServer(service) {
|
|
|
419
419
|
backend: { type: "string", minLength: 1 },
|
|
420
420
|
runtimeKind: { type: "string" },
|
|
421
421
|
runtimeSessionId: { type: "string" },
|
|
422
|
+
runtimePid: { type: "integer", minimum: 1 },
|
|
422
423
|
tmuxPaneId: { type: "string" },
|
|
423
424
|
tty: { type: "string" },
|
|
424
425
|
termProgram: { type: "string" },
|
|
@@ -439,6 +440,7 @@ function buildFastifyServer(service) {
|
|
|
439
440
|
backend: String(body.backend),
|
|
440
441
|
runtimeKind: optionalString(body.runtimeKind),
|
|
441
442
|
runtimeSessionId: optionalString(body.runtimeSessionId),
|
|
443
|
+
runtimePid: typeof body.runtimePid === "number" ? body.runtimePid : null,
|
|
442
444
|
mode: "agent_prompt",
|
|
443
445
|
tmuxPaneId: optionalString(body.tmuxPaneId),
|
|
444
446
|
tty: optionalString(body.tty),
|
|
@@ -485,6 +487,24 @@ function buildFastifyServer(service) {
|
|
|
485
487
|
const params = request.params;
|
|
486
488
|
return service.removeAgent(decodeURIComponent(params.agentId));
|
|
487
489
|
});
|
|
490
|
+
app.post("/agents/:agentId/resume", {
|
|
491
|
+
schema: {
|
|
492
|
+
tags: ["agents"],
|
|
493
|
+
params: {
|
|
494
|
+
type: "object",
|
|
495
|
+
required: ["agentId"],
|
|
496
|
+
properties: {
|
|
497
|
+
agentId: { type: "string", minLength: 1 },
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
response: {
|
|
501
|
+
200: jsonObjectSchema,
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
}, async (request) => {
|
|
505
|
+
const params = request.params;
|
|
506
|
+
return service.resumeAgent(decodeURIComponent(params.agentId));
|
|
507
|
+
});
|
|
488
508
|
app.get("/agents/:agentId/targets", {
|
|
489
509
|
schema: {
|
|
490
510
|
tags: ["agents"],
|
|
@@ -563,6 +583,142 @@ function buildFastifyServer(service) {
|
|
|
563
583
|
const params = request.params;
|
|
564
584
|
return service.removeActivationTarget(decodeURIComponent(params.agentId), decodeURIComponent(params.targetId));
|
|
565
585
|
});
|
|
586
|
+
app.post("/agents/:agentId/targets/:targetId/resume", {
|
|
587
|
+
schema: {
|
|
588
|
+
tags: ["agents"],
|
|
589
|
+
params: {
|
|
590
|
+
type: "object",
|
|
591
|
+
required: ["agentId", "targetId"],
|
|
592
|
+
properties: {
|
|
593
|
+
agentId: { type: "string", minLength: 1 },
|
|
594
|
+
targetId: { type: "string", minLength: 1 },
|
|
595
|
+
},
|
|
596
|
+
},
|
|
597
|
+
response: {
|
|
598
|
+
200: jsonObjectSchema,
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
}, async (request) => {
|
|
602
|
+
const params = request.params;
|
|
603
|
+
return service.resumeActivationTarget(decodeURIComponent(params.agentId), decodeURIComponent(params.targetId));
|
|
604
|
+
});
|
|
605
|
+
app.get("/timers", {
|
|
606
|
+
schema: {
|
|
607
|
+
tags: ["timers"],
|
|
608
|
+
querystring: {
|
|
609
|
+
type: "object",
|
|
610
|
+
additionalProperties: false,
|
|
611
|
+
properties: {
|
|
612
|
+
agent_id: { type: "string" },
|
|
613
|
+
},
|
|
614
|
+
},
|
|
615
|
+
response: {
|
|
616
|
+
200: {
|
|
617
|
+
type: "object",
|
|
618
|
+
required: ["timers"],
|
|
619
|
+
properties: {
|
|
620
|
+
timers: { type: "array", items: jsonObjectSchema },
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
}, async (request) => {
|
|
626
|
+
const query = request.query;
|
|
627
|
+
return { timers: service.listTimers(query.agent_id) };
|
|
628
|
+
});
|
|
629
|
+
app.post("/timers", {
|
|
630
|
+
schema: {
|
|
631
|
+
tags: ["timers"],
|
|
632
|
+
body: {
|
|
633
|
+
type: "object",
|
|
634
|
+
additionalProperties: false,
|
|
635
|
+
required: ["agentId", "message"],
|
|
636
|
+
properties: {
|
|
637
|
+
agentId: { type: "string", minLength: 1 },
|
|
638
|
+
at: { type: "string", minLength: 1 },
|
|
639
|
+
every: { type: "integer", minimum: 60000 },
|
|
640
|
+
cron: { type: "string", minLength: 1 },
|
|
641
|
+
timezone: { type: "string", minLength: 1 },
|
|
642
|
+
message: { type: "string", minLength: 1 },
|
|
643
|
+
sender: { type: "string", minLength: 1 },
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
response: {
|
|
647
|
+
200: jsonObjectSchema,
|
|
648
|
+
400: errorResponseSchema,
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
}, async (request) => {
|
|
652
|
+
const body = request.body;
|
|
653
|
+
return service.registerTimer({
|
|
654
|
+
agentId: String(body.agentId),
|
|
655
|
+
at: optionalString(body.at) ?? null,
|
|
656
|
+
every: typeof body.every === "number" ? body.every : null,
|
|
657
|
+
cron: optionalString(body.cron) ?? null,
|
|
658
|
+
timezone: optionalString(body.timezone) ?? null,
|
|
659
|
+
message: String(body.message),
|
|
660
|
+
sender: optionalString(body.sender) ?? null,
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
app.post("/timers/:scheduleId/pause", {
|
|
664
|
+
schema: {
|
|
665
|
+
tags: ["timers"],
|
|
666
|
+
params: {
|
|
667
|
+
type: "object",
|
|
668
|
+
required: ["scheduleId"],
|
|
669
|
+
properties: {
|
|
670
|
+
scheduleId: { type: "string", minLength: 1 },
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
response: {
|
|
674
|
+
200: jsonObjectSchema,
|
|
675
|
+
400: errorResponseSchema,
|
|
676
|
+
404: errorResponseSchema,
|
|
677
|
+
},
|
|
678
|
+
},
|
|
679
|
+
}, async (request) => {
|
|
680
|
+
const params = request.params;
|
|
681
|
+
return service.pauseTimer(decodeURIComponent(params.scheduleId));
|
|
682
|
+
});
|
|
683
|
+
app.post("/timers/:scheduleId/resume", {
|
|
684
|
+
schema: {
|
|
685
|
+
tags: ["timers"],
|
|
686
|
+
params: {
|
|
687
|
+
type: "object",
|
|
688
|
+
required: ["scheduleId"],
|
|
689
|
+
properties: {
|
|
690
|
+
scheduleId: { type: "string", minLength: 1 },
|
|
691
|
+
},
|
|
692
|
+
},
|
|
693
|
+
response: {
|
|
694
|
+
200: jsonObjectSchema,
|
|
695
|
+
400: errorResponseSchema,
|
|
696
|
+
404: errorResponseSchema,
|
|
697
|
+
},
|
|
698
|
+
},
|
|
699
|
+
}, async (request) => {
|
|
700
|
+
const params = request.params;
|
|
701
|
+
return service.resumeTimer(decodeURIComponent(params.scheduleId));
|
|
702
|
+
});
|
|
703
|
+
app.delete("/timers/:scheduleId", {
|
|
704
|
+
schema: {
|
|
705
|
+
tags: ["timers"],
|
|
706
|
+
params: {
|
|
707
|
+
type: "object",
|
|
708
|
+
required: ["scheduleId"],
|
|
709
|
+
properties: {
|
|
710
|
+
scheduleId: { type: "string", minLength: 1 },
|
|
711
|
+
},
|
|
712
|
+
},
|
|
713
|
+
response: {
|
|
714
|
+
200: jsonObjectSchema,
|
|
715
|
+
404: errorResponseSchema,
|
|
716
|
+
},
|
|
717
|
+
},
|
|
718
|
+
}, async (request) => {
|
|
719
|
+
const params = request.params;
|
|
720
|
+
return service.removeTimer(decodeURIComponent(params.scheduleId));
|
|
721
|
+
});
|
|
566
722
|
app.get("/subscriptions", {
|
|
567
723
|
schema: {
|
|
568
724
|
tags: ["subscriptions"],
|
|
@@ -812,6 +968,39 @@ function buildFastifyServer(service) {
|
|
|
812
968
|
}),
|
|
813
969
|
};
|
|
814
970
|
});
|
|
971
|
+
app.post("/agents/:agentId/inbox/items", {
|
|
972
|
+
schema: {
|
|
973
|
+
tags: ["inbox"],
|
|
974
|
+
params: {
|
|
975
|
+
type: "object",
|
|
976
|
+
required: ["agentId"],
|
|
977
|
+
properties: {
|
|
978
|
+
agentId: { type: "string", minLength: 1 },
|
|
979
|
+
},
|
|
980
|
+
},
|
|
981
|
+
body: {
|
|
982
|
+
type: "object",
|
|
983
|
+
additionalProperties: false,
|
|
984
|
+
required: ["message"],
|
|
985
|
+
properties: {
|
|
986
|
+
message: { type: "string", minLength: 1 },
|
|
987
|
+
sender: { type: "string", minLength: 1 },
|
|
988
|
+
},
|
|
989
|
+
},
|
|
990
|
+
response: {
|
|
991
|
+
200: jsonObjectSchema,
|
|
992
|
+
400: errorResponseSchema,
|
|
993
|
+
404: errorResponseSchema,
|
|
994
|
+
},
|
|
995
|
+
},
|
|
996
|
+
}, async (request) => {
|
|
997
|
+
const params = request.params;
|
|
998
|
+
const body = request.body;
|
|
999
|
+
return service.addDirectInboxTextMessage(decodeURIComponent(params.agentId), {
|
|
1000
|
+
message: body.message,
|
|
1001
|
+
sender: body.sender ?? null,
|
|
1002
|
+
});
|
|
1003
|
+
});
|
|
815
1004
|
app.get("/agents/:agentId/inbox/watch", {
|
|
816
1005
|
schema: {
|
|
817
1006
|
tags: ["inbox"],
|
|
@@ -1060,7 +1249,11 @@ function normalizeValidationMessage(message) {
|
|
|
1060
1249
|
return message;
|
|
1061
1250
|
}
|
|
1062
1251
|
function isBadRequestError(message) {
|
|
1063
|
-
return (message.startsWith("
|
|
1252
|
+
return (message.startsWith("direct inbox ") ||
|
|
1253
|
+
message.startsWith("timers require ") ||
|
|
1254
|
+
message.startsWith("timer ") ||
|
|
1255
|
+
message.startsWith("invalid timezone: ") ||
|
|
1256
|
+
message.startsWith("manual append is not supported") ||
|
|
1064
1257
|
message.startsWith("sources/events requires") ||
|
|
1065
1258
|
message.startsWith("source remove requires") ||
|
|
1066
1259
|
message.startsWith("deliveryHandle requires") ||
|