@mce-bt/microagents-communication 0.1.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/dist/auth.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Generate an HMAC signature for a request.
3
+ */
4
+ export declare function signRequest(sharedSecret: string, payload: string, timestamp: string): string;
5
+ /**
6
+ * Verify an HMAC signature from a request.
7
+ * Uses timing-safe comparison to prevent timing attacks.
8
+ */
9
+ export declare function verifySignature(sharedSecret: string, payload: string, timestamp: string, signature: string): boolean;
10
+ /**
11
+ * Verify a signature against multiple secrets (supports secret rotation).
12
+ * Returns true if ANY secret produces a valid signature.
13
+ */
14
+ export declare function verifySignatureWithRotation(secrets: string[], payload: string, timestamp: string, signature: string): boolean;
15
+ /**
16
+ * Check that a request timestamp is within an acceptable window (default: 5 minutes).
17
+ */
18
+ export declare function isTimestampValid(timestamp: string, windowMs?: number): boolean;
19
+ /**
20
+ * Sanitize a string input by removing control characters and null bytes.
21
+ * Preserves normal whitespace (spaces, tabs, newlines).
22
+ */
23
+ export declare function sanitizeString(input: string): string;
24
+ /**
25
+ * Deep-sanitize an object: recursively sanitize all string values.
26
+ */
27
+ export declare function sanitizeInput<T>(input: T): T;
28
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,WAAW,CACzB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,MAAM,CAGR;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAQT;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAET;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAM7F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAe5C"}
package/dist/auth.js ADDED
@@ -0,0 +1,65 @@
1
+ import { createHmac, timingSafeEqual } from 'node:crypto';
2
+ const HMAC_ALGORITHM = 'sha256';
3
+ /**
4
+ * Generate an HMAC signature for a request.
5
+ */
6
+ export function signRequest(sharedSecret, payload, timestamp) {
7
+ const data = `${timestamp}.${payload}`;
8
+ return createHmac(HMAC_ALGORITHM, sharedSecret).update(data).digest('hex');
9
+ }
10
+ /**
11
+ * Verify an HMAC signature from a request.
12
+ * Uses timing-safe comparison to prevent timing attacks.
13
+ */
14
+ export function verifySignature(sharedSecret, payload, timestamp, signature) {
15
+ const expected = signRequest(sharedSecret, payload, timestamp);
16
+ if (expected.length !== signature.length) {
17
+ return false;
18
+ }
19
+ return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
20
+ }
21
+ /**
22
+ * Verify a signature against multiple secrets (supports secret rotation).
23
+ * Returns true if ANY secret produces a valid signature.
24
+ */
25
+ export function verifySignatureWithRotation(secrets, payload, timestamp, signature) {
26
+ return secrets.some((secret) => verifySignature(secret, payload, timestamp, signature));
27
+ }
28
+ /**
29
+ * Check that a request timestamp is within an acceptable window (default: 5 minutes).
30
+ */
31
+ export function isTimestampValid(timestamp, windowMs = 5 * 60 * 1000) {
32
+ const ts = parseInt(timestamp, 10);
33
+ if (isNaN(ts))
34
+ return false;
35
+ const now = Date.now();
36
+ return Math.abs(now - ts) <= windowMs;
37
+ }
38
+ /**
39
+ * Sanitize a string input by removing control characters and null bytes.
40
+ * Preserves normal whitespace (spaces, tabs, newlines).
41
+ */
42
+ export function sanitizeString(input) {
43
+ // Remove null bytes and control characters except \t, \n, \r
44
+ return input.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
45
+ }
46
+ /**
47
+ * Deep-sanitize an object: recursively sanitize all string values.
48
+ */
49
+ export function sanitizeInput(input) {
50
+ if (typeof input === 'string') {
51
+ return sanitizeString(input);
52
+ }
53
+ if (Array.isArray(input)) {
54
+ return input.map(sanitizeInput);
55
+ }
56
+ if (input !== null && typeof input === 'object') {
57
+ const result = {};
58
+ for (const [key, value] of Object.entries(input)) {
59
+ result[sanitizeString(key)] = sanitizeInput(value);
60
+ }
61
+ return result;
62
+ }
63
+ return input;
64
+ }
65
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,cAAc,GAAG,QAAQ,CAAC;AAEhC;;GAEG;AACH,MAAM,UAAU,WAAW,CACzB,YAAoB,EACpB,OAAe,EACf,SAAiB;IAEjB,MAAM,IAAI,GAAG,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC;IACvC,OAAO,UAAU,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,YAAoB,EACpB,OAAe,EACf,SAAiB,EACjB,SAAiB;IAEjB,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAY,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAE/D,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAiB,EACjB,OAAe,EACf,SAAiB,EACjB,SAAiB;IAEjB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,WAAmB,CAAC,GAAG,EAAE,GAAG,IAAI;IAClF,MAAM,EAAE,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAE5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,IAAI,QAAQ,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,6DAA6D;IAC7D,OAAO,KAAK,CAAC,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC,CAAC;AAChE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAI,KAAQ;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,cAAc,CAAC,KAAK,CAAM,CAAC;IACpC,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,aAAa,CAAM,CAAC;IACvC,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;YAC5E,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,MAAW,CAAC;IACrB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { type RetryOptions, type CircuitBreakerOptions } from './resilience.js';
2
+ export interface HttpClientConfig {
3
+ agentId: string;
4
+ sharedSecret: string;
5
+ timeoutMs?: number;
6
+ /** Retry options for transient failures (default: 3 retries with backoff) */
7
+ retry?: RetryOptions;
8
+ /** Circuit breaker options */
9
+ circuitBreaker?: CircuitBreakerOptions;
10
+ }
11
+ export declare class HttpResponseError extends Error {
12
+ readonly statusCode: number;
13
+ readonly body: string;
14
+ constructor(statusCode: number, body: string);
15
+ }
16
+ /**
17
+ * HTTP client for inter-agent communication.
18
+ * Signs all requests with the shared secret for authentication.
19
+ * Includes retry with exponential backoff and circuit breaker.
20
+ */
21
+ export declare class HttpClient {
22
+ private config;
23
+ private breaker;
24
+ constructor(config: HttpClientConfig);
25
+ request<T = unknown>(url: string, options?: {
26
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
27
+ body?: unknown;
28
+ headers?: Record<string, string>;
29
+ }): Promise<T>;
30
+ private doRequest;
31
+ /** Get the current circuit breaker state */
32
+ getCircuitState(): import("./resilience.js").CircuitState;
33
+ }
34
+ //# sourceMappingURL=http-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,YAAY,EAAE,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAEvG,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,8BAA8B;IAC9B,cAAc,CAAC,EAAE,qBAAqB,CAAC;CACxC;AAaD,qBAAa,iBAAkB,SAAQ,KAAK;aAExB,UAAU,EAAE,MAAM;aAClB,IAAI,EAAE,MAAM;gBADZ,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM;CAK/B;AAED;;;;GAIG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,OAAO,CAAiB;gBAEpB,MAAM,EAAE,gBAAgB;IAK9B,OAAO,CAAC,CAAC,GAAG,OAAO,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;QACP,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;QAC3C,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC7B,GACL,OAAO,CAAC,CAAC,CAAC;YAcC,SAAS;IA2CvB,4CAA4C;IAC5C,eAAe;CAGhB"}
@@ -0,0 +1,84 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { signRequest } from './auth.js';
3
+ import { retry, CircuitBreaker } from './resilience.js';
4
+ /** Errors considered transient and safe to retry */
5
+ function isTransientError(error) {
6
+ if (error instanceof DOMException && error.name === 'AbortError')
7
+ return true;
8
+ if (error instanceof TypeError)
9
+ return true; // fetch network errors
10
+ if (error instanceof HttpResponseError) {
11
+ const code = error.statusCode;
12
+ return code === 429 || code === 502 || code === 503 || code === 504;
13
+ }
14
+ return false;
15
+ }
16
+ export class HttpResponseError extends Error {
17
+ statusCode;
18
+ body;
19
+ constructor(statusCode, body) {
20
+ super(`HTTP ${statusCode}: ${body}`);
21
+ this.statusCode = statusCode;
22
+ this.body = body;
23
+ this.name = 'HttpResponseError';
24
+ }
25
+ }
26
+ /**
27
+ * HTTP client for inter-agent communication.
28
+ * Signs all requests with the shared secret for authentication.
29
+ * Includes retry with exponential backoff and circuit breaker.
30
+ */
31
+ export class HttpClient {
32
+ config;
33
+ breaker;
34
+ constructor(config) {
35
+ this.config = config;
36
+ this.breaker = new CircuitBreaker(config.circuitBreaker);
37
+ }
38
+ async request(url, options = {}) {
39
+ const retryOpts = {
40
+ maxRetries: 3,
41
+ baseDelayMs: 500,
42
+ isRetryable: isTransientError,
43
+ ...this.config.retry,
44
+ };
45
+ return retry(() => this.breaker.execute(() => this.doRequest(url, options)), retryOpts);
46
+ }
47
+ async doRequest(url, options) {
48
+ const method = options.method ?? 'POST';
49
+ const body = options.body ? JSON.stringify(options.body) : '';
50
+ const timestamp = Date.now().toString();
51
+ const signature = signRequest(this.config.sharedSecret, body, timestamp);
52
+ const controller = new AbortController();
53
+ const timeout = this.config.timeoutMs ?? 30_000;
54
+ const timer = setTimeout(() => controller.abort(), timeout);
55
+ try {
56
+ const response = await fetch(url, {
57
+ method,
58
+ headers: {
59
+ 'Content-Type': 'application/json',
60
+ 'X-Agent-Id': this.config.agentId,
61
+ 'X-Signature': signature,
62
+ 'X-Timestamp': timestamp,
63
+ 'X-Correlation-Id': randomUUID(),
64
+ ...options.headers,
65
+ },
66
+ body: body || undefined,
67
+ signal: controller.signal,
68
+ });
69
+ if (!response.ok) {
70
+ const text = await response.text();
71
+ throw new HttpResponseError(response.status, text);
72
+ }
73
+ return response.json();
74
+ }
75
+ finally {
76
+ clearTimeout(timer);
77
+ }
78
+ }
79
+ /** Get the current circuit breaker state */
80
+ getCircuitState() {
81
+ return this.breaker.getState();
82
+ }
83
+ }
84
+ //# sourceMappingURL=http-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { Agent } from '@mce-bt/microagents-core';
2
+ export interface HttpServerConfig {
3
+ port: number;
4
+ host: string;
5
+ sharedSecret: string;
6
+ /** Previous shared secrets still accepted during rotation (default: []) */
7
+ previousSecrets?: string[];
8
+ /** Max request body size in bytes (default: 1MB) */
9
+ bodyLimit?: number;
10
+ /** Rate limit: max requests per window per IP (default: 100) */
11
+ rateLimitMax?: number;
12
+ /** Rate limit window in ms (default: 60_000) */
13
+ rateLimitWindowMs?: number;
14
+ /**
15
+ * Paths served WITHOUT HMAC auth, in addition to /health and /ready.
16
+ * Entries ending in '/' match as prefixes ('/wiki/' matches '/wiki/x'),
17
+ * other entries match exactly. Everything else requires a signature.
18
+ */
19
+ publicPaths?: string[];
20
+ }
21
+ /**
22
+ * HTTP server resource for an agent.
23
+ * Mounts the agent's public route handlers with shared-secret auth.
24
+ */
25
+ export declare class HttpServer {
26
+ private server;
27
+ private config;
28
+ private rateLimiter;
29
+ private pruneTimer;
30
+ constructor(config: HttpServerConfig);
31
+ start(agent: Agent): Promise<void>;
32
+ private mountRoute;
33
+ stop(): Promise<void>;
34
+ }
35
+ //# sourceMappingURL=http-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAA4C,MAAM,0BAA0B,CAAC;AAEhG,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAoCD;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,UAAU,CAA+C;gBAErD,MAAM,EAAE,gBAAgB;IAQ9B,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IA+RxC,OAAO,CAAC,UAAU;IA2BZ,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAU5B"}
@@ -0,0 +1,326 @@
1
+ import Fastify, {} from 'fastify';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { verifySignature, verifySignatureWithRotation, isTimestampValid, sanitizeInput } from './auth.js';
4
+ /** Simple in-memory sliding window rate limiter */
5
+ class RateLimiter {
6
+ windows = new Map();
7
+ max;
8
+ windowMs;
9
+ constructor(max, windowMs) {
10
+ this.max = max;
11
+ this.windowMs = windowMs;
12
+ }
13
+ check(key) {
14
+ const now = Date.now();
15
+ const entry = this.windows.get(key);
16
+ if (!entry || now >= entry.resetAt) {
17
+ this.windows.set(key, { count: 1, resetAt: now + this.windowMs });
18
+ return { allowed: true, remaining: this.max - 1, resetAt: now + this.windowMs };
19
+ }
20
+ entry.count++;
21
+ const allowed = entry.count <= this.max;
22
+ return { allowed, remaining: Math.max(0, this.max - entry.count), resetAt: entry.resetAt };
23
+ }
24
+ /** Prune expired entries to prevent memory leaks */
25
+ prune() {
26
+ const now = Date.now();
27
+ for (const [key, entry] of this.windows) {
28
+ if (now >= entry.resetAt)
29
+ this.windows.delete(key);
30
+ }
31
+ }
32
+ }
33
+ /**
34
+ * HTTP server resource for an agent.
35
+ * Mounts the agent's public route handlers with shared-secret auth.
36
+ */
37
+ export class HttpServer {
38
+ server = null;
39
+ config;
40
+ rateLimiter;
41
+ pruneTimer = null;
42
+ constructor(config) {
43
+ this.config = config;
44
+ this.rateLimiter = new RateLimiter(config.rateLimitMax ?? 100, config.rateLimitWindowMs ?? 60_000);
45
+ }
46
+ async start(agent) {
47
+ const bodyLimit = this.config.bodyLimit ?? 20_971_520; // 20MB default (supports base64-encoded media)
48
+ this.server = Fastify({
49
+ logger: false,
50
+ genReqId: () => randomUUID(),
51
+ bodyLimit,
52
+ });
53
+ // Prune rate limiter every 60s to prevent memory leaks
54
+ this.pruneTimer = setInterval(() => this.rateLimiter.prune(), 60_000);
55
+ // Health endpoint (no auth required)
56
+ this.server.get('/health', async () => {
57
+ const health = {
58
+ status: 'ok',
59
+ agentId: agent.definition.id,
60
+ agentName: agent.definition.name,
61
+ uptime: process.uptime(),
62
+ };
63
+ // Include scheduler status if available
64
+ if (agent.schedulerStatus) {
65
+ health.scheduler = agent.schedulerStatus;
66
+ }
67
+ return health;
68
+ });
69
+ // Ready endpoint (no auth required)
70
+ this.server.get('/ready', async () => ({
71
+ status: agent.state === 'running' ? 'ready' : 'not-ready',
72
+ }));
73
+ // Scheduler detail endpoint (no auth required)
74
+ this.server.get('/scheduler', async () => {
75
+ if (!agent.schedulerStatus) {
76
+ return { status: 'no-scheduler' };
77
+ }
78
+ return agent.schedulerStatus;
79
+ });
80
+ // ─── Dashboard data endpoints (no auth required) ───
81
+ // Aggregated metrics for the dashboard
82
+ this.server.get('/dashboard/metrics', async () => {
83
+ const sessions = await agent.sessionManager.list(50);
84
+ const activeSessions = agent.sessionManager.getActiveSessions();
85
+ // Completion usage — try getUsageSummary first (includes per-model/tier breakdown)
86
+ let completionUsage = null;
87
+ let callHistory = [];
88
+ try {
89
+ const completion = agent
90
+ .resources?.completion;
91
+ if (completion && typeof completion === 'object') {
92
+ if ('getUsageSummary' in completion && typeof completion.getUsageSummary === 'function') {
93
+ completionUsage = completion.getUsageSummary();
94
+ }
95
+ else if ('getUsage' in completion && typeof completion.getUsage === 'function') {
96
+ completionUsage = completion.getUsage();
97
+ }
98
+ if ('getCallHistory' in completion && typeof completion.getCallHistory === 'function') {
99
+ // Return last 100 calls
100
+ const history = completion.getCallHistory();
101
+ callHistory = history.slice(-100);
102
+ }
103
+ }
104
+ }
105
+ catch { /* completion may not support these methods */ }
106
+ return {
107
+ agent: {
108
+ id: agent.definition.id,
109
+ name: agent.definition.name,
110
+ domain: agent.definition.domain,
111
+ version: agent.definition.version,
112
+ state: agent.state,
113
+ uptime: process.uptime(),
114
+ },
115
+ scheduler: agent.schedulerStatus ?? null,
116
+ sessions: {
117
+ active: activeSessions.length,
118
+ activeIds: activeSessions,
119
+ recent: sessions.map((s) => ({
120
+ id: s.id,
121
+ startedAt: s.startedAt.toISOString(),
122
+ endedAt: s.endedAt?.toISOString() ?? null,
123
+ metadata: s.metadata ?? {},
124
+ })),
125
+ },
126
+ completion: completionUsage,
127
+ callHistory,
128
+ channels: agent
129
+ .resources?.channels?.map(ch => ({
130
+ type: ch.type,
131
+ activeChatIds: typeof ch.getActiveChatIds === 'function' ? ch.getActiveChatIds() : [],
132
+ })) ?? [],
133
+ tools: agent.toolRegistry.getAll().map((t) => ({
134
+ name: t.name,
135
+ description: t.description,
136
+ visibility: t.visibility,
137
+ })),
138
+ };
139
+ });
140
+ // Full session log for deep inspection
141
+ this.server.get('/dashboard/sessions/:sessionId', async (request) => {
142
+ const { sessionId } = request.params;
143
+ // Get session metadata
144
+ const session = await agent.sessionManager.get(sessionId);
145
+ if (!session) {
146
+ return { error: 'Session not found' };
147
+ }
148
+ // Get STM entries if memory is available
149
+ let entries = [];
150
+ try {
151
+ const memory = agent.resources?.memory;
152
+ if (memory && 'stm' in memory && memory.stm) {
153
+ entries = await memory.stm.getSessionLog(sessionId);
154
+ }
155
+ }
156
+ catch { /* memory may not be configured */ }
157
+ return {
158
+ session: {
159
+ id: session.id,
160
+ agentId: session.agentId,
161
+ startedAt: session.startedAt.toISOString(),
162
+ endedAt: session.endedAt?.toISOString() ?? null,
163
+ metadata: session.metadata ?? {},
164
+ },
165
+ entries,
166
+ };
167
+ });
168
+ // Recent log entries for dashboard
169
+ this.server.get('/dashboard/logs', async (request) => {
170
+ const { limit } = request.query ?? {};
171
+ const maxEntries = Math.min(parseInt(limit ?? '100', 10) || 100, 500);
172
+ const logBuffer = agent.resources?.logBuffer;
173
+ if (!logBuffer) {
174
+ return { logs: [], agentId: agent.definition.id, agentName: agent.definition.name };
175
+ }
176
+ return {
177
+ logs: logBuffer.getEntries(maxEntries),
178
+ agentId: agent.definition.id,
179
+ agentName: agent.definition.name,
180
+ };
181
+ });
182
+ // Rate limiting hook — applied to all requests
183
+ this.server.addHook('onRequest', async (request, reply) => {
184
+ const ip = request.ip || 'unknown';
185
+ const { allowed, remaining, resetAt } = this.rateLimiter.check(ip);
186
+ reply.header('X-RateLimit-Remaining', remaining.toString());
187
+ reply.header('X-RateLimit-Reset', Math.ceil(resetAt / 1000).toString());
188
+ if (!allowed) {
189
+ reply.code(429).send({ error: 'Too many requests' });
190
+ return;
191
+ }
192
+ });
193
+ // Shared-secret auth middleware for all other routes
194
+ // Uses preHandler (not onRequest) because request.body must be parsed first
195
+ this.server.addHook('preHandler', async (request, reply) => {
196
+ // Only /health, /ready, and explicitly configured publicPaths skip
197
+ // auth. Everything else — including /scheduler and /dashboard/* —
198
+ // requires a valid signature.
199
+ const url = request.url.split('?')[0];
200
+ const publicPaths = this.config.publicPaths ?? [];
201
+ const isPublic = url === '/health' ||
202
+ url === '/ready' ||
203
+ publicPaths.some((p) => (p.endsWith('/') ? url === p.slice(0, -1) || url.startsWith(p) : url === p));
204
+ if (isPublic) {
205
+ return;
206
+ }
207
+ const signature = request.headers['x-signature'];
208
+ const timestamp = request.headers['x-timestamp'];
209
+ const agentId = request.headers['x-agent-id'];
210
+ if (!signature || !timestamp || !agentId) {
211
+ reply.code(401).send({ error: 'Missing authentication headers' });
212
+ return;
213
+ }
214
+ if (!isTimestampValid(timestamp)) {
215
+ reply.code(401).send({ error: 'Request timestamp expired' });
216
+ return;
217
+ }
218
+ const body = typeof request.body === 'string'
219
+ ? request.body
220
+ : JSON.stringify(request.body ?? '');
221
+ const secrets = [this.config.sharedSecret, ...(this.config.previousSecrets ?? [])];
222
+ if (!verifySignatureWithRotation(secrets, body, timestamp, signature)) {
223
+ reply.code(401).send({ error: 'Invalid signature' });
224
+ return;
225
+ }
226
+ });
227
+ // Input sanitization hook — clean all incoming request bodies
228
+ this.server.addHook('preHandler', async (request) => {
229
+ if (request.body && typeof request.body === 'object') {
230
+ request.body = sanitizeInput(request.body);
231
+ }
232
+ });
233
+ // Mount agent routes
234
+ for (const handler of agent.routes) {
235
+ this.mountRoute(handler);
236
+ }
237
+ // AG-UI SSE endpoint — streams AG-UI events for a run
238
+ this.server.post('/ag-ui/runs', async (request, reply) => {
239
+ const body = request.body;
240
+ if (!body || !body.threadId || !body.runId || !body.message) {
241
+ reply.code(400).send({ error: 'Missing required fields: threadId, runId, message' });
242
+ return;
243
+ }
244
+ // Set SSE headers
245
+ reply.raw.writeHead(200, {
246
+ 'Content-Type': 'text/event-stream',
247
+ 'Cache-Control': 'no-cache',
248
+ 'Connection': 'keep-alive',
249
+ 'X-Accel-Buffering': 'no',
250
+ });
251
+ // Use or create session
252
+ const sessionId = body.sessionId ?? await agent.createSession();
253
+ try {
254
+ const eventStream = agent.agentLoop.runStream({
255
+ sessionId,
256
+ message: body.message,
257
+ tier: body.tier,
258
+ temperature: body.temperature,
259
+ maxTokens: body.maxTokens,
260
+ maxToolRounds: body.maxToolRounds,
261
+ threadId: body.threadId,
262
+ runId: body.runId,
263
+ });
264
+ for await (const event of eventStream) {
265
+ if (reply.raw.destroyed)
266
+ break;
267
+ reply.raw.write(`data: ${JSON.stringify(event)}\n\n`);
268
+ }
269
+ }
270
+ catch (err) {
271
+ const errorEvent = {
272
+ type: 'RUN_ERROR',
273
+ message: err instanceof Error ? err.message : String(err),
274
+ timestamp: new Date().toISOString(),
275
+ };
276
+ if (!reply.raw.destroyed) {
277
+ reply.raw.write(`data: ${JSON.stringify(errorEvent)}\n\n`);
278
+ }
279
+ }
280
+ finally {
281
+ if (!reply.raw.destroyed) {
282
+ reply.raw.end();
283
+ }
284
+ }
285
+ });
286
+ await this.server.listen({
287
+ port: this.config.port,
288
+ host: this.config.host,
289
+ });
290
+ }
291
+ mountRoute(handler) {
292
+ if (!this.server)
293
+ return;
294
+ const path = handler.url.startsWith('/') ? handler.url : `/${handler.url}`;
295
+ this.server.route({
296
+ method: handler.method.toUpperCase(),
297
+ url: path,
298
+ handler: async (request, reply) => {
299
+ // Validate input if schema is provided
300
+ if (handler.schema) {
301
+ const input = handler.method === 'get' ? request.query : request.body;
302
+ const result = handler.schema.safeParse(input);
303
+ if (!result.success) {
304
+ reply.code(400).send({
305
+ error: 'Validation failed',
306
+ details: result.error.issues,
307
+ });
308
+ return;
309
+ }
310
+ }
311
+ return handler.callback(request, reply);
312
+ },
313
+ });
314
+ }
315
+ async stop() {
316
+ if (this.pruneTimer) {
317
+ clearInterval(this.pruneTimer);
318
+ this.pruneTimer = null;
319
+ }
320
+ if (this.server) {
321
+ await this.server.close();
322
+ this.server = null;
323
+ }
324
+ }
325
+ }
326
+ //# sourceMappingURL=http-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { HttpServer, type HttpServerConfig } from './http-server.js';
2
+ export { HttpClient, HttpResponseError, type HttpClientConfig } from './http-client.js';
3
+ export { RabbitMQClient, type RabbitConfig } from './rabbitmq.js';
4
+ export { signRequest, verifySignature, verifySignatureWithRotation, isTimestampValid, sanitizeString, sanitizeInput } from './auth.js';
5
+ export { retry, CircuitBreaker, CircuitOpenError, type RetryOptions, type CircuitBreakerOptions, type CircuitState, } from './resilience.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvI,OAAO,EACL,KAAK,EACL,cAAc,EACd,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,YAAY,GAClB,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { HttpServer } from './http-server.js';
2
+ export { HttpClient, HttpResponseError } from './http-client.js';
3
+ export { RabbitMQClient } from './rabbitmq.js';
4
+ export { signRequest, verifySignature, verifySignatureWithRotation, isTimestampValid, sanitizeString, sanitizeInput } from './auth.js';
5
+ export { retry, CircuitBreaker, CircuitOpenError, } from './resilience.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAyB,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAyB,MAAM,kBAAkB,CAAC;AACxF,OAAO,EAAE,cAAc,EAAqB,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvI,OAAO,EACL,KAAK,EACL,cAAc,EACd,gBAAgB,GAIjB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,59 @@
1
+ import type { Agent } from '@mce-bt/microagents-core';
2
+ import { type RetryOptions } from './resilience.js';
3
+ export interface RabbitConfig {
4
+ url: string;
5
+ /** Exchange name for events (topic exchange) */
6
+ eventsExchange?: string;
7
+ /** Exchange name for tasks (direct exchange) */
8
+ tasksExchange?: string;
9
+ /** Reconnect delay in ms (default: 5000) */
10
+ reconnectDelayMs?: number;
11
+ /** Maximum reconnect attempts (default: Infinity) */
12
+ maxReconnectAttempts?: number;
13
+ /** Retry options for message handler failures */
14
+ handlerRetry?: RetryOptions;
15
+ }
16
+ interface MessageMetadata {
17
+ sourceAgentId: string;
18
+ sessionId?: string;
19
+ timestamp: string;
20
+ correlationId: string;
21
+ }
22
+ /**
23
+ * RabbitMQ communication resource.
24
+ * Handles events (topic exchange, pub/sub) and tasks (work queues, guaranteed delivery).
25
+ * Includes automatic reconnection with backoff and handler retry support.
26
+ */
27
+ export declare class RabbitMQClient {
28
+ private config;
29
+ private connection;
30
+ private channel;
31
+ private agentId;
32
+ private eventsExchange;
33
+ private tasksExchange;
34
+ private agent;
35
+ private stopping;
36
+ private reconnecting;
37
+ /** Monotonic counter — incremented on each reconnect so in-flight handlers can detect stale channels. */
38
+ private channelEpoch;
39
+ /** Number of messages currently being processed. */
40
+ private inflightCount;
41
+ constructor(config: RabbitConfig);
42
+ start(agent: Agent): Promise<void>;
43
+ private connect;
44
+ private handleMessage;
45
+ private scheduleReconnect;
46
+ emitEvent(topic: string, payload: unknown, sessionId?: string): Promise<void>;
47
+ emitTask(topic: string, payload: unknown, sessionId?: string): Promise<void>;
48
+ /**
49
+ * Dynamically register a task consumer after start().
50
+ * Used by the Scheduler to self-consume cron task messages.
51
+ */
52
+ consumeTask(topic: string, callback: (data: {
53
+ payload: unknown;
54
+ metadata: MessageMetadata;
55
+ }) => Promise<void>, concurrency?: number): Promise<void>;
56
+ stop(): Promise<void>;
57
+ }
58
+ export {};
59
+ //# sourceMappingURL=rabbitmq.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq.d.ts","sourceRoot":"","sources":["../src/rabbitmq.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE3D,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iDAAiD;IACjD,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,UAAU,eAAe;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,UAAU,CAA4D;IAC9E,OAAO,CAAC,OAAO,CAAkG;IACjH,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAS;IAC7B,yGAAyG;IACzG,OAAO,CAAC,YAAY,CAAK;IACzB,oDAAoD;IACpD,OAAO,CAAC,aAAa,CAAK;gBAEd,MAAM,EAAE,YAAY;IAM1B,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;YAQ1B,OAAO;YA6FP,aAAa;IAgC3B,OAAO,CAAC,iBAAiB;IA4CnB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB7E,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBlF;;;OAGG;IACG,WAAW,CACf,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,eAAe,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EAClF,WAAW,GAAE,MAAU,GACtB,OAAO,CAAC,IAAI,CAAC;IA6BV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAe5B"}
@@ -0,0 +1,265 @@
1
+ import amqplib from 'amqplib';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { retry } from './resilience.js';
4
+ /**
5
+ * RabbitMQ communication resource.
6
+ * Handles events (topic exchange, pub/sub) and tasks (work queues, guaranteed delivery).
7
+ * Includes automatic reconnection with backoff and handler retry support.
8
+ */
9
+ export class RabbitMQClient {
10
+ config;
11
+ connection = null;
12
+ channel = null;
13
+ agentId = '';
14
+ eventsExchange;
15
+ tasksExchange;
16
+ agent = null;
17
+ stopping = false;
18
+ reconnecting = false;
19
+ /** Monotonic counter — incremented on each reconnect so in-flight handlers can detect stale channels. */
20
+ channelEpoch = 0;
21
+ /** Number of messages currently being processed. */
22
+ inflightCount = 0;
23
+ constructor(config) {
24
+ this.config = config;
25
+ this.eventsExchange = config.eventsExchange ?? 'microagents.events';
26
+ this.tasksExchange = config.tasksExchange ?? 'microagents.tasks';
27
+ }
28
+ async start(agent) {
29
+ this.agentId = agent.definition.id;
30
+ this.agent = agent;
31
+ this.stopping = false;
32
+ await this.connect();
33
+ }
34
+ async connect() {
35
+ if (!this.agent)
36
+ return;
37
+ const agent = this.agent;
38
+ const conn = await amqplib.connect(this.config.url);
39
+ this.connection = conn;
40
+ this.channel = await conn.createChannel();
41
+ // Declare exchanges
42
+ await this.channel.assertExchange(this.eventsExchange, 'topic', { durable: true });
43
+ await this.channel.assertExchange(this.tasksExchange, 'direct', { durable: true });
44
+ // Dead letter exchanges + queues
45
+ const eventsDlx = `${this.eventsExchange}.dlx`;
46
+ const tasksDlx = `${this.tasksExchange}.dlx`;
47
+ await this.channel.assertExchange(eventsDlx, 'topic', { durable: true });
48
+ await this.channel.assertExchange(tasksDlx, 'direct', { durable: true });
49
+ // Set up event handlers
50
+ for (const handler of agent.eventHandlers) {
51
+ const queueName = `${agent.definition.id}.events.${handler.topic}`;
52
+ const dlqName = `${queueName}.dlq`;
53
+ // DLQ — messages that fail after retries land here
54
+ await this.channel.assertQueue(dlqName, { durable: true });
55
+ await this.channel.bindQueue(dlqName, eventsDlx, handler.topic);
56
+ await this.channel.assertQueue(queueName, {
57
+ durable: true,
58
+ arguments: {
59
+ 'x-dead-letter-exchange': eventsDlx,
60
+ 'x-dead-letter-routing-key': handler.topic,
61
+ },
62
+ });
63
+ await this.channel.bindQueue(queueName, this.eventsExchange, handler.topic);
64
+ await this.channel.consume(queueName, async (msg) => {
65
+ if (!msg)
66
+ return;
67
+ await this.handleMessage(msg, handler.handleCallback.bind(handler));
68
+ });
69
+ }
70
+ // Set up task handlers
71
+ for (const handler of agent.taskHandlers) {
72
+ const queueName = `${agent.definition.id}.tasks.${handler.topic}`;
73
+ const dlqName = `${queueName}.dlq`;
74
+ // DLQ
75
+ await this.channel.assertQueue(dlqName, { durable: true });
76
+ await this.channel.bindQueue(dlqName, tasksDlx, handler.topic);
77
+ await this.channel.assertQueue(queueName, {
78
+ durable: true,
79
+ arguments: {
80
+ 'x-dead-letter-exchange': tasksDlx,
81
+ 'x-dead-letter-routing-key': handler.topic,
82
+ },
83
+ });
84
+ await this.channel.bindQueue(queueName, this.tasksExchange, handler.topic);
85
+ await this.channel.prefetch(handler.concurrency);
86
+ await this.channel.consume(queueName, async (msg) => {
87
+ if (!msg)
88
+ return;
89
+ await this.handleMessage(msg, handler.handleCallback.bind(handler));
90
+ });
91
+ }
92
+ // Handle channel errors (e.g., PRECONDITION_FAILED from stale delivery tags)
93
+ this.channel.on('error', (err) => {
94
+ if (!this.stopping) {
95
+ console.error('[RabbitMQ] Channel error:', err.message);
96
+ this.scheduleReconnect();
97
+ }
98
+ });
99
+ // Handle connection errors — trigger reconnect
100
+ this.connection.on('error', (err) => {
101
+ if (!this.stopping) {
102
+ console.error('[RabbitMQ] Connection error:', err.message);
103
+ this.scheduleReconnect();
104
+ }
105
+ });
106
+ this.connection.on('close', () => {
107
+ if (!this.stopping) {
108
+ console.warn('[RabbitMQ] Connection closed unexpectedly');
109
+ this.scheduleReconnect();
110
+ }
111
+ });
112
+ }
113
+ async handleMessage(msg,
114
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
115
+ callback) {
116
+ // Pin the channel reference and epoch at the moment the message was received.
117
+ // If a reconnect happens while the callback is running, we must NOT ack/nack
118
+ // on the new channel — that causes PRECONDITION_FAILED (unknown delivery tag).
119
+ const pinnedChannel = this.channel;
120
+ const pinnedEpoch = this.channelEpoch;
121
+ this.inflightCount++;
122
+ const retryOpts = this.config.handlerRetry ?? { maxRetries: 2, baseDelayMs: 500 };
123
+ try {
124
+ const data = JSON.parse(msg.content.toString());
125
+ await retry(() => callback(data), retryOpts);
126
+ // Only ack if the channel hasn't been replaced
127
+ if (this.channelEpoch === pinnedEpoch && pinnedChannel) {
128
+ try {
129
+ pinnedChannel.ack(msg);
130
+ }
131
+ catch { /* channel already closed */ }
132
+ }
133
+ }
134
+ catch (err) {
135
+ console.error('[RabbitMQ] Handler failed after retries, sending to DLQ:', err.message);
136
+ if (this.channelEpoch === pinnedEpoch && pinnedChannel) {
137
+ try {
138
+ pinnedChannel.nack(msg, false, false);
139
+ }
140
+ catch { /* channel already closed */ }
141
+ }
142
+ }
143
+ finally {
144
+ this.inflightCount--;
145
+ }
146
+ }
147
+ scheduleReconnect() {
148
+ if (this.reconnecting || this.stopping)
149
+ return;
150
+ this.reconnecting = true;
151
+ const baseDelay = this.config.reconnectDelayMs ?? 5_000;
152
+ const maxAttempts = this.config.maxReconnectAttempts ?? Infinity;
153
+ const doReconnect = async (attempt) => {
154
+ if (this.stopping) {
155
+ this.reconnecting = false;
156
+ return;
157
+ }
158
+ if (attempt > maxAttempts) {
159
+ console.error('[RabbitMQ] Max reconnect attempts reached, giving up');
160
+ this.reconnecting = false;
161
+ return;
162
+ }
163
+ const delay = Math.min(baseDelay * 2 ** (attempt - 1), 60_000);
164
+ console.log(`[RabbitMQ] Reconnecting in ${delay}ms (attempt ${attempt})...`);
165
+ await new Promise((resolve) => setTimeout(resolve, delay));
166
+ try {
167
+ // Bump epoch so in-flight handlers know their channel is stale
168
+ this.channelEpoch++;
169
+ // Clean up stale refs
170
+ this.channel = null;
171
+ try {
172
+ this.connection?.removeAllListeners();
173
+ }
174
+ catch { /* ignore */ }
175
+ this.connection = null;
176
+ await this.connect();
177
+ console.log('[RabbitMQ] Reconnected successfully');
178
+ this.reconnecting = false;
179
+ }
180
+ catch (err) {
181
+ console.error('[RabbitMQ] Reconnect failed:', err.message);
182
+ await doReconnect(attempt + 1);
183
+ }
184
+ };
185
+ void doReconnect(1);
186
+ }
187
+ async emitEvent(topic, payload, sessionId) {
188
+ if (!this.channel) {
189
+ throw new Error('RabbitMQ channel not initialized');
190
+ }
191
+ const message = {
192
+ payload,
193
+ metadata: {
194
+ sourceAgentId: this.agentId,
195
+ sessionId,
196
+ timestamp: new Date().toISOString(),
197
+ correlationId: randomUUID(),
198
+ },
199
+ };
200
+ this.channel.publish(this.eventsExchange, topic, Buffer.from(JSON.stringify(message)), { persistent: true });
201
+ }
202
+ async emitTask(topic, payload, sessionId) {
203
+ if (!this.channel) {
204
+ throw new Error('RabbitMQ channel not initialized');
205
+ }
206
+ const message = {
207
+ payload,
208
+ metadata: {
209
+ sourceAgentId: this.agentId,
210
+ sessionId,
211
+ timestamp: new Date().toISOString(),
212
+ correlationId: randomUUID(),
213
+ },
214
+ };
215
+ this.channel.publish(this.tasksExchange, topic, Buffer.from(JSON.stringify(message)), { persistent: true });
216
+ }
217
+ /**
218
+ * Dynamically register a task consumer after start().
219
+ * Used by the Scheduler to self-consume cron task messages.
220
+ */
221
+ async consumeTask(topic, callback, concurrency = 1) {
222
+ if (!this.channel) {
223
+ throw new Error('RabbitMQ channel not initialized');
224
+ }
225
+ const queueName = `${this.agentId}.tasks.${topic}`;
226
+ const tasksDlx = `${this.tasksExchange}.dlx`;
227
+ const dlqName = `${queueName}.dlq`;
228
+ await this.channel.assertQueue(dlqName, { durable: true });
229
+ await this.channel.bindQueue(dlqName, tasksDlx, topic);
230
+ await this.channel.assertQueue(queueName, {
231
+ durable: true,
232
+ arguments: {
233
+ 'x-dead-letter-exchange': tasksDlx,
234
+ 'x-dead-letter-routing-key': topic,
235
+ },
236
+ });
237
+ await this.channel.bindQueue(queueName, this.tasksExchange, topic);
238
+ await this.channel.prefetch(concurrency);
239
+ await this.channel.consume(queueName, async (msg) => {
240
+ if (!msg)
241
+ return;
242
+ await this.handleMessage(msg, callback);
243
+ });
244
+ }
245
+ async stop() {
246
+ this.stopping = true;
247
+ if (this.channel) {
248
+ try {
249
+ await this.channel.close();
250
+ }
251
+ catch { /* ignore during shutdown */ }
252
+ this.channel = null;
253
+ }
254
+ if (this.connection) {
255
+ try {
256
+ this.connection.removeAllListeners();
257
+ await this.connection.close();
258
+ }
259
+ catch { /* ignore during shutdown */ }
260
+ this.connection = null;
261
+ }
262
+ this.agent = null;
263
+ }
264
+ }
265
+ //# sourceMappingURL=rabbitmq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq.js","sourceRoot":"","sources":["../src/rabbitmq.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Resilience utilities — retry with exponential backoff and circuit breaker.
3
+ */
4
+ export interface RetryOptions {
5
+ /** Maximum number of retry attempts (default: 3) */
6
+ maxRetries?: number;
7
+ /** Base delay in ms (default: 1000) */
8
+ baseDelayMs?: number;
9
+ /** Maximum delay in ms (default: 30_000) */
10
+ maxDelayMs?: number;
11
+ /** Multiplier for exponential backoff (default: 2) */
12
+ multiplier?: number;
13
+ /** Add jitter to delays (default: true) */
14
+ jitter?: boolean;
15
+ /** Predicate to decide if an error is retryable (default: all errors are retryable) */
16
+ isRetryable?: (error: unknown) => boolean;
17
+ /** Called on each retry attempt */
18
+ onRetry?: (error: unknown, attempt: number, delayMs: number) => void;
19
+ }
20
+ /**
21
+ * Retry an async operation with exponential backoff.
22
+ */
23
+ export declare function retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
24
+ export type CircuitState = 'closed' | 'open' | 'half-open';
25
+ export interface CircuitBreakerOptions {
26
+ /** Number of failures before opening the circuit (default: 5) */
27
+ failureThreshold?: number;
28
+ /** Time in ms the circuit stays open before transitioning to half-open (default: 30_000) */
29
+ resetTimeoutMs?: number;
30
+ /** Max attempts allowed in half-open state (default: 1) */
31
+ halfOpenMaxAttempts?: number;
32
+ /** Called when state changes */
33
+ onStateChange?: (from: CircuitState, to: CircuitState) => void;
34
+ }
35
+ export declare class CircuitBreaker {
36
+ private state;
37
+ private failureCount;
38
+ private lastFailureTime;
39
+ private halfOpenAttempts;
40
+ private failureThreshold;
41
+ private resetTimeoutMs;
42
+ private halfOpenMaxAttempts;
43
+ private onStateChange?;
44
+ constructor(options?: CircuitBreakerOptions);
45
+ getState(): CircuitState;
46
+ private transition;
47
+ /**
48
+ * Execute an operation through the circuit breaker.
49
+ * Throws a CircuitOpenError if the circuit is open.
50
+ */
51
+ execute<T>(fn: () => Promise<T>): Promise<T>;
52
+ private onSuccess;
53
+ private onFailure;
54
+ reset(): void;
55
+ }
56
+ export declare class CircuitOpenError extends Error {
57
+ constructor(message: string);
58
+ }
59
+ //# sourceMappingURL=resilience.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilience.d.ts","sourceRoot":"","sources":["../src/resilience.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uFAAuF;IACvF,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAC1C,mCAAmC;IACnC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtE;AAwBD;;GAEG;AACH,wBAAsB,KAAK,CAAC,CAAC,EAC3B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,CAAC,CAAC,CA2BZ;AAID,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3D,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4FAA4F;IAC5F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2DAA2D;IAC3D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gCAAgC;IAChC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,YAAY,KAAK,IAAI,CAAC;CAChE;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,gBAAgB,CAAK;IAE7B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,aAAa,CAAC,CAAiD;gBAE3D,OAAO,GAAE,qBAA0B;IAO/C,QAAQ,IAAI,YAAY;IAIxB,OAAO,CAAC,UAAU;IAOlB;;;OAGG;IACG,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IA4BlD,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,SAAS;IAQjB,KAAK,IAAI,IAAI;CAMd;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Resilience utilities — retry with exponential backoff and circuit breaker.
3
+ */
4
+ const DEFAULT_RETRY = {
5
+ maxRetries: 3,
6
+ baseDelayMs: 1_000,
7
+ maxDelayMs: 30_000,
8
+ multiplier: 2,
9
+ jitter: true,
10
+ };
11
+ function computeDelay(attempt, baseDelayMs, maxDelayMs, multiplier, jitter) {
12
+ const expDelay = baseDelayMs * multiplier ** attempt;
13
+ const capped = Math.min(expDelay, maxDelayMs);
14
+ if (!jitter)
15
+ return capped;
16
+ // Full jitter: uniform random between 0 and capped delay
17
+ return Math.floor(Math.random() * capped);
18
+ }
19
+ /**
20
+ * Retry an async operation with exponential backoff.
21
+ */
22
+ export async function retry(fn, options = {}) {
23
+ const { maxRetries = DEFAULT_RETRY.maxRetries, baseDelayMs = DEFAULT_RETRY.baseDelayMs, maxDelayMs = DEFAULT_RETRY.maxDelayMs, multiplier = DEFAULT_RETRY.multiplier, jitter = DEFAULT_RETRY.jitter, } = options;
24
+ let lastError;
25
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
26
+ try {
27
+ return await fn();
28
+ }
29
+ catch (error) {
30
+ lastError = error;
31
+ if (attempt >= maxRetries)
32
+ break;
33
+ if (options.isRetryable && !options.isRetryable(error))
34
+ break;
35
+ const delay = computeDelay(attempt, baseDelayMs, maxDelayMs, multiplier, jitter);
36
+ options.onRetry?.(error, attempt + 1, delay);
37
+ await new Promise((resolve) => setTimeout(resolve, delay));
38
+ }
39
+ }
40
+ throw lastError;
41
+ }
42
+ export class CircuitBreaker {
43
+ state = 'closed';
44
+ failureCount = 0;
45
+ lastFailureTime = 0;
46
+ halfOpenAttempts = 0;
47
+ failureThreshold;
48
+ resetTimeoutMs;
49
+ halfOpenMaxAttempts;
50
+ onStateChange;
51
+ constructor(options = {}) {
52
+ this.failureThreshold = options.failureThreshold ?? 5;
53
+ this.resetTimeoutMs = options.resetTimeoutMs ?? 30_000;
54
+ this.halfOpenMaxAttempts = options.halfOpenMaxAttempts ?? 1;
55
+ this.onStateChange = options.onStateChange;
56
+ }
57
+ getState() {
58
+ return this.state;
59
+ }
60
+ transition(to) {
61
+ if (this.state === to)
62
+ return;
63
+ const from = this.state;
64
+ this.state = to;
65
+ this.onStateChange?.(from, to);
66
+ }
67
+ /**
68
+ * Execute an operation through the circuit breaker.
69
+ * Throws a CircuitOpenError if the circuit is open.
70
+ */
71
+ async execute(fn) {
72
+ if (this.state === 'open') {
73
+ // Check if enough time has elapsed to try half-open
74
+ if (Date.now() - this.lastFailureTime >= this.resetTimeoutMs) {
75
+ this.transition('half-open');
76
+ this.halfOpenAttempts = 0;
77
+ }
78
+ else {
79
+ throw new CircuitOpenError('Circuit breaker is open');
80
+ }
81
+ }
82
+ if (this.state === 'half-open' && this.halfOpenAttempts >= this.halfOpenMaxAttempts) {
83
+ throw new CircuitOpenError('Circuit breaker half-open limit reached');
84
+ }
85
+ try {
86
+ if (this.state === 'half-open') {
87
+ this.halfOpenAttempts++;
88
+ }
89
+ const result = await fn();
90
+ this.onSuccess();
91
+ return result;
92
+ }
93
+ catch (error) {
94
+ this.onFailure();
95
+ throw error;
96
+ }
97
+ }
98
+ onSuccess() {
99
+ this.failureCount = 0;
100
+ if (this.state === 'half-open') {
101
+ this.transition('closed');
102
+ }
103
+ }
104
+ onFailure() {
105
+ this.failureCount++;
106
+ this.lastFailureTime = Date.now();
107
+ if (this.failureCount >= this.failureThreshold) {
108
+ this.transition('open');
109
+ }
110
+ }
111
+ reset() {
112
+ this.failureCount = 0;
113
+ this.halfOpenAttempts = 0;
114
+ this.lastFailureTime = 0;
115
+ this.transition('closed');
116
+ }
117
+ }
118
+ export class CircuitOpenError extends Error {
119
+ constructor(message) {
120
+ super(message);
121
+ this.name = 'CircuitOpenError';
122
+ }
123
+ }
124
+ //# sourceMappingURL=resilience.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilience.js","sourceRoot":"","sources":["../src/resilience.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@mce-bt/microagents-communication",
3
+ "version": "0.1.0",
4
+ "description": "Communication layer — HTTP server/client + RabbitMQ events/tasks",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc --build",
16
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
17
+ "test": "vitest run"
18
+ },
19
+ "dependencies": {
20
+ "fastify": "^5.2.0",
21
+ "amqplib": "^0.10.0",
22
+ "zod": "^3.23.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/amqplib": "^0.10.0"
26
+ },
27
+ "peerDependencies": {
28
+ "@mce-bt/microagents-observability": "^0.1.0"
29
+ },
30
+ "peerDependenciesMeta": {
31
+ "@mce-bt/microagents-observability": {
32
+ "optional": true
33
+ }
34
+ },
35
+ "license": "MIT",
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/cavillo/microagents.git",
45
+ "directory": "packages/communication"
46
+ },
47
+ "homepage": "https://github.com/cavillo/microagents#readme",
48
+ "bugs": {
49
+ "url": "https://github.com/cavillo/microagents/issues"
50
+ },
51
+ "engines": {
52
+ "node": ">=20.0.0"
53
+ }
54
+ }