@ai-matrx/coding-sessions 0.1.81 → 0.1.83

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.
@@ -11,6 +11,22 @@ import { ChatThreadStore, ChatMessage } from '@ai-matrx/chat';
11
11
  * platform term (chat.coding_session, the Coding Session Bridge). */
12
12
  type CodingProvider = "claude" | "codex";
13
13
  type Billing = "subscription" | "api" | "unknown";
14
+ /** Where the CLI a provider runs came from. */
15
+ type BinarySource = "desktop-app" | "path" | "npm-global" | "configured";
16
+ /** The exact CLI runs use: the newest copy on this computer (or the host's pick). */
17
+ interface ProviderBinary {
18
+ path: string;
19
+ version: string | null;
20
+ source: BinarySource;
21
+ /** "from ChatGPT app", "from PATH", … */
22
+ sourceLabel: string;
23
+ /** A newer copy than the one in use, when one exists. */
24
+ newer: {
25
+ path: string;
26
+ version: string;
27
+ sourceLabel: string;
28
+ } | null;
29
+ }
14
30
  /** What `providers()` answers for one provider, in plain terms. */
15
31
  interface ProviderStatus {
16
32
  provider: CodingProvider;
@@ -48,6 +64,8 @@ interface ProviderStatus {
48
64
  } | null | undefined;
49
65
  /** The effort a run uses when none is picked (the person's own settings). */
50
66
  defaultEffort?: string | null | undefined;
67
+ /** Which CLI runs use, and its version. */
68
+ binary?: ProviderBinary | null | undefined;
51
69
  }
52
70
  interface ModelOption {
53
71
  id: string;
@@ -11,6 +11,22 @@ import { ChatThreadStore, ChatMessage } from '@ai-matrx/chat';
11
11
  * platform term (chat.coding_session, the Coding Session Bridge). */
12
12
  type CodingProvider = "claude" | "codex";
13
13
  type Billing = "subscription" | "api" | "unknown";
14
+ /** Where the CLI a provider runs came from. */
15
+ type BinarySource = "desktop-app" | "path" | "npm-global" | "configured";
16
+ /** The exact CLI runs use: the newest copy on this computer (or the host's pick). */
17
+ interface ProviderBinary {
18
+ path: string;
19
+ version: string | null;
20
+ source: BinarySource;
21
+ /** "from ChatGPT app", "from PATH", … */
22
+ sourceLabel: string;
23
+ /** A newer copy than the one in use, when one exists. */
24
+ newer: {
25
+ path: string;
26
+ version: string;
27
+ sourceLabel: string;
28
+ } | null;
29
+ }
14
30
  /** What `providers()` answers for one provider, in plain terms. */
15
31
  interface ProviderStatus {
16
32
  provider: CodingProvider;
@@ -48,6 +64,8 @@ interface ProviderStatus {
48
64
  } | null | undefined;
49
65
  /** The effort a run uses when none is picked (the person's own settings). */
50
66
  defaultEffort?: string | null | undefined;
67
+ /** Which CLI runs use, and its version. */
68
+ binary?: ProviderBinary | null | undefined;
51
69
  }
52
70
  interface ModelOption {
53
71
  id: string;
@@ -52,6 +52,21 @@ function formatUntil(until) {
52
52
  if (Number.isNaN(ms)) return until;
53
53
  return new Date(ms).toLocaleString(void 0, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
54
54
  }
55
+ var MODEL_UNAVAILABLE = [
56
+ /model is not supported when using codex/i,
57
+ /\bmodel[\s:'"`][^.\n]{0,80}\b(?:not supported|does not exist|not available|not found)\b/i,
58
+ /\bmodel_not_found\b/i,
59
+ /issue with the selected model/i,
60
+ /may not exist or you may not have access to it/i
61
+ ];
62
+ var MODEL_UNAVAILABLE_LABEL = "Model not available on this account";
63
+ function isModelUnavailable(text) {
64
+ const trimmed = (text ?? "").trim();
65
+ return trimmed !== "" && MODEL_UNAVAILABLE.some((re) => re.test(trimmed));
66
+ }
67
+ function runErrorLabel(text) {
68
+ return isModelUnavailable(text) ? MODEL_UNAVAILABLE_LABEL : text;
69
+ }
55
70
 
56
71
  // src/tool-labels.ts
57
72
  var BUILTIN = {
@@ -1507,14 +1522,15 @@ function createTranscriptBuilder() {
1507
1522
  }));
1508
1523
  return;
1509
1524
  case "error": {
1510
- const said = current?.message.parts.some((p) => p.type === "error" && p.message.trim() === item.text.trim());
1525
+ const text = runErrorLabel(item.text);
1526
+ const said = current?.message.parts.some((p) => p.type === "error" && p.message.trim() === text.trim());
1511
1527
  if (said) return;
1512
1528
  upsertPart(item.id, () => ({
1513
1529
  type: "error",
1514
1530
  errorType: "provider",
1515
1531
  code: null,
1516
- message: item.text,
1517
- userMessage: item.text,
1532
+ message: text,
1533
+ userMessage: text,
1518
1534
  recoverable: true,
1519
1535
  remedy: null
1520
1536
  }));
@@ -2026,7 +2042,7 @@ function ProvidersFooter(props) {
2026
2042
  "span",
2027
2043
  {
2028
2044
  className: cn4("cs-provider-chip", p.ready ? "" : "cs-provider-chip--problem"),
2029
- title: p.problem ? `${p.problem} ${p.fix ?? ""}` : `${p.label}${p.plan ? ` \xB7 ${p.plan}` : ""}`,
2045
+ title: p.problem ? `${p.problem} ${p.fix ?? ""}` : [binaryWords(p) ?? p.label, p.plan, newerWords(p)].filter(Boolean).join(" \xB7 "),
2030
2046
  children: [
2031
2047
  /* @__PURE__ */ jsx6(ProviderMark, { provider: p.provider, size: 13 }),
2032
2048
  p.label,
@@ -2181,6 +2197,13 @@ function LongChatNote(props) {
2181
2197
  /* @__PURE__ */ jsx6("button", { type: "button", className: "cs-link", onClick: props.onEarlier, disabled: props.loading, children: props.loading ? "Reading\u2026" : "Show earlier" })
2182
2198
  ] });
2183
2199
  }
2200
+ function binaryWords(p) {
2201
+ if (!p.version) return null;
2202
+ return `${p.label} ${p.version}${p.binary ? ` \xB7 ${p.binary.sourceLabel}` : ""}`;
2203
+ }
2204
+ function newerWords(p) {
2205
+ return p.binary?.newer ? `Newer: ${p.binary.newer.version} ${p.binary.newer.sourceLabel}` : null;
2206
+ }
2184
2207
  function SessionView({ session, changesOpen, setChangesOpen }) {
2185
2208
  const client = useCodingSessionsClient();
2186
2209
  const state = useCodingSessionsState();
@@ -2192,6 +2215,7 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
2192
2215
  const provider = state.providers.data.find((p) => p.provider === session.provider) ?? null;
2193
2216
  const blocked = provider && (!provider.installed || !provider.loggedIn) ? provider : null;
2194
2217
  const limited = !blocked && provider?.lastProblem ? provider : null;
2218
+ const modelRefused = run?.status === "failed" && isModelUnavailable(run.error);
2195
2219
  const [stopping, setStopping] = useState5(false);
2196
2220
  const [renaming, setRenaming] = useState5(false);
2197
2221
  const elsewhere = useLiveElsewhere(
@@ -2286,6 +2310,25 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
2286
2310
  limited.fix
2287
2311
  ] })
2288
2312
  ] }) : null,
