@llm-dev-ops/agentics-cli 2.4.0 → 2.5.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.
Files changed (51) hide show
  1. package/dist/adapters/base-adapter.d.ts +5 -1
  2. package/dist/adapters/base-adapter.d.ts.map +1 -1
  3. package/dist/adapters/base-adapter.js +13 -0
  4. package/dist/adapters/base-adapter.js.map +1 -1
  5. package/dist/agents/repo-agent-runner.d.ts +2 -0
  6. package/dist/agents/repo-agent-runner.d.ts.map +1 -1
  7. package/dist/agents/repo-agent-runner.js +4 -2
  8. package/dist/agents/repo-agent-runner.js.map +1 -1
  9. package/dist/agents/system-prompts.d.ts.map +1 -1
  10. package/dist/agents/system-prompts.js +19 -0
  11. package/dist/agents/system-prompts.js.map +1 -1
  12. package/dist/commands/agents.d.ts +25 -0
  13. package/dist/commands/agents.d.ts.map +1 -1
  14. package/dist/commands/agents.js +186 -3
  15. package/dist/commands/agents.js.map +1 -1
  16. package/dist/config/endpoints.d.ts.map +1 -1
  17. package/dist/config/endpoints.js +8 -0
  18. package/dist/config/endpoints.js.map +1 -1
  19. package/dist/config/qe-gating.d.ts +81 -0
  20. package/dist/config/qe-gating.d.ts.map +1 -0
  21. package/dist/config/qe-gating.js +138 -0
  22. package/dist/config/qe-gating.js.map +1 -0
  23. package/dist/pipeline/phase5-build/qe-gating-executor.d.ts +73 -0
  24. package/dist/pipeline/phase5-build/qe-gating-executor.d.ts.map +1 -0
  25. package/dist/pipeline/phase5-build/qe-gating-executor.js +134 -0
  26. package/dist/pipeline/phase5-build/qe-gating-executor.js.map +1 -0
  27. package/dist/promotion/graph-diff.d.ts +39 -0
  28. package/dist/promotion/graph-diff.d.ts.map +1 -0
  29. package/dist/promotion/graph-diff.js +60 -0
  30. package/dist/promotion/graph-diff.js.map +1 -0
  31. package/dist/promotion/sampler-lib.d.ts +45 -0
  32. package/dist/promotion/sampler-lib.d.ts.map +1 -0
  33. package/dist/promotion/sampler-lib.js +96 -0
  34. package/dist/promotion/sampler-lib.js.map +1 -0
  35. package/dist/routing/domain-boundary.d.ts +92 -0
  36. package/dist/routing/domain-boundary.d.ts.map +1 -0
  37. package/dist/routing/domain-boundary.js +208 -0
  38. package/dist/routing/domain-boundary.js.map +1 -0
  39. package/dist/routing/graph-router.d.ts +31 -1
  40. package/dist/routing/graph-router.d.ts.map +1 -1
  41. package/dist/routing/graph-router.js +91 -4
  42. package/dist/routing/graph-router.js.map +1 -1
  43. package/dist/routing/index.d.ts +13 -3
  44. package/dist/routing/index.d.ts.map +1 -1
  45. package/dist/routing/index.js +9 -4
  46. package/dist/routing/index.js.map +1 -1
  47. package/dist/types/index.d.ts +1 -0
  48. package/dist/types/index.d.ts.map +1 -1
  49. package/dist/types/index.js.map +1 -1
  50. package/docs/ecosystem.graph.json +87 -14
  51. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"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"}
@@ -94,6 +94,94 @@ async function runCopilotViaClaudeMax(agent, payload, correlationId) {
94
94
  return null; // claude --print failed — fall through to cloud function
95
95
  }
96
96
  }
