@ai-matrx/chat 0.3.20 → 0.3.23
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 +20 -0
- package/dist/agents/redux/agent-definition/slice.d.ts +7 -193
- package/dist/agents/redux/agent-definition/slice.js +7 -362
- package/dist/agents/redux/agent-definition/thunks.d.ts +0 -15
- package/dist/agents/redux/agent-definition/thunks.js +0 -17
- package/dist/agents/redux/execution-system/context-rules/request-context.js +6 -2
- package/dist/conversation/hooks/useDomCapturePrint.js +8 -4
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @ai-matrx/chat
|
|
2
2
|
|
|
3
|
+
## 0.3.23 — 2026-10-07
|
|
4
|
+
### The working document reaches the agent again
|
|
5
|
+
|
|
6
|
+
- The page rule (2026-10-01) withheld every value the chat page declares from the chat's own conversation. The chat manifest declares a lean ref named `working_document`, so the conversation's real, agent-editable working document was sent as `context_withheld: ["working_document"]` on every main-chat turn — the agent answered "I don't see a document". `working_document`, `user_scratchpad` and `user_scratchpad_<id8>` are now never the page's (`request-context.ts` `neverThePage`), matching aidream `page_withholds` and `@ai-matrx/agents` `pageContextWithholds` (parity corpus cases added).
|
|
7
|
+
- Consumer action: none.
|
|
8
|
+
|
|
9
|
+
## 0.3.22 — 2026-10-07
|
|
10
|
+
|
|
11
|
+
- `useDomCapturePrint`'s PDF goes through Alchemy's `/operate/capture` `documentToPdf` + kit `downloadFile` (needs alchemy 0.20.0), not `@ai-matrx/print/pdf` directly (AP-2 fifth check). Same options, same file name.
|
|
12
|
+
|
|
13
|
+
**Consumer action:** none.
|
|
14
|
+
|
|
15
|
+
## 0.3.21 — 2026-10-07
|
|
16
|
+
### The editable definition leaves chat (AGENT-CORE-PLAN B2, builder tier)
|
|
17
|
+
|
|
18
|
+
- Removed from `agents/redux/agent-definition/slice`: the 22 edit reducers (`setAgentField`, `setAgentMessages`, `setAgentSettings`, `setAgentVariableDefinitions`, `setAgentControlBinding`, `setAgentContextPolicies`, `setAgentTools`, `setAgentCustomTools`, `setAgentMcpServers`, `setAgentSkillConfig`, `setAgentModelTiers`, `setAgentOutputSchema`, `setAgentUiGates`, `setAgentMatrxDirectives`, `resetAgentField`, `resetAllAgentFields`, `markAgentSaved`, `markAgentFieldSaved`, `rollbackAgentOptimisticUpdate`, `undoAgentEdit`, `redoAgentEdit`, `clearAgentUndoHistory`) and the undo/redo machinery. Removed from `.../thunks`: `fetchFullAgent` (a run reads the run tier only).
|
|
19
|
+
- Added: `markAgentRecordClean(record)` (slice) — the one "clean baseline" helper, shared by `upsertAgent` and the host's builder.
|
|
20
|
+
- Guard G2 (`check:no-builder-tier`) is now a hard ban: 0 builder-tier references in chat source, no baseline.
|
|
21
|
+
- Consumer action: a host with an agent builder owns the edits. matrx-frontend: `features/agents/redux/agent-builder.slice` (actions `agentBuilder/*`, composed onto the `agentDefinition` key with `withAgentBuilderEdits(chatReducers.agentDefinition)`) and `features/agents/redux/fetch-full-agent.thunk`. A host without a builder: none.
|
|
22
|
+
|
|
3
23
|
## 0.3.20 — 2026-10-07
|
|
4
24
|
### Working-document realtime channel renamed
|
|
5
25
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { type PayloadAction } from "@reduxjs/toolkit";
|
|
2
|
-
import type { AgentDefinition, AgentDefinitionSliceState, AgentFetchStatus,
|
|
2
|
+
import type { AgentDefinition, AgentDefinitionRecord, AgentDefinitionSliceState, AgentFetchStatus, LoadedFields } from "../../types/agent-definition.types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Marks a record as clean. Clears dirty state, field history, and undo stacks.
|
|
5
|
+
* _loadedFields is NOT cleared — fetched state is cumulative.
|
|
6
|
+
*/
|
|
7
|
+
export declare function markAgentRecordClean(record: AgentDefinitionRecord): void;
|
|
3
8
|
export declare const agentDefinitionSlice: import("@reduxjs/toolkit").Slice<AgentDefinitionSliceState, {
|
|
4
9
|
/**
|
|
5
10
|
* Upserts a fully-fetched agent (live or version) and marks it clean.
|
|
@@ -28,134 +33,6 @@ export declare const agentDefinitionSlice: import("@reduxjs/toolkit").Slice<Agen
|
|
|
28
33
|
mergePartialAgent(state: AgentDefinitionSliceState, action: PayloadAction<Partial<AgentDefinition> & {
|
|
29
34
|
id: string;
|
|
30
35
|
}>): void;
|
|
31
|
-
/** Edit any single field by name. For scalars and simple values. */
|
|
32
|
-
setAgentField(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
33
|
-
id: string;
|
|
34
|
-
field: keyof AgentDefinition;
|
|
35
|
-
value: AgentDefinition[keyof AgentDefinition];
|
|
36
|
-
}>): void;
|
|
37
|
-
setAgentMessages(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
38
|
-
id: string;
|
|
39
|
-
messages: AgentDefinition["messages"];
|
|
40
|
-
}>): void;
|
|
41
|
-
setAgentSettings(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
42
|
-
id: string;
|
|
43
|
-
settings: AgentDefinition["settings"];
|
|
44
|
-
}>): void;
|
|
45
|
-
setAgentVariableDefinitions(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
46
|
-
id: string;
|
|
47
|
-
variableDefinitions: AgentDefinition["variableDefinitions"];
|
|
48
|
-
}>): void;
|
|
49
|
-
/**
|
|
50
|
-
* Bind or unbind a model control to a variable in ONE edit (one undo step):
|
|
51
|
-
* the settings literal and the variable definitions move together.
|
|
52
|
-
* See features/agents/utils/control-variables.ts.
|
|
53
|
-
*/
|
|
54
|
-
setAgentControlBinding(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
55
|
-
id: string;
|
|
56
|
-
settings: AgentDefinition["settings"];
|
|
57
|
-
variableDefinitions: AgentDefinition["variableDefinitions"];
|
|
58
|
-
}>): void;
|
|
59
|
-
setAgentContextPolicies(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
60
|
-
id: string;
|
|
61
|
-
contextPolicies: AgentDefinition["contextPolicies"];
|
|
62
|
-
}>): void;
|
|
63
|
-
setAgentTools(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
64
|
-
id: string;
|
|
65
|
-
tools: AgentDefinition["tools"];
|
|
66
|
-
}>): void;
|
|
67
|
-
setAgentCustomTools(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
68
|
-
id: string;
|
|
69
|
-
customTools: AgentDefinition["customTools"];
|
|
70
|
-
}>): void;
|
|
71
|
-
setAgentMcpServers(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
72
|
-
id: string;
|
|
73
|
-
mcpServers: AgentDefinition["mcpServers"];
|
|
74
|
-
}>): void;
|
|
75
|
-
/**
|
|
76
|
-
* Per-agent skill exposure config. The full SkillConfig object is
|
|
77
|
-
* replaced atomically; the picker UI computes the next value and
|
|
78
|
-
* dispatches once. Marked dirty so the next save flushes it through
|
|
79
|
-
* to `agent.definition.skill_config`.
|
|
80
|
-
*/
|
|
81
|
-
setAgentSkillConfig(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
82
|
-
id: string;
|
|
83
|
-
skillConfig: AgentDefinition["skillConfig"];
|
|
84
|
-
}>): void;
|
|
85
|
-
setAgentModelTiers(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
86
|
-
id: string;
|
|
87
|
-
modelTiers: AgentDefinition["modelTiers"];
|
|
88
|
-
}>): void;
|
|
89
|
-
setAgentOutputSchema(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
90
|
-
id: string;
|
|
91
|
-
outputSchema: AgentDefinition["outputSchema"];
|
|
92
|
-
}>): void;
|
|
93
|
-
/**
|
|
94
|
-
* Model-gated UI flags (FE-only). The full UiGates object is replaced
|
|
95
|
-
* atomically; the gate editor computes the next value and dispatches once.
|
|
96
|
-
* Persisted to `agent.definition.ui_gates` — never sent to the server.
|
|
97
|
-
*/
|
|
98
|
-
setAgentUiGates(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
99
|
-
id: string;
|
|
100
|
-
uiGates: AgentDefinition["uiGates"];
|
|
101
|
-
}>): void;
|
|
102
|
-
/**
|
|
103
|
-
* Matrx Directives apply config. Replaced atomically by the Matrx Directives tab;
|
|
104
|
-
* persisted to `agent.definition.matrx_actions`. Read by aidream's output-directive
|
|
105
|
-
* dispatcher (full rebrand of the retired settings["output_apply"]).
|
|
106
|
-
*/
|
|
107
|
-
setAgentMatrxDirectives(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
108
|
-
id: string;
|
|
109
|
-
matrxDirectives: AgentDefinition["matrxDirectives"];
|
|
110
|
-
}>): void;
|
|
111
|
-
/** Reset one field to its original value from _fieldHistory. */
|
|
112
|
-
resetAgentField(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
113
|
-
id: string;
|
|
114
|
-
field: keyof AgentDefinition;
|
|
115
|
-
}>): void;
|
|
116
|
-
/** Reset ALL dirty fields to their original values. No refetch needed. */
|
|
117
|
-
resetAllAgentFields(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
118
|
-
id: string;
|
|
119
|
-
}>): void;
|
|
120
|
-
/** Called after a successful save. Current values become the new clean baseline. */
|
|
121
|
-
markAgentSaved(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
122
|
-
id: string;
|
|
123
|
-
}>): void;
|
|
124
|
-
/**
|
|
125
|
-
* A SINGLE field was written to the database (inline edits such as the
|
|
126
|
-
* Agent Info Editor's name). Only that field becomes the clean baseline —
|
|
127
|
-
* every other staged edit (e.g. an Output Schema kind binding applied in
|
|
128
|
-
* Model Settings) must stay dirty so the main Save still persists it.
|
|
129
|
-
* `markAgentSaved` here used to wipe every dirty flag, silently dropping
|
|
130
|
-
* unrelated staged edits (feedback 222a2925).
|
|
131
|
-
*/
|
|
132
|
-
markAgentFieldSaved(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
133
|
-
id: string;
|
|
134
|
-
field: keyof AgentDefinition;
|
|
135
|
-
}>): void;
|
|
136
|
-
/** Save failed — restore from the snapshot taken before the optimistic write. */
|
|
137
|
-
rollbackAgentOptimisticUpdate(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
138
|
-
id: string;
|
|
139
|
-
snapshot: FieldSnapshot;
|
|
140
|
-
}>): void;
|
|
141
|
-
/**
|
|
142
|
-
* Pops the most recent entry from _undoPast, pushes current value to
|
|
143
|
-
* _undoFuture, and restores the previous value. Also maintains dirty tracking.
|
|
144
|
-
*/
|
|
145
|
-
undoAgentEdit(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
146
|
-
id: string;
|
|
147
|
-
}>): void;
|
|
148
|
-
/**
|
|
149
|
-
* Pops the most recent entry from _undoFuture, pushes current value to
|
|
150
|
-
* _undoPast, and applies the redo value. Also maintains dirty tracking.
|
|
151
|
-
*/
|
|
152
|
-
redoAgentEdit(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
153
|
-
id: string;
|
|
154
|
-
}>): void;
|
|
155
|
-
/** Clears the undo/redo stacks without affecting the current state. */
|
|
156
|
-
clearAgentUndoHistory(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
157
|
-
id: string;
|
|
158
|
-
}>): void;
|
|
159
36
|
markAgentFieldsLoaded(state: AgentDefinitionSliceState, action: PayloadAction<{
|
|
160
37
|
id: string;
|
|
161
38
|
fields: (keyof AgentDefinition)[];
|
|
@@ -188,70 +65,7 @@ export declare const upsertAgent: import("@reduxjs/toolkit").ActionCreatorWithPa
|
|
|
188
65
|
id: string;
|
|
189
66
|
}, "agentDefinition/seedAgentFromTemplate">, mergePartialAgent: import("@reduxjs/toolkit").ActionCreatorWithPayload<Partial<AgentDefinition> & {
|
|
190
67
|
id: string;
|
|
191
|
-
}, "agentDefinition/mergePartialAgent">,
|
|
192
|
-
id: string;
|
|
193
|
-
field: keyof AgentDefinition;
|
|
194
|
-
value: AgentDefinition[keyof AgentDefinition];
|
|
195
|
-
}, "agentDefinition/setAgentField">, setAgentMessages: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
196
|
-
id: string;
|
|
197
|
-
messages: AgentDefinition["messages"];
|
|
198
|
-
}, "agentDefinition/setAgentMessages">, setAgentSettings: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
199
|
-
id: string;
|
|
200
|
-
settings: AgentDefinition["settings"];
|
|
201
|
-
}, "agentDefinition/setAgentSettings">, setAgentVariableDefinitions: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
202
|
-
id: string;
|
|
203
|
-
variableDefinitions: AgentDefinition["variableDefinitions"];
|
|
204
|
-
}, "agentDefinition/setAgentVariableDefinitions">, setAgentControlBinding: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
205
|
-
id: string;
|
|
206
|
-
settings: AgentDefinition["settings"];
|
|
207
|
-
variableDefinitions: AgentDefinition["variableDefinitions"];
|
|
208
|
-
}, "agentDefinition/setAgentControlBinding">, setAgentContextPolicies: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
209
|
-
id: string;
|
|
210
|
-
contextPolicies: AgentDefinition["contextPolicies"];
|
|
211
|
-
}, "agentDefinition/setAgentContextPolicies">, setAgentTools: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
212
|
-
id: string;
|
|
213
|
-
tools: AgentDefinition["tools"];
|
|
214
|
-
}, "agentDefinition/setAgentTools">, setAgentCustomTools: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
215
|
-
id: string;
|
|
216
|
-
customTools: AgentDefinition["customTools"];
|
|
217
|
-
}, "agentDefinition/setAgentCustomTools">, setAgentMcpServers: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
218
|
-
id: string;
|
|
219
|
-
mcpServers: AgentDefinition["mcpServers"];
|
|
220
|
-
}, "agentDefinition/setAgentMcpServers">, setAgentSkillConfig: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
221
|
-
id: string;
|
|
222
|
-
skillConfig: AgentDefinition["skillConfig"];
|
|
223
|
-
}, "agentDefinition/setAgentSkillConfig">, setAgentModelTiers: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
224
|
-
id: string;
|
|
225
|
-
modelTiers: AgentDefinition["modelTiers"];
|
|
226
|
-
}, "agentDefinition/setAgentModelTiers">, setAgentOutputSchema: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
227
|
-
id: string;
|
|
228
|
-
outputSchema: AgentDefinition["outputSchema"];
|
|
229
|
-
}, "agentDefinition/setAgentOutputSchema">, setAgentUiGates: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
230
|
-
id: string;
|
|
231
|
-
uiGates: AgentDefinition["uiGates"];
|
|
232
|
-
}, "agentDefinition/setAgentUiGates">, setAgentMatrxDirectives: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
233
|
-
id: string;
|
|
234
|
-
matrxDirectives: AgentDefinition["matrxDirectives"];
|
|
235
|
-
}, "agentDefinition/setAgentMatrxDirectives">, resetAgentField: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
236
|
-
id: string;
|
|
237
|
-
field: keyof AgentDefinition;
|
|
238
|
-
}, "agentDefinition/resetAgentField">, resetAllAgentFields: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
239
|
-
id: string;
|
|
240
|
-
}, "agentDefinition/resetAllAgentFields">, markAgentSaved: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
241
|
-
id: string;
|
|
242
|
-
}, "agentDefinition/markAgentSaved">, markAgentFieldSaved: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
243
|
-
id: string;
|
|
244
|
-
field: keyof AgentDefinition;
|
|
245
|
-
}, "agentDefinition/markAgentFieldSaved">, rollbackAgentOptimisticUpdate: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
246
|
-
id: string;
|
|
247
|
-
snapshot: FieldSnapshot;
|
|
248
|
-
}, "agentDefinition/rollbackAgentOptimisticUpdate">, undoAgentEdit: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
249
|
-
id: string;
|
|
250
|
-
}, "agentDefinition/undoAgentEdit">, redoAgentEdit: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
251
|
-
id: string;
|
|
252
|
-
}, "agentDefinition/redoAgentEdit">, clearAgentUndoHistory: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
253
|
-
id: string;
|
|
254
|
-
}, "agentDefinition/clearAgentUndoHistory">, markAgentFieldsLoaded: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
68
|
+
}, "agentDefinition/mergePartialAgent">, markAgentFieldsLoaded: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
255
69
|
id: string;
|
|
256
70
|
fields: (keyof AgentDefinition)[];
|
|
257
71
|
}, "agentDefinition/markAgentFieldsLoaded">, setAgentFetchStatus: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import { createSlice } from "@reduxjs/toolkit";
|
|
2
|
-
import isEqual from "lodash/isEqual";
|
|
3
2
|
import { isJsonObject } from "../../../utils/json.js";
|
|
4
3
|
import {
|
|
5
|
-
shouldUpgradeFetchStatus
|
|
6
|
-
UNDO_MAX_ENTRIES,
|
|
7
|
-
UNDO_MAX_BYTES,
|
|
8
|
-
UNDO_COALESCE_MS
|
|
4
|
+
shouldUpgradeFetchStatus
|
|
9
5
|
} from "../../types/agent-definition.types.js";
|
|
10
6
|
import {
|
|
11
7
|
addField,
|
|
12
8
|
assignField,
|
|
13
|
-
createFieldFlags
|
|
14
|
-
fieldFlagsSize,
|
|
15
|
-
hasField,
|
|
16
|
-
removeField
|
|
9
|
+
createFieldFlags
|
|
17
10
|
} from "@ai-matrx/agents/field-flags";
|
|
18
11
|
function makeEmptyRecord(id) {
|
|
19
12
|
return {
|
|
@@ -115,89 +108,7 @@ function mergeAndTrack(record, partial) {
|
|
|
115
108
|
}
|
|
116
109
|
});
|
|
117
110
|
}
|
|
118
|
-
function
|
|
119
|
-
if (value == null) return 8;
|
|
120
|
-
if (typeof value === "string") return value.length * 2;
|
|
121
|
-
if (typeof value === "number" || typeof value === "boolean") return 8;
|
|
122
|
-
try {
|
|
123
|
-
return JSON.stringify(value).length * 2;
|
|
124
|
-
} catch {
|
|
125
|
-
return 1024;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
function totalStackBytes(stack) {
|
|
129
|
-
let total = 0;
|
|
130
|
-
for (const entry of stack) total += entry.byteEstimate;
|
|
131
|
-
return total;
|
|
132
|
-
}
|
|
133
|
-
function compressStack(stack) {
|
|
134
|
-
if (stack.length <= UNDO_MAX_ENTRIES && totalStackBytes(stack) <= UNDO_MAX_BYTES) {
|
|
135
|
-
return stack;
|
|
136
|
-
}
|
|
137
|
-
const protectedHead = 1;
|
|
138
|
-
const protectedTail = Math.min(20, Math.floor(stack.length * 0.4));
|
|
139
|
-
if (stack.length <= protectedHead + protectedTail) return stack;
|
|
140
|
-
const head = stack.slice(0, protectedHead);
|
|
141
|
-
const tail = stack.slice(-protectedTail);
|
|
142
|
-
let middle = stack.slice(protectedHead, stack.length - protectedTail);
|
|
143
|
-
const merged = [];
|
|
144
|
-
for (const entry of middle) {
|
|
145
|
-
const prev = merged[merged.length - 1];
|
|
146
|
-
if (prev && prev.field === entry.field) {
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
merged.push(entry);
|
|
150
|
-
}
|
|
151
|
-
middle = merged;
|
|
152
|
-
let result = [...head, ...middle, ...tail];
|
|
153
|
-
if (result.length > UNDO_MAX_ENTRIES) {
|
|
154
|
-
const thinned = [];
|
|
155
|
-
for (let i = 0; i < middle.length; i++) {
|
|
156
|
-
if (i % 2 === 0) thinned.push(middle[i]);
|
|
157
|
-
}
|
|
158
|
-
result = [...head, ...thinned, ...tail];
|
|
159
|
-
}
|
|
160
|
-
while (result.length > protectedHead + protectedTail + 1 && totalStackBytes(result) > UNDO_MAX_BYTES) {
|
|
161
|
-
result.splice(protectedHead, 1);
|
|
162
|
-
}
|
|
163
|
-
return result;
|
|
164
|
-
}
|
|
165
|
-
function pushUndoEntry(record, field, previousValue) {
|
|
166
|
-
const now = Date.now();
|
|
167
|
-
const bytes = estimateBytes(previousValue);
|
|
168
|
-
const top = record._undoPast[record._undoPast.length - 1];
|
|
169
|
-
if (top && top.field === field && now - top.timestamp < UNDO_COALESCE_MS) {
|
|
170
|
-
top.timestamp = now;
|
|
171
|
-
} else {
|
|
172
|
-
record._undoPast.push({
|
|
173
|
-
field,
|
|
174
|
-
value: previousValue,
|
|
175
|
-
timestamp: now,
|
|
176
|
-
byteEstimate: bytes
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
record._undoFuture = [];
|
|
180
|
-
record._undoPast = compressStack(record._undoPast);
|
|
181
|
-
}
|
|
182
|
-
function applyFieldEdit(record, field, value) {
|
|
183
|
-
const previousValue = record[field];
|
|
184
|
-
const wasDirty = hasField(record._dirtyFields, field);
|
|
185
|
-
if (!wasDirty && isEqual(value, previousValue)) return;
|
|
186
|
-
if (!wasDirty) {
|
|
187
|
-
record._fieldHistory[field] = previousValue;
|
|
188
|
-
}
|
|
189
|
-
pushUndoEntry(record, field, previousValue);
|
|
190
|
-
assignField(record, field, value);
|
|
191
|
-
const baseline = record._fieldHistory[field];
|
|
192
|
-
if (wasDirty && isEqual(value, baseline)) {
|
|
193
|
-
removeField(record._dirtyFields, field);
|
|
194
|
-
delete record._fieldHistory[field];
|
|
195
|
-
} else {
|
|
196
|
-
addField(record._dirtyFields, field);
|
|
197
|
-
}
|
|
198
|
-
record._dirty = fieldFlagsSize(record._dirtyFields) > 0;
|
|
199
|
-
}
|
|
200
|
-
function markRecordClean(record) {
|
|
111
|
+
function markAgentRecordClean(record) {
|
|
201
112
|
record._dirty = false;
|
|
202
113
|
record._dirtyFields = createFieldFlags();
|
|
203
114
|
record._fieldHistory = {};
|
|
@@ -241,7 +152,7 @@ const agentDefinitionSlice = createSlice({
|
|
|
241
152
|
const normalizedData = messagesWereNormalized ? { ...withStar, messages: normalizedMessages } : withStar;
|
|
242
153
|
if (existing) {
|
|
243
154
|
mergeAndTrack(existing, normalizedData);
|
|
244
|
-
|
|
155
|
+
markAgentRecordClean(existing);
|
|
245
156
|
if (messagesWereNormalized) {
|
|
246
157
|
addField(existing._dirtyFields, "messages");
|
|
247
158
|
existing._dirty = true;
|
|
@@ -250,7 +161,7 @@ const agentDefinitionSlice = createSlice({
|
|
|
250
161
|
} else {
|
|
251
162
|
const record = makeEmptyRecord(data.id);
|
|
252
163
|
mergeAndTrack(record, normalizedData);
|
|
253
|
-
|
|
164
|
+
markAgentRecordClean(record);
|
|
254
165
|
if (messagesWereNormalized) {
|
|
255
166
|
addField(record._dirtyFields, "messages");
|
|
256
167
|
record._dirty = true;
|
|
@@ -325,7 +236,7 @@ const agentDefinitionSlice = createSlice({
|
|
|
325
236
|
if (!state.agents[full.id]) {
|
|
326
237
|
const record = makeEmptyRecord(full.id);
|
|
327
238
|
mergeAndTrack(record, full);
|
|
328
|
-
|
|
239
|
+
markAgentRecordClean(record);
|
|
329
240
|
if (seedMessagesNormalized) {
|
|
330
241
|
addField(record._dirtyFields, "messages");
|
|
331
242
|
record._dirty = true;
|
|
@@ -355,229 +266,6 @@ const agentDefinitionSlice = createSlice({
|
|
|
355
266
|
state.agents[data.id] = record;
|
|
356
267
|
}
|
|
357
268
|
},
|
|
358
|
-
// ── User field edits (trigger dirty) ─────────────────────────────────────
|
|
359
|
-
/** Edit any single field by name. For scalars and simple values. */
|
|
360
|
-
setAgentField(state, action) {
|
|
361
|
-
const { id, field, value } = action.payload;
|
|
362
|
-
const record = state.agents[id];
|
|
363
|
-
if (!record) return;
|
|
364
|
-
applyFieldEdit(record, field, value);
|
|
365
|
-
},
|
|
366
|
-
// ── Dedicated actions for complex fields ──────────────────────────────────
|
|
367
|
-
setAgentMessages(state, action) {
|
|
368
|
-
const record = state.agents[action.payload.id];
|
|
369
|
-
if (!record) return;
|
|
370
|
-
applyFieldEdit(record, "messages", action.payload.messages);
|
|
371
|
-
},
|
|
372
|
-
setAgentSettings(state, action) {
|
|
373
|
-
const record = state.agents[action.payload.id];
|
|
374
|
-
if (!record) return;
|
|
375
|
-
applyFieldEdit(record, "settings", action.payload.settings);
|
|
376
|
-
},
|
|
377
|
-
setAgentVariableDefinitions(state, action) {
|
|
378
|
-
const record = state.agents[action.payload.id];
|
|
379
|
-
if (!record) return;
|
|
380
|
-
applyFieldEdit(
|
|
381
|
-
record,
|
|
382
|
-
"variableDefinitions",
|
|
383
|
-
action.payload.variableDefinitions
|
|
384
|
-
);
|
|
385
|
-
},
|
|
386
|
-
/**
|
|
387
|
-
* Bind or unbind a model control to a variable in ONE edit (one undo step):
|
|
388
|
-
* the settings literal and the variable definitions move together.
|
|
389
|
-
* See features/agents/utils/control-variables.ts.
|
|
390
|
-
*/
|
|
391
|
-
setAgentControlBinding(state, action) {
|
|
392
|
-
const record = state.agents[action.payload.id];
|
|
393
|
-
if (!record) return;
|
|
394
|
-
applyFieldEdit(record, "settings", action.payload.settings);
|
|
395
|
-
applyFieldEdit(
|
|
396
|
-
record,
|
|
397
|
-
"variableDefinitions",
|
|
398
|
-
action.payload.variableDefinitions
|
|
399
|
-
);
|
|
400
|
-
},
|
|
401
|
-
setAgentContextPolicies(state, action) {
|
|
402
|
-
const record = state.agents[action.payload.id];
|
|
403
|
-
if (!record) return;
|
|
404
|
-
applyFieldEdit(record, "contextPolicies", action.payload.contextPolicies);
|
|
405
|
-
},
|
|
406
|
-
setAgentTools(state, action) {
|
|
407
|
-
const record = state.agents[action.payload.id];
|
|
408
|
-
if (!record) return;
|
|
409
|
-
applyFieldEdit(record, "tools", action.payload.tools);
|
|
410
|
-
},
|
|
411
|
-
setAgentCustomTools(state, action) {
|
|
412
|
-
const record = state.agents[action.payload.id];
|
|
413
|
-
if (!record) return;
|
|
414
|
-
applyFieldEdit(record, "customTools", action.payload.customTools);
|
|
415
|
-
},
|
|
416
|
-
setAgentMcpServers(state, action) {
|
|
417
|
-
const record = state.agents[action.payload.id];
|
|
418
|
-
if (!record) return;
|
|
419
|
-
applyFieldEdit(record, "mcpServers", action.payload.mcpServers);
|
|
420
|
-
},
|
|
421
|
-
/**
|
|
422
|
-
* Per-agent skill exposure config. The full SkillConfig object is
|
|
423
|
-
* replaced atomically; the picker UI computes the next value and
|
|
424
|
-
* dispatches once. Marked dirty so the next save flushes it through
|
|
425
|
-
* to `agent.definition.skill_config`.
|
|
426
|
-
*/
|
|
427
|
-
setAgentSkillConfig(state, action) {
|
|
428
|
-
const record = state.agents[action.payload.id];
|
|
429
|
-
if (!record) return;
|
|
430
|
-
applyFieldEdit(record, "skillConfig", action.payload.skillConfig);
|
|
431
|
-
},
|
|
432
|
-
setAgentModelTiers(state, action) {
|
|
433
|
-
const record = state.agents[action.payload.id];
|
|
434
|
-
if (!record) return;
|
|
435
|
-
applyFieldEdit(record, "modelTiers", action.payload.modelTiers);
|
|
436
|
-
},
|
|
437
|
-
setAgentOutputSchema(state, action) {
|
|
438
|
-
const record = state.agents[action.payload.id];
|
|
439
|
-
if (!record) return;
|
|
440
|
-
applyFieldEdit(record, "outputSchema", action.payload.outputSchema);
|
|
441
|
-
},
|
|
442
|
-
/**
|
|
443
|
-
* Model-gated UI flags (FE-only). The full UiGates object is replaced
|
|
444
|
-
* atomically; the gate editor computes the next value and dispatches once.
|
|
445
|
-
* Persisted to `agent.definition.ui_gates` — never sent to the server.
|
|
446
|
-
*/
|
|
447
|
-
setAgentUiGates(state, action) {
|
|
448
|
-
const record = state.agents[action.payload.id];
|
|
449
|
-
if (!record) return;
|
|
450
|
-
applyFieldEdit(record, "uiGates", action.payload.uiGates);
|
|
451
|
-
},
|
|
452
|
-
/**
|
|
453
|
-
* Matrx Directives apply config. Replaced atomically by the Matrx Directives tab;
|
|
454
|
-
* persisted to `agent.definition.matrx_actions`. Read by aidream's output-directive
|
|
455
|
-
* dispatcher (full rebrand of the retired settings["output_apply"]).
|
|
456
|
-
*/
|
|
457
|
-
setAgentMatrxDirectives(state, action) {
|
|
458
|
-
const record = state.agents[action.payload.id];
|
|
459
|
-
if (!record) return;
|
|
460
|
-
applyFieldEdit(record, "matrxDirectives", action.payload.matrxDirectives);
|
|
461
|
-
},
|
|
462
|
-
// ── Dirty / history management ────────────────────────────────────────────
|
|
463
|
-
/** Reset one field to its original value from _fieldHistory. */
|
|
464
|
-
resetAgentField(state, action) {
|
|
465
|
-
const { id, field } = action.payload;
|
|
466
|
-
const record = state.agents[id];
|
|
467
|
-
if (!record || !hasField(record._dirtyFields, field)) return;
|
|
468
|
-
const original = record._fieldHistory[field];
|
|
469
|
-
if (original !== void 0) {
|
|
470
|
-
assignField(record, field, original);
|
|
471
|
-
}
|
|
472
|
-
removeField(record._dirtyFields, field);
|
|
473
|
-
delete record._fieldHistory[field];
|
|
474
|
-
record._dirty = fieldFlagsSize(record._dirtyFields) > 0;
|
|
475
|
-
},
|
|
476
|
-
/** Reset ALL dirty fields to their original values. No refetch needed. */
|
|
477
|
-
resetAllAgentFields(state, action) {
|
|
478
|
-
const record = state.agents[action.payload.id];
|
|
479
|
-
if (!record) return;
|
|
480
|
-
Object.keys(record._fieldHistory).forEach(
|
|
481
|
-
(field) => {
|
|
482
|
-
const original = record._fieldHistory[field];
|
|
483
|
-
if (original !== void 0) {
|
|
484
|
-
assignField(record, field, original);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
);
|
|
488
|
-
markRecordClean(record);
|
|
489
|
-
},
|
|
490
|
-
/** Called after a successful save. Current values become the new clean baseline. */
|
|
491
|
-
markAgentSaved(state, action) {
|
|
492
|
-
const record = state.agents[action.payload.id];
|
|
493
|
-
if (!record) return;
|
|
494
|
-
markRecordClean(record);
|
|
495
|
-
},
|
|
496
|
-
/**
|
|
497
|
-
* A SINGLE field was written to the database (inline edits such as the
|
|
498
|
-
* Agent Info Editor's name). Only that field becomes the clean baseline —
|
|
499
|
-
* every other staged edit (e.g. an Output Schema kind binding applied in
|
|
500
|
-
* Model Settings) must stay dirty so the main Save still persists it.
|
|
501
|
-
* `markAgentSaved` here used to wipe every dirty flag, silently dropping
|
|
502
|
-
* unrelated staged edits (feedback 222a2925).
|
|
503
|
-
*/
|
|
504
|
-
markAgentFieldSaved(state, action) {
|
|
505
|
-
const { id, field } = action.payload;
|
|
506
|
-
const record = state.agents[id];
|
|
507
|
-
if (!record) return;
|
|
508
|
-
removeField(record._dirtyFields, field);
|
|
509
|
-
delete record._fieldHistory[field];
|
|
510
|
-
record._undoPast = record._undoPast.filter((e) => e.field !== field);
|
|
511
|
-
record._undoFuture = record._undoFuture.filter((e) => e.field !== field);
|
|
512
|
-
record._dirty = fieldFlagsSize(record._dirtyFields) > 0;
|
|
513
|
-
},
|
|
514
|
-
/** Save failed — restore from the snapshot taken before the optimistic write. */
|
|
515
|
-
rollbackAgentOptimisticUpdate(state, action) {
|
|
516
|
-
const { id, snapshot } = action.payload;
|
|
517
|
-
const record = state.agents[id];
|
|
518
|
-
if (!record) return;
|
|
519
|
-
Object.keys(snapshot).forEach((field) => {
|
|
520
|
-
const value = snapshot[field];
|
|
521
|
-
if (value !== void 0) {
|
|
522
|
-
assignField(record, field, value);
|
|
523
|
-
}
|
|
524
|
-
});
|
|
525
|
-
record._dirty = fieldFlagsSize(record._dirtyFields) > 0;
|
|
526
|
-
},
|
|
527
|
-
// ── Undo / Redo ──────────────────────────────────────────────────────────
|
|
528
|
-
/**
|
|
529
|
-
* Pops the most recent entry from _undoPast, pushes current value to
|
|
530
|
-
* _undoFuture, and restores the previous value. Also maintains dirty tracking.
|
|
531
|
-
*/
|
|
532
|
-
undoAgentEdit(state, action) {
|
|
533
|
-
const record = state.agents[action.payload.id];
|
|
534
|
-
if (!record || record._undoPast.length === 0) return;
|
|
535
|
-
const entry = record._undoPast.pop();
|
|
536
|
-
if (!entry) return;
|
|
537
|
-
const currentValue = record[entry.field];
|
|
538
|
-
record._undoFuture.push({
|
|
539
|
-
field: entry.field,
|
|
540
|
-
value: currentValue,
|
|
541
|
-
timestamp: Date.now(),
|
|
542
|
-
byteEstimate: estimateBytes(currentValue)
|
|
543
|
-
});
|
|
544
|
-
assignField(record, entry.field, entry.value);
|
|
545
|
-
const originalValue = record._fieldHistory[entry.field];
|
|
546
|
-
if (originalValue !== void 0 && isEqual(entry.value, originalValue)) {
|
|
547
|
-
removeField(record._dirtyFields, entry.field);
|
|
548
|
-
delete record._fieldHistory[entry.field];
|
|
549
|
-
} else if (!hasField(record._dirtyFields, entry.field)) {
|
|
550
|
-
addField(record._dirtyFields, entry.field);
|
|
551
|
-
}
|
|
552
|
-
record._dirty = fieldFlagsSize(record._dirtyFields) > 0;
|
|
553
|
-
},
|
|
554
|
-
/**
|
|
555
|
-
* Pops the most recent entry from _undoFuture, pushes current value to
|
|
556
|
-
* _undoPast, and applies the redo value. Also maintains dirty tracking.
|
|
557
|
-
*/
|
|
558
|
-
redoAgentEdit(state, action) {
|
|
559
|
-
const record = state.agents[action.payload.id];
|
|
560
|
-
if (!record || record._undoFuture.length === 0) return;
|
|
561
|
-
const entry = record._undoFuture.pop();
|
|
562
|
-
if (!entry) return;
|
|
563
|
-
const currentValue = record[entry.field];
|
|
564
|
-
record._undoPast.push({
|
|
565
|
-
field: entry.field,
|
|
566
|
-
value: currentValue,
|
|
567
|
-
timestamp: Date.now(),
|
|
568
|
-
byteEstimate: estimateBytes(currentValue)
|
|
569
|
-
});
|
|
570
|
-
assignField(record, entry.field, entry.value);
|
|
571
|
-
addField(record._dirtyFields, entry.field);
|
|
572
|
-
record._dirty = true;
|
|
573
|
-
},
|
|
574
|
-
/** Clears the undo/redo stacks without affecting the current state. */
|
|
575
|
-
clearAgentUndoHistory(state, action) {
|
|
576
|
-
const record = state.agents[action.payload.id];
|
|
577
|
-
if (!record) return;
|
|
578
|
-
record._undoPast = [];
|
|
579
|
-
record._undoFuture = [];
|
|
580
|
-
},
|
|
581
269
|
// ── Explicitly mark fields as loaded (without writing data) ──────────────
|
|
582
270
|
markAgentFieldsLoaded(state, action) {
|
|
583
271
|
const record = state.agents[action.payload.id];
|
|
@@ -637,28 +325,6 @@ const {
|
|
|
637
325
|
upsertAgent,
|
|
638
326
|
seedAgentFromTemplate,
|
|
639
327
|
mergePartialAgent,
|
|
640
|
-
setAgentField,
|
|
641
|
-
setAgentMessages,
|
|
642
|
-
setAgentSettings,
|
|
643
|
-
setAgentVariableDefinitions,
|
|
644
|
-
setAgentControlBinding,
|
|
645
|
-
setAgentContextPolicies,
|
|
646
|
-
setAgentTools,
|
|
647
|
-
setAgentCustomTools,
|
|
648
|
-
setAgentMcpServers,
|
|
649
|
-
setAgentSkillConfig,
|
|
650
|
-
setAgentModelTiers,
|
|
651
|
-
setAgentOutputSchema,
|
|
652
|
-
setAgentUiGates,
|
|
653
|
-
setAgentMatrxDirectives,
|
|
654
|
-
resetAgentField,
|
|
655
|
-
resetAllAgentFields,
|
|
656
|
-
markAgentSaved,
|
|
657
|
-
markAgentFieldSaved,
|
|
658
|
-
rollbackAgentOptimisticUpdate,
|
|
659
|
-
undoAgentEdit,
|
|
660
|
-
redoAgentEdit,
|
|
661
|
-
clearAgentUndoHistory,
|
|
662
328
|
markAgentFieldsLoaded,
|
|
663
329
|
setAgentFetchStatus,
|
|
664
330
|
setAgentLoading,
|
|
@@ -672,39 +338,18 @@ const {
|
|
|
672
338
|
var slice_default = agentDefinitionSlice.reducer;
|
|
673
339
|
export {
|
|
674
340
|
agentDefinitionSlice,
|
|
675
|
-
clearAgentUndoHistory,
|
|
676
341
|
slice_default as default,
|
|
677
|
-
markAgentFieldSaved,
|
|
678
342
|
markAgentFieldsLoaded,
|
|
679
|
-
|
|
343
|
+
markAgentRecordClean,
|
|
680
344
|
mergePartialAgent,
|
|
681
|
-
redoAgentEdit,
|
|
682
345
|
removeAgent,
|
|
683
346
|
removeVersionsByParentId,
|
|
684
|
-
resetAgentField,
|
|
685
|
-
resetAllAgentFields,
|
|
686
|
-
rollbackAgentOptimisticUpdate,
|
|
687
347
|
seedAgentFromTemplate,
|
|
688
348
|
setActiveAgentId,
|
|
689
|
-
setAgentContextPolicies,
|
|
690
|
-
setAgentControlBinding,
|
|
691
|
-
setAgentCustomTools,
|
|
692
349
|
setAgentError,
|
|
693
350
|
setAgentFetchStatus,
|
|
694
|
-
setAgentField,
|
|
695
351
|
setAgentLoading,
|
|
696
|
-
setAgentMatrxDirectives,
|
|
697
|
-
setAgentMcpServers,
|
|
698
|
-
setAgentMessages,
|
|
699
|
-
setAgentModelTiers,
|
|
700
|
-
setAgentOutputSchema,
|
|
701
|
-
setAgentSettings,
|
|
702
|
-
setAgentSkillConfig,
|
|
703
|
-
setAgentTools,
|
|
704
|
-
setAgentUiGates,
|
|
705
|
-
setAgentVariableDefinitions,
|
|
706
352
|
setAgentsError,
|
|
707
353
|
setAgentsStatus,
|
|
708
|
-
undoAgentEdit,
|
|
709
354
|
upsertAgent
|
|
710
355
|
};
|
|
@@ -227,21 +227,6 @@ export declare const fetchAgentRunControls: import("@reduxjs/toolkit").AsyncThun
|
|
|
227
227
|
dispatch: ChatDispatch;
|
|
228
228
|
state: ChatRootState;
|
|
229
229
|
}>;
|
|
230
|
-
/**
|
|
231
|
-
* Fetches the complete agent row via PostgREST and upserts it into state.
|
|
232
|
-
* Marks the record fully clean — all fields tracked as loaded.
|
|
233
|
-
* Use this when opening the agent builder or after creating/duplicating an agent.
|
|
234
|
-
*/
|
|
235
|
-
export declare const fetchFullAgent: import("@reduxjs/toolkit").AsyncThunk<void, string, {
|
|
236
|
-
extra?: unknown;
|
|
237
|
-
rejectValue?: unknown;
|
|
238
|
-
serializedErrorType?: unknown;
|
|
239
|
-
pendingMeta?: unknown;
|
|
240
|
-
fulfilledMeta?: unknown;
|
|
241
|
-
rejectedMeta?: unknown;
|
|
242
|
-
dispatch: ChatDispatch;
|
|
243
|
-
state: ChatRootState;
|
|
244
|
-
}>;
|
|
245
230
|
export interface SharedAgentItem {
|
|
246
231
|
id: string;
|
|
247
232
|
name: string;
|
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
readFavoriteIds
|
|
31
31
|
} from "../../../context/sources/scopes.js";
|
|
32
32
|
import {
|
|
33
|
-
upsertAgent,
|
|
34
33
|
mergePartialAgent,
|
|
35
34
|
setAgentFetchStatus,
|
|
36
35
|
setAgentLoading,
|
|
@@ -43,7 +42,6 @@ import {
|
|
|
43
42
|
selectAgentRunControlsReady
|
|
44
43
|
} from "./selectors.js";
|
|
45
44
|
import {
|
|
46
|
-
dbRowToAgentDefinition,
|
|
47
45
|
parseSkillConfigJson
|
|
48
46
|
} from "./converters.js";
|
|
49
47
|
import {
|
|
@@ -362,20 +360,6 @@ const fetchAgentRunControls = createAsyncThunk(
|
|
|
362
360
|
);
|
|
363
361
|
}
|
|
364
362
|
);
|
|
365
|
-
const fetchFullAgent = createAsyncThunk(
|
|
366
|
-
"agentDefinition/fetchFull",
|
|
367
|
-
async (agentId, { dispatch }) => {
|
|
368
|
-
dispatch(setAgentLoading({ id: agentId, loading: true }));
|
|
369
|
-
const { data, error } = await supabase.schema("agent").from("definition").select("*").eq("id", agentId).single();
|
|
370
|
-
dispatch(setAgentLoading({ id: agentId, loading: false }));
|
|
371
|
-
if (error) {
|
|
372
|
-
dispatch(setAgentError({ id: agentId, error: error.message }));
|
|
373
|
-
throw agentNameTakenError(error) ?? pgErrorToError(error);
|
|
374
|
-
}
|
|
375
|
-
dispatch(upsertAgent(dbRowToAgentDefinition(data)));
|
|
376
|
-
await overlayAgentFavorites(dispatch, [agentId]);
|
|
377
|
-
}
|
|
378
|
-
);
|
|
379
363
|
const fetchSharedAgents = createAsyncThunk("agentDefinition/fetchShared", async (_, { dispatch }) => {
|
|
380
364
|
const { data, error } = await supabase.rpc("agx_get_shared_with_me");
|
|
381
365
|
if (error) throw pgErrorToError(error);
|
|
@@ -455,7 +439,6 @@ export {
|
|
|
455
439
|
fetchAgentRunTier,
|
|
456
440
|
fetchAgentsList,
|
|
457
441
|
fetchAgentsListFull,
|
|
458
|
-
fetchFullAgent,
|
|
459
442
|
fetchSharedAgents,
|
|
460
443
|
fetchSharedAgentsForChat,
|
|
461
444
|
initializeChatAgents,
|
|
@@ -41,6 +41,10 @@ import { selectSavedContextRuleRows } from "./context-rules.thunks.js";
|
|
|
41
41
|
import { deliveredFieldsFor, toContextReceipt } from "./receipt-check.js";
|
|
42
42
|
import { resolveClientSurface } from "../utils/build-tool-injection.js";
|
|
43
43
|
import { surfaceWritesNoteSource } from "../utils/surface-writes-note.js";
|
|
44
|
+
import { docKindForContextKey } from "../../../utils/workingDocumentContext.js";
|
|
45
|
+
function neverThePage(key) {
|
|
46
|
+
return PERSON_CONTEXT_VALUES.has(key) || docKindForContextKey(key) !== null;
|
|
47
|
+
}
|
|
44
48
|
function pageContextFor(state, conversationId) {
|
|
45
49
|
const owner = pageOwningConversation(conversationId);
|
|
46
50
|
if (owner) {
|
|
@@ -49,7 +53,7 @@ function pageContextFor(state, conversationId) {
|
|
|
49
53
|
return {
|
|
50
54
|
mode: "own",
|
|
51
55
|
withheld: listed.filter(
|
|
52
|
-
(key) => !
|
|
56
|
+
(key) => !neverThePage(key) && !(companionOpen && key === SURFACE_CHAIN_KEY)
|
|
53
57
|
)
|
|
54
58
|
};
|
|
55
59
|
}
|
|
@@ -59,7 +63,7 @@ function pageContextFor(state, conversationId) {
|
|
|
59
63
|
return null;
|
|
60
64
|
}
|
|
61
65
|
function pageWithholds(page, key, surfaceKey) {
|
|
62
|
-
if (!page ||
|
|
66
|
+
if (!page || neverThePage(key)) return false;
|
|
63
67
|
if (page.withheld.includes(key)) return true;
|
|
64
68
|
return Boolean(surfaceKey && surfaceKey !== DEFAULT_SURFACE_KEY);
|
|
65
69
|
}
|
|
@@ -18,16 +18,20 @@ function useDomCapturePrint() {
|
|
|
18
18
|
try {
|
|
19
19
|
const { renderAllDiagrams } = await import("../../host/markdown-slots.js");
|
|
20
20
|
releaseRenderAll = (await renderAllDiagrams()).release;
|
|
21
|
-
const {
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
const [{ documentToPdf }, { downloadFile }] = await Promise.all([
|
|
22
|
+
import("@ai-matrx/alchemy/operate/capture"),
|
|
23
|
+
import("@ai-matrx/kit/download")
|
|
24
|
+
]);
|
|
25
|
+
const { filename = "ai-response", ...captureOptions } = options;
|
|
26
|
+
const pdf = await documentToPdf(el, {
|
|
24
27
|
scale: 2,
|
|
25
|
-
...
|
|
28
|
+
...captureOptions,
|
|
26
29
|
onProgress: (page, total) => {
|
|
27
30
|
setProgress(Math.round(page / Math.max(total, 1) * 100));
|
|
28
31
|
options.onProgress?.(page, total);
|
|
29
32
|
}
|
|
30
33
|
});
|
|
34
|
+
downloadFile(`${filename}.pdf`, pdf, "application/pdf");
|
|
31
35
|
} catch (err) {
|
|
32
36
|
const msg = err instanceof Error ? err.message : "PDF export failed";
|
|
33
37
|
setError(msg);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-matrx/chat",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.23",
|
|
4
4
|
"description": "THE one AI Matrx person-to-agent chat system: the full chat (running agents, conversations, tool calls, streaming, context, surfaces, voice) as per-module subpaths @ai-matrx/chat/<domain>/<module> over a host contract (/host, /host/react) whose only required value is a db; plus the kernel compatibility entries (., /external-store, /matrx, /react, /tools, styles.css, tokens.css) until P28.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -226,24 +226,24 @@
|
|
|
226
226
|
"server-only": "^0.0.1",
|
|
227
227
|
"uuid": "^14.0.2",
|
|
228
228
|
"zod": "^4.6.5",
|
|
229
|
-
"@ai-matrx/
|
|
229
|
+
"@ai-matrx/alchemy": "latest",
|
|
230
230
|
"@ai-matrx/associations": "latest",
|
|
231
|
+
"@ai-matrx/agents": "latest",
|
|
231
232
|
"@ai-matrx/canvas": "latest",
|
|
232
|
-
"@ai-matrx/browser-audio": "latest",
|
|
233
|
-
"@ai-matrx/alchemy": "latest",
|
|
234
233
|
"@ai-matrx/content-ir": "latest",
|
|
235
|
-
"@ai-matrx/
|
|
236
|
-
"@ai-matrx/data": "latest",
|
|
234
|
+
"@ai-matrx/browser-audio": "latest",
|
|
237
235
|
"@ai-matrx/design-system": "latest",
|
|
238
236
|
"@ai-matrx/diff": "latest",
|
|
237
|
+
"@ai-matrx/data": "latest",
|
|
239
238
|
"@ai-matrx/icons": "latest",
|
|
239
|
+
"@ai-matrx/kit": "latest",
|
|
240
240
|
"@ai-matrx/media": "latest",
|
|
241
241
|
"@ai-matrx/print": "latest",
|
|
242
242
|
"@ai-matrx/realtime": "latest",
|
|
243
|
-
"@ai-matrx/kit": "latest",
|
|
244
|
-
"@ai-matrx/tap-target": "latest",
|
|
245
243
|
"@ai-matrx/records": "latest",
|
|
246
|
-
"@ai-matrx/records-ui": "latest"
|
|
244
|
+
"@ai-matrx/records-ui": "latest",
|
|
245
|
+
"@ai-matrx/tap-target": "latest",
|
|
246
|
+
"@ai-matrx/content-ir-react": "latest"
|
|
247
247
|
},
|
|
248
248
|
"devDependencies": {
|
|
249
249
|
"@arethetypeswrong/cli": "^0.18.5",
|