nexus-agents 2.26.1 → 2.28.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.
Files changed (49) hide show
  1. package/README.md +7 -7
  2. package/dist/{chunk-X33QNBGA.js → chunk-E7EX2KQJ.js} +3 -5
  3. package/dist/{chunk-X33QNBGA.js.map → chunk-E7EX2KQJ.js.map} +1 -1
  4. package/dist/{chunk-BOWNZMPH.js → chunk-L2SHSW4T.js} +3017 -1300
  5. package/dist/chunk-L2SHSW4T.js.map +1 -0
  6. package/dist/{chunk-ARNVVQ5W.js → chunk-LKSTILEE.js} +1213 -117
  7. package/dist/chunk-LKSTILEE.js.map +1 -0
  8. package/dist/{chunk-L3LQ3RP5.js → chunk-QZEAD6AG.js} +10339 -6289
  9. package/dist/chunk-QZEAD6AG.js.map +1 -0
  10. package/dist/{chunk-LCHCASB7.js → chunk-UGNLR4NZ.js} +2 -2
  11. package/dist/{chunk-UVQ7R4C4.js → chunk-YSDUVCCZ.js} +137 -717
  12. package/dist/chunk-YSDUVCCZ.js.map +1 -0
  13. package/dist/cli.d.ts +8 -1
  14. package/dist/cli.js +644 -216
  15. package/dist/cli.js.map +1 -1
  16. package/dist/{dist-Y5F6UM2N.js → dist-H5XNXVAV.js} +1384 -1295
  17. package/dist/dist-H5XNXVAV.js.map +1 -0
  18. package/dist/doctor-deep-BDE2PHVX.js +11 -0
  19. package/dist/index.d.ts +4299 -7411
  20. package/dist/index.js +588 -132
  21. package/dist/index.js.map +1 -1
  22. package/dist/{setup-command-VNF3KTCJ.js → setup-command-SS7LMN7Y.js} +5 -6
  23. package/dist/setup-config-DSMOOLVW.js +9 -0
  24. package/dist/workflows/templates/code-review.yaml +1 -1
  25. package/dist/workflows/templates/refactoring.yaml +1 -1
  26. package/dist/workflows/templates/research-review.yaml +19 -4
  27. package/dist/workflows/templates/security-audit.yaml +1 -1
  28. package/dist/workflows/templates/standards-review.yaml +1 -1
  29. package/package.json +12 -12
  30. package/src/workflows/templates/code-review.yaml +1 -1
  31. package/src/workflows/templates/refactoring.yaml +1 -1
  32. package/src/workflows/templates/research-review.yaml +19 -4
  33. package/src/workflows/templates/security-audit.yaml +1 -1
  34. package/src/workflows/templates/standards-review.yaml +1 -1
  35. package/dist/chunk-ARNVVQ5W.js.map +0 -1
  36. package/dist/chunk-BOWNZMPH.js.map +0 -1
  37. package/dist/chunk-L3LQ3RP5.js.map +0 -1
  38. package/dist/chunk-LCDOP543.js +0 -365
  39. package/dist/chunk-LCDOP543.js.map +0 -1
  40. package/dist/chunk-PGNRXCYY.js +0 -776
  41. package/dist/chunk-PGNRXCYY.js.map +0 -1
  42. package/dist/chunk-UVQ7R4C4.js.map +0 -1
  43. package/dist/dist-Y5F6UM2N.js.map +0 -1
  44. package/dist/doctor-deep-I2J5CRFG.js +0 -13
  45. package/dist/setup-config-VQSWWJ5O.js +0 -9
  46. /package/dist/{chunk-LCHCASB7.js.map → chunk-UGNLR4NZ.js.map} +0 -0
  47. /package/dist/{doctor-deep-I2J5CRFG.js.map → doctor-deep-BDE2PHVX.js.map} +0 -0
  48. /package/dist/{setup-command-VNF3KTCJ.js.map → setup-command-SS7LMN7Y.js.map} +0 -0
  49. /package/dist/{setup-config-VQSWWJ5O.js.map → setup-config-DSMOOLVW.js.map} +0 -0
