@llm-dev-ops/agentics-cli 2.7.1 → 2.7.2

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 (52) hide show
  1. package/dist/pipeline/auto-chain.d.ts +28 -2
  2. package/dist/pipeline/auto-chain.d.ts.map +1 -1
  3. package/dist/pipeline/auto-chain.js +66 -4
  4. package/dist/pipeline/auto-chain.js.map +1 -1
  5. package/dist/pipeline/enterprise/agent-error-capture.d.ts +76 -0
  6. package/dist/pipeline/enterprise/agent-error-capture.d.ts.map +1 -0
  7. package/dist/pipeline/enterprise/agent-error-capture.js +141 -0
  8. package/dist/pipeline/enterprise/agent-error-capture.js.map +1 -0
  9. package/dist/pipeline/enterprise/pass-executor.d.ts.map +1 -1
  10. package/dist/pipeline/enterprise/pass-executor.js +52 -0
  11. package/dist/pipeline/enterprise/pass-executor.js.map +1 -1
  12. package/dist/pipeline/enterprise/pipeline-orchestrator.d.ts.map +1 -1
  13. package/dist/pipeline/enterprise/pipeline-orchestrator.js +15 -0
  14. package/dist/pipeline/enterprise/pipeline-orchestrator.js.map +1 -1
  15. package/dist/pipeline/enterprise/types.d.ts +21 -0
  16. package/dist/pipeline/enterprise/types.d.ts.map +1 -1
  17. package/dist/pipeline/gate/feature-flags.d.ts +30 -0
  18. package/dist/pipeline/gate/feature-flags.d.ts.map +1 -0
  19. package/dist/pipeline/gate/feature-flags.js +37 -0
  20. package/dist/pipeline/gate/feature-flags.js.map +1 -0
  21. package/dist/pipeline/gate/phase-dependency-gate.d.ts +86 -0
  22. package/dist/pipeline/gate/phase-dependency-gate.d.ts.map +1 -1
  23. package/dist/pipeline/gate/phase-dependency-gate.js +263 -41
  24. package/dist/pipeline/gate/phase-dependency-gate.js.map +1 -1
  25. package/dist/pipeline/local-fallback/phase1-consensus-reader.d.ts +33 -0
  26. package/dist/pipeline/local-fallback/phase1-consensus-reader.d.ts.map +1 -0
  27. package/dist/pipeline/local-fallback/phase1-consensus-reader.js +99 -0
  28. package/dist/pipeline/local-fallback/phase1-consensus-reader.js.map +1 -0
  29. package/dist/pipeline/local-fallback/phase3-local-fallback.d.ts +26 -0
  30. package/dist/pipeline/local-fallback/phase3-local-fallback.d.ts.map +1 -0
  31. package/dist/pipeline/local-fallback/phase3-local-fallback.js +127 -0
  32. package/dist/pipeline/local-fallback/phase3-local-fallback.js.map +1 -0
  33. package/dist/pipeline/local-fallback/phase4-local-fallback.d.ts +21 -0
  34. package/dist/pipeline/local-fallback/phase4-local-fallback.d.ts.map +1 -0
  35. package/dist/pipeline/local-fallback/phase4-local-fallback.js +240 -0
  36. package/dist/pipeline/local-fallback/phase4-local-fallback.js.map +1 -0
  37. package/dist/pipeline/local-fallback/phase5a-local-fallback.d.ts +28 -0
  38. package/dist/pipeline/local-fallback/phase5a-local-fallback.d.ts.map +1 -0
  39. package/dist/pipeline/local-fallback/phase5a-local-fallback.js +166 -0
  40. package/dist/pipeline/local-fallback/phase5a-local-fallback.js.map +1 -0
  41. package/dist/pipeline/phases/prompt-generator.d.ts.map +1 -1
  42. package/dist/pipeline/phases/prompt-generator.js +209 -1
  43. package/dist/pipeline/phases/prompt-generator.js.map +1 -1
  44. package/dist/pipeline/ruflo-phase-executor.d.ts +8 -28
  45. package/dist/pipeline/ruflo-phase-executor.d.ts.map +1 -1
  46. package/dist/pipeline/ruflo-phase-executor.js +87 -0
  47. package/dist/pipeline/ruflo-phase-executor.js.map +1 -1
  48. package/dist/pipeline/swarm-orchestrator.d.ts +47 -0
  49. package/dist/pipeline/swarm-orchestrator.d.ts.map +1 -1
  50. package/dist/pipeline/swarm-orchestrator.js +130 -3
  51. package/dist/pipeline/swarm-orchestrator.js.map +1 -1
  52. package/package.json +1 -1