97
+ // ADR-066 extension: inference-gateway/route via claude --print.
98
+ // The gateway's "route" agent is a pure reasoning task (pick best provider/model
99
+ // for a request given hints). We run it locally through the user's Claude Max
100
+ // session so no server-side Anthropic API key is required.
101
+ async function runInferenceRoutingViaClaudeMax(payload, correlationId) {
102
+ let claudeBin = null;
103
+ const envBin = process.env['AGENTICS_CLAUDE_BIN'];
104
+ if (envBin) {
105
+ claudeBin = envBin;
106
+ }
107
+ else {
108
+ for (const candidate of ['claude', 'claude-code']) {
109
+ try {
110
+ const found = execFileSync(process.platform === 'win32' ? 'where' : 'which', [candidate], { stdio: ['pipe', 'pipe', 'pipe'], timeout: 5_000, encoding: 'utf-8' }).trim().split(/\r?\n/)[0]?.trim();
111
+ if (found) {
112
+ claudeBin = found;
113
+ break;
114
+ }
115
+ }
116
+ catch { /* not found */ }
117
+ }
118
+ }
119
+ if (!claudeBin)
120
+ return null;
121
+ const systemPrompt = [
122
+ 'You are an inference routing advisor.',
123
+ 'Given an inference request and routing hints, choose the best (provider, model) pair.',
124
+ 'Return ONLY valid JSON (no markdown fences) with shape:',
125
+ '{',
126
+ ' "chosen_provider": "anthropic" | "openai" | "google",',
127
+ ' "chosen_model": "<model-id>",',
128
+ ' "routing_decision": {',
129
+ ' "rationale": "<one-sentence reason>",',
130
+ ' "estimated_latency_ms": <number>,',
131
+ ' "estimated_cost_usd_per_1k_tokens": <number>,',
132
+ ' "quality_tier": "tier-1" | "tier-2" | "tier-3"',
133
+ ' },',
134
+ ' "fallbacks": [{ "provider": "...", "model": "...", "reason": "..." }],',
135
+ ' "honored_hints": [<list of hint fields respected>]',
136
+ '}',
137
+ 'Honor hints.preferred_providers and hints.excluded_providers strictly.',
138
+ 'Honor hints.max_latency_tier (1=fastest, 3=slowest-tolerable).',
139
+ 'If hints.optimize_cost is true, prefer cheaper models when quality allows.',
140
+ 'If request.model is specified and not excluded, prefer honoring it.',
141
+ ].join('\n');
142
+ const fullPrompt = `${systemPrompt}\n\nRequest:\n${JSON.stringify(payload, null, 2)}`;
143
+ try {
144
+ const rawOutput = execFileSync(claudeBin, [
145
+ '--print',
146
+ '--output-format', 'text',
147
+ '--model', process.env['AGENTICS_CLAUDE_MODEL'] || 'claude-sonnet-4-20250514',
148
+ fullPrompt,
149
+ ], {
150
+ encoding: 'utf-8',
151
+ timeout: 60_000,
152
+ maxBuffer: 5 * 1024 * 1024,
153
+ stdio: ['pipe', 'pipe', 'pipe'],
154
+ env: { ...process.env, MCP_SERVER_MODE: undefined },
155
+ });
156
+ let cleaned = rawOutput.trim();
157
+ if (cleaned.startsWith('```')) {
158
+ cleaned = cleaned.replace(/^```(?:json)?\s*\n?/, '').replace(/\n?```\s*$/, '');
159
+ }
160
+ const jsonMatch = cleaned.match(/\{[\s\S]*\}/);
161
+ if (!jsonMatch)
162
+ return null;
163
+ const parsed = JSON.parse(jsonMatch[0]);
164
+ return {
165
+ ...parsed,
166
+ _source: 'claude-max',
167
+ execution_metadata: {
168
+ trace_id: correlationId,
169
+ timestamp: new Date().toISOString(),
170
+ service: 'inference-gateway-agents',
171
+ execution_id: correlationId,
172
+ agent: 'inference-routing-agent',
173
+ engine: 'claude-max',
174
+ },
175
+ layers_executed: [
176
+ { layer: 'AGENT_ROUTING', status: 'completed' },
177
+ { layer: 'INFERENCE_GATEWAY_ROUTE', status: 'completed' },
178
+ ],
179
+ };
180
+ }
181
+ catch {
182
+ return null;
183
+ }
184
+ }
97
185
  export const AGENT_DOMAINS = {
98
186
  'test-bench': {
99
187
  serviceName: 'test-bench-agents',
@@ -230,6 +318,53 @@ export const AGENT_DOMAINS = {
230
318
  agents: ['decision', 'executive-summary', 'decision-memo', 'risk-score'],
231
319
  phase: 'Phase 9: Apex Platform',
232
320
  },
321
+ // ADR-PIPELINE-080 registered quality_engineering in the ecosystem graph and
322
+ // wired agentic-qe into repo-agent-runner FUNCTION_NAMES, but left the
323
+ // dispatch-time AGENT_DOMAINS registry untouched. ADR-PIPELINE-087 §1
324
+ // restores the missing entry so resolveAgentRef() → executeAgentsInvokeCommand
325
+ // does not throw "Unknown domain" on AQE selections.
326
+ 'quality-engineering': {
327
+ serviceName: 'agentic-qe-agents',
328
+ agents: [
329
+ 'test-design',
330
+ 'unit-test-gen',
331
+ 'integration-test-gen',
332
+ 'property-test-gen',
333
+ 'bdd-test-gen',
334
+ 'coverage-analysis',
335
+ 'coverage-gap-detect',
336
+ 'defect-prediction',
337
+ 'flaky-detection',
338
+ 'rca',
339
+ 'traceability',
340
+ 'chaos',
341
+ 'test-execution',
342
+ 'qe-reporting',
343
+ ],
344
+ phase: 'Phase 8: Validation',
345
+ },
346
+ // diligence-artifacts is driven by phase coordinators (phase2/phase3/phase4)
347
+ // rather than cloud-function dispatch. Registering it here lets
348
+ // ADR-PIPELINE-087 §1 resolve SPARC/ADR/DDD classifier selections to a known
349
+ // domain — dispatch returns a pipeline-owned-elsewhere 502 instead of the
350
+ // previous silent drop, which is the visibility the ADR is enforcing.
351
+ 'diligence-artifacts': {
352
+ serviceName: 'diligence-artifacts',
353
+ agents: [
354
+ 'sparc-specification',
355
+ 'sparc-pseudocode',
356
+ 'sparc-architecture',
357
+ 'sparc-refinement',
358
+ 'sparc-completion',
359
+ 'sparc-merge',
360
+ 'adr-generation',
361
+ 'ddd-domain-model',
362
+ 'context-map',
363
+ 'adr-validator',
364
+ 'documentation',
365
+ ],
366
+ phase: 'Phase 3-5: Diligence Artifacts',
367
+ },
233
368
  };
234
369
  // ============================================================================
235
370
  // Command Implementations
@@ -323,11 +458,35 @@ export async function executeAgentsInvokeCommand(domain, agent, payload, options
323
458
  invokeHeaders['X-Anthropic-Api-Key'] = anthropicKey;
324
459
  }
325
460
  }
