@antseed/cli 0.1.143 → 0.1.145

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.
Files changed (80) hide show
  1. package/README.md +16 -0
  2. package/dist/cli/commands/config/index.d.ts.map +1 -1
  3. package/dist/cli/commands/config/index.js +9 -0
  4. package/dist/cli/commands/config/index.js.map +1 -1
  5. package/dist/cli/commands/seller/capability-prompts.d.ts +17 -0
  6. package/dist/cli/commands/seller/capability-prompts.d.ts.map +1 -0
  7. package/dist/cli/commands/seller/capability-prompts.js +123 -0
  8. package/dist/cli/commands/seller/capability-prompts.js.map +1 -0
  9. package/dist/cli/commands/seller/capability-prompts.test.d.ts +2 -0
  10. package/dist/cli/commands/seller/capability-prompts.test.d.ts.map +1 -0
  11. package/dist/cli/commands/seller/capability-prompts.test.js +99 -0
  12. package/dist/cli/commands/seller/capability-prompts.test.js.map +1 -0
  13. package/dist/cli/commands/seller/setup.d.ts.map +1 -1
  14. package/dist/cli/commands/seller/setup.js +12 -0
  15. package/dist/cli/commands/seller/setup.js.map +1 -1
  16. package/dist/cli/commands/seller/start.d.ts +3 -2
  17. package/dist/cli/commands/seller/start.d.ts.map +1 -1
  18. package/dist/cli/commands/seller/start.js +39 -3
  19. package/dist/cli/commands/seller/start.js.map +1 -1
  20. package/dist/cli/commands/seller/start.test.js +46 -1
  21. package/dist/cli/commands/seller/start.test.js.map +1 -1
  22. package/dist/config/loader.d.ts.map +1 -1
  23. package/dist/config/loader.js +6 -0
  24. package/dist/config/loader.js.map +1 -1
  25. package/dist/config/loader.test.js +33 -0
  26. package/dist/config/loader.test.js.map +1 -1
  27. package/dist/config/service-metadata.d.ts +5 -0
  28. package/dist/config/service-metadata.d.ts.map +1 -0
  29. package/dist/config/service-metadata.js +47 -0
  30. package/dist/config/service-metadata.js.map +1 -0
  31. package/dist/config/service-metadata.test.d.ts +2 -0
  32. package/dist/config/service-metadata.test.d.ts.map +1 -0
  33. package/dist/config/service-metadata.test.js +18 -0
  34. package/dist/config/service-metadata.test.js.map +1 -0
  35. package/dist/config/types.d.ts +5 -0
  36. package/dist/config/types.d.ts.map +1 -1
  37. package/dist/config/validation.d.ts.map +1 -1
  38. package/dist/config/validation.js +2 -0
  39. package/dist/config/validation.js.map +1 -1
  40. package/dist/proxy/buyer-proxy.d.ts +76 -9
  41. package/dist/proxy/buyer-proxy.d.ts.map +1 -1
  42. package/dist/proxy/buyer-proxy.js +508 -68
  43. package/dist/proxy/buyer-proxy.js.map +1 -1
  44. package/dist/proxy/buyer-proxy.test.js +416 -13
  45. package/dist/proxy/buyer-proxy.test.js.map +1 -1
  46. package/dist/proxy/conversation-store.d.ts +6 -1
  47. package/dist/proxy/conversation-store.d.ts.map +1 -1
  48. package/dist/proxy/conversation-store.js +9 -2
  49. package/dist/proxy/conversation-store.js.map +1 -1
  50. package/dist/proxy/conversation-store.test.js +24 -0
  51. package/dist/proxy/conversation-store.test.js.map +1 -1
  52. package/dist/proxy/peer-attribution.d.ts +100 -0
  53. package/dist/proxy/peer-attribution.d.ts.map +1 -0
  54. package/dist/proxy/peer-attribution.js +175 -0
  55. package/dist/proxy/peer-attribution.js.map +1 -0
  56. package/dist/proxy/peer-attribution.test.d.ts +2 -0
  57. package/dist/proxy/peer-attribution.test.d.ts.map +1 -0
  58. package/dist/proxy/peer-attribution.test.js +140 -0
  59. package/dist/proxy/peer-attribution.test.js.map +1 -0
  60. package/dist/proxy/peer-health.d.ts +73 -0
  61. package/dist/proxy/peer-health.d.ts.map +1 -0
  62. package/dist/proxy/peer-health.js +182 -0
  63. package/dist/proxy/peer-health.js.map +1 -0
  64. package/dist/proxy/peer-health.test.d.ts +2 -0
  65. package/dist/proxy/peer-health.test.d.ts.map +1 -0
  66. package/dist/proxy/peer-health.test.js +197 -0
  67. package/dist/proxy/peer-health.test.js.map +1 -0
  68. package/dist/proxy/routing-parameters.test.d.ts +2 -0
  69. package/dist/proxy/routing-parameters.test.d.ts.map +1 -0
  70. package/dist/proxy/routing-parameters.test.js +97 -0
  71. package/dist/proxy/routing-parameters.test.js.map +1 -0
  72. package/dist/proxy/routing.d.ts +8 -0
  73. package/dist/proxy/routing.d.ts.map +1 -1
  74. package/dist/proxy/routing.js +36 -1
  75. package/dist/proxy/routing.js.map +1 -1
  76. package/dist/proxy/service-api-adapter.d.ts +1 -1
  77. package/dist/proxy/service-api-adapter.d.ts.map +1 -1
  78. package/dist/proxy/service-api-adapter.js +1 -1
  79. package/dist/proxy/service-api-adapter.js.map +1 -1
  80. package/package.json +6 -6
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Per-peer failure bookkeeping and cooldown state for the buyer proxy.
3
+ *
4
+ * A peer that stops responding should stop being picked, but only temporarily:
5
+ * peers go offline for legitimate reasons, so there is no permanent auto-ban.
6
+ * Whether a failure is even allowed to escalate is decided separately, by
7
+ * `peer-attribution.ts` — this module owns the state machine, not the blame.
8
+ *
9
+ * Cooldown is always advisory. The proxy still dispatches to a cooling-down
10
+ * peer when a request names it, so a pinned conversation keeps working and no
11
+ * amount of cooldown can deadlock routing.
12
+ */
13
+ // The escalation curve is defined once in
14
+ // `packages/router-core/src/peer-metrics.ts` (`computeFailureCooldownMs`).
15
+ // These constants mirror it; router-core is not a dependency of the CLI and a
16
+ // six-line curve does not justify making it one. Keep the two in step.
17
+ const MAX_FAILURES = 3;
18
+ const BASE_COOLDOWN_MS = 30_000;
19
+ const MAX_DOUBLINGS = 4;
20
+ /** Failures older than this start a fresh streak rather than compounding. */
21
+ export const PEER_HEALTH_WINDOW_MS = 5 * 60_000;
22
+ /** Concurrent requests failing together count as one episode, not several. */
23
+ export const PEER_HEALTH_COALESCE_MS = 1_000;
24
+ /** Ceiling on any single cooldown, and the sanity bound for persisted values. */
25
+ export const PEER_HEALTH_MAX_COOLDOWN_MS = 8 * 60_000;
26
+ /** How long an idle entry is kept before it is forgotten entirely. */
27
+ export const PEER_HEALTH_RETENTION_MS = 24 * 60 * 60_000;
28
+ /** Upper bound on tracked peers, newest failures retained. */
29
+ export const PEER_HEALTH_MAX_ENTRIES = 512;
30
+ const FAILURE_REASONS = [
31
+ 'request-failed', 'seller-5xx', 'seller-timeout', 'seller-busy', 'buyer-local',
32
+ ];
33
+ /** Whether a reason is even a candidate for cooling a peer down. */
34
+ export function reasonEscalates(reason) {
35
+ return reason === 'request-failed' || reason === 'seller-5xx' || reason === 'seller-timeout';
36
+ }
37
+ export function computeCooldownMs(failureStreak) {
38
+ if (!Number.isFinite(failureStreak) || failureStreak < MAX_FAILURES)
39
+ return 0;
40
+ const penaltyPower = Math.min(MAX_DOUBLINGS, Math.trunc(failureStreak) - MAX_FAILURES);
41
+ return Math.min(BASE_COOLDOWN_MS * (2 ** penaltyPower), PEER_HEALTH_MAX_COOLDOWN_MS);
42
+ }
43
+ function emptyEntry() {
44
+ return {
45
+ failureStreak: 0,
46
+ windowStartedAt: 0,
47
+ episodeStartedAt: 0,
48
+ lastFailureAt: 0,
49
+ lastReason: 'request-failed',
50
+ cooldownUntil: 0,
51
+ lastSuccessAt: 0,
52
+ };
53
+ }
54
+ /**
55
+ * Fold a failure into a peer's health.
56
+ *
57
+ * `escalate` comes from the attribution gates: when false the failure is still
58
+ * recorded for diagnostics and UI, but the streak and cooldown stay put.
59
+ */
60
+ export function recordPeerFailureEntry(previous, reason, now, escalate) {
61
+ const prev = previous ?? emptyEntry();
62
+ if (!escalate) {
63
+ return { ...prev, lastFailureAt: now, lastReason: reason };
64
+ }
65
+ // Two requests to the same dead peer failing together are one episode; without
66
+ // this they would skip a doubling step each time concurrency rises.
67
+ const episodeStartedAt = prev.episodeStartedAt;
68
+ if (episodeStartedAt > 0 && now - episodeStartedAt < PEER_HEALTH_COALESCE_MS && now >= prev.lastFailureAt) {
69
+ return { ...prev, lastFailureAt: now, lastReason: reason };
70
+ }
71
+ const windowLapsed = prev.lastFailureAt <= 0
72
+ || now - prev.lastFailureAt > PEER_HEALTH_WINDOW_MS
73
+ // Clock stepped backwards; the old window is meaningless.
74
+ || now < prev.lastFailureAt;
75
+ const failureStreak = windowLapsed ? 1 : prev.failureStreak + 1;
76
+ const cooldownMs = computeCooldownMs(failureStreak);
77
+ return {
78
+ failureStreak,
79
+ windowStartedAt: windowLapsed ? now : (prev.windowStartedAt || now),
80
+ episodeStartedAt: now,
81
+ lastFailureAt: now,
82
+ lastReason: reason,
83
+ cooldownUntil: cooldownMs > 0 ? now + cooldownMs : 0,
84
+ lastSuccessAt: prev.lastSuccessAt,
85
+ };
86
+ }
87
+ /**
88
+ * Any response from a peer is proof of life, so a success wipes the streak and
89
+ * releases the cooldown. `lastSuccessAt` is kept for diagnostics.
90
+ */
91
+ export function clearPeerHealthEntry(previous, now) {
92
+ return {
93
+ ...(previous ?? emptyEntry()),
94
+ failureStreak: 0,
95
+ windowStartedAt: 0,
96
+ episodeStartedAt: 0,
97
+ cooldownUntil: 0,
98
+ lastSuccessAt: now,
99
+ };
100
+ }
101
+ export function isCoolingDown(entry, now) {
102
+ if (!entry || entry.cooldownUntil <= now)
103
+ return false;
104
+ // A corrupt or clock-skewed future value must not hold a peer hostage.
105
+ return entry.cooldownUntil - now <= PEER_HEALTH_MAX_COOLDOWN_MS;
106
+ }
107
+ /** Whether an entry still carries information worth persisting. */
108
+ function isEntryMeaningful(entry, now) {
109
+ if (entry.cooldownUntil > now)
110
+ return true;
111
+ const lastActivity = Math.max(entry.lastFailureAt, entry.lastSuccessAt);
112
+ if (lastActivity <= 0)
113
+ return false;
114
+ return now - lastActivity < PEER_HEALTH_RETENTION_MS;
115
+ }
116
+ /** Drop stale entries and cap the map, keeping the most recently active peers. */
117
+ export function prunePeerHealth(entries, now) {
118
+ const kept = [...entries.entries()].filter(([, entry]) => isEntryMeaningful(entry, now));
119
+ if (kept.length > PEER_HEALTH_MAX_ENTRIES) {
120
+ kept.sort((a, b) => Math.max(b[1].lastFailureAt, b[1].lastSuccessAt)
121
+ - Math.max(a[1].lastFailureAt, a[1].lastSuccessAt));
122
+ kept.length = PEER_HEALTH_MAX_ENTRIES;
123
+ }
124
+ return new Map(kept);
125
+ }
126
+ function finiteNonNegative(value) {
127
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : 0;
128
+ }
129
+ /**
130
+ * Parse the `peerHealth` map out of a buyer.state.json blob.
131
+ *
132
+ * Cooldown survives a restart — a peer that died ten seconds before we exited is
133
+ * still dead — but is never extended or resurrected by one: anything expired,
134
+ * impossibly far in the future, or stamped after `now` is discarded.
135
+ */
136
+ export function parsePersistedPeerHealth(parsed, now = Date.now()) {
137
+ const result = new Map();
138
+ if (!parsed || typeof parsed !== 'object')
139
+ return result;
140
+ const raw = parsed.peerHealth;
141
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
142
+ return result;
143
+ for (const [rawPeerId, rawEntry] of Object.entries(raw)) {
144
+ const peerId = rawPeerId.toLowerCase();
145
+ if (!/^[0-9a-f]{40}$/.test(peerId))
146
+ continue;
147
+ if (!rawEntry || typeof rawEntry !== 'object' || Array.isArray(rawEntry))
148
+ continue;
149
+ const entry = rawEntry;
150
+ const lastFailureAt = finiteNonNegative(entry.lastFailureAt);
151
+ const lastSuccessAt = finiteNonNegative(entry.lastSuccessAt);
152
+ // Timestamps ahead of the clock mean the entry cannot be reasoned about.
153
+ if (lastFailureAt > now || lastSuccessAt > now)
154
+ continue;
155
+ const rawStreak = finiteNonNegative(entry.failureStreak);
156
+ const failureStreak = Math.min(64, Math.trunc(rawStreak));
157
+ const lastReason = FAILURE_REASONS.includes(entry.lastReason)
158
+ ? entry.lastReason
159
+ : 'request-failed';
160
+ const rawCooldown = finiteNonNegative(entry.cooldownUntil);
161
+ const cooldownUntil = rawCooldown > now && rawCooldown - now <= PEER_HEALTH_MAX_COOLDOWN_MS
162
+ ? rawCooldown
163
+ : 0;
164
+ const candidate = {
165
+ failureStreak,
166
+ windowStartedAt: Math.min(finiteNonNegative(entry.windowStartedAt), now),
167
+ episodeStartedAt: Math.min(finiteNonNegative(entry.episodeStartedAt) || lastFailureAt, now),
168
+ lastFailureAt,
169
+ lastReason,
170
+ cooldownUntil,
171
+ lastSuccessAt,
172
+ };
173
+ if (!isEntryMeaningful(candidate, now))
174
+ continue;
175
+ result.set(peerId, candidate);
176
+ }
177
+ return prunePeerHealth(result, now);
178
+ }
179
+ export function serializePeerHealth(entries) {
180
+ return Object.fromEntries(entries);
181
+ }
182
+ //# sourceMappingURL=peer-health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peer-health.js","sourceRoot":"","sources":["../../src/proxy/peer-health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=peer-health.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peer-health.test.d.ts","sourceRoot":"","sources":["../../src/proxy/peer-health.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,197 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { recordPeerFailureEntry, clearPeerHealthEntry, isCoolingDown, parsePersistedPeerHealth, prunePeerHealth, computeCooldownMs, reasonEscalates, PEER_HEALTH_WINDOW_MS, PEER_HEALTH_COALESCE_MS, PEER_HEALTH_MAX_COOLDOWN_MS, PEER_HEALTH_RETENTION_MS, PEER_HEALTH_MAX_ENTRIES, } from './peer-health.js';
4
+ const NOW = 1_700_000_000_000;
5
+ const A = 'a'.repeat(40);
6
+ function escalatingFailures(count, startAt = NOW, stepMs = 2_000) {
7
+ let entry;
8
+ for (let i = 0; i < count; i += 1) {
9
+ entry = recordPeerFailureEntry(entry, 'request-failed', startAt + i * stepMs, true);
10
+ }
11
+ return entry;
12
+ }
13
+ test('reasonEscalates only admits reasons that indicate the peer is down', () => {
14
+ assert.equal(reasonEscalates('request-failed'), true);
15
+ assert.equal(reasonEscalates('seller-5xx'), true);
16
+ assert.equal(reasonEscalates('seller-timeout'), true);
17
+ assert.equal(reasonEscalates('seller-busy'), false);
18
+ assert.equal(reasonEscalates('buyer-local'), false);
19
+ });
20
+ test('computeCooldownMs matches the shared escalation curve and its ceiling', () => {
21
+ assert.equal(computeCooldownMs(2), 0);
22
+ assert.equal(computeCooldownMs(3), 30_000);
23
+ assert.equal(computeCooldownMs(4), 60_000);
24
+ assert.equal(computeCooldownMs(5), 120_000);
25
+ assert.equal(computeCooldownMs(7), 480_000);
26
+ assert.equal(computeCooldownMs(50), PEER_HEALTH_MAX_COOLDOWN_MS);
27
+ });
28
+ test('a peer cools down only on the third failure in the window', () => {
29
+ const after1 = recordPeerFailureEntry(undefined, 'request-failed', NOW, true);
30
+ assert.equal(after1.failureStreak, 1);
31
+ assert.equal(isCoolingDown(after1, NOW), false);
32
+ const after2 = recordPeerFailureEntry(after1, 'request-failed', NOW + 2_000, true);
33
+ assert.equal(isCoolingDown(after2, NOW + 2_000), false);
34
+ const after3 = recordPeerFailureEntry(after2, 'request-failed', NOW + 4_000, true);
35
+ assert.equal(after3.failureStreak, 3);
36
+ assert.equal(after3.cooldownUntil, NOW + 4_000 + 30_000);
37
+ assert.equal(isCoolingDown(after3, NOW + 4_000), true);
38
+ });
39
+ test('further failures double the cooldown', () => {
40
+ const after4 = escalatingFailures(4);
41
+ assert.equal(after4.cooldownUntil - after4.lastFailureAt, 60_000);
42
+ const after5 = escalatingFailures(5);
43
+ assert.equal(after5.cooldownUntil - after5.lastFailureAt, 120_000);
44
+ });
45
+ test('a non-escalating failure updates diagnostics but never the streak or cooldown', () => {
46
+ const escalated = escalatingFailures(2);
47
+ const suppressed = recordPeerFailureEntry(escalated, 'seller-busy', NOW + 10_000, false);
48
+ assert.equal(suppressed.failureStreak, escalated.failureStreak);
49
+ assert.equal(suppressed.cooldownUntil, escalated.cooldownUntil);
50
+ assert.equal(suppressed.lastReason, 'seller-busy');
51
+ assert.equal(suppressed.lastFailureAt, NOW + 10_000);
52
+ });
53
+ test('a diagnostic-only failure does not coalesce away the next escalating failure', () => {
54
+ const diagnostic = recordPeerFailureEntry(undefined, 'seller-busy', NOW, false);
55
+ const escalated = recordPeerFailureEntry(diagnostic, 'request-failed', NOW + 100, true);
56
+ assert.equal(escalated.failureStreak, 1);
57
+ assert.equal(escalated.episodeStartedAt, NOW + 100);
58
+ });
59
+ test('failures inside the coalesce window count as a single episode', () => {
60
+ let entry = recordPeerFailureEntry(undefined, 'request-failed', NOW, true);
61
+ entry = recordPeerFailureEntry(entry, 'request-failed', NOW + 100, true);
62
+ entry = recordPeerFailureEntry(entry, 'request-failed', NOW + 200, true);
63
+ assert.equal(entry.failureStreak, 1);
64
+ assert.equal(isCoolingDown(entry, NOW + 200), false);
65
+ });
66
+ test('the coalesce window is anchored to the episode start', () => {
67
+ let entry = recordPeerFailureEntry(undefined, 'request-failed', NOW, true);
68
+ entry = recordPeerFailureEntry(entry, 'request-failed', NOW + PEER_HEALTH_COALESCE_MS - 100, true);
69
+ entry = recordPeerFailureEntry(entry, 'request-failed', NOW + PEER_HEALTH_COALESCE_MS + 100, true);
70
+ assert.equal(entry.failureStreak, 2);
71
+ assert.equal(entry.episodeStartedAt, NOW + PEER_HEALTH_COALESCE_MS + 100);
72
+ });
73
+ test('a lapsed window starts a fresh streak instead of compounding', () => {
74
+ const twoFailures = escalatingFailures(2);
75
+ const muchLater = recordPeerFailureEntry(twoFailures, 'request-failed', twoFailures.lastFailureAt + PEER_HEALTH_WINDOW_MS + 1, true);
76
+ assert.equal(muchLater.failureStreak, 1);
77
+ assert.equal(muchLater.cooldownUntil, 0);
78
+ });
79
+ test('a backwards clock jump resets the window rather than compounding', () => {
80
+ const twoFailures = escalatingFailures(2);
81
+ const backwards = recordPeerFailureEntry(twoFailures, 'request-failed', NOW - 60_000, true);
82
+ assert.equal(backwards.failureStreak, 1);
83
+ assert.equal(backwards.cooldownUntil, 0);
84
+ });
85
+ test('a success clears the streak and releases the cooldown', () => {
86
+ const cooling = escalatingFailures(3);
87
+ assert.equal(isCoolingDown(cooling, cooling.lastFailureAt), true);
88
+ const recovered = clearPeerHealthEntry(cooling, cooling.lastFailureAt + 1_000);
89
+ assert.equal(recovered.failureStreak, 0);
90
+ assert.equal(recovered.cooldownUntil, 0);
91
+ assert.equal(recovered.lastSuccessAt, cooling.lastFailureAt + 1_000);
92
+ assert.equal(isCoolingDown(recovered, recovered.lastSuccessAt), false);
93
+ });
94
+ test('isCoolingDown rejects an impossibly distant cooldown', () => {
95
+ const entry = {
96
+ ...escalatingFailures(3),
97
+ cooldownUntil: NOW + PEER_HEALTH_MAX_COOLDOWN_MS * 10,
98
+ };
99
+ assert.equal(isCoolingDown(entry, NOW), false);
100
+ });
101
+ test('parsePersistedPeerHealth ignores junk input', () => {
102
+ assert.equal(parsePersistedPeerHealth(null, NOW).size, 0);
103
+ assert.equal(parsePersistedPeerHealth('nope', NOW).size, 0);
104
+ assert.equal(parsePersistedPeerHealth({}, NOW).size, 0);
105
+ assert.equal(parsePersistedPeerHealth({ peerHealth: [] }, NOW).size, 0);
106
+ assert.equal(parsePersistedPeerHealth({ peerHealth: 'x' }, NOW).size, 0);
107
+ });
108
+ test('parsePersistedPeerHealth rejects malformed peer ids and entries', () => {
109
+ const parsed = parsePersistedPeerHealth({
110
+ peerHealth: {
111
+ 'not-a-peer-id': { lastFailureAt: NOW - 1_000, failureStreak: 3 },
112
+ [`0x${'a'.repeat(40)}`]: { lastFailureAt: NOW - 1_000, failureStreak: 3 },
113
+ [A]: 'not-an-object',
114
+ },
115
+ }, NOW);
116
+ assert.equal(parsed.size, 0);
117
+ });
118
+ test('parsePersistedPeerHealth restores a live cooldown unchanged', () => {
119
+ const cooldownUntil = NOW + 20_000;
120
+ const parsed = parsePersistedPeerHealth({
121
+ peerHealth: {
122
+ [A.toUpperCase()]: {
123
+ failureStreak: 3, windowStartedAt: NOW - 5_000, lastFailureAt: NOW - 1_000,
124
+ lastReason: 'seller-5xx', cooldownUntil, lastSuccessAt: 0,
125
+ },
126
+ },
127
+ }, NOW);
128
+ const entry = parsed.get(A);
129
+ assert.ok(entry);
130
+ assert.equal(entry.cooldownUntil, cooldownUntil);
131
+ assert.equal(entry.failureStreak, 3);
132
+ assert.equal(entry.lastReason, 'seller-5xx');
133
+ });
134
+ test('parsePersistedPeerHealth drops an expired or impossible cooldown', () => {
135
+ const expired = parsePersistedPeerHealth({
136
+ peerHealth: { [A]: { failureStreak: 3, lastFailureAt: NOW - 1_000, cooldownUntil: NOW - 1 } },
137
+ }, NOW);
138
+ assert.equal(expired.get(A)?.cooldownUntil, 0);
139
+ const absurd = parsePersistedPeerHealth({
140
+ peerHealth: {
141
+ [A]: {
142
+ failureStreak: 3,
143
+ lastFailureAt: NOW - 1_000,
144
+ cooldownUntil: NOW + PEER_HEALTH_MAX_COOLDOWN_MS * 100,
145
+ },
146
+ },
147
+ }, NOW);
148
+ assert.equal(absurd.get(A)?.cooldownUntil, 0);
149
+ });
150
+ test('parsePersistedPeerHealth discards entries stamped in the future', () => {
151
+ const parsed = parsePersistedPeerHealth({
152
+ peerHealth: { [A]: { failureStreak: 3, lastFailureAt: NOW + 60_000 } },
153
+ }, NOW);
154
+ assert.equal(parsed.size, 0);
155
+ });
156
+ test('parsePersistedPeerHealth coerces non-finite numbers and unknown reasons', () => {
157
+ const parsed = parsePersistedPeerHealth({
158
+ peerHealth: {
159
+ [A]: {
160
+ failureStreak: 'lots', windowStartedAt: Number.NaN, lastFailureAt: NOW - 1_000,
161
+ lastReason: 'made-up-reason', cooldownUntil: Number.POSITIVE_INFINITY,
162
+ lastSuccessAt: -5,
163
+ },
164
+ },
165
+ }, NOW);
166
+ const entry = parsed.get(A);
167
+ assert.ok(entry);
168
+ assert.equal(entry.failureStreak, 0);
169
+ assert.equal(entry.windowStartedAt, 0);
170
+ assert.equal(entry.lastReason, 'request-failed');
171
+ assert.equal(entry.cooldownUntil, 0);
172
+ assert.equal(entry.lastSuccessAt, 0);
173
+ });
174
+ test('parsePersistedPeerHealth forgets entries past the retention window', () => {
175
+ const parsed = parsePersistedPeerHealth({
176
+ peerHealth: { [A]: { failureStreak: 3, lastFailureAt: NOW - PEER_HEALTH_RETENTION_MS - 1 } },
177
+ }, NOW);
178
+ assert.equal(parsed.size, 0);
179
+ });
180
+ test('prunePeerHealth caps the map keeping the most recently active peers', () => {
181
+ const entries = new Map();
182
+ const total = PEER_HEALTH_MAX_ENTRIES + 10;
183
+ for (let i = 0; i < total; i += 1) {
184
+ const peerId = i.toString(16).padStart(40, '0');
185
+ entries.set(peerId, {
186
+ failureStreak: 1, windowStartedAt: 0, lastFailureAt: NOW - (total - i) * 1_000,
187
+ episodeStartedAt: NOW - (total - i) * 1_000,
188
+ lastReason: 'request-failed', cooldownUntil: 0, lastSuccessAt: 0,
189
+ });
190
+ }
191
+ const pruned = prunePeerHealth(entries, NOW);
192
+ assert.equal(pruned.size, PEER_HEALTH_MAX_ENTRIES);
193
+ // The freshest peer survives; the stalest is evicted.
194
+ assert.ok(pruned.has((total - 1).toString(16).padStart(40, '0')));
195
+ assert.equal(pruned.has((0).toString(16).padStart(40, '0')), false);
196
+ });
197
+ //# sourceMappingURL=peer-health.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peer-health.test.js","sourceRoot":"","sources":["../../src/proxy/peer-health.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=routing-parameters.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing-parameters.test.d.ts","sourceRoot":"","sources":["../../src/proxy/routing-parameters.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,97 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { findUnannouncedRequestParameters } from './routing.js';
4
+ const encode = (value) => new TextEncoder().encode(JSON.stringify(value));
5
+ function makePeer(overrides = {}) {
6
+ return {
7
+ peerId: 'a'.repeat(40),
8
+ lastSeen: 0,
9
+ providers: ['openai'],
10
+ ...overrides,
11
+ };
12
+ }
13
+ function makeRequest(body) {
14
+ return {
15
+ requestId: 'req-1',
16
+ method: 'POST',
17
+ path: '/v1/images/generations',
18
+ headers: { 'content-type': 'application/json' },
19
+ body: encode(body),
20
+ };
21
+ }
22
+ const imagePeer = makePeer({
23
+ providerServiceCapabilities: {
24
+ openai: {
25
+ services: {
26
+ 'gpt-image-1': {
27
+ outputs: ['image'],
28
+ supportedParameters: ['background', 'output_format', 'quality', 'size'],
29
+ },
30
+ },
31
+ },
32
+ },
33
+ });
34
+ test('flags parameters outside the announced list plus protocol baseline', () => {
35
+ const unannounced = findUnannouncedRequestParameters(imagePeer, 'openai', 'gpt-image-1', 'openai-images', makeRequest({ model: 'gpt-image-1', prompt: 'an ant', n: 2, size: '1024x1024', seed: 42, style: 'vivid' }));
36
+ assert.deepEqual(unannounced.sort(), ['seed', 'style']);
37
+ });
38
+ test('accepts requests that stay within the announced list', () => {
39
+ const unannounced = findUnannouncedRequestParameters(imagePeer, 'openai', 'gpt-image-1', 'openai-images', makeRequest({ model: 'gpt-image-1', prompt: 'an ant', background: 'transparent', output_format: 'webp' }));
40
+ assert.deepEqual(unannounced, []);
41
+ });
42
+ test('never flags when the peer announces no supportedParameters', () => {
43
+ const silentPeer = makePeer({
44
+ providerServiceCapabilities: {
45
+ openai: { services: { 'gpt-image-1': { outputs: ['image'] } } },
46
+ },
47
+ });
48
+ const request = makeRequest({ model: 'gpt-image-1', prompt: 'an ant', seed: 42 });
49
+ assert.deepEqual(findUnannouncedRequestParameters(silentPeer, 'openai', 'gpt-image-1', 'openai-images', request), []);
50
+ assert.deepEqual(findUnannouncedRequestParameters(makePeer(), 'openai', 'gpt-image-1', 'openai-images', request), []);
51
+ });
52
+ test('matches provider and service names case-insensitively', () => {
53
+ const unannounced = findUnannouncedRequestParameters(imagePeer, 'OpenAI', 'GPT-Image-1', 'openai-images', makeRequest({ model: 'gpt-image-1', prompt: 'an ant', seed: 42 }));
54
+ assert.deepEqual(unannounced, ['seed']);
55
+ });
56
+ test('checks multipart text fields and ignores file parts', () => {
57
+ const boundary = 'test-boundary';
58
+ const multipart = [
59
+ `--${boundary}`,
60
+ 'content-disposition: form-data; name="model"',
61
+ '',
62
+ 'gpt-image-1',
63
+ `--${boundary}`,
64
+ 'content-disposition: form-data; name="seed"',
65
+ '',
66
+ '42',
67
+ `--${boundary}`,
68
+ 'content-disposition: form-data; name="image"; filename="in.png"',
69
+ 'content-type: image/png',
70
+ '',
71
+ 'binary-bytes',
72
+ `--${boundary}--`,
73
+ '',
74
+ ].join('\r\n');
75
+ const unannounced = findUnannouncedRequestParameters(imagePeer, 'openai', 'gpt-image-1', 'openai-images', {
76
+ requestId: 'req-2',
77
+ method: 'POST',
78
+ path: '/v1/images/edits',
79
+ headers: { 'content-type': `multipart/form-data; boundary=${boundary}` },
80
+ body: new TextEncoder().encode(multipart),
81
+ });
82
+ assert.deepEqual(unannounced, ['seed']);
83
+ });
84
+ test('skips unparseable bodies and requests without a resolved service or protocol', () => {
85
+ const rawRequest = {
86
+ requestId: 'req-3',
87
+ method: 'POST',
88
+ path: '/v1/images/generations',
89
+ headers: { 'content-type': 'application/json' },
90
+ body: new TextEncoder().encode('not-json'),
91
+ };
92
+ assert.deepEqual(findUnannouncedRequestParameters(imagePeer, 'openai', 'gpt-image-1', 'openai-images', rawRequest), []);
93
+ const request = makeRequest({ model: 'gpt-image-1', prompt: 'an ant', seed: 42 });
94
+ assert.deepEqual(findUnannouncedRequestParameters(imagePeer, 'openai', null, 'openai-images', request), []);
95
+ assert.deepEqual(findUnannouncedRequestParameters(imagePeer, 'openai', 'gpt-image-1', null, request), []);
96
+ });
97
+ //# sourceMappingURL=routing-parameters.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing-parameters.test.js","sourceRoot":"","sources":["../../src/proxy/routing-parameters.test.ts"],"names":[],"mappings":"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"}
@@ -13,5 +13,13 @@ export declare function getExplicitProviderOverride(request: SerializedHttpReque
13
13
  export declare function getExplicitPeerIdOverride(request: SerializedHttpRequest, sessionPinnedPeerId: string | undefined, requestPinnedPeerId?: string | null): string | null;
14
14
  export declare function resolvePeerRoutePlan(peer: PeerInfo, requestProtocol: ServiceApiProtocol | null, requestedService: string | null, explicitProvider: string | null, serviceFilterMode?: ServiceFilterMode): PeerProtocolRoutePlan | null;
15
15
  export declare function selectCandidatePeersForRouting(peers: PeerInfo[], requestProtocol: ServiceApiProtocol | null, requestedService: string | null, explicitProvider: string | null, serviceFilterMode?: ServiceFilterMode): CandidatePeerRouteSelection;
16
+ /**
17
+ * Soft pre-flight check against the peer's announced `supportedParameters`
18
+ * capability: returns request-body parameter names the peer did not announce
19
+ * for the routed service. Empty when the peer announces no list (absence
20
+ * means unknown, not unsupported) or the body is not parseable. Callers log
21
+ * a warning — never reject — since the list is a hint, not a contract.
22
+ */
23
+ export declare function findUnannouncedRequestParameters(peer: PeerInfo, provider: string, requestedService: string | null, requestProtocol: ServiceApiProtocol | null, request: SerializedHttpRequest): string[];
16
24
  export declare function pickProviderForPeer(peer: PeerInfo, request: SerializedHttpRequest): string;
17
25
  //# sourceMappingURL=routing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/proxy/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AACpE,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC7B,MAAM,0BAA0B,CAAA;AAGjC,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,uBAAuB,GAAG,IAAI,CAAA;CAC1C,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,cAAc,EAAE,QAAQ,EAAE,CAAA;IAC1B,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;CACtD,CAAA;AAKD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,SAAS,CAAA;AAEpD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,GAAG,IAAI,CAGzF;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,qBAAqB,EAC9B,mBAAmB,EAAE,MAAM,GAAG,SAAS,EACvC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,GAClC,MAAM,GAAG,IAAI,CAMf;AAiGD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,QAAQ,EACd,eAAe,EAAE,kBAAkB,GAAG,IAAI,EAC1C,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,iBAAiB,GAAE,iBAA4B,GAC9C,qBAAqB,GAAG,IAAI,CAkC9B;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,QAAQ,EAAE,EACjB,eAAe,EAAE,kBAAkB,GAAG,IAAI,EAC1C,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,iBAAiB,GAAE,iBAA4B,GAC9C,2BAA2B,CAoB7B;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAgB1F"}
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/proxy/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AACpE,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC7B,MAAM,0BAA0B,CAAA;AAGjC,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,uBAAuB,GAAG,IAAI,CAAA;CAC1C,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,cAAc,EAAE,QAAQ,EAAE,CAAA;IAC1B,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;CACtD,CAAA;AAKD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,SAAS,CAAA;AAEpD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,GAAG,IAAI,CAGzF;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,qBAAqB,EAC9B,mBAAmB,EAAE,MAAM,GAAG,SAAS,EACvC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,GAClC,MAAM,GAAG,IAAI,CAMf;AAiGD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,QAAQ,EACd,eAAe,EAAE,kBAAkB,GAAG,IAAI,EAC1C,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,iBAAiB,GAAE,iBAA4B,GAC9C,qBAAqB,GAAG,IAAI,CAkC9B;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,QAAQ,EAAE,EACjB,eAAe,EAAE,kBAAkB,GAAG,IAAI,EAC1C,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,iBAAiB,GAAE,iBAA4B,GAC9C,2BAA2B,CAoB7B;AAYD;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,eAAe,EAAE,kBAAkB,GAAG,IAAI,EAC1C,OAAO,EAAE,qBAAqB,GAC7B,MAAM,EAAE,CAgBV;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAgB1F"}
@@ -1,4 +1,4 @@
1
- import { inferProviderDefaultServiceApiProtocols, selectTargetProtocolForRequest, } from './service-api-adapter.js';
1
+ import { extractRequestBodyFields, inferProviderDefaultServiceApiProtocols, selectTargetProtocolForRequest, } from './service-api-adapter.js';
2
2
  import { log, normalizePeerId } from './request-utils.js';
3
3
  export function getExplicitProviderOverride(request) {
4
4
  const provider = request.headers['x-antseed-provider']?.trim().toLowerCase();
@@ -112,6 +112,41 @@ export function selectCandidatePeersForRouting(peers, requestProtocol, requested
112
112
  routePlanByPeerId,
113
113
  };
114
114
  }
115
+ // Protocol-core request fields that are never flagged against a peer's
116
+ // announced supportedParameters: the announced list describes optional
117
+ // extras, not the fields every request on that protocol carries.
118
+ const PROTOCOL_BASELINE_FIELDS = {
119
+ 'openai-images': ['model', 'prompt', 'image', 'mask', 'n', 'stream'],
120
+ 'openai-chat-completions': ['model', 'messages', 'stream'],
121
+ 'openai-responses': ['model', 'input', 'stream'],
122
+ 'anthropic-messages': ['model', 'messages', 'max_tokens', 'stream'],
123
+ };
124
+ /**
125
+ * Soft pre-flight check against the peer's announced `supportedParameters`
126
+ * capability: returns request-body parameter names the peer did not announce
127
+ * for the routed service. Empty when the peer announces no list (absence
128
+ * means unknown, not unsupported) or the body is not parseable. Callers log
129
+ * a warning — never reject — since the list is a hint, not a contract.
130
+ */
131
+ export function findUnannouncedRequestParameters(peer, provider, requestedService, requestProtocol, request) {
132
+ const normalizedService = requestedService?.trim().toLowerCase();
133
+ if (!requestProtocol || !normalizedService)
134
+ return [];
135
+ const providerKey = Object.keys(peer.providerServiceCapabilities ?? {})
136
+ .find((key) => key.toLowerCase() === provider.toLowerCase());
137
+ const services = providerKey ? peer.providerServiceCapabilities?.[providerKey]?.services : undefined;
138
+ if (!services)
139
+ return [];
140
+ const serviceKey = Object.keys(services).find((key) => key.toLowerCase() === normalizedService);
141
+ const announced = serviceKey ? services[serviceKey]?.supportedParameters : undefined;
142
+ if (!announced || announced.length === 0)
143
+ return [];
144
+ const fields = extractRequestBodyFields(request.headers, request.body);
145
+ if (!fields)
146
+ return [];
147
+ const allowed = new Set([...announced, ...(PROTOCOL_BASELINE_FIELDS[requestProtocol] ?? [])]);
148
+ return Object.keys(fields).filter((key) => !allowed.has(key));
149
+ }
115
150
  export function pickProviderForPeer(peer, request) {
116
151
  const explicit = getExplicitProviderOverride(request);
117
152
  if (explicit) {
@@ -1 +1 @@
1
- {"version":3,"file":"routing.js","sourceRoot":"","sources":["../../src/proxy/routing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"routing.js","sourceRoot":"","sources":["../../src/proxy/routing.ts"],"names":[],"mappings":"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"}