agents-relay 2.0.16 → 2.0.17
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/cli-support.js +6 -3
- package/dist/dashboard.js +2 -21
- package/dist/events-bus-runtime.js +39 -0
- package/package.json +1 -1
- package/skills/agents-relay/SKILL.md +1 -1
package/dist/cli-support.js
CHANGED
|
@@ -4,6 +4,7 @@ import { githubAuthContext } from './github-auth.js';
|
|
|
4
4
|
import { NatsEventBus, eventFor } from './events.js';
|
|
5
5
|
import { parseJobSchedule } from './scheduler.js';
|
|
6
6
|
import { parseJobTagJson } from './task-tag.js';
|
|
7
|
+
import { resolveEventsBusRuntime } from './events-bus-runtime.js';
|
|
7
8
|
export const SERVICE_DEFAULTS = { port: 8787, watchdogMs: 300000, webhookWatchdogMs: 300000, dashboardRefreshMs: 300000, projectionFlushMs: 1000 };
|
|
8
9
|
export class ServiceEventBus {
|
|
9
10
|
upstream;
|
|
@@ -101,19 +102,21 @@ export async function relayTaskCommand(args, body) {
|
|
|
101
102
|
export async function resolveEventBus(args, probe) {
|
|
102
103
|
const explicit = hasArg(args, '--events');
|
|
103
104
|
const requested = arg(args, '--events');
|
|
104
|
-
const
|
|
105
|
+
const runtime = resolveEventsBusRuntime();
|
|
106
|
+
const natsUrl = arg(args, '--nats-url', runtime.natsUrl);
|
|
105
107
|
if (!explicit && hasArg(args, '--file'))
|
|
106
108
|
return { bus: undefined, transport: 'none', source: 'local', natsUrl };
|
|
107
109
|
if (explicit && requested !== 'nats')
|
|
108
110
|
return { bus: undefined, transport: 'none', source: 'explicit', natsUrl };
|
|
109
|
-
const
|
|
111
|
+
const subjectPrefix = arg(args, '--subject-prefix', runtime.subjectPrefix);
|
|
112
|
+
const bus = new NatsEventBus(natsUrl, subjectPrefix);
|
|
110
113
|
if (explicit)
|
|
111
114
|
return { bus, transport: 'nats', source: 'explicit', natsUrl };
|
|
112
115
|
const reachable = probe ? await probe(bus) : await bus.ping().then(() => true, () => false);
|
|
113
116
|
await bus.close().catch(() => undefined);
|
|
114
117
|
if (!reachable)
|
|
115
118
|
return { bus: undefined, transport: 'none', source: 'unavailable', natsUrl };
|
|
116
|
-
return { bus: new NatsEventBus(natsUrl,
|
|
119
|
+
return { bus: new NatsEventBus(natsUrl, subjectPrefix), transport: 'nats', source: 'auto', natsUrl };
|
|
117
120
|
}
|
|
118
121
|
export function eventBusResolutionMessage(resolution) {
|
|
119
122
|
if (resolution.transport === 'nats')
|
package/dist/dashboard.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createServer } from 'node:http';
|
|
2
2
|
import { readFile, readdir } from 'node:fs/promises';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
3
|
import { join } from 'node:path';
|
|
5
4
|
import { fileURLToPath } from 'node:url';
|
|
6
5
|
import { readUsageSnapshot } from './usage.js';
|
|
@@ -8,9 +7,9 @@ import { deriveJobRuntimeStatus } from './runtime-status.js';
|
|
|
8
7
|
import { DeliveryDeduper, parseGitHubWebhook, verifyGitHubWebhook } from './github-webhook.js';
|
|
9
8
|
import { loadExecutionRouterRules, saveExecutionRouterRules } from './routing-policy.js';
|
|
10
9
|
import { summarizeRuntime } from './runtime-summary.js';
|
|
10
|
+
import { eventsBusHistory } from './events-bus-runtime.js';
|
|
11
11
|
const GITHUB_REPOSITORY_PATTERN = /^([A-Za-z0-9](?:[A-Za-z0-9-]{0,36}[A-Za-z0-9])?)\/([A-Za-z0-9._-]{1,100})$/;
|
|
12
12
|
const SSE_HEARTBEAT_MS = 15000;
|
|
13
|
-
const EVENTS_HISTORY_FILE = process.env.EVENTS_BUS_DATA_DIR ? join(process.env.EVENTS_BUS_DATA_DIR, 'events.jsonl') : join(homedir(), 'Library', 'Application Support', 'EventsBus', 'events.jsonl');
|
|
14
13
|
const WORKFLOW_DIR = fileURLToPath(new URL('../workflow/', import.meta.url));
|
|
15
14
|
export async function dashboardWorkflowGraphs() {
|
|
16
15
|
const names = (await readdir(WORKFLOW_DIR)).filter(name => name.endsWith('.mmd')).sort();
|
|
@@ -49,30 +48,12 @@ export function githubPrUrl(repository, prNumber) {
|
|
|
49
48
|
return `https://github.com/${owner}/${repo}/pull/${prNumber}`;
|
|
50
49
|
}
|
|
51
50
|
async function eventHistory(jobId, taskId, limit) {
|
|
52
|
-
const boundedLimit = Math.max(1, Math.min(60, limit));
|
|
53
|
-
let content = '';
|
|
54
51
|
try {
|
|
55
|
-
|
|
52
|
+
return await eventsBusHistory(jobId, taskId, limit);
|
|
56
53
|
}
|
|
57
54
|
catch {
|
|
58
55
|
return [];
|
|
59
56
|
}
|
|
60
|
-
const output = [];
|
|
61
|
-
const lines = content.split(/\r?\n/);
|
|
62
|
-
for (let index = lines.length - 1; index >= 0 && output.length < boundedLimit; index -= 1) {
|
|
63
|
-
const line = lines[index];
|
|
64
|
-
if (!line)
|
|
65
|
-
continue;
|
|
66
|
-
try {
|
|
67
|
-
const row = JSON.parse(line);
|
|
68
|
-
const event = row.event;
|
|
69
|
-
if (!event || event.job_id !== jobId || (taskId && event.task_id !== taskId))
|
|
70
|
-
continue;
|
|
71
|
-
output.push(event);
|
|
72
|
-
}
|
|
73
|
-
catch { /* ignore malformed historical rows */ }
|
|
74
|
-
}
|
|
75
|
-
return output;
|
|
76
57
|
}
|
|
77
58
|
export { dashboardHtml, dashboardVersion } from './dashboard-html.js';
|
|
78
59
|
import { dashboardHtml, dashboardVersion } from './dashboard-html.js';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
export function eventsBusConfigPath(env = process.env) {
|
|
5
|
+
if (env.NEO_EVENTS_BUS_CONFIG)
|
|
6
|
+
return env.NEO_EVENTS_BUS_CONFIG;
|
|
7
|
+
const dataDir = env.EVENTS_BUS_DATA_DIR || join(homedir(), 'Library', 'Application Support', 'EventsBus');
|
|
8
|
+
return join(dataDir, 'runtime.json');
|
|
9
|
+
}
|
|
10
|
+
export function resolveEventsBusRuntime(env = process.env) {
|
|
11
|
+
const configPath = eventsBusConfigPath(env);
|
|
12
|
+
let saved = {};
|
|
13
|
+
try {
|
|
14
|
+
saved = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
15
|
+
}
|
|
16
|
+
catch { /* fall through to protocol defaults */ }
|
|
17
|
+
return {
|
|
18
|
+
configPath,
|
|
19
|
+
natsUrl: env.NEO_NATS_URL || String(saved.natsUrl || 'nats://127.0.0.1:4222'),
|
|
20
|
+
apiUrl: env.NEO_EVENTS_API_URL || String(saved.apiUrl || 'http://127.0.0.1:4223'),
|
|
21
|
+
subjectPrefix: env.NEO_EVENTS_SUBJECT_PREFIX || String(saved.subjectPrefix || 'neo.events.job'),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export async function eventsBusHistory(jobId, taskId, limit, env = process.env) {
|
|
25
|
+
const runtime = resolveEventsBusRuntime(env);
|
|
26
|
+
const url = new URL('/events', runtime.apiUrl);
|
|
27
|
+
url.searchParams.set('job', jobId);
|
|
28
|
+
if (taskId)
|
|
29
|
+
url.searchParams.set('task', taskId);
|
|
30
|
+
const boundedLimit = Math.max(1, Math.min(60, limit));
|
|
31
|
+
url.searchParams.set('limit', String(boundedLimit));
|
|
32
|
+
url.searchParams.set('order', 'desc');
|
|
33
|
+
const response = await fetch(url);
|
|
34
|
+
if (!response.ok)
|
|
35
|
+
throw new Error(`events-bus history unavailable: HTTP ${response.status}`);
|
|
36
|
+
const body = await response.json();
|
|
37
|
+
const rows = Array.isArray(body.events) ? body.events : [];
|
|
38
|
+
return rows.map(row => row.event).filter((event) => Boolean(event));
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -41,7 +41,7 @@ A running agent MUST use the canonical Neo `events-bus` protocol and publish exa
|
|
|
41
41
|
- `task.failed` when the task cannot complete;
|
|
42
42
|
- `task.blocked` when external or human action is required.
|
|
43
43
|
|
|
44
|
-
Event publishing is not an Agents Relay CLI responsibility. Sandboxed Codex and hosted ChatGPT workers use the federated `events__publish` MCP tool from `events-bus`; direct non-sandbox local workers may use the caller-provided `NEO_EVENTS_EMIT`. Agents Relay subscribes to the canonical `neo.events.job.<job_id>.>` stream and maps terminal events into durable task state.
|
|
44
|
+
Event publishing is not an Agents Relay CLI responsibility. Sandboxed Codex and hosted ChatGPT workers use the federated `events__publish` MCP tool from `events-bus`; direct non-sandbox local workers may use the caller-provided `NEO_EVENTS_EMIT`. Agents Relay subscribes to the canonical `neo.events.job.<job_id>.>` stream and maps terminal events into durable task state. Relay resolves its native NATS endpoint and subject prefix from the canonical events-bus runtime configuration (with explicit Relay CLI flags remaining authoritative). The same runtime configuration supplies the events-bus HTTP API used for replay/history. Relay and its dashboard must not read the events-bus private history file or maintain a second event-history backend.
|
|
45
45
|
|
|
46
46
|
The event must carry the exact durable `job_id` and `task_id`. Progress events are optional.
|
|
47
47
|
|