@ai-matrx/chat 0.3.26 → 0.3.27

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @ai-matrx/chat
2
2
 
3
+ ## 0.3.27
4
+
5
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
6
+ `git diff npm/chat/v0.3.26..npm/chat/v0.3.27 -- apps/shared/chat`).
7
+ No source changes intended and no consumer action required.
8
+
3
9
  ## 0.3.26 — 2026-10-07
4
10
 
5
11
  - `useDomCapturePrint` calls `captureDocumentPdf` (alchemy 0.20.2) — 0.3.22–0.3.25 imported the unpublished `documentToPdf`, so the PDF export reported an error.
@@ -0,0 +1,27 @@
1
+ /**
2
+ * THE RUN TIER HAS ONE HOLDER (agent core B2 tail): the core run tier store
3
+ * (`@ai-matrx/agents/runtime`, bound by `agents/identity/run-tier-store.ts`). Chat's agent record
4
+ * never receives a copy of its answer. The record holds what the agent's OWN reads put there (the
5
+ * builder's full definition and unsaved edits, the fetch status the run thunks set); every field the
6
+ * record has not read is completed here, at read time, from the store's last answer:
7
+ *
8
+ * field the record READ (builder / edit) > run tier (`agx_get_run_tier`) > run controls
9
+ * access level: the dedicated `agx_get_access_level` answer > the record > the run tier
10
+ *
11
+ * The completed record is derived and cached per (record, answers) — the same object until one of
12
+ * them changes, so memoized selectors stay stable. The run thunks resolve the store BEFORE they
13
+ * dispatch (fetch status / fulfilled), so every `useAppSelector` re-reads after an answer lands.
14
+ */
15
+ import type { RunTierState } from "@ai-matrx/agents/runtime";
16
+ import type { AccessLevel, AgentDefinitionRecord } from "../../types/agent-definition.types.js";
17
+ export declare function toRegistryAccessLevel(value: string | null | undefined): AccessLevel | null;
18
+ /**
19
+ * The store's state — the one place chat reads run tier answers from. A host with no database
20
+ * bound yet (a unit test, the first render before the host binds) has no answers: the records
21
+ * read as they are.
22
+ */
23
+ export declare function readRunTierState(): RunTierState;
24
+ /** One record completed from the store's answers (unchanged when the store holds none). */
25
+ export declare function completeAgentRecord(record: AgentDefinitionRecord, state: RunTierState): AgentDefinitionRecord;
26
+ /** Every record completed — the map `selectAllAgents` returns. Same object until either input changes. */
27
+ export declare function completeAgentRecords(agents: Record<string, AgentDefinitionRecord>, state: RunTierState): Record<string, AgentDefinitionRecord>;
@@ -0,0 +1,95 @@
1
+ import { addField, hasField } from "@ai-matrx/agents/field-flags";
2
+ import { getRunTierStore } from "../../identity/run-tier-store.js";
3
+ import { parseSkillConfigJson } from "./converters.js";
4
+ const REGISTRY_ACCESS_LEVELS = ["owner", "admin", "editor", "viewer", "system"];
5
+ function toRegistryAccessLevel(value) {
6
+ return REGISTRY_ACCESS_LEVELS.find((level) => level === value) ?? null;
7
+ }
8
+ const NO_ANSWERS = Object.freeze({
9
+ runTier: {},
10
+ runControls: {},
11
+ accessLevel: {},
12
+ sharedWithMe: { status: "idle", data: null, error: null },
13
+ sharedForChat: { status: "idle", data: null, error: null }
14
+ });
15
+ function readRunTierState() {
16
+ try {
17
+ return getRunTierStore().getState();
18
+ } catch {
19
+ return NO_ANSWERS;
20
+ }
21
+ }
22
+ const cache = /* @__PURE__ */ new WeakMap();
23
+ function answersFor(state, id) {
24
+ return {
25
+ rt: state.runTier[id]?.data ?? null,
26
+ rc: state.runControls[id]?.data ?? null,
27
+ al: state.accessLevel[id]?.data ?? null
28
+ };
29
+ }
30
+ function completeAgentRecord(record, state) {
31
+ const answers = answersFor(state, record.id);
32
+ if (!answers.rt && !answers.rc && !answers.al) return record;
33
+ const hit = cache.get(record);
34
+ if (hit && hit.rt === answers.rt && hit.rc === answers.rc && hit.al === answers.al) return hit.out;
35
+ const loaded = { ...record._loadedFields };
36
+ const out = { ...record, _loadedFields: loaded };
37
+ const unread = (field) => !hasField(record._loadedFields, field);
38
+ const fill = (field, value) => {
39
+ out[field] = value;
40
+ addField(loaded, field);
41
+ };
42
+ const rt = answers.rt;
43
+ if (rt) {
44
+ if (unread("variableDefinitions")) fill("variableDefinitions", rt.variable_definitions);
45
+ if (unread("contextPolicies")) fill("contextPolicies", rt.context_policies ?? []);
46
+ if (unread("autoContextDisabled")) fill("autoContextDisabled", rt.auto_context_disabled === true);
47
+ if (rt.model_id && unread("modelId")) fill("modelId", rt.model_id);
48
+ if (unread("uiGates")) fill("uiGates", rt.ui_gates ?? {});
49
+ if (rt.tool_ids && unread("tools")) fill("tools", rt.tool_ids);
50
+ if (!out.name && unread("name")) fill("name", rt.name);
51
+ if (out.description == null && unread("description")) fill("description", rt.description ?? "");
52
+ if (!out.accessLevel) fill("accessLevel", toRegistryAccessLevel(rt.access_level));
53
+ fill("runCounts", {
54
+ customTools: rt.custom_tool_count ?? 0,
55
+ skills: rt.skill_count ?? 0,
56
+ connections: rt.connection_count ?? 0
57
+ });
58
+ }
59
+ const rc = answers.rc;
60
+ if (rc) {
61
+ fill("runControls", { customToolNames: rc.custom_tool_names ?? [] });
62
+ if (!hasField(loaded, "tools")) fill("tools", rc.tool_ids ?? []);
63
+ if (!hasField(loaded, "autoToolsDisabled")) fill("autoToolsDisabled", rc.auto_tools_disabled === true);
64
+ if (!hasField(loaded, "skillConfig")) fill("skillConfig", parseSkillConfigJson(rc.skill_config));
65
+ if (!hasField(loaded, "mcpServers")) fill("mcpServers", rc.mcp_servers ?? []);
66
+ }
67
+ const al = answers.al;
68
+ if (al) {
69
+ fill("isOwner", al.is_owner);
70
+ fill("accessLevel", al.access_level);
71
+ }
72
+ cache.set(record, { ...answers, out });
73
+ return out;
74
+ }
75
+ const mapCache = /* @__PURE__ */ new WeakMap();
76
+ function completeAgentRecords(agents, state) {
77
+ const hit = mapCache.get(agents);
78
+ if (hit && hit.state === state) return hit.out;
79
+ let changed = false;
80
+ const out = {};
81
+ for (const [id, record] of Object.entries(agents)) {
82
+ const done = completeAgentRecord(record, state);
83
+ if (done !== record) changed = true;
84
+ out[id] = done;
85
+ }
86
+ const result = changed ? out : agents;
87
+ mapCache.set(agents, { state, out: result });
88
+ return result;
89
+ }
90
+ export {
91
+ completeAgentRecord,
92
+ completeAgentRecords,
93
+ readRunTierState,
94
+ toRegistryAccessLevel
95
+ };