@@ -1958,15 +1958,35 @@ function cfExec(command, timeoutMs = 10000) {
1958
1958
  */
1959
1959
  /** Per-agent timeout: 30s max per invocation to prevent hanging. */
1960
1960
  const AGENT_INVOKE_TIMEOUT_MS = 30000;
1961
- async function invokeAgenticsService(svc, prompt, traceId) {
1961
+ async function invokeAgenticsService(svc, prompt, traceId, breaker) {
1962
1962
  const start = Date.now();
1963
1963
  const options = { trace_id: traceId, verbose: true };
1964
+ // ADR-094 D7 — when the cloud circuit breaker has tripped for this fanout,
1965
+ // skip remaining cloud invocations entirely. The dispatcher already started
1966
+ // some invocations before the breaker tripped; those finish under their
1967
+ // own per-call timeout. Calls reaching this guard AFTER the trip return a
1968
+ // non-null result with `_breaker_skipped: true` so status.json sees them.
1969
+ if (breaker?.shouldSkip()) {
1970
+ return {
1971
+ domain: svc.domain,
1972
+ agent: svc.agent,
1973
+ role: svc.role,
1974
+ status: 0,
1975
+ response: { _breaker_skipped: true, reason: 'cloud-breaker-tripped' },
1976
+ timing: 0,
1977
+ };
1978
+ }
1964
1979
  try {
1965
1980
  // Wrap with timeout — if agent doesn't respond in 30s, move on
1966
1981
  const result = await Promise.race([
1967
1982
  executeAgentsInvokeCommand(svc.domain, svc.agent, { text: prompt }, options),
1968
1983
  new Promise((_, reject) => setTimeout(() => reject(new Error(`Agent ${svc.domain}/${svc.agent} timed out after ${AGENT_INVOKE_TIMEOUT_MS}ms`)), AGENT_INVOKE_TIMEOUT_MS)),
1969
1984
  ]);
1985
+ // ADR-094 D7 — record success or failure outcome so the breaker can
1986
+ // decide whether subsequent dispatches should bypass cloud entirely.
1987
+ const isFallback = isLocalFallbackResp(result.response);
1988
+ const failed = result.status >= 400;
1989
+ breaker?.record(failed, isFallback ? 'local' : 'cloud', `${svc.domain}/${svc.agent}`);
1970
1990
  return {
1971
1991
  domain: svc.domain,
1972
1992
  agent: svc.agent,
@@ -1980,22 +2000,110 @@ async function invokeAgenticsService(svc, prompt, traceId) {
1980
2000
  // Non-fatal — agent invocation failures never block the pipeline
1981
2001
  const errMsg = err instanceof Error ? err.message : String(err);
1982
2002
  console.error(` [AGENTICS] [FAIL] ${svc.domain}/${svc.agent} (${svc.role}) — ${errMsg}`);
2003
+ breaker?.record(true, 'cloud', `${svc.domain}/${svc.agent}`);
1983
2004
  return null;
1984
2005
  }
1985
2006
  }
2007
+ /** Detect a local-tier response. Mirrors the dispatcher's _fallback marker. */
2008
+ function isLocalFallbackResp(resp) {
2009
+ if (resp && typeof resp === 'object') {
2010
+ return resp['_fallback'] === true;
2011
+ }
2012
+ return false;
2013
+ }
2014
+ // ============================================================================
2015
+ // ADR-094 Decision 7 — Cloud-agent circuit breaker for Phase 5 fanout
2016
+ // ============================================================================
2017
+ /** Default consecutive cloud-failure threshold before the breaker trips. */
2018
+ const DEFAULT_CLOUD_BREAKER_THRESHOLD = 3;
2019
+ /**
2020
+ * ADR-094 D7 — per-fanout circuit breaker that trips after N consecutive
2021
+ * cloud-tier failures and short-circuits remaining cloud invocations.
2022
+ * Local-tier successes do not reset the streak; they bypass the breaker.
2023
+ *
2024
+ * Cloud-tier successes DO reset the streak — if even one cloud call works,
2025
+ * we trust the cloud is alive again. This matches the originating-run
2026
+ * failure mode where an entire backend fleet was down at once.
2027
+ *
2028
+ * Resets per phase. Exported for unit tests.
2029
+ */
2030
+ export class CloudCircuitBreaker {
2031
+ consecutiveCloudFailures = 0;
2032
+ trippedFlag = false;
2033
+ trippedAfterN = 0;
2034
+ trippedAgents = [];
2035
+ threshold;
2036
+ constructor(threshold = DEFAULT_CLOUD_BREAKER_THRESHOLD) {
2037
+ this.threshold = Math.max(1, threshold);
2038
+ }
2039
+ /**
2040
+ * Record an invocation outcome. `tier` is the tier the call was dispatched
2041
+ * on. `failed=true` AND `tier='cloud'` increments the consecutive-failure
2042
+ * counter; a cloud success resets it.
2043
+ */
2044
+ record(failed, tier, agentLabel) {
2045
+ if (this.trippedFlag)
2046
+ return; // already tripped — record-only mode
2047
+ if (tier === 'cloud') {
2048
+ if (failed) {
2049
+ this.consecutiveCloudFailures++;
2050
+ this.trippedAgents.push(agentLabel);
2051
+ if (this.consecutiveCloudFailures >= this.threshold) {
2052
+ this.trippedFlag = true;
2053
+ this.trippedAfterN = this.consecutiveCloudFailures;
2054
+ process.stderr.write(`[BREAKER] cloud breaker tripped after ${this.trippedAfterN} timeouts (${this.trippedAgents.slice(0, 5).join(', ')}${this.trippedAgents.length > 5 ? ', …' : ''})\n`);
2055
+ }
2056
+ }
2057
+ else {
2058
+ // Cloud success — clear the streak. Cloud is alive.
2059
+ this.consecutiveCloudFailures = 0;
2060
+ }
2061
+ }
2062
+ // local-tier outcomes don't move the breaker state.
2063
+ }
2064
+ /** Returns true once the breaker has tripped. */
2065
+ shouldSkip() { return this.trippedFlag; }
2066
+ /** Snapshot of the breaker state for status.json / gate-decision-log. */
2067
+ state() {
2068
+ return {
2069
+ tripped: this.trippedFlag,
2070
+ after_n_timeouts: this.trippedAfterN,
2071
+ agents: [...this.trippedAgents],
2072
+ };
2073
+ }
2074
+ }
2075
+ /**
2076
+ * Resolve the cloud-breaker threshold from env (`AGENTICS_CLOUD_BREAKER_THRESHOLD`).
2077
+ * Falls back to the default constant. Exposed so callers can centralize the
2078
+ * threshold lookup instead of duplicating env-var parsing.
2079
+ */
2080
+ export function resolveCloudBreakerThreshold() {
2081
+ const env = process.env['AGENTICS_CLOUD_BREAKER_THRESHOLD'];
2082
+ if (env) {
2083
+ const parsed = parseInt(env, 10);
2084
+ if (!Number.isNaN(parsed) && parsed >= 1)
2085
+ return parsed;
2086
+ }
2087
+ return DEFAULT_CLOUD_BREAKER_THRESHOLD;
2088
+ }
1986
2089
  /**
1987
2090
  * Dispatch all agentics platform agents for a phase in parallel.
1988
2091
  * Returns results from all agents (some may be null on failure).
1989
2092
  */
1990
2093
  /** Overall timeout for all agents in a phase: 45s. Individual agents have 30s timeout. */
1991
2094
  const DISPATCH_ALL_TIMEOUT_MS = 45000;
1992
- async function dispatchAgenticsServices(services, prompt, traceId) {
2095
+ async function dispatchAgenticsServices(services, prompt, traceId, breaker) {
1993
2096
  if (services.length === 0)
1994
2097
  return [];
2098
+ // ADR-094 D7 — every fanout gets a fresh cloud circuit breaker. Cloud
2099
+ // failures within this fanout accumulate and short-circuit remaining
2100
+ // dispatches once the threshold is reached. Tests can inject their own
2101
+ // breaker via the optional argument.
2102
+ const fanoutBreaker = breaker ?? new CloudCircuitBreaker(resolveCloudBreakerThreshold());
1995
2103
  // Track completed results as they arrive so fleet timeout can return partial results
1996
2104
  const completedResults = [];
1997
2105
  const wrappedPromises = services.map(async (svc) => {
1998
- const result = await invokeAgenticsService(svc, prompt, traceId);
2106
+ const result = await invokeAgenticsService(svc, prompt, traceId, fanoutBreaker);
1999
2107
  if (result !== null) {
2000
2108
  completedResults.push(result);
2001
2109
  }
@@ -2014,8 +2122,27 @@ async function dispatchAgenticsServices(services, prompt, traceId) {
2014
2122
  const pending = services.length - completedResults.length;
2015
2123
  console.error(` [AGENTICS] Fleet timeout after ${DISPATCH_ALL_TIMEOUT_MS}ms — ${completedResults.length} completed, ${pending} still pending`);
2016
2124
  }
2125
+ // ADR-094 D7 — surface breaker state so callers can record it in
2126
+ // status.json. We attach it as a non-enumerable property on the result
2127
+ // array so the existing call sites stay backwards-compatible.
2128
+ const breakerState = fanoutBreaker.state();
2129
+ if (breakerState.tripped) {
2130
+ Object.defineProperty(completedResults, '__cloudBreakerState', {
2131
+ value: breakerState,
2132
+ enumerable: false,
2133
+ });
2134
+ }
2017
2135
  return completedResults;
2018
2136
  }
2137
+ /**
2138
+ * ADR-094 D7 — read the breaker state recorded by `dispatchAgenticsServices`
2139
+ * onto the returned results array. Returns `undefined` when the breaker did
2140
+ * not trip (or when the array did not come from this dispatcher).
2141
+ */
2142
+ export function getCloudBreakerState(results) {
2143
+ const state = results.__cloudBreakerState;
2144
+ return state;
2145
+ }
2019
2146
  /**
2020
2147
  * Build the prompt text for agentics agents based on phase context.
2021
2148
  */