326
- // governance-dashboard and policy-engine require execution context in HTTP headers
327
- if (domain === 'governance-dashboard' || domain === 'policy-engine') {
461
+ // ADR-066 extension: inference-gateway/route via Claude Max the gateway's
462
+ // route agent is a reasoning task, so we run it locally through the user's
463
+ // Claude session instead of requiring a server-side Anthropic API key.
464
+ if (domain === 'inference-gateway' && agent === 'route') {
465
+ const routingResult = await runInferenceRoutingViaClaudeMax(normalizedPayload, correlationId);
466
+ if (routingResult) {
467
+ return {
468
+ domain,
469
+ agent,
470
+ status: 200,
471
+ response: routingResult,
472
+ timing: Date.now() - start,
473
+ };
474
+ }
475
+ // Fall through to cloud function (which will 503 without provider keys)
476
+ // and then to the existing computeUniversalFallback path.
477
+ }
478
+ // governance-dashboard, policy-engine, and costops require execution context in HTTP headers
479
+ if (domain === 'governance-dashboard' || domain === 'policy-engine' || domain === 'costops') {
328
480
  invokeHeaders['x-execution-id'] = correlationId;
329
481
  invokeHeaders['x-parent-span-id'] = correlationId;
330
482
  }
483
+ // research-lab requires execution_context as a top-level body field (not headers).
484
+ if (domain === 'research-lab' && normalizedPayload && typeof normalizedPayload === 'object') {
485
+ normalizedPayload = {
486
+ ...normalizedPayload,
487
+ execution_context: { execution_id: correlationId, parent_span_id: correlationId },
488
+ };
489
+ }
331
490
  let response;
332
491
  try {
333
492
  response = await adapter.invoke({
@@ -2028,7 +2187,7 @@ function extractScenarioContext(query) {
2028
2187
  * simulator wants "scenario_id" + "parameters"). This function maps the user's
2029
2188
  * natural-language query into the correct shape.
2030
2189
  */
2031
- function buildDomainPayload(domain, agent, query, correlationId) {
2190
+ export function buildDomainPayload(domain, agent, query, correlationId) {
2032
2191
  // Some agents have strict schema validation and reject unknown properties.
2033
2192
  // Only include execution_ref for agents that accept it.
2034
2193
  const base = { execution_ref: correlationId };
@@ -3733,12 +3892,19 @@ export async function executeNaturalLanguageRoute(query, options) {
3733
3892
  const artMsg = artifactErr instanceof Error ? artifactErr.message : String(artifactErr);
3734
3893
  console.error(`[WARN] Graph-routed artifact generation failed: ${artMsg}`);
3735
3894
  }
3895
+ // ADR-PIPELINE-087 §4: propagate classifier-selected-but-unresolved
3896
+ // agents to the caller. Empty array is the healthy case; any entry
3897
+ // indicates a graph→resolver gap (→ CI guard, §8) or a rename drift.
3898
+ const routingMeta = graphResult.unresolved.length > 0
3899
+ ? { unresolved: graphResult.unresolved.map(u => ({ stage: u.stage, agentName: u.agentName, capability: u.capability })) }
3900
+ : { unresolved: [] };
3736
3901
  return {
3737
3902
  kind: 'multi',
3738
3903
  result: {
3739
3904
  query,
3740
3905
  intents,
3741
3906
  invocations,
3907
+ routing: routingMeta,
3742
3908
  timing: elapsed,
3743
3909
  },
3744
3910
  };
@@ -4105,6 +4271,18 @@ export function formatMultiAgentRouteForDisplay(result) {
4105
4271
  lines.push(`Agents invoked: ${agentCount} (${succeeded} succeeded${failed > 0 ? `, ${failed} failed` : ''})`);
4106
4272
  lines.push(`Total Timing: ${result.timing}ms`);
4107
4273
  lines.push('');
4274
+ // ADR-PIPELINE-087 §4: surface unresolved classifier selections at the top
4275
+ // of the display so operators (and MCP clients relaying stdout) see the
4276
+ // routing gap immediately instead of having to infer it from missing work.
4277
+ const unresolved = result.routing?.unresolved ?? [];
4278
+ if (unresolved.length > 0) {
4279
+ lines.push(`⚠️ Routing gaps — ${unresolved.length} classifier-selected agent${unresolved.length === 1 ? '' : 's'} not dispatched (ADR-PIPELINE-087 §4):`);
4280
+ for (const u of unresolved) {
4281
+ lines.push(` - ${u.stage}: ${u.agentName} (capability "${u.capability}")`);
4282
+ }
4283
+ lines.push(' Fix: add these names to AGENT_NAME_TO_DOMAIN in src/routing/graph-router.ts.');
4284
+ lines.push('');
4285
+ }
4108
4286
  for (const inv of result.invocations) {
4109
4287
  const label = `[${inv.intent.domain}/${inv.intent.agent}]`;
4110
4288
  if ('error' in inv.result) {
@@ -4137,6 +4315,11 @@ export function routeResultToJson(routeResult, query) {
4137
4315
  reasoning: i.intent.reasoning,
4138
4316
  result: 'error' in i.result ? { error: i.result.error } : i.result,
4139
4317
  })),
4318
+ // ADR-PIPELINE-087 §4: include routing.unresolved in the JSON envelope
4319
+ // so programmatic consumers (MCP clients, CI) can detect drops.
4320
+ routing: {
4321
+ unresolved: routeResult.result.routing?.unresolved ?? [],
4322
+ },
4140
4323
  timing: routeResult.result.timing,
4141
4324
  };
4142
4325
  }