@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 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(conv.id, inFlight.evidentMessageId, sessionId, error2, usage);
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 --agent ${ctx.agentId} --port ${runningInstances[0].port}`
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 --agent explicitly."
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
  );