2313
+ modelRefused && !blocked ? /* @__PURE__ */ jsxs6(
2314
+ "div",
2315
+ {
2316
+ className: "mb-2 flex items-center gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-[12.5px]",
2317
+ role: "alert",
2318
+ children: [
2319
+ /* @__PURE__ */ jsx6(AlertIcon, { size: 15, className: "shrink-0 text-warning" }),
2320
+ /* @__PURE__ */ jsx6("span", { className: "min-w-0 flex-1 truncate", title: run?.error ?? void 0, children: MODEL_UNAVAILABLE_LABEL }),
2321
+ /* @__PURE__ */ jsx6(
2322
+ ModelPicker,
2323
+ {
2324
+ status: provider,
2325
+ value: { model: session.model, effort: session.effort ?? null },
2326
+ onChange: setOptions
2327
+ }
2328
+ )
2329
+ ]
2330
+ }
2331
+ ) : null,
2289
2332
  blocked ? /* @__PURE__ */ jsxs6("div", { className: "mb-2 flex items-start gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-[12.5px]", children: [
2290
2333
  /* @__PURE__ */ jsx6(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
2291
2334
  /* @__PURE__ */ jsxs6("span", { children: [
@@ -2809,9 +2852,20 @@ function Home({ onNew }) {
2809
2852
  " ",
2810
2853
  "\u2014 ready",
2811
2854
  p.plan ? ` on your ${p.plan} plan` : "",
2812
- p.billing === "api" ? " (API key, billed per use)" : "",
2813
- p.version ? ` \xB7 version ${p.version}` : ""
2814
- ] }) : /* @__PURE__ */ jsxs6("span", { className: "block text-muted-foreground", children: [
2855
+ p.billing === "api" ? " (API key, billed per use)" : ""
2856
+ ] }) : null,
2857
+ p.installed && p.version ? /* @__PURE__ */ jsxs6(
2858
+ "span",
2859
+ {
2860
+ className: "block text-[11.5px] text-muted-foreground",
2861
+ title: newerWords(p) ?? p.binary?.path ?? void 0,
2862
+ children: [
2863
+ binaryWords(p),
2864
+ p.binary?.newer ? ` \xB7 ${p.binary.newer.version} available` : ""
2865
+ ]
2866
+ }
2867
+ ) : null,
2868
+ p.ready ? null : /* @__PURE__ */ jsxs6("span", { className: "block text-muted-foreground", children: [
2815
2869
  p.problem,
2816
2870
  " ",
2817
2871
  p.fix
@@ -2960,7 +3014,7 @@ function useRunFinishedNotices(openSessionId, show) {
2960
3014
  unseen.current += 1;
2961
3015
  document.title = `(${unseen.current}) ${BASE_TITLE}`;
2962
3016
  if (typeof Notification !== "undefined" && Notification.permission === "granted") {
2963
- const note = new Notification(sentence, run.error ? { tag: run.runId, body: run.error } : { tag: run.runId });
3017
+ const note = new Notification(sentence, run.error ? { tag: run.runId, body: runErrorLabel(run.error) } : { tag: run.runId });
2964
3018
  note.onclick = () => {
2965
3019
  window.focus();
2966
3020
  location.hash = `#s/${run.sessionId}`;