@@ -1,776 +0,0 @@
1
- import {
2
- HEARTBEAT_TIMEOUTS
3
- } from "./chunk-LCDOP543.js";
4
- import {
5
- CLI_NAMES,
6
- RateLimitError,
7
- TASK_CATEGORIES,
8
- computeAdaptiveThresholds,
9
- getErrorMessage,
10
- getOutcomeStore,
11
- getSpecialization,
12
- getTimeProvider
13
- } from "./chunk-BOWNZMPH.js";
14
-
15
- // src/mcp/tools/weather-report-types.ts
16
- import { z } from "zod";
17
- var WeatherReportInputSchema = z.object({
18
- /** Filter by CLI name. */
19
- cli: z.enum(CLI_NAMES).optional().describe("Filter by CLI"),
20
- /** Filter by task category. */
21
- category: z.enum([
22
- "architecture",
23
- "code_generation",
24
- "code_review",
25
- "research",
26
- "security_review",
27
- "planning",
28
- "documentation",
29
- "testing",
30
- "devops",
31
- "exploration"
32
- ]).optional().describe("Filter by task category"),
33
- /** Include adaptive routing bonus data. */
34
- includeAdaptive: z.boolean().optional().default(true).describe("Include adaptive routing bonuses (default: true)")
35
- });
36
- var WeatherReportConfigSchema = z.object({
37
- /** Minimum observations before adjusting bonuses (lowered for faster activation). */
38
- coldStartThreshold: z.number().int().min(1).max(1e3).default(3),
39
- /** Exploration rate: fraction of random routing (0.0-1.0). */
40
- explorationRate: z.number().min(0).max(1).default(0.1),
41
- /** Max adaptive bonus adjustment (+/-). */
42
- maxBonusAdjustment: z.number().min(0).max(10).default(5)
43
- });
44
- function createDefaultWeatherConfig() {
45
- return WeatherReportConfigSchema.parse({});
46
- }
47
-
48
- // src/mcp/gateway/gateway-keywords.ts
49
- var SECURITY_KEYWORDS = [
50
- "security",
51
- "vulnerabilit",
52
- "cve-",
53
- "exploit",
54
- "injection",
55
- "xss",
56
- "csrf",
57
- "auth",
58
- "penetration",
59
- "threat",
60
- "malware",
61
- "credentials",
62
- "secrets",
63
- "encryption",
64
- "certificate"
65
- ];
66
- var ARCHITECTURE_KEYWORDS = [
67
- "architecture",
68
- "breaking change",
69
- "breaking api",
70
- "api change",
71
- "migration",
72
- "refactor.*system",
73
- "redesign",
74
- "microservice",
75
- "monolith",
76
- "deprecation",
77
- "schema change",
78
- "database",
79
- "infrastructure"
80
- ];
81
- var PROMOTED_ROLES = /* @__PURE__ */ new Set(["security_expert", "architecture_expert"]);
82
-
83
- // src/mcp/gateway/tier-classifier.ts
84
- var TOOL_TIER_MAP = {
85
- // Tier 1 — Read-only
86
- list_experts: 1 /* DIRECT */,
87
- list_workflows: 1 /* DIRECT */,
88
- memory_query: 1 /* DIRECT */,
89
- memory_stats: 1 /* DIRECT */,
90
- weather_report: 1 /* DIRECT */,
91
- research_query: 1 /* DIRECT */,
92
- research_analyze: 1 /* DIRECT */,
93
- research_catalog_review: 1 /* DIRECT */,
94
- // Tier 2 — Model selection
95
- delegate_to_model: 2 /* ANALYZED */,
96
- create_expert: 2 /* ANALYZED */,
97
- execute_expert: 2 /* ANALYZED */,
98
- research_add: 2 /* ANALYZED */,
99
- research_discover: 2 /* ANALYZED */,
100
- registry_import: 2 /* ANALYZED */,
101
- // Tier 3 — Full orchestration
102
- orchestrate: 3 /* ORCHESTRATED */,
103
- consensus_vote: 3 /* ORCHESTRATED */,
104
- execute_spec: 3 /* ORCHESTRATED */,
105
- run_workflow: 3 /* ORCHESTRATED */,
106
- run_graph_workflow: 3 /* ORCHESTRATED */,
107
- issue_triage: 3 /* ORCHESTRATED */
108
- };
109
- function classifyRequestTier(toolName, params, overrides) {
110
- const defaultTier = TOOL_TIER_MAP[toolName] ?? 2 /* ANALYZED */;
111
- const effectiveTier = overrides?.[toolName] ?? defaultTier;
112
- if (defaultTier === 1 /* DIRECT */ && effectiveTier === 1 /* DIRECT */) {
113
- return 1 /* DIRECT */;
114
- }
115
- if (effectiveTier < 3 /* ORCHESTRATED */ && shouldPromote(params)) {
116
- return 3 /* ORCHESTRATED */;
117
- }
118
- return effectiveTier;
119
- }
120
- function shouldPromote(params) {
121
- const role = params["role"];
122
- if (typeof role === "string" && PROMOTED_ROLES.has(role)) {
123
- return true;
124
- }
125
- const textFields = ["task", "proposal", "prompt"];
126
- for (const field of textFields) {
127
- const value = params[field];
128
- if (typeof value === "string" && containsPromotionKeyword(value)) {
129
- return true;
130
- }
131
- }
132
- return false;
133
- }
134
- var TIER_NAME_TO_ENUM = {
135
- DIRECT: 1 /* DIRECT */,
136
- ANALYZED: 2 /* ANALYZED */,
137
- ORCHESTRATED: 3 /* ORCHESTRATED */
138
- };
139
- function parseTierOverrides(overrides) {
140
- if (overrides === void 0) return void 0;
141
- const result = {};
142
- for (const [tool, tierName] of Object.entries(overrides)) {
143
- const tier = TIER_NAME_TO_ENUM[tierName];
144
- if (tier !== void 0) {
145
- result[tool] = tier;
146
- }
147
- }
148
- return Object.keys(result).length > 0 ? result : void 0;
149
- }
150
- function containsPromotionKeyword(text) {
151
- const lower = text.toLowerCase();
152
- for (const kw of SECURITY_KEYWORDS) {
153
- if (lower.includes(kw)) return true;
154
- }
155
- for (const kw of ARCHITECTURE_KEYWORDS) {
156
- if (new RegExp(kw, "i").test(text)) return true;
157
- }
158
- return false;
159
- }
160
-
161
- // src/mcp/gateway/tier-recommender.ts
162
- var DEFAULT_CONFIG = {
163
- minSamples: 20,
164
- promoteFailureRate: 0.3,
165
- demoteSuccessRate: 0.95,
166
- demoteMinSamples: 50
167
- };
168
- function getCategoryTier(category) {
169
- const categoryToolMap = {
170
- research: "research_query",
171
- exploration: "research_discover",
172
- code_generation: "delegate_to_model",
173
- code_review: "run_workflow",
174
- architecture: "orchestrate",
175
- security_review: "orchestrate",
176
- planning: "orchestrate",
177
- documentation: "run_workflow",
178
- testing: "run_workflow",
179
- devops: "delegate_to_model"
180
- };
181
- const tool = categoryToolMap[category];
182
- if (tool !== void 0) {
183
- return TOOL_TIER_MAP[tool] ?? 2 /* ANALYZED */;
184
- }
185
- return 2 /* ANALYZED */;
186
- }
187
- function generateTierRecommendations(summary, config) {
188
- const cfg = { ...DEFAULT_CONFIG, ...config };
189
- const recommendations = [];
190
- for (const [category, stats] of summary.byCategory) {
191
- const rec = evaluateCategory(category, stats, cfg);
192
- if (rec !== null) recommendations.push(rec);
193
- }
194
- return recommendations;
195
- }
196
- function evaluateCategory(category, stats, cfg) {
197
- if (stats.count < cfg.minSamples) return null;
198
- const currentTier = getCategoryTier(category);
199
- const failureRate = 1 - stats.successRate;
200
- if (failureRate > cfg.promoteFailureRate && currentTier < 3 /* ORCHESTRATED */) {
201
- const recommendedTier = currentTier + 1;
202
- return {
203
- category,
204
- currentTier,
205
- recommendedTier,
206
- direction: "promote",
207
- successRate: stats.successRate,
208
- sampleCount: stats.count,
209
- reason: `${category}: ${(failureRate * 100).toFixed(0)}% failure rate over ${String(stats.count)} tasks \u2014 recommend promoting to Tier ${String(recommendedTier)}`
210
- };
211
- }
212
- if (stats.successRate > cfg.demoteSuccessRate && stats.count >= cfg.demoteMinSamples && currentTier > 1 /* DIRECT */) {
213
- const recommendedTier = currentTier - 1;
214
- return {
215
- category,
216
- currentTier,
217
- recommendedTier,
218
- direction: "demote",
219
- successRate: stats.successRate,
220
- sampleCount: stats.count,
221
- reason: `${category}: ${(stats.successRate * 100).toFixed(0)}% success rate over ${String(stats.count)} tasks \u2014 eligible for demotion to Tier ${String(recommendedTier)}`
222
- };
223
- }
224
- return null;
225
- }
226
-
227
- // src/adapters/rate-limit-detector.ts
228
- var RATE_LIMIT_PATTERNS = [
229
- "rate limit",
230
- "rate_limit",
231
- "too many requests",
232
- "429",
233
- "quota exceeded",
234
- "throttl",
235
- "requests per minute",
236
- "tokens per minute"
237
- ];
238
- function isRateLimitLikeError(error) {
239
- const message = getErrorMessage(error).toLowerCase();
240
- return RATE_LIMIT_PATTERNS.some((p) => message.includes(p));
241
- }
242
- function parseRetryAfterMs(errorMessage) {
243
- const lower = errorMessage.toLowerCase();
244
- const secondsMatch = /retry[- ]?after[:\s]+(\d+(?:\.\d+)?)\s*(?:s|sec)/i.exec(lower);
245
- if (secondsMatch !== null) {
246
- const parsed = parseFloat(secondsMatch[1] ?? "0");
247
- return Math.ceil(parsed * 1e3);
248
- }
249
- const msMatch = /(?:retry[- ]?after|wait)[:\s]+(\d+)\s*(?:ms|millisecond)/i.exec(lower);
250
- if (msMatch !== null) {
251
- return parseInt(msMatch[1] ?? "0", 10);
252
- }
253
- const againMatch = /try again in (\d+(?:\.\d+)?)\s*(?:s|sec)/i.exec(lower);
254
- if (againMatch !== null) {
255
- const parsed = parseFloat(againMatch[1] ?? "0");
256
- return Math.ceil(parsed * 1e3);
257
- }
258
- return void 0;
259
- }
260
- function toRateLimitError(error, provider) {
261
- const message = getErrorMessage(error);
262
- const retryAfterMs = parseRetryAfterMs(message);
263
- return new RateLimitError(message, {
264
- ...retryAfterMs !== void 0 ? { retryAfterMs } : {},
265
- ...provider !== void 0 ? { provider } : {},
266
- ...error instanceof Error ? { cause: error } : {}
267
- });
268
- }
269
- var MAX_EVENTS = 200;
270
- var events = [];
271
- function recordRateLimitEvent(event) {
272
- events.push(event);
273
- if (events.length > MAX_EVENTS) {
274
- events.splice(0, events.length - MAX_EVENTS);
275
- }
276
- }
277
- function getRateLimitStats() {
278
- const grouped = /* @__PURE__ */ new Map();
279
- for (const event of events) {
280
- const existing = grouped.get(event.provider);
281
- if (existing !== void 0) {
282
- existing.push(event);
283
- } else {
284
- grouped.set(event.provider, [event]);
285
- }
286
- }
287
- const stats = [];
288
- for (const [provider, providerEvents] of grouped) {
289
- const retryValues = providerEvents.map((e) => e.retryAfterMs).filter((v) => v !== void 0);
290
- const avgRetry = retryValues.length > 0 ? retryValues.reduce((a, b) => a + b, 0) / retryValues.length : void 0;
291
- const lastEvent = providerEvents[providerEvents.length - 1];
292
- stats.push({
293
- provider,
294
- totalHits: providerEvents.length,
295
- lastHitAt: lastEvent?.timestamp ?? 0,
296
- ...avgRetry !== void 0 ? { avgRetryAfterMs: Math.round(avgRetry) } : { avgRetryAfterMs: void 0 }
297
- });
298
- }
299
- return stats;
300
- }
301
-
302
- // src/mcp/middleware/tool-metrics.ts
303
- var MAX_ENTRIES = 5e3;
304
- var metrics = [];
305
- function recordToolMetric(metric) {
306
- metrics.push(metric);
307
- if (metrics.length > MAX_ENTRIES) {
308
- metrics.splice(0, metrics.length - MAX_ENTRIES);
309
- }
310
- }
311
- function getToolStats() {
312
- const groups = /* @__PURE__ */ new Map();
313
- for (const m of metrics) {
314
- const list = groups.get(m.toolName);
315
- if (list !== void 0) {
316
- list.push(m);
317
- } else {
318
- groups.set(m.toolName, [m]);
319
- }
320
- }
321
- const stats = [];
322
- for (const [toolName, list] of groups) {
323
- const sc = list.filter((m) => m.success).length;
324
- const td = list.reduce((s, m) => s + m.durationMs, 0);
325
- stats.push({
326
- toolName,
327
- totalCalls: list.length,
328
- successRate: sc / list.length,
329
- avgDurationMs: td / list.length,
330
- errorCount: list.length - sc
331
- });
332
- }
333
- return stats.sort((a, b) => b.totalCalls - a.totalCalls);
334
- }
335
- function createMetricsMiddleware() {
336
- return async (args, ctx, next) => {
337
- const startTime = getTimeProvider().now();
338
- try {
339
- const result = await next(args, ctx);
340
- const durationMs = getTimeProvider().now() - startTime;
341
- recordToolMetric({
342
- toolName: ctx.requestContext.toolName,
343
- durationMs,
344
- success: result.isError !== true,
345
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
346
- });
347
- return result;
348
- } catch (error) {
349
- const durationMs = getTimeProvider().now() - startTime;
350
- recordToolMetric({
351
- toolName: ctx.requestContext.toolName,
352
- durationMs,
353
- success: false,
354
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
355
- });
356
- throw error;
357
- }
358
- };
359
- }
360
-
361
- // src/agents/heartbeat-monitor.ts
362
- var DEFAULT_SLOW_THRESHOLD_MS = HEARTBEAT_TIMEOUTS.slowThresholdMs;
363
- var DEFAULT_STALLED_THRESHOLD_MS = HEARTBEAT_TIMEOUTS.stalledThresholdMs;
364
- var DEFAULT_ABSOLUTE_MAX_MS = HEARTBEAT_TIMEOUTS.absoluteMaxMs;
365
- var HeartbeatMonitor = class {
366
- config;
367
- sessions = /* @__PURE__ */ new Map();
368
- constructor(config) {
369
- this.config = {
370
- slowThresholdMs: config?.slowThresholdMs ?? DEFAULT_SLOW_THRESHOLD_MS,
371
- stalledThresholdMs: config?.stalledThresholdMs ?? DEFAULT_STALLED_THRESHOLD_MS,
372
- absoluteMaxMs: config?.absoluteMaxMs ?? DEFAULT_ABSOLUTE_MAX_MS
373
- };
374
- }
375
- /** Start tracking a new expert session. Returns session ID. */
376
- startSession(expertId) {
377
- const sessionId = `hb-${expertId}-${String(Date.now())}`;
378
- const now = Date.now();
379
- this.sessions.set(sessionId, {
380
- expertId,
381
- startedAt: now,
382
- lastHeartbeat: now,
383
- heartbeatCount: 0,
384
- previousHealth: "alive"
385
- });
386
- return sessionId;
387
- }
388
- /** Record a heartbeat for an active session. */
389
- heartbeat(sessionId) {
390
- const entry = this.sessions.get(sessionId);
391
- if (entry === void 0) return;
392
- entry.lastHeartbeat = Date.now();
393
- entry.heartbeatCount++;
394
- }
395
- /** Stop tracking a session. */
396
- endSession(sessionId) {
397
- this.sessions.delete(sessionId);
398
- }
399
- /** Check if a session has exceeded the stalled threshold. */
400
- isStalled(sessionId) {
401
- const entry = this.sessions.get(sessionId);
402
- if (entry === void 0) return false;
403
- const elapsed = Date.now() - entry.lastHeartbeat;
404
- return elapsed >= this.config.stalledThresholdMs;
405
- }
406
- /** Check if a session has exceeded the absolute max lifetime. */
407
- isExpired(sessionId) {
408
- const entry = this.sessions.get(sessionId);
409
- if (entry === void 0) return false;
410
- return Date.now() - entry.startedAt >= this.config.absoluteMaxMs;
411
- }
412
- /** Get aggregate health report for all active sessions. */
413
- getHealth() {
414
- const now = Date.now();
415
- const sessions = [];
416
- let stalledCount = 0;
417
- for (const [sessionId, entry] of this.sessions) {
418
- const timeSince = now - entry.lastHeartbeat;
419
- const health = this.classifyHealth(timeSince);
420
- if (health === "stalled") stalledCount++;
421
- sessions.push({
422
- sessionId,
423
- expertId: entry.expertId,
424
- startedAt: entry.startedAt,
425
- lastHeartbeat: entry.lastHeartbeat,
426
- heartbeatCount: entry.heartbeatCount,
427
- health,
428
- elapsedMs: now - entry.startedAt,
429
- timeSinceHeartbeatMs: timeSince
430
- });
431
- }
432
- return {
433
- activeSessions: this.sessions.size,
434
- stalledSessions: stalledCount,
435
- sessions
436
- };
437
- }
438
- /**
439
- * Get health state with transition detection for a session.
440
- * Updates previousHealth on each call to track transitions.
441
- * (Issue #1088 Phase 4 — observability)
442
- */
443
- getSessionHealth(sessionId) {
444
- const entry = this.sessions.get(sessionId);
445
- if (entry === void 0) return void 0;
446
- const now = Date.now();
447
- const timeSince = now - entry.lastHeartbeat;
448
- const health = this.classifyHealth(timeSince);
449
- const changed = health !== entry.previousHealth;
450
- const result = {
451
- sessionId,
452
- agentId: entry.expertId,
453
- health,
454
- previousHealth: entry.previousHealth,
455
- changed,
456
- elapsedMs: now - entry.startedAt,
457
- heartbeatCount: entry.heartbeatCount
458
- };
459
- entry.previousHealth = health;
460
- return result;
461
- }
462
- /** Number of currently tracked sessions. */
463
- get activeCount() {
464
- return this.sessions.size;
465
- }
466
- classifyHealth(timeSinceMs) {
467
- if (timeSinceMs >= this.config.stalledThresholdMs) return "stalled";
468
- if (timeSinceMs >= this.config.slowThresholdMs) return "slow";
469
- return "alive";
470
- }
471
- };
472
- var globalMonitor;
473
- function getHeartbeatMonitor() {
474
- globalMonitor ??= new HeartbeatMonitor();
475
- return globalMonitor;
476
- }
477
-
478
- // src/mcp/tools/weather-report.ts
479
- var CLI_NAMES2 = ["claude", "gemini", "codex", "opencode"];
480
- function generateWeatherReport(input, config) {
481
- const cfg = { ...createDefaultWeatherConfig(), ...config };
482
- const store = getOutcomeStore();
483
- const includeAdaptive = input.includeAdaptive ?? true;
484
- const summary = store.summarize(buildQuery(input.cli, input.category));
485
- const cliWeather = buildCliWeather(summary, input);
486
- const adaptiveBonuses = includeAdaptive ? computeAdaptiveBonuses(cfg) : [];
487
- const tierRecommendations = buildTierRecommendations(summary);
488
- const rateLimits = buildRateLimitReport();
489
- const toolPerformance = buildToolPerformance();
490
- const failureBreakdown = buildFailureBreakdown(input);
491
- const agentHealth = buildAgentHealth();
492
- const expertPerformance = buildExpertPerformance();
493
- const base = {
494
- overall: {
495
- totalTasks: summary.totalTasks,
496
- successRate: summary.successRate,
497
- avgDurationMs: summary.avgDurationMs
498
- },
499
- cliWeather,
500
- adaptiveBonuses,
501
- tierRecommendations,
502
- ...rateLimits.length > 0 ? { rateLimits } : {},
503
- ...toolPerformance.length > 0 ? { toolPerformance } : {},
504
- ...failureBreakdown.length > 0 ? { failureBreakdown } : {},
505
- ...agentHealth !== void 0 ? { agentHealth } : {},
506
- ...expertPerformance.length > 0 ? { expertPerformance } : {},
507
- explorationRate: cfg.explorationRate,
508
- coldStartThreshold: cfg.coldStartThreshold,
509
- collectedAt: (/* @__PURE__ */ new Date()).toISOString()
510
- };
511
- if (includeAdaptive) {
512
- return {
513
- ...base,
514
- learningInsights: buildLearningInsights(),
515
- recommendedMappings: buildRecommendedMappings()
516
- };
517
- }
518
- return base;
519
- }
520
- function buildAgentHealth() {
521
- const monitor = getHeartbeatMonitor();
522
- if (monitor.activeCount === 0) return void 0;
523
- const health = monitor.getHealth();
524
- return {
525
- activeSessions: health.activeSessions,
526
- stalledSessions: health.stalledSessions,
527
- sessions: health.sessions.map((s) => ({
528
- sessionId: s.sessionId,
529
- expertId: s.expertId,
530
- health: s.health,
531
- elapsedMs: s.elapsedMs,
532
- timeSinceHeartbeatMs: s.timeSinceHeartbeatMs,
533
- heartbeatCount: s.heartbeatCount
534
- }))
535
- };
536
- }
537
- function buildRateLimitReport() {
538
- return getRateLimitStats().map((s) => ({
539
- provider: s.provider,
540
- totalHits: s.totalHits,
541
- lastHitAt: s.lastHitAt,
542
- avgRetryAfterMs: s.avgRetryAfterMs
543
- }));
544
- }
545
- function getAdaptiveBonus(cli, category, config) {
546
- const cfg = { ...createDefaultWeatherConfig(), ...config };
547
- const store = getOutcomeStore();
548
- const cliName = cli;
549
- const outcomes = store.query({ cli: cliName, category });
550
- if (outcomes.length < cfg.coldStartThreshold) return 0;
551
- const thresholds = computeAdaptiveThresholds(store, cliName, category);
552
- const successRate = outcomes.filter((o) => o.success).length / outcomes.length;
553
- const delta = successRate - thresholds.baseline;
554
- const maxBonus = thresholds.maxBonus > 0 ? thresholds.maxBonus : cfg.maxBonusAdjustment;
555
- const scaled = delta / 0.3 * maxBonus;
556
- return clamp(scaled, -maxBonus, maxBonus);
557
- }
558
- function buildQuery(cli, category) {
559
- const query = {};
560
- if (cli !== void 0) query.cli = cli;
561
- if (category !== void 0) query.category = category;
562
- return query;
563
- }
564
- function buildCliWeather(summary, input) {
565
- const clis = input.cli !== void 0 ? [input.cli] : [...CLI_NAMES2];
566
- return clis.map((cli) => {
567
- const stats = summary.byCli.get(cli);
568
- const store = getOutcomeStore();
569
- const cliOutcomes = store.query({ cli });
570
- const byCategory = /* @__PURE__ */ new Map();
571
- for (const cat of TASK_CATEGORIES) {
572
- const catOutcomes = cliOutcomes.filter((o) => o.category === cat);
573
- if (catOutcomes.length > 0) {
574
- const sc = catOutcomes.filter((o) => o.success).length;
575
- const td = catOutcomes.reduce((s, o) => s + o.durationMs, 0);
576
- byCategory.set(cat, {
577
- count: catOutcomes.length,
578
- successRate: sc / catOutcomes.length,
579
- avgDurationMs: td / catOutcomes.length
580
- });
581
- }
582
- }
583
- return {
584
- cli,
585
- totalTasks: stats?.count ?? 0,
586
- successRate: stats?.successRate ?? 0,
587
- avgDurationMs: stats?.avgDurationMs ?? 0,
588
- byCategory
589
- };
590
- });
591
- }
592
- function computeAdaptiveBonuses(cfg) {
593
- const bonuses = [];
594
- for (const cli of CLI_NAMES2) {
595
- for (const category of TASK_CATEGORIES) {
596
- const spec = getSpecialization(category);
597
- const staticBonus = getStaticBonusForCli(cli, spec);
598
- const store = getOutcomeStore();
599
- const outcomes = store.query({ cli, category });
600
- const sampleCount = outcomes.length;
601
- const sufficient = sampleCount >= cfg.coldStartThreshold;
602
- const adaptiveAdj = sufficient ? getAdaptiveBonus(cli, category, cfg) : 0;
603
- if (sampleCount > 0 || staticBonus > 0 || adaptiveAdj !== 0) {
604
- bonuses.push({
605
- cli,
606
- category,
607
- staticBonus,
608
- adaptiveBonus: Math.round(adaptiveAdj * 10) / 10,
609
- sampleCount,
610
- sufficient
611
- });
612
- }
613
- }
614
- }
615
- return bonuses;
616
- }
617
- function getStaticBonusForCli(cli, spec) {
618
- if (cli === spec.primaryCli) return spec.bonus;
619
- if (cli === spec.secondaryCli) return Math.floor(spec.bonus / 2);
620
- return 0;
621
- }
622
- function clamp(value, min, max) {
623
- return Math.min(max, Math.max(min, value));
624
- }
625
- function buildLearningInsights() {
626
- const store = getOutcomeStore();
627
- const insights = [];
628
- for (const cli of CLI_NAMES2) {
629
- for (const category of TASK_CATEGORIES) {
630
- const thresholds = computeAdaptiveThresholds(store, cli, category);
631
- if (thresholds.sampleCount > 0) {
632
- insights.push({
633
- cli,
634
- category,
635
- trend: thresholds.trend,
636
- confidence: thresholds.confidence,
637
- adjustedBaseline: thresholds.baseline,
638
- sampleCount: thresholds.sampleCount
639
- });
640
- }
641
- }
642
- }
643
- return insights;
644
- }
645
- function buildRecommendedMappings() {
646
- const store = getOutcomeStore();
647
- const mappings = [];
648
- for (const category of TASK_CATEGORIES) {
649
- let bestCli = "";
650
- let bestRate = -1;
651
- let bestCount = 0;
652
- for (const cli of CLI_NAMES2) {
653
- const outcomes = store.query({ cli, category });
654
- if (outcomes.length === 0) continue;
655
- const rate = outcomes.filter((o) => o.success).length / outcomes.length;
656
- if (rate > bestRate || rate === bestRate && outcomes.length > bestCount) {
657
- bestCli = cli;
658
- bestRate = rate;
659
- bestCount = outcomes.length;
660
- }
661
- }
662
- if (bestCli !== "") {
663
- const confidence = bestCount >= 20 ? "high" : bestCount >= 10 ? "medium" : "low";
664
- mappings.push({
665
- category,
666
- recommendedCli: bestCli,
667
- successRate: bestRate,
668
- sampleCount: bestCount,
669
- confidence
670
- });
671
- }
672
- }
673
- return mappings;
674
- }
675
- var WORKER_MODEL_PREFIX = "worker-";
676
- function findDominantError(failed) {
677
- if (failed.length === 0) return void 0;
678
- const counts = /* @__PURE__ */ new Map();
679
- for (const f of failed) {
680
- const cat = f.failureCategory ?? "unknown";
681
- counts.set(cat, (counts.get(cat) ?? 0) + 1);
682
- }
683
- let maxCount = 0;
684
- let dominant;
685
- for (const [cat, count] of counts) {
686
- if (count > maxCount) {
687
- maxCount = count;
688
- dominant = cat;
689
- }
690
- }
691
- return dominant;
692
- }
693
- function buildExpertPerformance() {
694
- const store = getOutcomeStore();
695
- const allOutcomes = store.query();
696
- const workerOutcomes = allOutcomes.filter((o) => o.model.startsWith(WORKER_MODEL_PREFIX));
697
- if (workerOutcomes.length === 0) return [];
698
- const byRole = /* @__PURE__ */ new Map();
699
- for (const o of workerOutcomes) {
700
- const role = o.model.slice(WORKER_MODEL_PREFIX.length);
701
- const existing = byRole.get(role) ?? [];
702
- existing.push(o);
703
- byRole.set(role, existing);
704
- }
705
- const entries = [];
706
- for (const [role, outcomes] of byRole) {
707
- const successes = outcomes.filter((o) => o.success).length;
708
- const totalDuration = outcomes.reduce((s, o) => s + o.durationMs, 0);
709
- const dominantErrorPattern = findDominantError(outcomes.filter((o) => !o.success));
710
- entries.push({
711
- role,
712
- totalTasks: outcomes.length,
713
- successRate: successes / outcomes.length,
714
- avgDurationMs: Math.round(totalDuration / outcomes.length),
715
- ...dominantErrorPattern !== void 0 ? { dominantErrorPattern } : {}
716
- });
717
- }
718
- return entries.sort((a, b) => b.totalTasks - a.totalTasks);
719
- }
720
- function buildFailureBreakdown(input) {
721
- const store = getOutcomeStore();
722
- const outcomes = store.query(buildQuery(input.cli, input.category));
723
- const failed = outcomes.filter((o) => !o.success);
724
- if (failed.length === 0) return [];
725
- const counts = /* @__PURE__ */ new Map();
726
- for (const o of failed) {
727
- const cat = o.failureCategory ?? "unknown";
728
- counts.set(cat, (counts.get(cat) ?? 0) + 1);
729
- }
730
- const entries = [];
731
- for (const [category, count] of counts) {
732
- entries.push({
733
- category,
734
- count,
735
- percentage: Math.round(count / failed.length * 1e3) / 10
736
- });
737
- }
738
- return entries.sort((a, b) => b.count - a.count);
739
- }
740
- function buildToolPerformance() {
741
- return getToolStats().map((s) => ({
742
- toolName: s.toolName,
743
- totalCalls: s.totalCalls,
744
- successRate: Math.round(s.successRate * 1e3) / 1e3,
745
- avgDurationMs: Math.round(s.avgDurationMs),
746
- errorCount: s.errorCount
747
- }));
748
- }
749
- function buildTierRecommendations(summary) {
750
- return generateTierRecommendations(summary).map((r) => ({
751
- category: r.category,
752
- direction: r.direction,
753
- currentTier: r.currentTier,
754
- recommendedTier: r.recommendedTier,
755
- successRate: r.successRate,
756
- sampleCount: r.sampleCount,
757
- reason: r.reason
758
- }));
759
- }
760
-
761
- export {
762
- isRateLimitLikeError,
763
- toRateLimitError,
764
- recordRateLimitEvent,
765
- getHeartbeatMonitor,
766
- createMetricsMiddleware,
767
- WeatherReportInputSchema,
768
- SECURITY_KEYWORDS,
769
- ARCHITECTURE_KEYWORDS,
770
- PROMOTED_ROLES,
771
- classifyRequestTier,
772
- parseTierOverrides,
773
- generateWeatherReport,
774
- getAdaptiveBonus
775
- };
776
- //# sourceMappingURL=chunk-PGNRXCYY.js.map