niahere 0.4.5 → 0.4.6
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/package.json +1 -1
- package/src/agent/backends/codex.ts +2 -1
- package/src/core/scheduler.ts +18 -4
- package/src/utils/retry.ts +28 -0
package/package.json
CHANGED
|
@@ -6,6 +6,7 @@ import type { Attachment } from "../../types/attachment";
|
|
|
6
6
|
import type { McpSourceContext } from "../../mcp";
|
|
7
7
|
import { CodexNormalizer } from "./codex-normalize";
|
|
8
8
|
import { mintRun, revokeRun } from "../mcp-endpoint";
|
|
9
|
+
import { isCliProviderDownError } from "../../utils/retry";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Resolve the codex binary's absolute path. The daemon runs under launchd with a
|
|
@@ -188,7 +189,7 @@ class CodexSession implements AgentSession {
|
|
|
188
189
|
type: "error",
|
|
189
190
|
message: stderr.trim() || `codex exited ${exit}`,
|
|
190
191
|
retryable: false,
|
|
191
|
-
providerDown:
|
|
192
|
+
providerDown: isCliProviderDownError(stderr),
|
|
192
193
|
};
|
|
193
194
|
}
|
|
194
195
|
} finally {
|
package/src/core/scheduler.ts
CHANGED
|
@@ -3,9 +3,25 @@ import { runJob } from "./runner";
|
|
|
3
3
|
import { getConfig } from "../utils/config";
|
|
4
4
|
import { log } from "../utils/log";
|
|
5
5
|
import { computeInitialNextRun, computeNextRun } from "../utils/schedule";
|
|
6
|
+
import type { JobResult } from "../types";
|
|
6
7
|
|
|
7
8
|
export { computeInitialNextRun, computeNextRun };
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Log a finished job at a level matching its outcome. `runJob` resolves with
|
|
12
|
+
* `status: "error"` instead of throwing, so the caller's `.catch` only ever sees
|
|
13
|
+
* an infrastructure fault — a job that ran and failed must be branched on here
|
|
14
|
+
* or it is indistinguishable from success in the log.
|
|
15
|
+
*/
|
|
16
|
+
export function logJobOutcome(result: JobResult): void {
|
|
17
|
+
const fields = { job: result.job, status: result.status, duration: result.duration_ms };
|
|
18
|
+
if (result.status === "error") {
|
|
19
|
+
log.error({ ...fields, error: result.error, terminal_reason: result.terminal_reason }, "scheduler: job failed");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
log.info(fields, "scheduler: job completed");
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
function isWithinActiveHours(): boolean {
|
|
10
26
|
const config = getConfig();
|
|
11
27
|
const { start, end } = config.activeHours;
|
|
@@ -57,11 +73,9 @@ async function tick(): Promise<void> {
|
|
|
57
73
|
runningJobs.add(job.name);
|
|
58
74
|
|
|
59
75
|
runJob(job)
|
|
60
|
-
.then(
|
|
61
|
-
log.info({ job: job.name, status: result.status, duration: result.duration_ms }, "scheduler: job completed");
|
|
62
|
-
})
|
|
76
|
+
.then(logJobOutcome)
|
|
63
77
|
.catch((err) => {
|
|
64
|
-
log.error({ err, job: job.name }, "scheduler: job
|
|
78
|
+
log.error({ err, job: job.name }, "scheduler: job crashed");
|
|
65
79
|
})
|
|
66
80
|
.finally(() => {
|
|
67
81
|
runningJobs.delete(job.name);
|
package/src/utils/retry.ts
CHANGED
|
@@ -31,6 +31,34 @@ export function isProviderDownError(error: string | null | undefined): boolean {
|
|
|
31
31
|
return !trimmed || trimmed.toLowerCase() === "unknown error";
|
|
32
32
|
}
|
|
33
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
|
+
|
|
34
62
|
/** Sleep for ms milliseconds. */
|
|
35
63
|
export function sleep(ms: number): Promise<void> {
|
|
36
64
|
return new Promise((r) => setTimeout(r, ms));
|