@ai-matrx/agents 0.59.239 → 0.59.241
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/CHANGELOG.md +6 -1
- package/dist/context/react/index.cjs +7 -2
- package/dist/context/react/index.js +7 -2
- package/dist/models/react/index.cjs +93 -9
- package/dist/models/react/index.d.cts +23 -2
- package/dist/models/react/index.d.ts +23 -2
- package/dist/models/react/index.js +95 -10
- package/dist/settings/index.d.cts +20 -2
- package/dist/settings/index.d.ts +20 -2
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.59.
|
|
3
|
+
## 0.59.241
|
|
4
4
|
|
|
5
5
|
UNVERIFIED: this release has no Unreleased entry and the source comparison could not be made (the caller supplied no source comparison). Whether source changed is unknown; consumer action is unknown.
|
|
6
6
|
Check the package's gitHead on npm against this version's gitHead: `git diff <previous gitHead> <this gitHead> -- apps/shared/matrx-agents/src`.
|
|
7
7
|
|
|
8
|
+
## 0.59.239
|
|
9
|
+
|
|
10
|
+
Automatic changed-only republish (docs/metadata drift since the last published version; verified: `git diff 9df1465977 6acfc6b938 -- apps/shared/matrx-agents/src`
|
|
11
|
+
has no shipped-source changes outside tests, fixtures and docs). No consumer action required.
|
|
12
|
+
|
|
8
13
|
## 0.59.238
|
|
9
14
|
|
|
10
15
|
- **The context views never warn the person (Arman, 2026-10-22).** `ContextRulesChip` loses `mismatchCount` / `mismatches` (no amber face, no warning glyph, no "N · M" count); `ContextRulesTable` and `ContextRulesPanelBody` lose `mismatches` (no row marker, no "expected X, got Y" banner); `describeMismatches` is deleted. `compareReceipt` is unchanged — the host still files the silent `context_truth_mismatch`. A self-check row keeps its tooltip from `row.blockedBy`. Guard: `context/react/a-context-view-never-warns-the-person.test.tsx`. Consumer action: stop passing `mismatchCount` / `mismatches`.
|
|
@@ -310,6 +310,10 @@ function onRequestReason(row) {
|
|
|
310
310
|
if (row.max_inline_chars === 0) return "Never inline \u2014 the agent reads it on request";
|
|
311
311
|
return "Over the limit \u2014 the agent reads it on request";
|
|
312
312
|
}
|
|
313
|
+
function offByDefaultReason(row) {
|
|
314
|
+
if (row.include || row.decided_by.include !== "page") return null;
|
|
315
|
+
return row.layers?.surface?.auto_context === false ? "Off by default on this page" : null;
|
|
316
|
+
}
|
|
313
317
|
|
|
314
318
|
// context/react/InlineMaxInput.tsx
|
|
315
319
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -666,7 +670,8 @@ function ContextRuleRow({
|
|
|
666
670
|
trail
|
|
667
671
|
}) {
|
|
668
672
|
const selfChecked = row.blockedBy === "self_check";
|
|
669
|
-
const decided = selfChecked ? SELF_CHECK_TOOLTIP : row.serverResolved ? SERVER_RESOLVED_TOOLTIP : `Include: ${LAYER_LABEL[row.decided_by.include]} \xB7 Limit: ${LAYER_LABEL[row.decided_by.max_inline_chars]}`;
|
|
673
|
+
const decided = selfChecked ? SELF_CHECK_TOOLTIP : row.serverResolved ? SERVER_RESOLVED_TOOLTIP : offByDefaultReason(row) ?? `Include: ${LAYER_LABEL[row.decided_by.include]} \xB7 Limit: ${LAYER_LABEL[row.decided_by.max_inline_chars]}`;
|
|
674
|
+
const shownTrail = trail ?? offByDefaultReason(row);
|
|
670
675
|
const labelNode = onOpenRow ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
671
676
|
"button",
|
|
672
677
|
{
|
|
@@ -710,7 +715,7 @@ function ContextRuleRow({
|
|
|
710
715
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "font-normal text-muted-foreground", children: decided })
|
|
711
716
|
] })
|
|
712
717
|
] }),
|
|
713
|
-
|
|
718
|
+
shownTrail ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "min-w-0 max-w-[45%] shrink truncate text-muted-foreground", children: shownTrail }) : null
|
|
714
719
|
]
|
|
715
720
|
}
|
|
716
721
|
),
|
|
@@ -280,6 +280,10 @@ function onRequestReason(row) {
|
|
|
280
280
|
if (row.max_inline_chars === 0) return "Never inline \u2014 the agent reads it on request";
|
|
281
281
|
return "Over the limit \u2014 the agent reads it on request";
|
|
282
282
|
}
|
|
283
|
+
function offByDefaultReason(row) {
|
|
284
|
+
if (row.include || row.decided_by.include !== "page") return null;
|
|
285
|
+
return row.layers?.surface?.auto_context === false ? "Off by default on this page" : null;
|
|
286
|
+
}
|
|
283
287
|
|
|
284
288
|
// context/react/InlineMaxInput.tsx
|
|
285
289
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -636,7 +640,8 @@ function ContextRuleRow({
|
|
|
636
640
|
trail
|
|
637
641
|
}) {
|
|
638
642
|
const selfChecked = row.blockedBy === "self_check";
|
|
639
|
-
const decided = selfChecked ? SELF_CHECK_TOOLTIP : row.serverResolved ? SERVER_RESOLVED_TOOLTIP : `Include: ${LAYER_LABEL[row.decided_by.include]} \xB7 Limit: ${LAYER_LABEL[row.decided_by.max_inline_chars]}`;
|
|
643
|
+
const decided = selfChecked ? SELF_CHECK_TOOLTIP : row.serverResolved ? SERVER_RESOLVED_TOOLTIP : offByDefaultReason(row) ?? `Include: ${LAYER_LABEL[row.decided_by.include]} \xB7 Limit: ${LAYER_LABEL[row.decided_by.max_inline_chars]}`;
|
|
644
|
+
const shownTrail = trail ?? offByDefaultReason(row);
|
|
640
645
|
const labelNode = onOpenRow ? /* @__PURE__ */ jsx3(
|
|
641
646
|
"button",
|
|
642
647
|
{
|
|
@@ -680,7 +685,7 @@ function ContextRuleRow({
|
|
|
680
685
|
/* @__PURE__ */ jsx3("div", { className: "font-normal text-muted-foreground", children: decided })
|
|
681
686
|
] })
|
|
682
687
|
] }),
|
|
683
|
-
|
|
688
|
+
shownTrail ? /* @__PURE__ */ jsx3("span", { className: "min-w-0 max-w-[45%] shrink truncate text-muted-foreground", children: shownTrail }) : null
|
|
684
689
|
]
|
|
685
690
|
}
|
|
686
691
|
),
|
|
@@ -107,7 +107,14 @@ function useLocalModels(override) {
|
|
|
107
107
|
port ? port.getModels : () => NO_LOCAL_MODELS,
|
|
108
108
|
port ? port.getModels : () => NO_LOCAL_MODELS
|
|
109
109
|
);
|
|
110
|
-
return {
|
|
110
|
+
return {
|
|
111
|
+
models,
|
|
112
|
+
groupLabel: port?.groupLabel ?? "On this computer",
|
|
113
|
+
open: port?.open ? (id) => port.open?.(id) : void 0,
|
|
114
|
+
start: port?.start ? (id) => port.start?.(id) : void 0,
|
|
115
|
+
stop: port?.stop ? (id) => port.stop?.(id) : void 0,
|
|
116
|
+
getMore: port?.getMore ? () => port.getMore?.() : void 0
|
|
117
|
+
};
|
|
111
118
|
}
|
|
112
119
|
var NO_ACCESS = {};
|
|
113
120
|
function useModelAccess(override) {
|
|
@@ -1405,7 +1412,13 @@ function ModelRow({
|
|
|
1405
1412
|
}
|
|
1406
1413
|
);
|
|
1407
1414
|
}
|
|
1408
|
-
function LocalModelRow({
|
|
1415
|
+
function LocalModelRow({
|
|
1416
|
+
model,
|
|
1417
|
+
selected,
|
|
1418
|
+
onSelect,
|
|
1419
|
+
control,
|
|
1420
|
+
failure
|
|
1421
|
+
}) {
|
|
1409
1422
|
const unusable = model.unusable ?? null;
|
|
1410
1423
|
const dim = model.needsMoreMemory === true;
|
|
1411
1424
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
@@ -1446,11 +1459,23 @@ function LocalModelRow({ model, selected, onSelect }) {
|
|
|
1446
1459
|
),
|
|
1447
1460
|
dim && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "shrink-0 rounded bg-muted px-1 text-[9px] text-muted-foreground", title: "Needs more memory than this computer has free", children: "needs memory" })
|
|
1448
1461
|
] }),
|
|
1449
|
-
unusable && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "data-local-model-reason": true, className: "truncate text-[11px] text-muted-foreground", children: unusable })
|
|
1462
|
+
(unusable || failure) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "data-local-model-reason": true, className: (0, import_design_system.cn)("truncate text-[11px]", failure ? "text-destructive" : "text-muted-foreground"), title: failure ?? void 0, children: failure ?? unusable })
|
|
1450
1463
|
] }),
|
|
1451
1464
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-11" }),
|
|
1452
1465
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "block w-12 whitespace-nowrap text-right font-mono text-[11px] tabular-nums text-foreground/80", children: model.contextWindow == null ? "\u2014" : fmtPointsCompact(model.contextWindow) }),
|
|
1453
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-[2.75rem]"
|
|
1466
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "flex w-[2.75rem] justify-end", onClick: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), children: control && !unusable ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1467
|
+
import_design_system.IconButton,
|
|
1468
|
+
{
|
|
1469
|
+
icon: control.kind === "stop" ? import_icons5.StopIcon : import_icons5.PlayIcon,
|
|
1470
|
+
tooltip: control.pending ? control.kind === "stop" ? "Stopping" : "Starting" : control.kind === "stop" ? "Stop" : "Start",
|
|
1471
|
+
"aria-label": control.kind === "stop" ? `Stop ${model.name}` : `Start ${model.name}`,
|
|
1472
|
+
"data-local-model-control": control.kind,
|
|
1473
|
+
"data-pending": control.pending ? "" : void 0,
|
|
1474
|
+
disabled: control.pending,
|
|
1475
|
+
spinning: control.pending,
|
|
1476
|
+
onClick: control.onPress
|
|
1477
|
+
}
|
|
1478
|
+
) : null })
|
|
1454
1479
|
]
|
|
1455
1480
|
}
|
|
1456
1481
|
);
|
|
@@ -1553,7 +1578,41 @@ function ModelListDropdown({
|
|
|
1553
1578
|
const priorityModelSet = priorityModelIds ? new Set(priorityModelIds) : null;
|
|
1554
1579
|
const eligibleModels = allowedModelSet ? models.filter((model) => allowedModelSet.has(model.id)) : models;
|
|
1555
1580
|
const selected = models.find((m) => m.id === value) ?? null;
|
|
1556
|
-
const { models: localAll, groupLabel: localGroupLabel, open: openLocal } = useLocalModels(localModelsProp);
|
|
1581
|
+
const { models: localAll, groupLabel: localGroupLabel, open: openLocal, start: startLocal, stop: stopLocal, getMore: getMoreLocal } = useLocalModels(localModelsProp);
|
|
1582
|
+
const [localPending, setLocalPending] = (0, import_react2.useState)(() => /* @__PURE__ */ new Set());
|
|
1583
|
+
const [localFailure, setLocalFailure] = (0, import_react2.useState)(() => /* @__PURE__ */ new Map());
|
|
1584
|
+
const runLocal = (id2, action, verb) => {
|
|
1585
|
+
setLocalFailure((cur) => {
|
|
1586
|
+
if (!cur.has(id2)) return cur;
|
|
1587
|
+
const next = new Map(cur);
|
|
1588
|
+
next.delete(id2);
|
|
1589
|
+
return next;
|
|
1590
|
+
});
|
|
1591
|
+
setLocalPending((cur) => new Set(cur).add(id2));
|
|
1592
|
+
let result;
|
|
1593
|
+
try {
|
|
1594
|
+
result = action(id2);
|
|
1595
|
+
} catch (error2) {
|
|
1596
|
+
result = Promise.reject(error2);
|
|
1597
|
+
}
|
|
1598
|
+
void Promise.resolve(result).catch((error2) => {
|
|
1599
|
+
console.error(`[model-picker] could not ${verb} ${id2}:`, error2);
|
|
1600
|
+
const why = error2 instanceof Error && error2.message ? error2.message : `Could not ${verb}`;
|
|
1601
|
+
setLocalFailure((cur) => new Map(cur).set(id2, why));
|
|
1602
|
+
}).finally(
|
|
1603
|
+
() => setLocalPending((cur) => {
|
|
1604
|
+
const next = new Set(cur);
|
|
1605
|
+
next.delete(id2);
|
|
1606
|
+
return next;
|
|
1607
|
+
})
|
|
1608
|
+
);
|
|
1609
|
+
};
|
|
1610
|
+
const localControl = (m) => {
|
|
1611
|
+
const pending = localPending.has(m.id) || m.starting === true;
|
|
1612
|
+
if (m.running === true && stopLocal) return { kind: "stop", pending, onPress: () => runLocal(m.id, stopLocal, "stop") };
|
|
1613
|
+
if (m.running !== true && startLocal) return { kind: "start", pending, onPress: () => runLocal(m.id, startLocal, "start") };
|
|
1614
|
+
return null;
|
|
1615
|
+
};
|
|
1557
1616
|
const selectedLocal = localAll.find((m) => m.id === value) ?? null;
|
|
1558
1617
|
const localEligible = !modelOnly && variant === "user" && !allowedModelSet && (effectiveSelectionPurpose === "chat" || effectiveSelectionPurpose === "agent");
|
|
1559
1618
|
const localRows = (0, import_react2.useMemo)(() => {
|
|
@@ -1954,11 +2013,36 @@ function ModelListDropdown({
|
|
|
1954
2013
|
children: emptyOptionLabel
|
|
1955
2014
|
}
|
|
1956
2015
|
),
|
|
1957
|
-
localRows.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1958
|
-
localRunnable.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: GROUP_HEADING, children: localGroupLabel }),
|
|
1959
|
-
localRunnable.map((l) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocalModelRow, { model: l, selected: l.id === value, onSelect: () => handleSelectLocal(l) }, l.id)),
|
|
2016
|
+
(localRows.length > 0 || localEligible && tab === "all" && !query.trim() && getMoreLocal) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
2017
|
+
(localRunnable.length > 0 || localRows.length === 0 && getMoreLocal) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: GROUP_HEADING, children: localGroupLabel }),
|
|
2018
|
+
localRunnable.map((l) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocalModelRow, { model: l, selected: l.id === value, onSelect: () => handleSelectLocal(l), control: localControl(l), failure: localFailure.get(l.id) ?? null }, l.id)),
|
|
2019
|
+
getMoreLocal && localEligible && tab === "all" && !query.trim() && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2020
|
+
"div",
|
|
2021
|
+
{
|
|
2022
|
+
role: "button",
|
|
2023
|
+
tabIndex: 0,
|
|
2024
|
+
"data-local-get-more": "",
|
|
2025
|
+
onClick: () => {
|
|
2026
|
+
getMoreLocal();
|
|
2027
|
+
handleOpen(false);
|
|
2028
|
+
},
|
|
2029
|
+
onKeyDown: (e) => {
|
|
2030
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2031
|
+
e.preventDefault();
|
|
2032
|
+
getMoreLocal();
|
|
2033
|
+
handleOpen(false);
|
|
2034
|
+
}
|
|
2035
|
+
},
|
|
2036
|
+
className: "grid w-full cursor-pointer grid-cols-[16px_20px_minmax(0,1fr)] items-center gap-2 rounded px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground focus:bg-muted/60 focus:outline-none",
|
|
2037
|
+
children: [
|
|
2038
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-4" }),
|
|
2039
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "flex w-5 justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_icons5.PlusIcon, { className: "h-3.5 w-3.5" }) }),
|
|
2040
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "truncate", children: "Get More Models..." })
|
|
2041
|
+
]
|
|
2042
|
+
}
|
|
2043
|
+
),
|
|
1960
2044
|
localUnusable.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: GROUP_HEADING, children: "Cannot run here" }),
|
|
1961
|
-
localUnusable.map((l) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocalModelRow, { model: l, selected: false, onSelect: () => void 0 }, l.id)),
|
|
2045
|
+
localUnusable.map((l) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocalModelRow, { model: l, selected: false, onSelect: () => void 0, failure: localFailure.get(l.id) ?? null }, l.id)),
|
|
1962
2046
|
filtered.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: GROUP_HEADING, children: "Cloud" })
|
|
1963
2047
|
] }),
|
|
1964
2048
|
filtered.length === 0 ? localRows.length > 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "p-4 text-center text-xs text-muted-foreground", children: "No models match your filters." }) : listRows.map(({ model: m, classTier }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -436,11 +436,20 @@ interface LocalModelEntry {
|
|
|
436
436
|
* picker lists it under "Cannot run here" with this reason, dimmed and never pickable.
|
|
437
437
|
*/
|
|
438
438
|
unusable?: string;
|
|
439
|
+
/**
|
|
440
|
+
* The model is loaded and answering now. With a port `stop`, the row draws Stop; with `start`
|
|
441
|
+
* and not running, Start. Absent = the host does not say (no control is drawn).
|
|
442
|
+
*/
|
|
443
|
+
running?: boolean;
|
|
444
|
+
/** The host is loading it right now: the row's control shows its pending state. */
|
|
445
|
+
starting?: boolean;
|
|
439
446
|
}
|
|
440
447
|
/**
|
|
441
448
|
* The host's local-model source (a store: `getModels` + `subscribe`, like the catalog). The picker
|
|
442
|
-
* draws its models as one "On this computer" group marked local.
|
|
443
|
-
*
|
|
449
|
+
* draws its models as one "On this computer" group marked local. Starting and stopping a model and
|
|
450
|
+
* getting more of them are capabilities by presence: a host that supplies `start` / `stop` / `getMore`
|
|
451
|
+
* gets a compact Start/Stop control per row and one "Get More Models..." row; a host that leaves them
|
|
452
|
+
* out gets neither (its own screens stay the only way).
|
|
444
453
|
*/
|
|
445
454
|
interface LocalModelsPort {
|
|
446
455
|
/** Must return the SAME array until the list changes (it is a store snapshot). */
|
|
@@ -455,6 +464,15 @@ interface LocalModelsPort {
|
|
|
455
464
|
* the id through `onValueChange` (the override path).
|
|
456
465
|
*/
|
|
457
466
|
open?(id: string): void;
|
|
467
|
+
/**
|
|
468
|
+
* Start the model (load it so it can answer). Present = a row that is not running draws Start. The
|
|
469
|
+
* row shows a pending state until the returned promise settles; a rejection says why on the row.
|
|
470
|
+
*/
|
|
471
|
+
start?(id: string): void | Promise<unknown>;
|
|
472
|
+
/** Stop the running model. Present = a running row draws Stop (same pending state and failure line). */
|
|
473
|
+
stop?(id: string): void | Promise<unknown>;
|
|
474
|
+
/** Open the host's place to find and install more models. Present = one "Get More Models..." row ends the group. */
|
|
475
|
+
getMore?(): void;
|
|
458
476
|
}
|
|
459
477
|
/**
|
|
460
478
|
* How the person may reach a cloud model in THIS place (a chat composer passes it to its own picker,
|
|
@@ -514,6 +532,9 @@ declare function useLocalModels(override?: LocalModelsPort): {
|
|
|
514
532
|
models: readonly LocalModelEntry[];
|
|
515
533
|
groupLabel: string;
|
|
516
534
|
open: ((id: string) => void) | undefined;
|
|
535
|
+
start: ((id: string) => void | Promise<unknown>) | undefined;
|
|
536
|
+
stop: ((id: string) => void | Promise<unknown>) | undefined;
|
|
537
|
+
getMore: (() => void) | undefined;
|
|
517
538
|
};
|
|
518
539
|
/** The cloud-access rules for this picker; a port passed straight to the picker beats the provider's. */
|
|
519
540
|
declare function useModelAccess(override?: ModelAccessPort): ModelAccessPort;
|
|
@@ -436,11 +436,20 @@ interface LocalModelEntry {
|
|
|
436
436
|
* picker lists it under "Cannot run here" with this reason, dimmed and never pickable.
|
|
437
437
|
*/
|
|
438
438
|
unusable?: string;
|
|
439
|
+
/**
|
|
440
|
+
* The model is loaded and answering now. With a port `stop`, the row draws Stop; with `start`
|
|
441
|
+
* and not running, Start. Absent = the host does not say (no control is drawn).
|
|
442
|
+
*/
|
|
443
|
+
running?: boolean;
|
|
444
|
+
/** The host is loading it right now: the row's control shows its pending state. */
|
|
445
|
+
starting?: boolean;
|
|
439
446
|
}
|
|
440
447
|
/**
|
|
441
448
|
* The host's local-model source (a store: `getModels` + `subscribe`, like the catalog). The picker
|
|
442
|
-
* draws its models as one "On this computer" group marked local.
|
|
443
|
-
*
|
|
449
|
+
* draws its models as one "On this computer" group marked local. Starting and stopping a model and
|
|
450
|
+
* getting more of them are capabilities by presence: a host that supplies `start` / `stop` / `getMore`
|
|
451
|
+
* gets a compact Start/Stop control per row and one "Get More Models..." row; a host that leaves them
|
|
452
|
+
* out gets neither (its own screens stay the only way).
|
|
444
453
|
*/
|
|
445
454
|
interface LocalModelsPort {
|
|
446
455
|
/** Must return the SAME array until the list changes (it is a store snapshot). */
|
|
@@ -455,6 +464,15 @@ interface LocalModelsPort {
|
|
|
455
464
|
* the id through `onValueChange` (the override path).
|
|
456
465
|
*/
|
|
457
466
|
open?(id: string): void;
|
|
467
|
+
/**
|
|
468
|
+
* Start the model (load it so it can answer). Present = a row that is not running draws Start. The
|
|
469
|
+
* row shows a pending state until the returned promise settles; a rejection says why on the row.
|
|
470
|
+
*/
|
|
471
|
+
start?(id: string): void | Promise<unknown>;
|
|
472
|
+
/** Stop the running model. Present = a running row draws Stop (same pending state and failure line). */
|
|
473
|
+
stop?(id: string): void | Promise<unknown>;
|
|
474
|
+
/** Open the host's place to find and install more models. Present = one "Get More Models..." row ends the group. */
|
|
475
|
+
getMore?(): void;
|
|
458
476
|
}
|
|
459
477
|
/**
|
|
460
478
|
* How the person may reach a cloud model in THIS place (a chat composer passes it to its own picker,
|
|
@@ -514,6 +532,9 @@ declare function useLocalModels(override?: LocalModelsPort): {
|
|
|
514
532
|
models: readonly LocalModelEntry[];
|
|
515
533
|
groupLabel: string;
|
|
516
534
|
open: ((id: string) => void) | undefined;
|
|
535
|
+
start: ((id: string) => void | Promise<unknown>) | undefined;
|
|
536
|
+
stop: ((id: string) => void | Promise<unknown>) | undefined;
|
|
537
|
+
getMore: (() => void) | undefined;
|
|
517
538
|
};
|
|
518
539
|
/** The cloud-access rules for this picker; a port passed straight to the picker beats the provider's. */
|
|
519
540
|
declare function useModelAccess(override?: ModelAccessPort): ModelAccessPort;
|
|
@@ -71,7 +71,14 @@ function useLocalModels(override) {
|
|
|
71
71
|
port ? port.getModels : () => NO_LOCAL_MODELS,
|
|
72
72
|
port ? port.getModels : () => NO_LOCAL_MODELS
|
|
73
73
|
);
|
|
74
|
-
return {
|
|
74
|
+
return {
|
|
75
|
+
models,
|
|
76
|
+
groupLabel: port?.groupLabel ?? "On this computer",
|
|
77
|
+
open: port?.open ? (id) => port.open?.(id) : void 0,
|
|
78
|
+
start: port?.start ? (id) => port.start?.(id) : void 0,
|
|
79
|
+
stop: port?.stop ? (id) => port.stop?.(id) : void 0,
|
|
80
|
+
getMore: port?.getMore ? () => port.getMore?.() : void 0
|
|
81
|
+
};
|
|
75
82
|
}
|
|
76
83
|
var NO_ACCESS = {};
|
|
77
84
|
function useModelAccess(override) {
|
|
@@ -88,6 +95,7 @@ import {
|
|
|
88
95
|
Popover,
|
|
89
96
|
PopoverTrigger,
|
|
90
97
|
PopoverContent,
|
|
98
|
+
IconButton,
|
|
91
99
|
Tooltip,
|
|
92
100
|
TooltipContent,
|
|
93
101
|
TooltipProvider,
|
|
@@ -302,7 +310,7 @@ var ScaleIcon = sized(GScaleIcon);
|
|
|
302
310
|
var LanguagesIcon = sized(GLanguagesIcon);
|
|
303
311
|
|
|
304
312
|
// models/react/ModelListDropdown.tsx
|
|
305
|
-
import { ChevronDownIcon, ChevronRightIcon, SearchIcon, StarIcon, VideoIcon } from "@ai-matrx/design-system/icons";
|
|
313
|
+
import { ChevronDownIcon, ChevronRightIcon, PlayIcon, PlusIcon, SearchIcon, StarIcon, StopIcon, VideoIcon } from "@ai-matrx/design-system/icons";
|
|
306
314
|
|
|
307
315
|
// models/succession.ts
|
|
308
316
|
var MAX_SUCCESSION_HOPS = 8;
|
|
@@ -1396,7 +1404,13 @@ function ModelRow({
|
|
|
1396
1404
|
}
|
|
1397
1405
|
);
|
|
1398
1406
|
}
|
|
1399
|
-
function LocalModelRow({
|
|
1407
|
+
function LocalModelRow({
|
|
1408
|
+
model,
|
|
1409
|
+
selected,
|
|
1410
|
+
onSelect,
|
|
1411
|
+
control,
|
|
1412
|
+
failure
|
|
1413
|
+
}) {
|
|
1400
1414
|
const unusable = model.unusable ?? null;
|
|
1401
1415
|
const dim = model.needsMoreMemory === true;
|
|
1402
1416
|
return /* @__PURE__ */ jsxs2(
|
|
@@ -1437,11 +1451,23 @@ function LocalModelRow({ model, selected, onSelect }) {
|
|
|
1437
1451
|
),
|
|
1438
1452
|
dim && /* @__PURE__ */ jsx3("span", { className: "shrink-0 rounded bg-muted px-1 text-[9px] text-muted-foreground", title: "Needs more memory than this computer has free", children: "needs memory" })
|
|
1439
1453
|
] }),
|
|
1440
|
-
unusable && /* @__PURE__ */ jsx3("span", { "data-local-model-reason": true, className: "truncate text-[11px] text-muted-foreground", children: unusable })
|
|
1454
|
+
(unusable || failure) && /* @__PURE__ */ jsx3("span", { "data-local-model-reason": true, className: cn("truncate text-[11px]", failure ? "text-destructive" : "text-muted-foreground"), title: failure ?? void 0, children: failure ?? unusable })
|
|
1441
1455
|
] }),
|
|
1442
1456
|
/* @__PURE__ */ jsx3("span", { className: "w-11" }),
|
|
1443
1457
|
/* @__PURE__ */ jsx3("span", { className: "block w-12 whitespace-nowrap text-right font-mono text-[11px] tabular-nums text-foreground/80", children: model.contextWindow == null ? "\u2014" : fmtPointsCompact(model.contextWindow) }),
|
|
1444
|
-
/* @__PURE__ */ jsx3("span", { className: "w-[2.75rem]"
|
|
1458
|
+
/* @__PURE__ */ jsx3("span", { className: "flex w-[2.75rem] justify-end", onClick: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), children: control && !unusable ? /* @__PURE__ */ jsx3(
|
|
1459
|
+
IconButton,
|
|
1460
|
+
{
|
|
1461
|
+
icon: control.kind === "stop" ? StopIcon : PlayIcon,
|
|
1462
|
+
tooltip: control.pending ? control.kind === "stop" ? "Stopping" : "Starting" : control.kind === "stop" ? "Stop" : "Start",
|
|
1463
|
+
"aria-label": control.kind === "stop" ? `Stop ${model.name}` : `Start ${model.name}`,
|
|
1464
|
+
"data-local-model-control": control.kind,
|
|
1465
|
+
"data-pending": control.pending ? "" : void 0,
|
|
1466
|
+
disabled: control.pending,
|
|
1467
|
+
spinning: control.pending,
|
|
1468
|
+
onClick: control.onPress
|
|
1469
|
+
}
|
|
1470
|
+
) : null })
|
|
1445
1471
|
]
|
|
1446
1472
|
}
|
|
1447
1473
|
);
|
|
@@ -1544,7 +1570,41 @@ function ModelListDropdown({
|
|
|
1544
1570
|
const priorityModelSet = priorityModelIds ? new Set(priorityModelIds) : null;
|
|
1545
1571
|
const eligibleModels = allowedModelSet ? models.filter((model) => allowedModelSet.has(model.id)) : models;
|
|
1546
1572
|
const selected = models.find((m) => m.id === value) ?? null;
|
|
1547
|
-
const { models: localAll, groupLabel: localGroupLabel, open: openLocal } = useLocalModels(localModelsProp);
|
|
1573
|
+
const { models: localAll, groupLabel: localGroupLabel, open: openLocal, start: startLocal, stop: stopLocal, getMore: getMoreLocal } = useLocalModels(localModelsProp);
|
|
1574
|
+
const [localPending, setLocalPending] = useState(() => /* @__PURE__ */ new Set());
|
|
1575
|
+
const [localFailure, setLocalFailure] = useState(() => /* @__PURE__ */ new Map());
|
|
1576
|
+
const runLocal = (id2, action, verb) => {
|
|
1577
|
+
setLocalFailure((cur) => {
|
|
1578
|
+
if (!cur.has(id2)) return cur;
|
|
1579
|
+
const next = new Map(cur);
|
|
1580
|
+
next.delete(id2);
|
|
1581
|
+
return next;
|
|
1582
|
+
});
|
|
1583
|
+
setLocalPending((cur) => new Set(cur).add(id2));
|
|
1584
|
+
let result;
|
|
1585
|
+
try {
|
|
1586
|
+
result = action(id2);
|
|
1587
|
+
} catch (error2) {
|
|
1588
|
+
result = Promise.reject(error2);
|
|
1589
|
+
}
|
|
1590
|
+
void Promise.resolve(result).catch((error2) => {
|
|
1591
|
+
console.error(`[model-picker] could not ${verb} ${id2}:`, error2);
|
|
1592
|
+
const why = error2 instanceof Error && error2.message ? error2.message : `Could not ${verb}`;
|
|
1593
|
+
setLocalFailure((cur) => new Map(cur).set(id2, why));
|
|
1594
|
+
}).finally(
|
|
1595
|
+
() => setLocalPending((cur) => {
|
|
1596
|
+
const next = new Set(cur);
|
|
1597
|
+
next.delete(id2);
|
|
1598
|
+
return next;
|
|
1599
|
+
})
|
|
1600
|
+
);
|
|
1601
|
+
};
|
|
1602
|
+
const localControl = (m) => {
|
|
1603
|
+
const pending = localPending.has(m.id) || m.starting === true;
|
|
1604
|
+
if (m.running === true && stopLocal) return { kind: "stop", pending, onPress: () => runLocal(m.id, stopLocal, "stop") };
|
|
1605
|
+
if (m.running !== true && startLocal) return { kind: "start", pending, onPress: () => runLocal(m.id, startLocal, "start") };
|
|
1606
|
+
return null;
|
|
1607
|
+
};
|
|
1548
1608
|
const selectedLocal = localAll.find((m) => m.id === value) ?? null;
|
|
1549
1609
|
const localEligible = !modelOnly && variant === "user" && !allowedModelSet && (effectiveSelectionPurpose === "chat" || effectiveSelectionPurpose === "agent");
|
|
1550
1610
|
const localRows = useMemo2(() => {
|
|
@@ -1945,11 +2005,36 @@ function ModelListDropdown({
|
|
|
1945
2005
|
children: emptyOptionLabel
|
|
1946
2006
|
}
|
|
1947
2007
|
),
|
|
1948
|
-
localRows.length > 0 && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1949
|
-
localRunnable.length > 0 && /* @__PURE__ */ jsx3("div", { className: GROUP_HEADING, children: localGroupLabel }),
|
|
1950
|
-
localRunnable.map((l) => /* @__PURE__ */ jsx3(LocalModelRow, { model: l, selected: l.id === value, onSelect: () => handleSelectLocal(l) }, l.id)),
|
|
2008
|
+
(localRows.length > 0 || localEligible && tab === "all" && !query.trim() && getMoreLocal) && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2009
|
+
(localRunnable.length > 0 || localRows.length === 0 && getMoreLocal) && /* @__PURE__ */ jsx3("div", { className: GROUP_HEADING, children: localGroupLabel }),
|
|
2010
|
+
localRunnable.map((l) => /* @__PURE__ */ jsx3(LocalModelRow, { model: l, selected: l.id === value, onSelect: () => handleSelectLocal(l), control: localControl(l), failure: localFailure.get(l.id) ?? null }, l.id)),
|
|
2011
|
+
getMoreLocal && localEligible && tab === "all" && !query.trim() && /* @__PURE__ */ jsxs2(
|
|
2012
|
+
"div",
|
|
2013
|
+
{
|
|
2014
|
+
role: "button",
|
|
2015
|
+
tabIndex: 0,
|
|
2016
|
+
"data-local-get-more": "",
|
|
2017
|
+
onClick: () => {
|
|
2018
|
+
getMoreLocal();
|
|
2019
|
+
handleOpen(false);
|
|
2020
|
+
},
|
|
2021
|
+
onKeyDown: (e) => {
|
|
2022
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2023
|
+
e.preventDefault();
|
|
2024
|
+
getMoreLocal();
|
|
2025
|
+
handleOpen(false);
|
|
2026
|
+
}
|
|
2027
|
+
},
|
|
2028
|
+
className: "grid w-full cursor-pointer grid-cols-[16px_20px_minmax(0,1fr)] items-center gap-2 rounded px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground focus:bg-muted/60 focus:outline-none",
|
|
2029
|
+
children: [
|
|
2030
|
+
/* @__PURE__ */ jsx3("span", { className: "w-4" }),
|
|
2031
|
+
/* @__PURE__ */ jsx3("span", { className: "flex w-5 justify-center", children: /* @__PURE__ */ jsx3(PlusIcon, { className: "h-3.5 w-3.5" }) }),
|
|
2032
|
+
/* @__PURE__ */ jsx3("span", { className: "truncate", children: "Get More Models..." })
|
|
2033
|
+
]
|
|
2034
|
+
}
|
|
2035
|
+
),
|
|
1951
2036
|
localUnusable.length > 0 && /* @__PURE__ */ jsx3("div", { className: GROUP_HEADING, children: "Cannot run here" }),
|
|
1952
|
-
localUnusable.map((l) => /* @__PURE__ */ jsx3(LocalModelRow, { model: l, selected: false, onSelect: () => void 0 }, l.id)),
|
|
2037
|
+
localUnusable.map((l) => /* @__PURE__ */ jsx3(LocalModelRow, { model: l, selected: false, onSelect: () => void 0, failure: localFailure.get(l.id) ?? null }, l.id)),
|
|
1953
2038
|
filtered.length > 0 && /* @__PURE__ */ jsx3("div", { className: GROUP_HEADING, children: "Cloud" })
|
|
1954
2039
|
] }),
|
|
1955
2040
|
filtered.length === 0 ? localRows.length > 0 ? null : /* @__PURE__ */ jsx3("div", { className: "p-4 text-center text-xs text-muted-foreground", children: "No models match your filters." }) : listRows.map(({ model: m, classTier }) => /* @__PURE__ */ jsx3(
|
|
@@ -568,11 +568,20 @@ interface LocalModelEntry {
|
|
|
568
568
|
* picker lists it under "Cannot run here" with this reason, dimmed and never pickable.
|
|
569
569
|
*/
|
|
570
570
|
unusable?: string;
|
|
571
|
+
/**
|
|
572
|
+
* The model is loaded and answering now. With a port `stop`, the row draws Stop; with `start`
|
|
573
|
+
* and not running, Start. Absent = the host does not say (no control is drawn).
|
|
574
|
+
*/
|
|
575
|
+
running?: boolean;
|
|
576
|
+
/** The host is loading it right now: the row's control shows its pending state. */
|
|
577
|
+
starting?: boolean;
|
|
571
578
|
}
|
|
572
579
|
/**
|
|
573
580
|
* The host's local-model source (a store: `getModels` + `subscribe`, like the catalog). The picker
|
|
574
|
-
* draws its models as one "On this computer" group marked local.
|
|
575
|
-
*
|
|
581
|
+
* draws its models as one "On this computer" group marked local. Starting and stopping a model and
|
|
582
|
+
* getting more of them are capabilities by presence: a host that supplies `start` / `stop` / `getMore`
|
|
583
|
+
* gets a compact Start/Stop control per row and one "Get More Models..." row; a host that leaves them
|
|
584
|
+
* out gets neither (its own screens stay the only way).
|
|
576
585
|
*/
|
|
577
586
|
interface LocalModelsPort {
|
|
578
587
|
/** Must return the SAME array until the list changes (it is a store snapshot). */
|
|
@@ -587,6 +596,15 @@ interface LocalModelsPort {
|
|
|
587
596
|
* the id through `onValueChange` (the override path).
|
|
588
597
|
*/
|
|
589
598
|
open?(id: string): void;
|
|
599
|
+
/**
|
|
600
|
+
* Start the model (load it so it can answer). Present = a row that is not running draws Start. The
|
|
601
|
+
* row shows a pending state until the returned promise settles; a rejection says why on the row.
|
|
602
|
+
*/
|
|
603
|
+
start?(id: string): void | Promise<unknown>;
|
|
604
|
+
/** Stop the running model. Present = a running row draws Stop (same pending state and failure line). */
|
|
605
|
+
stop?(id: string): void | Promise<unknown>;
|
|
606
|
+
/** Open the host's place to find and install more models. Present = one "Get More Models..." row ends the group. */
|
|
607
|
+
getMore?(): void;
|
|
590
608
|
}
|
|
591
609
|
/**
|
|
592
610
|
* How the person may reach a cloud model in THIS place (a chat composer passes it to its own picker,
|
package/dist/settings/index.d.ts
CHANGED
|
@@ -568,11 +568,20 @@ interface LocalModelEntry {
|
|
|
568
568
|
* picker lists it under "Cannot run here" with this reason, dimmed and never pickable.
|
|
569
569
|
*/
|
|
570
570
|
unusable?: string;
|
|
571
|
+
/**
|
|
572
|
+
* The model is loaded and answering now. With a port `stop`, the row draws Stop; with `start`
|
|
573
|
+
* and not running, Start. Absent = the host does not say (no control is drawn).
|
|
574
|
+
*/
|
|
575
|
+
running?: boolean;
|
|
576
|
+
/** The host is loading it right now: the row's control shows its pending state. */
|
|
577
|
+
starting?: boolean;
|
|
571
578
|
}
|
|
572
579
|
/**
|
|
573
580
|
* The host's local-model source (a store: `getModels` + `subscribe`, like the catalog). The picker
|
|
574
|
-
* draws its models as one "On this computer" group marked local.
|
|
575
|
-
*
|
|
581
|
+
* draws its models as one "On this computer" group marked local. Starting and stopping a model and
|
|
582
|
+
* getting more of them are capabilities by presence: a host that supplies `start` / `stop` / `getMore`
|
|
583
|
+
* gets a compact Start/Stop control per row and one "Get More Models..." row; a host that leaves them
|
|
584
|
+
* out gets neither (its own screens stay the only way).
|
|
576
585
|
*/
|
|
577
586
|
interface LocalModelsPort {
|
|
578
587
|
/** Must return the SAME array until the list changes (it is a store snapshot). */
|
|
@@ -587,6 +596,15 @@ interface LocalModelsPort {
|
|
|
587
596
|
* the id through `onValueChange` (the override path).
|
|
588
597
|
*/
|
|
589
598
|
open?(id: string): void;
|
|
599
|
+
/**
|
|
600
|
+
* Start the model (load it so it can answer). Present = a row that is not running draws Start. The
|
|
601
|
+
* row shows a pending state until the returned promise settles; a rejection says why on the row.
|
|
602
|
+
*/
|
|
603
|
+
start?(id: string): void | Promise<unknown>;
|
|
604
|
+
/** Stop the running model. Present = a running row draws Stop (same pending state and failure line). */
|
|
605
|
+
stop?(id: string): void | Promise<unknown>;
|
|
606
|
+
/** Open the host's place to find and install more models. Present = one "Get More Models..." row ends the group. */
|
|
607
|
+
getMore?(): void;
|
|
590
608
|
}
|
|
591
609
|
/**
|
|
592
610
|
* How the person may reach a cloud model in THIS place (a chat composer passes it to its own picker,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-matrx/agents",
|
|
3
|
-
"version": "0.59.
|
|
3
|
+
"version": "0.59.241",
|
|
4
4
|
"description": "Portable AI Matrx agent stream protocol, event projection, and safe result-presentation primitives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -509,13 +509,13 @@
|
|
|
509
509
|
"sideEffects": false,
|
|
510
510
|
"dependencies": {
|
|
511
511
|
"@ai-matrx/alchemy": "latest",
|
|
512
|
-
"@ai-matrx/associations": "latest",
|
|
513
512
|
"@ai-matrx/api": "latest",
|
|
514
|
-
"@ai-matrx/
|
|
515
|
-
"@ai-matrx/data": "latest",
|
|
513
|
+
"@ai-matrx/associations": "latest",
|
|
516
514
|
"@ai-matrx/design-system": "latest",
|
|
517
|
-
"@ai-matrx/
|
|
515
|
+
"@ai-matrx/data": "latest",
|
|
516
|
+
"@ai-matrx/content-ir": "latest",
|
|
518
517
|
"@ai-matrx/icons": "latest",
|
|
518
|
+
"@ai-matrx/diff": "latest",
|
|
519
519
|
"@ai-matrx/kit": "latest"
|
|
520
520
|
},
|
|
521
521
|
"peerDependencies": {
|
|
@@ -561,5 +561,5 @@
|
|
|
561
561
|
"verify:tarball": "node ./scripts/verify-tarball.mjs",
|
|
562
562
|
"typegen:self-test": "node scripts/typegen/drop-guard.self-test.mjs && node scripts/typegen/check-api-types-fresh.mjs --self-test"
|
|
563
563
|
},
|
|
564
|
-
"gitHead": "
|
|
564
|
+
"gitHead": "a53838052abf9a4a70364e27933ecdf4b05a0b40"
|
|
565
565
|
}
|