@evident-ai/cli 3.1.1-dev.6db490b → 3.1.1-dev.6dbc950
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 +108 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1548,6 +1548,42 @@ function messageError(messages, userMessageId) {
|
|
|
1548
1548
|
}
|
|
1549
1549
|
return "The agent run failed.";
|
|
1550
1550
|
}
|
|
1551
|
+
function messageFailure(messages, userMessageId) {
|
|
1552
|
+
const reply = findLastAssistantReplyFor(messages, userMessageId);
|
|
1553
|
+
const error2 = errorOf(reply);
|
|
1554
|
+
if (error2 == null || typeof error2 !== "object") return null;
|
|
1555
|
+
const e = error2;
|
|
1556
|
+
const replyProviderId = reply?.info?.providerID ?? null;
|
|
1557
|
+
const replyModelId = reply?.info?.modelID ?? null;
|
|
1558
|
+
if (e.name === "ProviderAuthError") {
|
|
1559
|
+
const data = e.data;
|
|
1560
|
+
const providerId = typeof data?.providerID === "string" && data.providerID || replyProviderId;
|
|
1561
|
+
return { kind: "model_auth", providerId, modelId: replyModelId, reason: "missing" };
|
|
1562
|
+
}
|
|
1563
|
+
if (e.name === "APIError") {
|
|
1564
|
+
const data = e.data;
|
|
1565
|
+
const statusCode = data?.statusCode;
|
|
1566
|
+
if (statusCode === 401 || statusCode === 403) {
|
|
1567
|
+
return {
|
|
1568
|
+
kind: "model_auth",
|
|
1569
|
+
providerId: replyProviderId,
|
|
1570
|
+
modelId: replyModelId,
|
|
1571
|
+
reason: "rejected"
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
return null;
|
|
1576
|
+
}
|
|
1577
|
+
function applyZeroProviderFallback(classified, hasConfiguredProvider, replyProviderId, replyModelId = null) {
|
|
1578
|
+
if (classified != null) return classified;
|
|
1579
|
+
if (hasConfiguredProvider !== false) return null;
|
|
1580
|
+
return {
|
|
1581
|
+
kind: "model_auth",
|
|
1582
|
+
providerId: replyProviderId,
|
|
1583
|
+
modelId: replyModelId,
|
|
1584
|
+
reason: "missing"
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1551
1587
|
function hasRunningAssistantExcept(messages, exceptUserMessageId) {
|
|
1552
1588
|
if (!messages || messages.length === 0) return false;
|
|
1553
1589
|
return messages.some(
|
|
@@ -2076,6 +2112,18 @@ var RunnerConnection = class {
|
|
|
2076
2112
|
}
|
|
2077
2113
|
};
|
|
2078
2114
|
|
|
2115
|
+
// src/lib/tunnel/ready-marker.ts
|
|
2116
|
+
import { writeFileSync } from "fs";
|
|
2117
|
+
function writeTunnelReadyMarker(path, agentId) {
|
|
2118
|
+
try {
|
|
2119
|
+
writeFileSync(path, `${agentId}
|
|
2120
|
+
`);
|
|
2121
|
+
return { ok: true };
|
|
2122
|
+
} catch (error2) {
|
|
2123
|
+
return { ok: false, error: error2 instanceof Error ? error2.message : String(error2) };
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2079
2127
|
// src/lib/channels/driver.ts
|
|
2080
2128
|
import { homedir } from "os";
|
|
2081
2129
|
|
|
@@ -3586,8 +3634,16 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
3586
3634
|
message_id: inFlight.evidentMessageId
|
|
3587
3635
|
});
|
|
3588
3636
|
const usage = messageUsage(messages, inFlight.opencodeMessageId);
|
|
3637
|
+
const failure = await this.classifyModelAuthFailure(messages, inFlight.opencodeMessageId);
|
|
3589
3638
|
try {
|
|
3590
|
-
await this.markFailed(
|
|
3639
|
+
await this.markFailed(
|
|
3640
|
+
conv.id,
|
|
3641
|
+
inFlight.evidentMessageId,
|
|
3642
|
+
sessionId,
|
|
3643
|
+
error2,
|
|
3644
|
+
usage,
|
|
3645
|
+
failure
|
|
3646
|
+
);
|
|
3591
3647
|
} catch (err) {
|
|
3592
3648
|
if (err instanceof ChannelAuthError) throw err;
|
|
3593
3649
|
if (err instanceof ChannelTerminalError) {
|
|
@@ -3968,6 +4024,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
3968
4024
|
if (state === "failed") {
|
|
3969
4025
|
const error2 = messageError(messages, ocId ?? "") ?? void 0;
|
|
3970
4026
|
const usage = messageUsage(messages, ocId ?? "");
|
|
4027
|
+
const failure = await this.classifyModelAuthFailure(messages, ocId ?? "");
|
|
3971
4028
|
this.log({
|
|
3972
4029
|
level: "error",
|
|
3973
4030
|
message: `Re-adopt: message ${row.id.slice(0, 8)} errored while unwatched \u2014 marking failed: ${error2 ?? "(no error text)"}`,
|
|
@@ -3975,7 +4032,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
3975
4032
|
message_id: row.id
|
|
3976
4033
|
});
|
|
3977
4034
|
try {
|
|
3978
|
-
await this.markFailed(row.conversation_id, row.id, sessionId, error2, usage);
|
|
4035
|
+
await this.markFailed(row.conversation_id, row.id, sessionId, error2, usage, failure);
|
|
3979
4036
|
} catch (err) {
|
|
3980
4037
|
if (err instanceof ChannelAuthError) throw err;
|
|
3981
4038
|
if (err instanceof ChannelTerminalError) {
|
|
@@ -4953,7 +5010,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
4953
5010
|
* exists but is wedged, so the next attempt must get a fresh one
|
|
4954
5011
|
* instead of reusing it — see WI-1's server-side null-clearing PATCH).
|
|
4955
5012
|
*/
|
|
4956
|
-
async markFailed(conversationId, messageId, sessionId, error2, usage) {
|
|
5013
|
+
async markFailed(conversationId, messageId, sessionId, error2, usage, failure) {
|
|
4957
5014
|
const body = { status: "failed" };
|
|
4958
5015
|
if (sessionId === null) {
|
|
4959
5016
|
body.opencode_session_id = null;
|
|
@@ -4962,6 +5019,12 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
4962
5019
|
}
|
|
4963
5020
|
if (error2 !== void 0) body.error = error2;
|
|
4964
5021
|
if (usage) Object.assign(body, usage);
|
|
5022
|
+
if (failure) {
|
|
5023
|
+
body.failure_kind = failure.kind;
|
|
5024
|
+
body.failure_provider_id = failure.providerId;
|
|
5025
|
+
body.failure_model_id = failure.modelId;
|
|
5026
|
+
body.failure_reason = failure.reason;
|
|
5027
|
+
}
|
|
4965
5028
|
await this.callWithRetry(
|
|
4966
5029
|
"marking message as failed",
|
|
4967
5030
|
() => this.fetchImpl(
|
|
@@ -4974,6 +5037,29 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
4974
5037
|
)
|
|
4975
5038
|
);
|
|
4976
5039
|
}
|
|
5040
|
+
/**
|
|
5041
|
+
* Classify an errored turn as a model-auth failure (#736 P1-4), for `markFailed`.
|
|
5042
|
+
*
|
|
5043
|
+
* `messageFailure` alone (structured OpenCode error → `model_auth`) covers
|
|
5044
|
+
* most cases; when it returns `null` on this ALREADY-FAILED turn, fall back
|
|
5045
|
+
* to the P1-2b zero-provider check — one extra loopback call to
|
|
5046
|
+
* `hasAnyConfiguredProvider`, only reached when the structured classifier
|
|
5047
|
+
* couldn't place it. Fails open (never throws): a fallback probe failure
|
|
5048
|
+
* (`null`/indeterminate) leaves the classification `null`, which produces
|
|
5049
|
+
* today's byte-identical PATCH body via `markFailed`'s `if (failure)` guard.
|
|
5050
|
+
*/
|
|
5051
|
+
async classifyModelAuthFailure(messages, userMessageId) {
|
|
5052
|
+
const classified = messageFailure(messages, userMessageId);
|
|
5053
|
+
if (classified != null) return classified;
|
|
5054
|
+
const reply = findLastAssistantReplyFor(messages, userMessageId);
|
|
5055
|
+
const hasProvider = await hasAnyConfiguredProvider(this.port);
|
|
5056
|
+
return applyZeroProviderFallback(
|
|
5057
|
+
classified,
|
|
5058
|
+
hasProvider,
|
|
5059
|
+
reply?.info?.providerID ?? null,
|
|
5060
|
+
reply?.info?.modelID ?? null
|
|
5061
|
+
);
|
|
5062
|
+
}
|
|
4977
5063
|
/**
|
|
4978
5064
|
* Best-effort, SINGLE-ATTEMPT runner→server telemetry ping
|
|
4979
5065
|
* (queued-followup-redrive). `POST .../messages/:id/signal {signal, ...extra}`
|
|
@@ -5150,7 +5236,7 @@ async function ensureOpenCodeRunning(ctx) {
|
|
|
5150
5236
|
console.log(chalk5.yellow("Tip: Run with the correct port:"));
|
|
5151
5237
|
console.log(
|
|
5152
5238
|
chalk5.dim(
|
|
5153
|
-
` ${getCliName()} run --
|
|
5239
|
+
` ${getCliName()} run --runner ${ctx.agentId} --port ${runningInstances[0].port}`
|
|
5154
5240
|
)
|
|
5155
5241
|
);
|
|
5156
5242
|
}
|
|
@@ -5280,7 +5366,7 @@ async function resolveAgentIdFromKey(authHeader) {
|
|
|
5280
5366
|
return { agent_id: data.agent_id };
|
|
5281
5367
|
}
|
|
5282
5368
|
return {
|
|
5283
|
-
error: "Cannot resolve runner ID: auth type is not agent_key. Please provide --
|
|
5369
|
+
error: "Cannot resolve runner ID: auth type is not agent_key. Please provide --runner explicitly."
|
|
5284
5370
|
};
|
|
5285
5371
|
} catch (error2) {
|
|
5286
5372
|
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
@@ -6076,6 +6162,18 @@ async function run(options) {
|
|
|
6076
6162
|
type: "info",
|
|
6077
6163
|
message: `Tunnel ${isReconnect ? "reconnected" : "connected"} (runner: ${agentId})`
|
|
6078
6164
|
});
|
|
6165
|
+
if (options.tunnelReadyFile) {
|
|
6166
|
+
const marker = writeTunnelReadyMarker(options.tunnelReadyFile, agentId);
|
|
6167
|
+
if (marker.ok) {
|
|
6168
|
+
log2(state, `Wrote tunnel readiness marker to ${options.tunnelReadyFile}`, "debug");
|
|
6169
|
+
} else {
|
|
6170
|
+
log2(
|
|
6171
|
+
state,
|
|
6172
|
+
`Failed to write tunnel readiness marker to ${options.tunnelReadyFile}: ${marker.error}`,
|
|
6173
|
+
"error"
|
|
6174
|
+
);
|
|
6175
|
+
}
|
|
6176
|
+
}
|
|
6079
6177
|
emitAgentConnected(state.agentId, {
|
|
6080
6178
|
port: state.port,
|
|
6081
6179
|
cli_version: getCliVersion(),
|
|
@@ -6240,6 +6338,9 @@ program.command("run").description("Connect to Evident and process messages").op
|
|
|
6240
6338
|
"Allow Evident to write files into this directory (repeatable). Omit to disable file sync entirely.",
|
|
6241
6339
|
(value, previous) => previous.concat([value]),
|
|
6242
6340
|
[]
|
|
6341
|
+
).option(
|
|
6342
|
+
"--tunnel-ready-file <path>",
|
|
6343
|
+
"Path to write once the tunnel is connected (set by the MicroVM hooks; unused on a developer machine)"
|
|
6243
6344
|
).action(
|
|
6244
6345
|
(options) => {
|
|
6245
6346
|
run({
|
|
@@ -6259,7 +6360,8 @@ program.command("run").description("Connect to Evident and process messages").op
|
|
|
6259
6360
|
sessionCleanupInterval: options.sessionCleanupInterval,
|
|
6260
6361
|
// Raw values — expansion/validation is single-sourced in run.ts's
|
|
6261
6362
|
// resolveFileSyncDirectories.
|
|
6262
|
-
enableFileSyncTo: options.enableFileSyncTo
|
|
6363
|
+
enableFileSyncTo: options.enableFileSyncTo,
|
|
6364
|
+
tunnelReadyFile: options.tunnelReadyFile
|
|
6263
6365
|
});
|
|
6264
6366
|
}
|
|
6265
6367
|
);
|