@sagentlab/navarch-runtime 0.1.146 → 0.1.149
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/agent-model.cjs +22 -4
- package/dist/cli.cjs +2 -4
- package/dist/machine-store.cjs +5 -1
- package/dist/model-reference.cjs +25 -0
- package/dist/session.cjs +4 -1
- package/package.json +2 -2
package/dist/agent-model.cjs
CHANGED
|
@@ -11,6 +11,22 @@ exports.detectAgentModelUnavailable = detectAgentModelUnavailable;
|
|
|
11
11
|
*/
|
|
12
12
|
const NO_ROUTE_PATTERN = /\bprovider\.no-route\b|\bModelUnavailableError\b|\bModel unavailable:/i;
|
|
13
13
|
const MODEL_NAME_PATTERN = /\bModel unavailable:\s*([^\s"'\\,;)]+)/i;
|
|
14
|
+
const TRANSPORT_PATTERN = /\bprovider\.transport\b|\bConnectionRefused\b|\bECONNREFUSED\b|\bconnection refused\b/i;
|
|
15
|
+
/** A failed connection is a machine problem only before the session does work. */
|
|
16
|
+
function madeModelProgress(result) {
|
|
17
|
+
if (result.reportText?.trim() || (result.tokensIn ?? 0) > 0 ||
|
|
18
|
+
(result.tokensOut ?? 0) > 0 || (result.costUsd ?? 0) > 0)
|
|
19
|
+
return true;
|
|
20
|
+
return result.stdout.split(/\r?\n/).some((line) => {
|
|
21
|
+
try {
|
|
22
|
+
const event = JSON.parse(line);
|
|
23
|
+
return ["step_start", "step_finish", "text", "reasoning", "tool_use", "tool_result", "tool"].includes(event?.type);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
14
30
|
function clip(text) {
|
|
15
31
|
const trimmed = text.trim().replace(/\s+/g, " ");
|
|
16
32
|
return trimmed.length > 300 ? `${trimmed.slice(0, 299)}…` : trimmed;
|
|
@@ -50,7 +66,8 @@ function errorEventMessages(stdout) {
|
|
|
50
66
|
}
|
|
51
67
|
/**
|
|
52
68
|
* Detects a turn the coding agent CLI could not start because the model it
|
|
53
|
-
* was told to use has no route on this machine (OpenCode `provider.no-route`)
|
|
69
|
+
* was told to use has no route on this machine (OpenCode `provider.no-route`),
|
|
70
|
+
* or its provider connection fails before any model progress in this session.
|
|
54
71
|
* Like a dead login (agent-auth.cts), every task the machine claims then fails
|
|
55
72
|
* the same way within seconds, so the control plane requeues the task without
|
|
56
73
|
* spending a retry and pauses the machine until the model is fixed.
|
|
@@ -59,19 +76,20 @@ function errorEventMessages(stdout) {
|
|
|
59
76
|
* ERROR log lines — and only for a turn that failed or produced no report, so
|
|
60
77
|
* an agent writing about this very error cannot pause its own machine.
|
|
61
78
|
*/
|
|
62
|
-
function detectAgentModelUnavailable(result) {
|
|
79
|
+
function detectAgentModelUnavailable(result, previousAttempts = []) {
|
|
63
80
|
if (result.killedByLeaseLoss || result.timedOut || result.capacityError || result.authError)
|
|
64
81
|
return null;
|
|
65
82
|
if (result.exitCode === 0 && result.reportText)
|
|
66
83
|
return null;
|
|
84
|
+
const beforeProgress = !madeModelProgress(result) && !previousAttempts.some(madeModelProgress);
|
|
67
85
|
for (const message of errorEventMessages(result.stdout)) {
|
|
68
|
-
if (NO_ROUTE_PATTERN.test(message))
|
|
86
|
+
if (NO_ROUTE_PATTERN.test(message) || (beforeProgress && TRANSPORT_PATTERN.test(message)))
|
|
69
87
|
return failure(message);
|
|
70
88
|
}
|
|
71
89
|
if (result.exitCode === 0)
|
|
72
90
|
return null;
|
|
73
91
|
for (const line of result.stderr.split(/\r?\n/)) {
|
|
74
|
-
if (/ERROR/.test(line) && NO_ROUTE_PATTERN.test(line)) {
|
|
92
|
+
if (/ERROR/.test(line) && (NO_ROUTE_PATTERN.test(line) || (beforeProgress && TRANSPORT_PATTERN.test(line)))) {
|
|
75
93
|
const cause = line.match(/Model unavailable:[^"\n]*/i)?.[0];
|
|
76
94
|
return failure(cause ?? line);
|
|
77
95
|
}
|
package/dist/cli.cjs
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.main = main;
|
|
7
7
|
const config_cjs_1 = require("./config.cjs");
|
|
8
8
|
const node_crypto_1 = require("node:crypto");
|
|
9
|
+
const model_reference_cjs_1 = require("./model-reference.cjs");
|
|
9
10
|
const node_os_1 = __importDefault(require("node:os"));
|
|
10
11
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
12
|
const machine_store_cjs_1 = require("./machine-store.cjs");
|
|
@@ -126,10 +127,7 @@ function warnUnknownAdapters(config) {
|
|
|
126
127
|
/** Saved pins only apply to the adapter they were selected for. */
|
|
127
128
|
function modelFromFlags(flags, agentType, identity) {
|
|
128
129
|
const model = flags.model ?? (identity?.agent_type === agentType ? identity.model : undefined);
|
|
129
|
-
|
|
130
|
-
throw new Error("--model requires a non-empty model reference without whitespace.");
|
|
131
|
-
}
|
|
132
|
-
return model;
|
|
130
|
+
return model === undefined ? undefined : (0, model_reference_cjs_1.normalizeRuntimeModelReference)(model);
|
|
133
131
|
}
|
|
134
132
|
function parseArgs(argv) {
|
|
135
133
|
const [command, ...rest] = argv;
|
package/dist/machine-store.cjs
CHANGED
|
@@ -8,15 +8,19 @@ exports.loadMachineIdentity = loadMachineIdentity;
|
|
|
8
8
|
exports.resolveMachineIdentity = resolveMachineIdentity;
|
|
9
9
|
const node_fs_1 = require("node:fs");
|
|
10
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const model_reference_cjs_1 = require("./model-reference.cjs");
|
|
11
12
|
const agent_types_cjs_1 = require("./agent-types.cjs");
|
|
12
13
|
function storePath(configDir) {
|
|
13
14
|
return node_path_1.default.join(configDir, "machine.json");
|
|
14
15
|
}
|
|
15
16
|
/** Persists the machine's long-lived auth token to `<configDir>/machine.json`, mode 0600. */
|
|
16
17
|
async function saveMachineIdentity(configDir, identity) {
|
|
18
|
+
const normalized = identity.model === undefined
|
|
19
|
+
? identity
|
|
20
|
+
: { ...identity, model: (0, model_reference_cjs_1.normalizeRuntimeModelReference)(identity.model) };
|
|
17
21
|
await node_fs_1.promises.mkdir(configDir, { recursive: true, mode: 0o700 });
|
|
18
22
|
const file = storePath(configDir);
|
|
19
|
-
await node_fs_1.promises.writeFile(file, `${JSON.stringify(
|
|
23
|
+
await node_fs_1.promises.writeFile(file, `${JSON.stringify(normalized, null, 2)}\n`, { mode: 0o600 });
|
|
20
24
|
await node_fs_1.promises.chmod(file, 0o600);
|
|
21
25
|
}
|
|
22
26
|
async function loadMachineIdentity(configDir) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeModelReference = normalizeModelReference;
|
|
4
|
+
exports.normalizeRuntimeModelReference = normalizeRuntimeModelReference;
|
|
5
|
+
/** Mirrors normalizeModelReference in lib/navarch/execution-policy.ts for this standalone package. */
|
|
6
|
+
function normalizeModelReference(value) {
|
|
7
|
+
if (typeof value !== "string")
|
|
8
|
+
return null;
|
|
9
|
+
let model = value.trim();
|
|
10
|
+
const pairs = { '"': '"', "'": "'", "`": "`", "‘": "’", "“": "”" };
|
|
11
|
+
if (model.length >= 2 && pairs[model[0]] === model.at(-1)) {
|
|
12
|
+
model = model.slice(1, -1).trim();
|
|
13
|
+
}
|
|
14
|
+
if (!model || model.length > 500 || /[\u0000-\u001f\u007f'"`‘’“”]/.test(model))
|
|
15
|
+
return null;
|
|
16
|
+
return model;
|
|
17
|
+
}
|
|
18
|
+
/** Validate both new CLI pins and saved identities before use or persistence. */
|
|
19
|
+
function normalizeRuntimeModelReference(value) {
|
|
20
|
+
const model = normalizeModelReference(value);
|
|
21
|
+
if (!model || model === "true" || /\s/.test(model)) {
|
|
22
|
+
throw new Error("--model requires a non-empty model reference without whitespace or embedded quotes.");
|
|
23
|
+
}
|
|
24
|
+
return model;
|
|
25
|
+
}
|
package/dist/session.cjs
CHANGED
|
@@ -1080,7 +1080,10 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
1080
1080
|
}
|
|
1081
1081
|
// A model the CLI has no route to (OpenCode `provider.no-route`) fails
|
|
1082
1082
|
// every task the same way, so it gets the same treatment as a dead login.
|
|
1083
|
-
|
|
1083
|
+
// Startup transport failures also qualify, unless this session already
|
|
1084
|
+
// made model progress in this or an earlier turn.
|
|
1085
|
+
const modelUnavailable = capacityLimit || authFailure
|
|
1086
|
+
? null : (0, agent_model_cjs_1.detectAgentModelUnavailable)(turnResult, attempts.slice(0, -1));
|
|
1084
1087
|
if (modelUnavailable) {
|
|
1085
1088
|
turnResult.modelUnavailableError = modelUnavailable.detail;
|
|
1086
1089
|
log.warn(`session ${leaseId}: coding agent model unavailable: ${modelUnavailable.detail}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sagentlab/navarch-runtime",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.149",
|
|
4
4
|
"description": "Navarch machine-side session manager: claims delivery tasks and runs them through local coding agents.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsc -p tsconfig.json",
|
|
42
|
-
"typecheck": "
|
|
42
|
+
"typecheck": "bun check -p tsconfig.json",
|
|
43
43
|
"test": "vitest run",
|
|
44
44
|
"test:watch": "vitest",
|
|
45
45
|
"prepublishOnly": "npm run build && npm test",
|