@elisym/cli 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1970,6 +1970,22 @@ function resolveJobAsset(tags, skills) {
1970
1970
  return skill?.asset ?? NATIVE_SOL;
1971
1971
  }
1972
1972
  var BILLING_BODY_MARKERS3 = ["credit balance", "billing", "insufficient", "insufficient_quota"];
1973
+ var SCRIPT_BILLING_INVALID_MARKERS = [
1974
+ "credit balance",
1975
+ "billing",
1976
+ "insufficient",
1977
+ "insufficient_quota",
1978
+ "x-api-key",
1979
+ "invalid api key",
1980
+ "invalid_api_key",
1981
+ "authentication_error",
1982
+ "unauthorized",
1983
+ "unauthenticated"
1984
+ ];
1985
+ function scriptMessageLooksLikeBillingOrInvalid(message) {
1986
+ const lower = message.toLowerCase();
1987
+ return SCRIPT_BILLING_INVALID_MARKERS.some((marker) => lower.includes(marker));
1988
+ }
1973
1989
  var AGENT_UNAVAILABLE_MESSAGE = "Agent temporarily unavailable";
1974
1990
  var AgentUnavailableError = class extends Error {
1975
1991
  constructor() {
@@ -2070,6 +2086,32 @@ var AgentRuntime = class {
2070
2086
  * Anything else is a transient/skill error and does NOT touch health
2071
2087
  * state - the recovery loop should not be poisoned by skill bugs.
2072
2088
  */
2089
+ /**
2090
+ * Build a "and N other model(s) for the same provider" suffix for
2091
+ * cascade-narrating log lines. The SDK monitor cascades `invalid` /
2092
+ * `billing` flips across every sibling pair sharing the same provider
2093
+ * (shared API key); this helper just narrates that to the operator log
2094
+ * so they can see why unrelated skills are now refusing jobs.
2095
+ */
2096
+ cascadeSuffix(provider, triggeringModel) {
2097
+ if (!this.healthMonitor) {
2098
+ return "";
2099
+ }
2100
+ let siblings = 0;
2101
+ for (const entry of this.healthMonitor.snapshot()) {
2102
+ if (entry.provider !== provider) {
2103
+ continue;
2104
+ }
2105
+ if (entry.model === triggeringModel) {
2106
+ continue;
2107
+ }
2108
+ siblings += 1;
2109
+ }
2110
+ if (siblings === 0) {
2111
+ return "";
2112
+ }
2113
+ return ` (cascading to ${siblings} other model(s) for ${provider} sharing the same API key)`;
2114
+ }
2073
2115
  markHealthFromExecuteError(skill, err, log, jobId) {
2074
2116
  if (!this.healthMonitor) {
2075
2117
  return false;
@@ -2085,7 +2127,7 @@ var AgentRuntime = class {
2085
2127
  return false;
2086
2128
  }
2087
2129
  log(
2088
- `${tag} Script signaled billing-exhausted (exit ${err.exitCode}). Marking ${provider}/${model} unhealthy; future jobs against this pair will be refused until recovery probe succeeds.`
2130
+ `${tag} Script signaled billing-exhausted (exit ${err.exitCode}). Marking ${provider}/${model} unhealthy${this.cascadeSuffix(provider, model)}; future jobs against this pair will be refused until recovery probe succeeds.`
2089
2131
  );
2090
2132
  this.healthMonitor.markUnhealthyFromJob(provider, model, "billing", err.message);
2091
2133
  return true;
@@ -2109,11 +2151,32 @@ var AgentRuntime = class {
2109
2151
  const provider = skill.resolvedTriple.provider;
2110
2152
  const model = skill.resolvedTriple.model;
2111
2153
  log(
2112
- `${tag} LLM provider returned HTTP ${status} (${reason}). Marking ${provider}/${model} unhealthy; future jobs against this pair will be refused until recovery probe succeeds.`
2154
+ `${tag} LLM provider returned HTTP ${status} (${reason}). Marking ${provider}/${model} unhealthy${this.cascadeSuffix(provider, model)}; future jobs against this pair will be refused until recovery probe succeeds.`
2113
2155
  );
2114
2156
  this.healthMonitor.markUnhealthyFromJob(provider, model, reason, body);
2115
2157
  return true;
2116
2158
  }
2159
+ if (skill.mode !== "llm") {
2160
+ const message = err instanceof Error ? err.message : String(err);
2161
+ if (!scriptMessageLooksLikeBillingOrInvalid(message)) {
2162
+ return false;
2163
+ }
2164
+ const provider = skill.llmOverride?.provider;
2165
+ const model = skill.llmOverride?.model;
2166
+ if (!provider || !model) {
2167
+ log(
2168
+ `${tag} Script failure looks like billing/invalid ("${message.slice(0, 120)}") but skill "${skill.name}" did not declare provider/model in SKILL.md - cannot gate future jobs.`
2169
+ );
2170
+ return false;
2171
+ }
2172
+ const lower = message.toLowerCase();
2173
+ const reason = lower.includes("credit balance") || lower.includes("billing") || lower.includes("insufficient") ? "billing" : "invalid";
2174
+ log(
2175
+ `${tag} Script failure carries ${reason} signal in stderr. Marking ${provider}/${model} unhealthy${this.cascadeSuffix(provider, model)}; future jobs against this pair will be refused until recovery probe succeeds.`
2176
+ );
2177
+ this.healthMonitor.markUnhealthyFromJob(provider, model, reason, message.slice(0, 200));
2178
+ return true;
2179
+ }
2117
2180
  return false;
2118
2181
  }
2119
2182
  /** Fetch on-chain protocol config (fee, treasury). Always fetches fresh to avoid stale treasury. */