niahere 0.4.6 → 0.5.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.
@@ -10,8 +10,7 @@ const TIME_RE = /^\d{2}:\d{2}$/;
10
10
 
11
11
  const DEFAULTS: Config = {
12
12
  model: "default",
13
- runner: "claude",
14
- fallback: [],
13
+ fallback_models: [],
15
14
  timezone: process.env.TZ || Intl.DateTimeFormat().resolvedOptions().timeZone,
16
15
  activeHours: { start: "00:00", end: "23:59" },
17
16
  database_url: DEFAULT_DATABASE_URL,
@@ -96,10 +95,10 @@ export function loadConfig(): Config {
96
95
  // Model
97
96
  const model = typeof raw.model === "string" ? raw.model : DEFAULTS.model;
98
97
 
99
- // Backends primary "runner" + ordered "fallback" chain for provider-down failover.
100
- const isBackend = (v: unknown): v is Config["runner"] => v === "claude" || v === "codex" || v === "gemini";
101
- const runner: Config["runner"] = isBackend(raw.runner) ? raw.runner : DEFAULTS.runner;
102
- const fallback: Config["fallback"] = Array.isArray(raw.fallback) ? raw.fallback.filter(isBackend) : DEFAULTS.fallback;
98
+ // Ordered fallback models; each one's provider is derived from its name.
99
+ const fallback_models = Array.isArray(raw.fallback_models)
100
+ ? raw.fallback_models.filter((m): m is string => typeof m === "string" && m.trim().length > 0)
101
+ : DEFAULTS.fallback_models;
103
102
 
104
103
  // Timezone
105
104
  let timezone = DEFAULTS.timezone;
@@ -252,8 +251,7 @@ export function loadConfig(): Config {
252
251
 
253
252
  return {
254
253
  model,
255
- runner,
256
- fallback,
254
+ fallback_models,
257
255
  timezone,
258
256
  activeHours: { start, end },
259
257
  database_url,
@@ -14,51 +14,6 @@ export async function withRetry<T>(fn: () => Promise<T>, retries = 3): Promise<T
14
14
  throw new Error("unreachable"); // satisfies TS return type
15
15
  }
16
16
 
17
- const RETRYABLE_PATTERNS = [/\b500\b/i, /internal server error/i, /overloaded/i, /529/, /rate limit/i];
18
-
19
- /** Check if an error string from the Claude API looks transient/retryable. */
20
- export function isRetryableApiError(error: string): boolean {
21
- return RETRYABLE_PATTERNS.some((p) => p.test(error));
22
- }
23
-
24
- /**
25
- * A blank or opaque ("unknown error") failure means the provider is down rather
26
- * than a specific, surfaceable error — the signal that should trigger failover.
27
- * Distinct from `isRetryableApiError` (a transient error worth an in-backend retry).
28
- */
29
- export function isProviderDownError(error: string | null | undefined): boolean {
30
- const trimmed = error?.trim();
31
- return !trimmed || trimmed.toLowerCase() === "unknown error";
32
- }
33
-
34
- const CLI_PROVIDER_DOWN_PATTERNS = [
35
- /authenticat/i,
36
- /unauthoriz/i,
37
- /\b(401|403)\b/,
38
- /not logged in/i,
39
- /\blogin\b/i,
40
- /\bcredentials?\b/i,
41
- /\bapi key\b/i,
42
- /(session|token) expired/i,
43
- /\b(econnrefused|enotfound|etimedout|econnreset)\b/i,
44
- /connection (refused|reset|timed out)/i,
45
- /network (error|unreachable)/i,
46
- /failed to refresh available models/i,
47
- ];
48
-
49
- /**
50
- * Provider-down classification for CLI-subprocess backends (codex), whose
51
- * failures surface as free-form stderr rather than the Claude SDK's structured
52
- * error. Matches the ways a CLI reports "I could not reach or authenticate with
53
- * the provider" — as opposed to a task that ran and genuinely failed, which must
54
- * stay a real error so the chain does not burn a second backend replaying it.
55
- */
56
- export function isCliProviderDownError(stderr: string | null | undefined): boolean {
57
- const trimmed = stderr?.trim();
58
- if (!trimmed) return true;
59
- return CLI_PROVIDER_DOWN_PATTERNS.some((p) => p.test(trimmed));
60
- }
61
-
62
17
  /** Sleep for ms milliseconds. */
63
18
  export function sleep(ms: number): Promise<void> {
64
19
  return new Promise((r) => setTimeout(r, ms));