@clawcrony/claw-crony 1.0.1
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/LICENSE +21 -0
- package/README.md +82 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +720 -0
- package/dist/index.js.map +1 -0
- package/dist/src/agent-card.d.ts +4 -0
- package/dist/src/agent-card.d.ts.map +1 -0
- package/dist/src/agent-card.js +61 -0
- package/dist/src/agent-card.js.map +1 -0
- package/dist/src/audit.d.ts +36 -0
- package/dist/src/audit.d.ts.map +1 -0
- package/dist/src/audit.js +88 -0
- package/dist/src/audit.js.map +1 -0
- package/dist/src/client.d.ts +53 -0
- package/dist/src/client.d.ts.map +1 -0
- package/dist/src/client.js +322 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/executor.d.ts +34 -0
- package/dist/src/executor.d.ts.map +1 -0
- package/dist/src/executor.js +994 -0
- package/dist/src/executor.js.map +1 -0
- package/dist/src/file-security.d.ts +63 -0
- package/dist/src/file-security.d.ts.map +1 -0
- package/dist/src/file-security.js +350 -0
- package/dist/src/file-security.js.map +1 -0
- package/dist/src/hub-match.d.ts +73 -0
- package/dist/src/hub-match.d.ts.map +1 -0
- package/dist/src/hub-match.js +120 -0
- package/dist/src/hub-match.js.map +1 -0
- package/dist/src/hub-registration.d.ts +24 -0
- package/dist/src/hub-registration.d.ts.map +1 -0
- package/dist/src/hub-registration.js +242 -0
- package/dist/src/hub-registration.js.map +1 -0
- package/dist/src/internal/envelope.d.ts +33 -0
- package/dist/src/internal/envelope.d.ts.map +1 -0
- package/dist/src/internal/envelope.js +152 -0
- package/dist/src/internal/envelope.js.map +1 -0
- package/dist/src/internal/idempotency.d.ts +48 -0
- package/dist/src/internal/idempotency.d.ts.map +1 -0
- package/dist/src/internal/idempotency.js +82 -0
- package/dist/src/internal/idempotency.js.map +1 -0
- package/dist/src/internal/metrics.d.ts +38 -0
- package/dist/src/internal/metrics.d.ts.map +1 -0
- package/dist/src/internal/metrics.js +83 -0
- package/dist/src/internal/metrics.js.map +1 -0
- package/dist/src/internal/outbox.d.ts +49 -0
- package/dist/src/internal/outbox.d.ts.map +1 -0
- package/dist/src/internal/outbox.js +149 -0
- package/dist/src/internal/outbox.js.map +1 -0
- package/dist/src/internal/routing.d.ts +28 -0
- package/dist/src/internal/routing.d.ts.map +1 -0
- package/dist/src/internal/routing.js +57 -0
- package/dist/src/internal/routing.js.map +1 -0
- package/dist/src/internal/security.d.ts +53 -0
- package/dist/src/internal/security.d.ts.map +1 -0
- package/dist/src/internal/security.js +122 -0
- package/dist/src/internal/security.js.map +1 -0
- package/dist/src/internal/transport.d.ts +49 -0
- package/dist/src/internal/transport.d.ts.map +1 -0
- package/dist/src/internal/transport.js +207 -0
- package/dist/src/internal/transport.js.map +1 -0
- package/dist/src/internal/types-internal.d.ts +95 -0
- package/dist/src/internal/types-internal.d.ts.map +1 -0
- package/dist/src/internal/types-internal.js +9 -0
- package/dist/src/internal/types-internal.js.map +1 -0
- package/dist/src/peer-health.d.ts +47 -0
- package/dist/src/peer-health.d.ts.map +1 -0
- package/dist/src/peer-health.js +169 -0
- package/dist/src/peer-health.js.map +1 -0
- package/dist/src/peer-retry.d.ts +16 -0
- package/dist/src/peer-retry.d.ts.map +1 -0
- package/dist/src/peer-retry.js +75 -0
- package/dist/src/peer-retry.js.map +1 -0
- package/dist/src/queueing-executor.d.ts +23 -0
- package/dist/src/queueing-executor.d.ts.map +1 -0
- package/dist/src/queueing-executor.js +179 -0
- package/dist/src/queueing-executor.js.map +1 -0
- package/dist/src/routing-rules.d.ts +53 -0
- package/dist/src/routing-rules.d.ts.map +1 -0
- package/dist/src/routing-rules.js +130 -0
- package/dist/src/routing-rules.js.map +1 -0
- package/dist/src/task-cleanup.d.ts +21 -0
- package/dist/src/task-cleanup.d.ts.map +1 -0
- package/dist/src/task-cleanup.js +77 -0
- package/dist/src/task-cleanup.js.map +1 -0
- package/dist/src/task-store.d.ts +16 -0
- package/dist/src/task-store.d.ts.map +1 -0
- package/dist/src/task-store.js +80 -0
- package/dist/src/task-store.js.map +1 -0
- package/dist/src/telemetry.d.ts +88 -0
- package/dist/src/telemetry.d.ts.map +1 -0
- package/dist/src/telemetry.js +235 -0
- package/dist/src/telemetry.js.map +1 -0
- package/dist/src/transport-fallback.d.ts +29 -0
- package/dist/src/transport-fallback.d.ts.map +1 -0
- package/dist/src/transport-fallback.js +81 -0
- package/dist/src/transport-fallback.js.map +1 -0
- package/dist/src/types.d.ts +160 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +7 -0
- package/dist/src/types.js.map +1 -0
- package/openclaw.plugin.json +272 -0
- package/package.json +56 -0
- package/skill/SKILL.md +230 -0
- package/skill/references/tools-md-template.md +57 -0
- package/skill/scripts/a2a-send.mjs +357 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages per-peer health checks and circuit breaker state.
|
|
3
|
+
*
|
|
4
|
+
* Health checks periodically probe each peer's Agent Card endpoint.
|
|
5
|
+
* The circuit breaker follows the standard three-state pattern:
|
|
6
|
+
* closed → open → half-open → closed
|
|
7
|
+
*/
|
|
8
|
+
export class PeerHealthManager {
|
|
9
|
+
states = new Map();
|
|
10
|
+
peers;
|
|
11
|
+
healthConfig;
|
|
12
|
+
cbConfig;
|
|
13
|
+
probe;
|
|
14
|
+
log;
|
|
15
|
+
timer = null;
|
|
16
|
+
halfOpenInFlight = new Set();
|
|
17
|
+
/** Cached skills per peer, refreshed on each successful health check probe. */
|
|
18
|
+
peerSkills = new Map();
|
|
19
|
+
constructor(peers, healthConfig, cbConfig, probe, log) {
|
|
20
|
+
this.peers = peers;
|
|
21
|
+
this.healthConfig = healthConfig;
|
|
22
|
+
this.cbConfig = cbConfig;
|
|
23
|
+
this.probe = probe;
|
|
24
|
+
this.log = log;
|
|
25
|
+
// Initialize state for each peer
|
|
26
|
+
for (const peer of peers) {
|
|
27
|
+
this.states.set(peer.name, {
|
|
28
|
+
health: "unknown",
|
|
29
|
+
circuit: "closed",
|
|
30
|
+
consecutiveFailures: 0,
|
|
31
|
+
lastFailureAt: null,
|
|
32
|
+
lastCheckAt: null,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Start periodic health checks. */
|
|
37
|
+
start() {
|
|
38
|
+
if (!this.healthConfig.enabled || this.peers.length === 0)
|
|
39
|
+
return;
|
|
40
|
+
this.log("info", "peer.health.start", {
|
|
41
|
+
peers: this.peers.map((p) => p.name),
|
|
42
|
+
interval_ms: this.healthConfig.intervalMs,
|
|
43
|
+
});
|
|
44
|
+
// Run immediately, then on interval
|
|
45
|
+
this.runHealthChecks();
|
|
46
|
+
this.timer = setInterval(() => this.runHealthChecks(), this.healthConfig.intervalMs);
|
|
47
|
+
}
|
|
48
|
+
/** Stop periodic health checks. */
|
|
49
|
+
stop() {
|
|
50
|
+
if (this.timer) {
|
|
51
|
+
clearInterval(this.timer);
|
|
52
|
+
this.timer = null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Check if a peer is available for requests (circuit is not open). */
|
|
56
|
+
isAvailable(peerName) {
|
|
57
|
+
const state = this.states.get(peerName);
|
|
58
|
+
if (!state)
|
|
59
|
+
return true; // Unknown peer → allow (fail at send)
|
|
60
|
+
if (state.circuit === "closed")
|
|
61
|
+
return true;
|
|
62
|
+
if (state.circuit === "open") {
|
|
63
|
+
// Check if cooldown has elapsed → transition to half-open
|
|
64
|
+
if (state.lastFailureAt &&
|
|
65
|
+
Date.now() - state.lastFailureAt >= this.cbConfig.resetTimeoutMs) {
|
|
66
|
+
state.circuit = "half-open";
|
|
67
|
+
this.halfOpenInFlight.add(peerName); // Only one probe allowed
|
|
68
|
+
this.log("info", "peer.circuit.half-open", { peer: peerName });
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
// half-open: allow one request at a time
|
|
74
|
+
if (this.halfOpenInFlight.has(peerName))
|
|
75
|
+
return false;
|
|
76
|
+
this.halfOpenInFlight.add(peerName);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
/** Record a successful call to a peer. */
|
|
80
|
+
recordSuccess(peerName) {
|
|
81
|
+
const state = this.states.get(peerName);
|
|
82
|
+
if (!state)
|
|
83
|
+
return;
|
|
84
|
+
const prevCircuit = state.circuit;
|
|
85
|
+
state.consecutiveFailures = 0;
|
|
86
|
+
state.health = "healthy";
|
|
87
|
+
this.halfOpenInFlight.delete(peerName);
|
|
88
|
+
if (state.circuit !== "closed") {
|
|
89
|
+
state.circuit = "closed";
|
|
90
|
+
this.log("info", "peer.circuit.closed", {
|
|
91
|
+
peer: peerName,
|
|
92
|
+
previous: prevCircuit,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Record a failed call to a peer. May trigger circuit open. */
|
|
97
|
+
recordFailure(peerName) {
|
|
98
|
+
const state = this.states.get(peerName);
|
|
99
|
+
if (!state)
|
|
100
|
+
return;
|
|
101
|
+
state.consecutiveFailures += 1;
|
|
102
|
+
state.lastFailureAt = Date.now();
|
|
103
|
+
this.halfOpenInFlight.delete(peerName);
|
|
104
|
+
// half-open failure → back to open
|
|
105
|
+
if (state.circuit === "half-open") {
|
|
106
|
+
state.circuit = "open";
|
|
107
|
+
this.log("warn", "peer.circuit.open", {
|
|
108
|
+
peer: peerName,
|
|
109
|
+
reason: "half-open probe failed",
|
|
110
|
+
consecutive_failures: state.consecutiveFailures,
|
|
111
|
+
});
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// closed: check threshold
|
|
115
|
+
if (state.circuit === "closed" &&
|
|
116
|
+
state.consecutiveFailures >= this.cbConfig.failureThreshold) {
|
|
117
|
+
state.circuit = "open";
|
|
118
|
+
state.health = "unhealthy";
|
|
119
|
+
this.log("warn", "peer.circuit.open", {
|
|
120
|
+
peer: peerName,
|
|
121
|
+
reason: "failure threshold reached",
|
|
122
|
+
consecutive_failures: state.consecutiveFailures,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Get state for a single peer. */
|
|
127
|
+
getState(peerName) {
|
|
128
|
+
return this.states.get(peerName);
|
|
129
|
+
}
|
|
130
|
+
/** Get states for all peers. */
|
|
131
|
+
getAllStates() {
|
|
132
|
+
return new Map(this.states);
|
|
133
|
+
}
|
|
134
|
+
/** Get cached skills for all peers (populated during health checks). */
|
|
135
|
+
getPeerSkills() {
|
|
136
|
+
return new Map(this.peerSkills);
|
|
137
|
+
}
|
|
138
|
+
/** Update cached skills for a peer (called by the health probe). */
|
|
139
|
+
setPeerSkills(peerName, skills) {
|
|
140
|
+
this.peerSkills.set(peerName, skills);
|
|
141
|
+
}
|
|
142
|
+
/** Run health checks for all peers. */
|
|
143
|
+
runHealthChecks() {
|
|
144
|
+
for (const peer of this.peers) {
|
|
145
|
+
this.checkPeer(peer).catch((err) => {
|
|
146
|
+
this.log("error", "peer.health.check-error", {
|
|
147
|
+
peer: peer.name,
|
|
148
|
+
error: err instanceof Error ? err.message : String(err),
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/** Probe a single peer and update its state. */
|
|
154
|
+
async checkPeer(peer) {
|
|
155
|
+
const state = this.states.get(peer.name);
|
|
156
|
+
if (!state)
|
|
157
|
+
return;
|
|
158
|
+
const healthy = await this.probe(peer);
|
|
159
|
+
state.lastCheckAt = Date.now();
|
|
160
|
+
if (healthy) {
|
|
161
|
+
this.recordSuccess(peer.name);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
state.health = "unhealthy";
|
|
165
|
+
this.recordFailure(peer.name);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=peer-health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-health.js","sourceRoot":"","sources":["../../src/peer-health.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RetryConfig, OutboundSendResult } from "./types.js";
|
|
2
|
+
type LogFn = (level: "info" | "warn", msg: string, details?: Record<string, unknown>) => void;
|
|
3
|
+
/**
|
|
4
|
+
* Determine whether an error or failed result is retryable.
|
|
5
|
+
* Delegates to isRetryableTransportError for comprehensive transport-level error classification.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isRetryable(errorOrResult: unknown): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Wrap an async operation with configurable retry + exponential backoff.
|
|
10
|
+
*
|
|
11
|
+
* The function `fn` should throw on network errors or return an
|
|
12
|
+
* OutboundSendResult. Non-retryable failures are returned immediately.
|
|
13
|
+
*/
|
|
14
|
+
export declare function withRetry(fn: () => Promise<OutboundSendResult>, config: RetryConfig, log?: LogFn, peerName?: string): Promise<OutboundSendResult>;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=peer-retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-retry.d.ts","sourceRoot":"","sources":["../../src/peer-retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGlE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;AAE9F;;;GAGG;AACH,wBAAgB,WAAW,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO,CAa3D;AAeD;;;;;GAKG;AACH,wBAAsB,SAAS,CAC7B,EAAE,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,EACrC,MAAM,EAAE,WAAW,EACnB,GAAG,CAAC,EAAE,KAAK,EACX,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CA6C7B"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { isRetryableTransportError } from "./transport-fallback.js";
|
|
2
|
+
/**
|
|
3
|
+
* Determine whether an error or failed result is retryable.
|
|
4
|
+
* Delegates to isRetryableTransportError for comprehensive transport-level error classification.
|
|
5
|
+
*/
|
|
6
|
+
export function isRetryable(errorOrResult) {
|
|
7
|
+
if (errorOrResult &&
|
|
8
|
+
typeof errorOrResult === "object" &&
|
|
9
|
+
"ok" in errorOrResult &&
|
|
10
|
+
"statusCode" in errorOrResult) {
|
|
11
|
+
const result = errorOrResult;
|
|
12
|
+
if (result.ok)
|
|
13
|
+
return false;
|
|
14
|
+
return isRetryableTransportError(result);
|
|
15
|
+
}
|
|
16
|
+
return isRetryableTransportError(errorOrResult);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Calculate delay with exponential backoff + jitter.
|
|
20
|
+
*/
|
|
21
|
+
function calcDelay(attempt, config) {
|
|
22
|
+
const exponential = Math.min(config.baseDelayMs * Math.pow(2, attempt), config.maxDelayMs);
|
|
23
|
+
// Add 0–10% jitter to prevent thundering herd
|
|
24
|
+
const jitter = Math.random() * exponential * 0.1;
|
|
25
|
+
return exponential + jitter;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Wrap an async operation with configurable retry + exponential backoff.
|
|
29
|
+
*
|
|
30
|
+
* The function `fn` should throw on network errors or return an
|
|
31
|
+
* OutboundSendResult. Non-retryable failures are returned immediately.
|
|
32
|
+
*/
|
|
33
|
+
export async function withRetry(fn, config, log, peerName) {
|
|
34
|
+
let lastResult;
|
|
35
|
+
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
36
|
+
try {
|
|
37
|
+
const result = await fn();
|
|
38
|
+
// Success → return immediately
|
|
39
|
+
if (result.ok)
|
|
40
|
+
return result;
|
|
41
|
+
// Non-retryable failure → return immediately
|
|
42
|
+
if (!isRetryable(result))
|
|
43
|
+
return result;
|
|
44
|
+
lastResult = result;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (!isRetryable(error)) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
statusCode: 500,
|
|
51
|
+
response: { error: error instanceof Error ? error.message : String(error) },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
lastResult = {
|
|
55
|
+
ok: false,
|
|
56
|
+
statusCode: 500,
|
|
57
|
+
response: { error: error instanceof Error ? error.message : String(error) },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// If we have retries left, wait before the next attempt
|
|
61
|
+
if (attempt < config.maxRetries) {
|
|
62
|
+
const delay = calcDelay(attempt, config);
|
|
63
|
+
log?.("warn", "peer.retry", {
|
|
64
|
+
peer: peerName,
|
|
65
|
+
attempt: attempt + 1,
|
|
66
|
+
max_retries: config.maxRetries,
|
|
67
|
+
delay_ms: Math.round(delay),
|
|
68
|
+
});
|
|
69
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// All retries exhausted
|
|
73
|
+
return lastResult;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=peer-retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-retry.js","sourceRoot":"","sources":["../../src/peer-retry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAIpE;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,aAAsB;IAChD,IACE,aAAa;QACb,OAAO,aAAa,KAAK,QAAQ;QACjC,IAAI,IAAI,aAAa;QACrB,YAAY,IAAI,aAAa,EAC7B,CAAC;QACD,MAAM,MAAM,GAAG,aAAmC,CAAC;QACnD,IAAI,MAAM,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC;QAC5B,OAAO,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,yBAAyB,CAAC,aAAa,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,OAAe,EAAE,MAAmB;IACrD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAC1B,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,EACzC,MAAM,CAAC,UAAU,CAClB,CAAC;IACF,8CAA8C;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,WAAW,GAAG,GAAG,CAAC;IACjD,OAAO,WAAW,GAAG,MAAM,CAAC;AAC9B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAqC,EACrC,MAAmB,EACnB,GAAW,EACX,QAAiB;IAEjB,IAAI,UAA0C,CAAC;IAE/C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QAC9D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;YAE1B,+BAA+B;YAC/B,IAAI,MAAM,CAAC,EAAE;gBAAE,OAAO,MAAM,CAAC;YAE7B,6CAA6C;YAC7C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBAAE,OAAO,MAAM,CAAC;YAExC,UAAU,GAAG,MAAM,CAAC;QACtB,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,UAAU,EAAE,GAAG;oBACf,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;iBAC5E,CAAC;YACJ,CAAC;YAED,UAAU,GAAG;gBACX,EAAE,EAAE,KAAK;gBACT,UAAU,EAAE,GAAG;gBACf,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;aAC5E,CAAC;QACJ,CAAC;QAED,wDAAwD;QACxD,IAAI,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACzC,GAAG,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE;gBAC1B,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,OAAO,GAAG,CAAC;gBACpB,WAAW,EAAE,MAAM,CAAC,UAAU;gBAC9B,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;aAC5B,CAAC,CAAC;YACH,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,OAAO,UAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AgentExecutor, ExecutionEventBus, RequestContext } from "@a2a-js/sdk/server";
|
|
2
|
+
import { GatewayTelemetry } from "./telemetry.js";
|
|
3
|
+
interface QueueingExecutorOptions {
|
|
4
|
+
maxConcurrentTasks: number;
|
|
5
|
+
maxQueuedTasks: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class QueueingAgentExecutor implements AgentExecutor {
|
|
8
|
+
private readonly delegate;
|
|
9
|
+
private readonly telemetry;
|
|
10
|
+
private readonly options;
|
|
11
|
+
private readonly queue;
|
|
12
|
+
private readonly pendingByTaskId;
|
|
13
|
+
private activeTasks;
|
|
14
|
+
constructor(delegate: AgentExecutor, telemetry: GatewayTelemetry, options: QueueingExecutorOptions);
|
|
15
|
+
execute(requestContext: RequestContext, eventBus: ExecutionEventBus): Promise<void>;
|
|
16
|
+
cancelTask(taskId: string, eventBus: ExecutionEventBus): Promise<void>;
|
|
17
|
+
private runEntry;
|
|
18
|
+
private drainQueue;
|
|
19
|
+
private queueDelete;
|
|
20
|
+
private pickAgentId;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=queueing-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queueing-executor.d.ts","sourceRoot":"","sources":["../../src/queueing-executor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,aAAa,EACb,iBAAiB,EACjB,cAAc,EACf,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,UAAU,uBAAuB;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;CACxB;AAwED,qBAAa,qBAAsB,YAAW,aAAa;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;IAC/C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsC;IACtE,OAAO,CAAC,WAAW,CAAK;gBAEZ,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,uBAAuB;IASlG,OAAO,CAAC,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsD7E,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;YA0B9D,QAAQ;IAwEtB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,WAAW;CAIpB"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from "uuid";
|
|
2
|
+
function statusMessage(contextId, text) {
|
|
3
|
+
return {
|
|
4
|
+
kind: "message",
|
|
5
|
+
messageId: uuidv4(),
|
|
6
|
+
role: "agent",
|
|
7
|
+
contextId,
|
|
8
|
+
parts: [{ kind: "text", text }],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function taskEvent(taskId, contextId, state, text) {
|
|
12
|
+
return {
|
|
13
|
+
kind: "task",
|
|
14
|
+
id: taskId,
|
|
15
|
+
contextId,
|
|
16
|
+
status: {
|
|
17
|
+
state,
|
|
18
|
+
message: text ? statusMessage(contextId, text) : undefined,
|
|
19
|
+
timestamp: new Date().toISOString(),
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function createObservedEventBus(eventBus, observer) {
|
|
24
|
+
const wrapped = {
|
|
25
|
+
publish(event) {
|
|
26
|
+
observer(event);
|
|
27
|
+
eventBus.publish(event);
|
|
28
|
+
},
|
|
29
|
+
on(eventName, listener) {
|
|
30
|
+
eventBus.on(eventName, listener);
|
|
31
|
+
return wrapped;
|
|
32
|
+
},
|
|
33
|
+
off(eventName, listener) {
|
|
34
|
+
eventBus.off(eventName, listener);
|
|
35
|
+
return wrapped;
|
|
36
|
+
},
|
|
37
|
+
once(eventName, listener) {
|
|
38
|
+
eventBus.once(eventName, listener);
|
|
39
|
+
return wrapped;
|
|
40
|
+
},
|
|
41
|
+
removeAllListeners(eventName) {
|
|
42
|
+
eventBus.removeAllListeners(eventName);
|
|
43
|
+
return wrapped;
|
|
44
|
+
},
|
|
45
|
+
finished() {
|
|
46
|
+
eventBus.finished();
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
return wrapped;
|
|
50
|
+
}
|
|
51
|
+
export class QueueingAgentExecutor {
|
|
52
|
+
delegate;
|
|
53
|
+
telemetry;
|
|
54
|
+
options;
|
|
55
|
+
queue = [];
|
|
56
|
+
pendingByTaskId = new Map();
|
|
57
|
+
activeTasks = 0;
|
|
58
|
+
constructor(delegate, telemetry, options) {
|
|
59
|
+
this.delegate = delegate;
|
|
60
|
+
this.telemetry = telemetry;
|
|
61
|
+
this.options = {
|
|
62
|
+
maxConcurrentTasks: Math.max(1, options.maxConcurrentTasks),
|
|
63
|
+
maxQueuedTasks: Math.max(0, options.maxQueuedTasks),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
execute(requestContext, eventBus) {
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
const entry = {
|
|
69
|
+
requestContext,
|
|
70
|
+
eventBus,
|
|
71
|
+
resolve,
|
|
72
|
+
reject,
|
|
73
|
+
};
|
|
74
|
+
this.pendingByTaskId.set(requestContext.taskId, entry);
|
|
75
|
+
if (this.activeTasks < this.options.maxConcurrentTasks) {
|
|
76
|
+
void this.runEntry(entry);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (this.queue.length >= this.options.maxQueuedTasks) {
|
|
80
|
+
this.pendingByTaskId.delete(requestContext.taskId);
|
|
81
|
+
this.telemetry.recordQueueRejected(requestContext.taskId, requestContext.contextId, this.queue.length);
|
|
82
|
+
eventBus.publish(taskEvent(requestContext.taskId, requestContext.contextId, "rejected", "Gateway is overloaded; queue limit reached"));
|
|
83
|
+
eventBus.finished();
|
|
84
|
+
resolve();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.queue.push(entry);
|
|
88
|
+
this.telemetry.recordTaskQueued(requestContext.taskId, requestContext.contextId, this.queue.length, this.queue.length);
|
|
89
|
+
eventBus.publish(taskEvent(requestContext.taskId, requestContext.contextId, "submitted", `Queued for execution (position ${this.queue.length})`));
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async cancelTask(taskId, eventBus) {
|
|
93
|
+
const queuedIndex = this.queue.findIndex((entry) => entry.requestContext.taskId === taskId);
|
|
94
|
+
if (queuedIndex !== -1) {
|
|
95
|
+
const [entry] = this.queue.splice(queuedIndex, 1);
|
|
96
|
+
if (entry) {
|
|
97
|
+
this.pendingByTaskId.delete(taskId);
|
|
98
|
+
entry.eventBus.publish(taskEvent(taskId, entry.requestContext.contextId, "canceled", "Task canceled while queued"));
|
|
99
|
+
entry.eventBus.finished();
|
|
100
|
+
entry.resolve();
|
|
101
|
+
this.telemetry.recordTaskFinish(taskId, entry.requestContext.contextId, "canceled", 0, this.activeTasks, this.queue.length);
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
await this.delegate.cancelTask(taskId, eventBus);
|
|
106
|
+
}
|
|
107
|
+
async runEntry(entry) {
|
|
108
|
+
const { requestContext } = entry;
|
|
109
|
+
const startedAt = Date.now();
|
|
110
|
+
let finalState;
|
|
111
|
+
let finalErrorMessage;
|
|
112
|
+
this.queueDelete(requestContext.taskId);
|
|
113
|
+
this.activeTasks += 1;
|
|
114
|
+
this.telemetry.recordTaskStart(requestContext.taskId, requestContext.contextId, this.pickAgentId(requestContext), this.activeTasks, this.queue.length);
|
|
115
|
+
const observedBus = createObservedEventBus(entry.eventBus, (event) => {
|
|
116
|
+
const status = event.kind === "task" || event.kind === "status-update" ? event.status : undefined;
|
|
117
|
+
if (!status) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (status.state === "completed" ||
|
|
121
|
+
status.state === "failed" ||
|
|
122
|
+
status.state === "canceled" ||
|
|
123
|
+
status.state === "rejected") {
|
|
124
|
+
finalState = status.state;
|
|
125
|
+
if (status.state !== "completed") {
|
|
126
|
+
finalErrorMessage =
|
|
127
|
+
typeof status.message?.parts?.[0] === "object" && status.message.parts[0]?.kind === "text"
|
|
128
|
+
? status.message.parts[0].text
|
|
129
|
+
: finalErrorMessage;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
try {
|
|
134
|
+
await this.delegate.execute(requestContext, observedBus);
|
|
135
|
+
entry.resolve();
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
139
|
+
finalState = finalState || "failed";
|
|
140
|
+
finalErrorMessage = finalErrorMessage || message;
|
|
141
|
+
entry.reject(error instanceof Error ? error : new Error(message));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
this.pendingByTaskId.delete(requestContext.taskId);
|
|
146
|
+
this.activeTasks = Math.max(0, this.activeTasks - 1);
|
|
147
|
+
this.telemetry.recordTaskFinish(requestContext.taskId, requestContext.contextId, finalState || "failed", Date.now() - startedAt, this.activeTasks, this.queue.length, finalErrorMessage);
|
|
148
|
+
// Ensure eventBus.finished() is always called so the SDK's
|
|
149
|
+
// DefaultRequestHandler does not hang waiting for the signal.
|
|
150
|
+
try {
|
|
151
|
+
entry.eventBus.finished();
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// already finished — safe to ignore
|
|
155
|
+
}
|
|
156
|
+
this.drainQueue();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
drainQueue() {
|
|
160
|
+
while (this.activeTasks < this.options.maxConcurrentTasks && this.queue.length > 0) {
|
|
161
|
+
const next = this.queue.shift();
|
|
162
|
+
if (!next) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
void this.runEntry(next);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
queueDelete(taskId) {
|
|
169
|
+
const index = this.queue.findIndex((entry) => entry.requestContext.taskId === taskId);
|
|
170
|
+
if (index !== -1) {
|
|
171
|
+
this.queue.splice(index, 1);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
pickAgentId(requestContext) {
|
|
175
|
+
const message = requestContext.userMessage;
|
|
176
|
+
return typeof message?.agentId === "string" ? message.agentId : "default";
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=queueing-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queueing-executor.js","sourceRoot":"","sources":["../../src/queueing-executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule-based routing — choose peer + agentId based on message content.
|
|
3
|
+
*
|
|
4
|
+
* Rules are evaluated at send-time in priority order (higher priority first).
|
|
5
|
+
* The first matching rule wins.
|
|
6
|
+
*/
|
|
7
|
+
export interface RoutingRule {
|
|
8
|
+
name: string;
|
|
9
|
+
match: {
|
|
10
|
+
/** Regex pattern to match against message text (case-insensitive). */
|
|
11
|
+
pattern?: string;
|
|
12
|
+
/** Match if message contains any of these tags (OR logic). */
|
|
13
|
+
tags?: string[];
|
|
14
|
+
/** Match if target peer has any of these skills. */
|
|
15
|
+
skills?: string[];
|
|
16
|
+
};
|
|
17
|
+
target: {
|
|
18
|
+
peer: string;
|
|
19
|
+
agentId?: string;
|
|
20
|
+
};
|
|
21
|
+
/** Higher = checked first (default: 0). */
|
|
22
|
+
priority?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface RoutingMatch {
|
|
25
|
+
peer: string;
|
|
26
|
+
agentId?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse and validate routing rules from raw config.
|
|
30
|
+
*
|
|
31
|
+
* Invalid entries (missing name, target.peer, or at least one match criterion)
|
|
32
|
+
* are silently dropped.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseRoutingRules(raw: unknown): RoutingRule[];
|
|
35
|
+
/**
|
|
36
|
+
* Evaluate rules in priority order against a message.
|
|
37
|
+
*
|
|
38
|
+
* Match criteria within a single rule are AND-combined:
|
|
39
|
+
* - pattern: regex test against message text
|
|
40
|
+
* - tags: any overlap between message tags and rule tags
|
|
41
|
+
* - skills: target peer advertises at least one required skill
|
|
42
|
+
*
|
|
43
|
+
* Returns the first match or null.
|
|
44
|
+
*
|
|
45
|
+
* The `peerSkills` map is populated from Agent Card discovery during
|
|
46
|
+
* periodic health checks. Skills are cached per peer and refreshed
|
|
47
|
+
* on each successful health check probe.
|
|
48
|
+
*/
|
|
49
|
+
export declare function matchRule(rules: RoutingRule[], message: {
|
|
50
|
+
text: string;
|
|
51
|
+
tags?: string[];
|
|
52
|
+
}, peerSkills?: Map<string, string[]>): RoutingMatch | null;
|
|
53
|
+
//# sourceMappingURL=routing-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing-rules.d.ts","sourceRoot":"","sources":["../../src/routing-rules.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QACL,sEAAsE;QACtE,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,8DAA8D;QAC9D,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,oDAAoD;QACpD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,EAAE,CAuD7D;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,WAAW,EAAE,EACpB,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,EAC1C,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GACjC,YAAY,GAAG,IAAI,CAWrB"}
|