@ai-matrx/chat 0.2.9 → 0.3.2
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 +34 -0
- package/dist/agent-copy/clipboard.d.ts +2 -4
- package/dist/agent-copy/clipboard.js +1 -14
- package/dist/agent-copy/page-capture/pageCapture.d.ts +11 -62
- package/dist/agent-copy/page-capture/pageCapture.js +5 -22
- package/dist/agents/components/context-items/bodies/WebpageBody.js +1 -1
- package/dist/agents/components/context-preview/AttachedContextSection.js +9 -8
- package/dist/agents/components/context-preview/ContextCompareView.js +13 -13
- package/dist/agents/components/context-preview/ContextPreviewPanel.js +13 -13
- package/dist/agents/components/conversation-actions/conversation-verbs.js +2 -6
- package/dist/agents/components/debug/SandboxFileViewer.js +1 -1
- package/dist/agents/components/debug/StreamDebugPanel.js +2 -2
- package/dist/agents/components/messages-display/TranscriptIntegrityCopyButton.js +1 -1
- package/dist/agents/components/observational-memory/components/MemoryStateInspector.js +4 -4
- package/dist/agents/components/run-controls/AgentExecutionTestModal.js +2 -2
- package/dist/agents/components/run-controls/PayloadTab.js +7 -1
- package/dist/agents/components/run-controls/panels/BackendTargetPanel.js +7 -1
- package/dist/agents/components/shared/AgentSaveStatus.js +22 -1
- package/dist/agents/hooks/useAgentAutoSave.js +14 -2
- package/dist/agents/menu/agent-actions.js +3 -5
- package/dist/agents/prompt-preview/PromptPreviewContent.js +1 -1
- package/dist/agents/redux/agent-definition/slice.js +1 -0
- package/dist/agents/redux/agent-settings/agentSettingsSlice.d.ts +3 -0
- package/dist/agents/redux/agent-settings/agentSettingsSlice.js +12 -2
- package/dist/agents/redux/agent-settings/types.d.ts +7 -0
- package/dist/agents/redux/agent-shortcuts/thunks.js +9 -5
- package/dist/agents/redux/execution-system/instance-resources/remarks.d.ts +6 -0
- package/dist/agents/redux/execution-system/instance-resources/remarks.js +16 -0
- package/dist/agents/redux/execution-system/instance-ui-state/components/InstanceUIStateCore.js +7 -1
- package/dist/agents/redux/execution-system/instance-ui-state/components/InstanceUIStateList.js +7 -1
- package/dist/agents/redux/execution-system/message-crud/commit-inline-edit.thunk.js +2 -1
- package/dist/canvas/workspace/useCanvasWorkspaceConversation.d.ts +12 -0
- package/dist/canvas/workspace/useCanvasWorkspaceConversation.js +29 -1
- package/dist/context-menu/types.d.ts +7 -0
- package/dist/cx-chat/components/messages/AssistantMessage.js +8 -10
- package/dist/cx-chat/components/messages/UserMessage.js +7 -1
- package/dist/cx-conversation/AssistantMessage.js +8 -10
- package/dist/cx-conversation/UserMessage.js +7 -1
- package/dist/host/clipboard.d.ts +7 -0
- package/dist/host/clipboard.js +11 -0
- package/dist/host/db-types.d.ts +15 -12
- package/dist/host/ui-slots.d.ts +2 -8
- package/dist/host/ui-slots.js +11 -16
- package/dist/public-chat/components/PublicMessageOptionsMenu.js +9 -16
- package/dist/store/create-chat-store.d.ts +10 -1
- package/dist/store/create-chat-store.js +4 -2
- package/dist/surfaces/runtime/SurfaceRuntimeContext.d.ts +10 -0
- package/dist/surfaces/runtime/SurfaceRuntimeContext.js +23 -1
- package/dist/surfaces/services/surface-config.service.d.ts +3 -1
- package/dist/surfaces/services/surface-config.service.js +33 -17
- package/dist/tool-call-visualization/components/ToolTabBodies.d.ts +0 -4
- package/dist/tool-call-visualization/components/ToolTabBodies.js +2 -25
- package/dist/tool-call-visualization/result-fields/ResultFile.js +2 -8
- package/dist/tool-call-visualization/result-fields/ShortId.js +1 -23
- package/dist/voice-agent/components/LiveVoiceDoor.js +1 -1
- package/dist/voice-agent/components/VoiceDebugPanel.js +1 -1
- package/dist/voice-agent/hooks/useVoiceAgentInstance.js +1 -1
- package/dist/window-panels/windows/agents/ObservationalMemoryWindow.d.ts +0 -17
- package/dist/window-panels/windows/agents/ObservationalMemoryWindow.js +7 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,45 @@
|
|
|
1
1
|
# @ai-matrx/chat
|
|
2
2
|
|
|
3
|
+
## 0.3.2
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/chat/v0.2.10..npm/chat/v0.3.2 -- apps/shared/chat`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## 0.3.1 — 2026-10-07
|
|
10
|
+
### Re-sync before matrx-frontend consumes the published package (P27)
|
|
11
|
+
|
|
12
|
+
- Carries every matrx-frontend `packages/chat` edit after `636e7ef2dd` (context-preview copy, agent-settings
|
|
13
|
+
`offeringId`, surface-config service, db-types) and `surfaces/lib/ui-surfaces-agent-writes` +
|
|
14
|
+
`ui-surfaces-scope` (+ suite), which earlier re-syncs missed; the app imports both.
|
|
15
|
+
- Consumer action: none.
|
|
16
|
+
|
|
17
|
+
## 0.3.0 — 2026-10-07
|
|
18
|
+
|
|
19
|
+
ALC-19: the chat clipboard slot is content-shaped.
|
|
20
|
+
|
|
21
|
+
- Host UI slot `copyToClipboard` (`host/ui-slots`) is renamed `copyContent(content, options)`; its stand-in copies a string as text (anything else as JSON) through `@ai-matrx/kit/clipboard` and calls `options.onError` on failure. `agent-copy/clipboard` no longer exports the failure-swallowing `writeClipboard` (only `approxTokens`).
|
|
22
|
+
- Consumer action: register `copyContent` (not `copyToClipboard`) in `registerChatUi`; import `copyContent` from `@ai-matrx/chat/host/ui-slots`; replace any `writeClipboard` import with `@ai-matrx/kit/clipboard` `copyText`.
|
|
23
|
+
|
|
24
|
+
## 0.2.10 — 2026-10-07
|
|
25
|
+
### Re-sync before matrx-frontend consumes the published package (P27)
|
|
26
|
+
|
|
27
|
+
- Carries every matrx-frontend `packages/chat` edit made after base `f5f30ae893` (32 files): ALC-18 live
|
|
28
|
+
values reach the surface scope and the clicked row's declared item, ALC-19 kit copy/`host/clipboard`,
|
|
29
|
+
board chat keeps its conversation id across a reload, voices read from `@ai-matrx/media/voices`,
|
|
30
|
+
remarks durability-port announcement.
|
|
31
|
+
- Their `@/lib/toast` imports use the package notify port and their `agent-copy/export` download imports
|
|
32
|
+
use `@ai-matrx/kit/download` (0.2.9 dropped the chat copy). Public "Save as file" passes the text,
|
|
33
|
+
not a pre-built Blob, so the saved file holds the markdown.
|
|
34
|
+
- Consumer action: none.
|
|
35
|
+
|
|
3
36
|
## 0.2.9 — 2026-10-07
|
|
4
37
|
|
|
5
38
|
ALC-19: the download door moved to the base package.
|
|
6
39
|
|
|
7
40
|
- `agent-copy/export` no longer exports `downloadFile` / `downloadUrl`; they live in `@ai-matrx/kit/download` (kit 0.26.0).
|
|
8
41
|
- Consumer action: import `downloadFile` / `downloadUrl` from `@ai-matrx/kit/download`.
|
|
42
|
+
- The audio-response download, the public chat "save as file" and tool-result file links save through kit's door too (no hand-built anchors left in the package).
|
|
9
43
|
|
|
10
44
|
## 0.2.8 — 2026-10-07
|
|
11
45
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared
|
|
3
|
-
*
|
|
4
|
-
* never re-roll a clipboard write or a token estimate at a callsite.
|
|
2
|
+
* Shared payload-size helper for the agent-copy primitives. Clipboard writes go through
|
|
3
|
+
* `@ai-matrx/kit/clipboard`; never re-roll a token estimate at a callsite.
|
|
5
4
|
*/
|
|
6
|
-
export declare function writeClipboard(text: string): Promise<void>;
|
|
7
5
|
/** Rough token estimate (chars / 4) — same convention as the Groomer window. */
|
|
8
6
|
export declare function approxTokens(text: string): number;
|
|
@@ -1,19 +1,6 @@
|
|
|
1
|
-
async function writeClipboard(text) {
|
|
2
|
-
try {
|
|
3
|
-
await navigator.clipboard.writeText(text);
|
|
4
|
-
} catch {
|
|
5
|
-
const textarea = document.createElement("textarea");
|
|
6
|
-
textarea.value = text;
|
|
7
|
-
document.body.appendChild(textarea);
|
|
8
|
-
textarea.select();
|
|
9
|
-
document.execCommand("copy");
|
|
10
|
-
document.body.removeChild(textarea);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
1
|
function approxTokens(text) {
|
|
14
2
|
return Math.ceil(text.length / 4);
|
|
15
3
|
}
|
|
16
4
|
export {
|
|
17
|
-
approxTokens
|
|
18
|
-
writeClipboard
|
|
5
|
+
approxTokens
|
|
19
6
|
};
|
|
@@ -16,67 +16,15 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import type { AgentPayloadInput } from "@ai-matrx/alchemy/operate";
|
|
18
18
|
import type { AlchemyGroomerConfig } from "@ai-matrx/alchemy/react/workspace";
|
|
19
|
-
|
|
19
|
+
import { mergeLiveCapture, type LiveCapture, type LiveCaptureKind, type LiveCaptureValue, type LiveContribution, type LiveNamed, type LiveRequest, type LiveSection } from "@ai-matrx/alchemy/surface";
|
|
20
|
+
export type PageCaptureKind = LiveCaptureKind;
|
|
20
21
|
/** A chosen thing, by name and id. Either may be null (not chosen / not loaded). */
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export type
|
|
26
|
-
export
|
|
27
|
-
/** Stable id — the Groomer's section id. Unique within one capture. */
|
|
28
|
-
id: string;
|
|
29
|
-
/** What the person calls this part of the page. */
|
|
30
|
-
title: string;
|
|
31
|
-
description?: string;
|
|
32
|
-
/** `data` survives "Only the data"; `request` does not. */
|
|
33
|
-
role: "data" | "request";
|
|
34
|
-
value: unknown;
|
|
35
|
-
/** The one-line brief (counts, a sentence). Defaults to the value's shape. */
|
|
36
|
-
brief?: unknown;
|
|
37
|
-
/**
|
|
38
|
-
* A section too big to hold on the page (a table's records): `value` is the
|
|
39
|
-
* honest stub saying it is not included, and `load` reads it at copy time for
|
|
40
|
-
* the "with …" variants. Never a second read while the page is only open.
|
|
41
|
-
*/
|
|
42
|
-
load?: () => Promise<unknown>;
|
|
43
|
-
}
|
|
44
|
-
export interface PageCaptureRequest {
|
|
45
|
-
method: string;
|
|
46
|
-
path: string;
|
|
47
|
-
status: string;
|
|
48
|
-
httpStatus?: number;
|
|
49
|
-
durationMs?: number;
|
|
50
|
-
requestId?: string;
|
|
51
|
-
/** Which client door (supabase-rest, supabase-rpc, aidream, next-api …). */
|
|
52
|
-
client?: string;
|
|
53
|
-
/** The JSON request body under 8 KB, credentials redacted. */
|
|
54
|
-
requestBody?: unknown;
|
|
55
|
-
requestBodyNote?: string;
|
|
56
|
-
/** A failed request's own sentence from the server (the refusal, verbatim). */
|
|
57
|
-
errorSentence?: string;
|
|
58
|
-
timestamp: number;
|
|
59
|
-
}
|
|
60
|
-
export interface PageCapture {
|
|
61
|
-
kind: PageCaptureKind;
|
|
62
|
-
title: string;
|
|
63
|
-
route: string;
|
|
64
|
-
url?: string;
|
|
65
|
-
/** What this page is OF (table, record, dialog subject …), names and ids. */
|
|
66
|
-
identity: Record<string, PageCaptureValue>;
|
|
67
|
-
/** The exact choices the person made on the page, in order. */
|
|
68
|
-
selection: Record<string, PageCaptureValue>;
|
|
69
|
-
sections: PageCaptureSection[];
|
|
70
|
-
/** The error sentences on screen, verbatim. */
|
|
71
|
-
errors: string[];
|
|
72
|
-
requests: PageCaptureRequest[];
|
|
73
|
-
}
|
|
74
|
-
export interface PageCaptureContribution {
|
|
75
|
-
owner: string;
|
|
76
|
-
sections: PageCaptureSection[];
|
|
77
|
-
/** Names a descendant knows and the page does not (a table's name read inside its mount). */
|
|
78
|
-
identity?: Record<string, PageCaptureValue>;
|
|
79
|
-
}
|
|
22
|
+
export type PageCaptureNamed = LiveNamed;
|
|
23
|
+
export type PageCaptureValue = LiveCaptureValue;
|
|
24
|
+
export type PageCaptureSection = LiveSection;
|
|
25
|
+
export type PageCaptureRequest = LiveRequest;
|
|
26
|
+
export type PageCapture = LiveCapture;
|
|
27
|
+
export type PageCaptureContribution = LiveContribution;
|
|
80
28
|
/** The marker a cycle leaves where the repeated object would have been. */
|
|
81
29
|
export declare const CIRCULAR_MARKER_PREFIX = "[circular reference to ";
|
|
82
30
|
/** A JSON pointer path in words: `/sections/1/load` → `sections › 1 › load`; root is "the capture itself". */
|
|
@@ -95,9 +43,10 @@ export declare function checkedTransferJson<T>(value: T, what: string): T;
|
|
|
95
43
|
/** `Name (id)`, `Name`, `(id)`, or "not chosen". */
|
|
96
44
|
export declare function describeValue(v: PageCaptureValue): string;
|
|
97
45
|
/** Merge descendant sections into a capture. Two owners claiming one id is a loud error. */
|
|
98
|
-
|
|
46
|
+
/** The page's capture plus its descendants' contributions — alchemy's one merge. */
|
|
47
|
+
export declare const mergePageCapture: typeof mergeLiveCapture;
|
|
99
48
|
/**
|
|
100
|
-
* THE CAPTURE MADE PLAIN AT
|
|
49
|
+
* THE CAPTURE MADE PLAIN AT READ (`getActivePageCapture` calls this): identity, selection,
|
|
101
50
|
* every section's value and brief, and every request body are plain JSON. A section's `load` stays a
|
|
102
51
|
* function — it is how the "with …" copies read — and is never handed to a transfer (see
|
|
103
52
|
* `pageCaptureJson`).
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { formatCount } from "@ai-matrx/kit/format";
|
|
2
|
+
import {
|
|
3
|
+
mergeLiveCapture
|
|
4
|
+
} from "@ai-matrx/alchemy/surface";
|
|
2
5
|
const COMPACT_CHARS = 6e3;
|
|
3
6
|
const CIRCULAR_MARKER_PREFIX = "[circular reference to ";
|
|
4
7
|
function pathInWords(path) {
|
|
@@ -118,28 +121,7 @@ function compactValue(value) {
|
|
|
118
121
|
preview: text.slice(0, COMPACT_CHARS)
|
|
119
122
|
};
|
|
120
123
|
}
|
|
121
|
-
|
|
122
|
-
const owners = new Map(base.sections.map((s) => [s.id, "page"]));
|
|
123
|
-
const sections = [...base.sections];
|
|
124
|
-
const identity = { ...base.identity };
|
|
125
|
-
for (const c of contributions) {
|
|
126
|
-
for (const [k, v] of Object.entries(c.identity ?? {})) {
|
|
127
|
-
const prior = identity[k];
|
|
128
|
-
if (prior === void 0 || prior === null || isNamed(prior) && !prior.name) identity[k] = v;
|
|
129
|
-
}
|
|
130
|
-
for (const s of c.sections) {
|
|
131
|
-
const prior = owners.get(s.id);
|
|
132
|
-
if (prior) {
|
|
133
|
-
throw new Error(
|
|
134
|
-
`[page-capture] section "${s.id}" is claimed by both "${prior}" and "${c.owner}"`
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
owners.set(s.id, c.owner);
|
|
138
|
-
sections.push(s);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return { ...base, identity, sections };
|
|
142
|
-
}
|
|
124
|
+
const mergePageCapture = mergeLiveCapture;
|
|
143
125
|
function plainNamedRecord(rec) {
|
|
144
126
|
return toPlainJson(rec);
|
|
145
127
|
}
|
|
@@ -192,6 +174,7 @@ function envelopeContext(c) {
|
|
|
192
174
|
return {
|
|
193
175
|
page: c.title,
|
|
194
176
|
"surface-kind": c.kind,
|
|
177
|
+
...c.surfaceName ? { surface: c.surfaceName } : {},
|
|
195
178
|
route: c.route,
|
|
196
179
|
...keyed(describeRecord(c.identity)),
|
|
197
180
|
...keyed(describeRecord(c.selection))
|
|
@@ -32,7 +32,7 @@ import { setConversationDocumentEnabledThunk } from "../../redux/execution-syste
|
|
|
32
32
|
import { setScratchpadGateThunk } from "../../redux/execution-system/instance-working-document/scratchpad.thunks.js";
|
|
33
33
|
import { useActiveContextLayerItems } from "../context-items/useActiveContextLayerItems.js";
|
|
34
34
|
import { docKindForContextKey } from "../../utils/workingDocumentContext.js";
|
|
35
|
-
import {
|
|
35
|
+
import { CopyButtons } from "../../../host/ui-slots.js";
|
|
36
36
|
import { cn } from "@ai-matrx/design-system";
|
|
37
37
|
import { contextEntryLabel } from "../context-policies-display/contextEntryLabel.js";
|
|
38
38
|
const COPY_REVEAL = "opacity-0 transition-opacity pointer-coarse:opacity-100";
|
|
@@ -196,11 +196,12 @@ function AttachedContextSection({
|
|
|
196
196
|
k
|
|
197
197
|
)) }),
|
|
198
198
|
/* @__PURE__ */ jsx(
|
|
199
|
-
|
|
199
|
+
CopyButtons,
|
|
200
200
|
{
|
|
201
|
-
|
|
201
|
+
label: "Copy",
|
|
202
|
+
json: variables,
|
|
202
203
|
size: "xs",
|
|
203
|
-
className: cn(COPY_REVEAL, "group-hover/vars:opacity-100")
|
|
204
|
+
className: cn("absolute top-1 right-1 z-10", COPY_REVEAL, "group-hover/vars:opacity-100")
|
|
204
205
|
}
|
|
205
206
|
)
|
|
206
207
|
] }),
|
|
@@ -285,12 +286,12 @@ function AttachedContextSection({
|
|
|
285
286
|
/* @__PURE__ */ jsx("span", { className: "italic text-muted-foreground", children: "(empty \u2014 sent, but has no content yet)" })
|
|
286
287
|
) }),
|
|
287
288
|
/* @__PURE__ */ jsx(
|
|
288
|
-
|
|
289
|
+
CopyButtons,
|
|
289
290
|
{
|
|
290
|
-
|
|
291
|
-
|
|
291
|
+
label: "Copy",
|
|
292
|
+
human: item.preview,
|
|
292
293
|
size: "xs",
|
|
293
|
-
className: cn(COPY_REVEAL, "group-hover/entry:opacity-100")
|
|
294
|
+
className: cn("absolute top-1 right-1 z-10", COPY_REVEAL, "group-hover/entry:opacity-100")
|
|
294
295
|
}
|
|
295
296
|
)
|
|
296
297
|
] }, item.key);
|
|
@@ -9,7 +9,7 @@ import { Skeleton } from "@ai-matrx/design-system";
|
|
|
9
9
|
import { Badge, Button, Chip } from "@ai-matrx/design-system/controls";
|
|
10
10
|
import { Textarea } from "@ai-matrx/design-system";
|
|
11
11
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../../ui/tabs.js";
|
|
12
|
-
import {
|
|
12
|
+
import { CopyButtons } from "../../../host/ui-slots.js";
|
|
13
13
|
import { RichContent } from "../../../host/ui-slots.js";
|
|
14
14
|
import { SystemItemsLine } from "./SystemItemsLine.js";
|
|
15
15
|
import { useAppDispatch, useAppSelector } from "../../../store/hooks.js";
|
|
@@ -109,12 +109,12 @@ function Block({
|
|
|
109
109
|
) : block ? /* @__PURE__ */ jsxs("div", { className: "group/block relative mt-1.5", children: [
|
|
110
110
|
/* @__PURE__ */ jsx("pre", { "data-kind-source": "explicit", className: "whitespace-pre-wrap break-words rounded-md border border-border bg-muted/40 px-2.5 py-2 font-mono text-[11px] leading-relaxed text-foreground", children: block }),
|
|
111
111
|
/* @__PURE__ */ jsx(
|
|
112
|
-
|
|
112
|
+
CopyButtons,
|
|
113
113
|
{
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
label: "Copy",
|
|
115
|
+
human: block,
|
|
116
116
|
size: "sm",
|
|
117
|
-
className: "opacity-0 transition-opacity pointer-coarse:opacity-100 group-hover/block:opacity-100"
|
|
117
|
+
className: "absolute top-1 right-1 z-10 opacity-0 transition-opacity pointer-coarse:opacity-100 group-hover/block:opacity-100"
|
|
118
118
|
}
|
|
119
119
|
)
|
|
120
120
|
] }) : /* @__PURE__ */ jsx("div", { className: "mt-1.5 rounded-md border border-border bg-muted/30 px-2.5 py-2 text-xs italic text-muted-foreground", children: "No block \u2014 this side delivers no context for this selection." }),
|
|
@@ -141,12 +141,12 @@ function FedBlock({ label, text, slot }) {
|
|
|
141
141
|
text ? /* @__PURE__ */ jsxs("div", { className: "group/block relative mt-1", children: [
|
|
142
142
|
/* @__PURE__ */ jsx("pre", { "data-kind-source": "explicit", className: "max-h-[28rem] overflow-auto whitespace-pre-wrap break-words rounded-md border border-border bg-muted/40 px-2.5 py-2 font-mono text-[11px] leading-relaxed text-foreground", children: text }),
|
|
143
143
|
/* @__PURE__ */ jsx(
|
|
144
|
-
|
|
144
|
+
CopyButtons,
|
|
145
145
|
{
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
label: "Copy",
|
|
147
|
+
human: text,
|
|
148
148
|
size: "sm",
|
|
149
|
-
className: "opacity-0 transition-opacity pointer-coarse:opacity-100 group-hover/block:opacity-100"
|
|
149
|
+
className: "absolute top-1 right-1 z-10 opacity-0 transition-opacity pointer-coarse:opacity-100 group-hover/block:opacity-100"
|
|
150
150
|
}
|
|
151
151
|
)
|
|
152
152
|
] }) : /* @__PURE__ */ jsxs("p", { className: "mt-1 rounded-md border border-border bg-muted/30 px-2.5 py-2 text-xs italic text-muted-foreground", children: [
|
|
@@ -278,12 +278,12 @@ function JsonBlock({ label, value, slot }) {
|
|
|
278
278
|
/* @__PURE__ */ jsxs("div", { className: "group/block relative mt-1", children: [
|
|
279
279
|
/* @__PURE__ */ jsx("pre", { "data-kind-source": "explicit", className: "overflow-auto whitespace-pre-wrap break-all rounded-md border border-border bg-muted/40 px-2.5 py-2 font-mono text-[11px] leading-relaxed text-foreground", children: text }),
|
|
280
280
|
/* @__PURE__ */ jsx(
|
|
281
|
-
|
|
281
|
+
CopyButtons,
|
|
282
282
|
{
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
label: "Copy",
|
|
284
|
+
human: text,
|
|
285
285
|
size: "sm",
|
|
286
|
-
className: "opacity-0 transition-opacity pointer-coarse:opacity-100 group-hover/block:opacity-100"
|
|
286
|
+
className: "absolute top-1 right-1 z-10 opacity-0 transition-opacity pointer-coarse:opacity-100 group-hover/block:opacity-100"
|
|
287
287
|
}
|
|
288
288
|
)
|
|
289
289
|
] })
|
|
@@ -5,7 +5,7 @@ import { AlertTriangle, Braces, FileCode2, RefreshCw } from "lucide-react";
|
|
|
5
5
|
import { cn } from "@ai-matrx/design-system";
|
|
6
6
|
import { Skeleton } from "@ai-matrx/design-system";
|
|
7
7
|
import { Badge, Button, Chip, SegmentedControl } from "@ai-matrx/design-system/controls";
|
|
8
|
-
import {
|
|
8
|
+
import { CopyButtons } from "../../../host/ui-slots.js";
|
|
9
9
|
import { useAppSelector } from "../../../store/hooks.js";
|
|
10
10
|
import { SurfaceRuntimeProvider } from "../../../surfaces/runtime/SurfaceRuntimeContext.js";
|
|
11
11
|
import {
|
|
@@ -68,12 +68,12 @@ function VariableGroup({
|
|
|
68
68
|
] }),
|
|
69
69
|
/* @__PURE__ */ jsx("div", { className: "mt-1 whitespace-pre-wrap break-words rounded bg-muted/40 px-2 py-1 font-mono text-[11px] leading-relaxed text-foreground/90", children: f.value || /* @__PURE__ */ jsx("span", { className: "italic text-muted-foreground", children: "(empty)" }) }),
|
|
70
70
|
/* @__PURE__ */ jsx(
|
|
71
|
-
|
|
71
|
+
CopyButtons,
|
|
72
72
|
{
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
label: "Copy",
|
|
74
|
+
human: f.value,
|
|
75
75
|
size: "xs",
|
|
76
|
-
className: "opacity-0 transition-opacity pointer-coarse:opacity-100 group-hover/var:opacity-100"
|
|
76
|
+
className: "absolute top-1 right-1 z-10 opacity-0 transition-opacity pointer-coarse:opacity-100 group-hover/var:opacity-100"
|
|
77
77
|
}
|
|
78
78
|
)
|
|
79
79
|
] }, key);
|
|
@@ -201,12 +201,12 @@ function ResolvedView({
|
|
|
201
201
|
className: "relative h-7 w-7 shrink-0",
|
|
202
202
|
title: "Copy everything the agent receives",
|
|
203
203
|
children: /* @__PURE__ */ jsx(
|
|
204
|
-
|
|
204
|
+
CopyButtons,
|
|
205
205
|
{
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
label: "Copy all for AI",
|
|
207
|
+
human: copyAllText,
|
|
208
208
|
size: "sm",
|
|
209
|
-
|
|
209
|
+
className: "absolute top-1 right-1 z-10"
|
|
210
210
|
}
|
|
211
211
|
)
|
|
212
212
|
}
|
|
@@ -286,12 +286,12 @@ function ResolvedBody({
|
|
|
286
286
|
block ? /* @__PURE__ */ jsxs("div", { className: "group/block relative mt-1.5", children: [
|
|
287
287
|
/* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap break-words rounded-md border border-primary/20 bg-muted/40 px-2.5 py-2 font-mono text-[11px] leading-relaxed text-foreground", children: block }),
|
|
288
288
|
/* @__PURE__ */ jsx(
|
|
289
|
-
|
|
289
|
+
CopyButtons,
|
|
290
290
|
{
|
|
291
|
-
|
|
292
|
-
|
|
291
|
+
label: "Copy",
|
|
292
|
+
human: block,
|
|
293
293
|
size: "sm",
|
|
294
|
-
className: "opacity-0 transition-opacity pointer-coarse:opacity-100 group-hover/block:opacity-100"
|
|
294
|
+
className: "absolute top-1 right-1 z-10 opacity-0 transition-opacity pointer-coarse:opacity-100 group-hover/block:opacity-100"
|
|
295
295
|
}
|
|
296
296
|
)
|
|
297
297
|
] }) : /* @__PURE__ */ jsx("div", { className: "mt-1.5 rounded-md border border-border bg-muted/30 px-2.5 py-2 text-xs italic text-muted-foreground", children: "No block would be injected \u2014 no organization or scopes active." }),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { toast } from "../../../host/notify.js";
|
|
2
|
+
import { copyToHostClipboard } from "../../../host/clipboard.js";
|
|
2
3
|
import { toastDoor } from "../../../host/ui-slots.js";
|
|
3
4
|
import { openOverlay, CHAT_WINDOWS } from "../../../host/windows.js";
|
|
4
5
|
import {
|
|
@@ -23,12 +24,7 @@ function resolveAbsoluteHref(href) {
|
|
|
23
24
|
return `${window.location.origin}${href.startsWith("/") ? href : `/${href}`}`;
|
|
24
25
|
}
|
|
25
26
|
async function copyConversationLink(href) {
|
|
26
|
-
|
|
27
|
-
await navigator.clipboard.writeText(resolveAbsoluteHref(href));
|
|
28
|
-
toast.success("Link copied");
|
|
29
|
-
} catch {
|
|
30
|
-
toast.error("Couldn't copy \u2014 your browser blocked clipboard access");
|
|
31
|
-
}
|
|
27
|
+
await copyToHostClipboard(resolveAbsoluteHref(href), "Link copied");
|
|
32
28
|
}
|
|
33
29
|
function shareConversation(dispatch, conversationId, title) {
|
|
34
30
|
dispatch(
|
|
@@ -50,7 +50,7 @@ function SandboxFileViewer({
|
|
|
50
50
|
}, [initialPath, sandboxRowId, load]);
|
|
51
51
|
const handleCopy = async () => {
|
|
52
52
|
if (content == null) return;
|
|
53
|
-
await copyText(content);
|
|
53
|
+
if (!await copyText(content)) return;
|
|
54
54
|
setCopied(true);
|
|
55
55
|
toast.success("File contents copied");
|
|
56
56
|
setTimeout(() => setCopied(false), 1500);
|
|
@@ -55,8 +55,8 @@ function useCopy() {
|
|
|
55
55
|
notify: (message, kind) => kind === "error" ? toast.error(message) : toast.success(message)
|
|
56
56
|
});
|
|
57
57
|
const [copied, setCopied] = useState(null);
|
|
58
|
-
const copy = (text, id) => {
|
|
59
|
-
copyText(text);
|
|
58
|
+
const copy = async (text, id) => {
|
|
59
|
+
if (!await copyText(text)) return;
|
|
60
60
|
setCopied(id);
|
|
61
61
|
setTimeout(() => setCopied(null), 1500);
|
|
62
62
|
};
|
|
@@ -68,7 +68,7 @@ function TranscriptIntegrityCopyButtonInner({
|
|
|
68
68
|
effectiveVisibleGroupLimit
|
|
69
69
|
});
|
|
70
70
|
try {
|
|
71
|
-
await copyText(formatTranscriptIntegrityReport(report));
|
|
71
|
+
if (!await copyText(formatTranscriptIntegrityReport(report))) return;
|
|
72
72
|
toast.success(
|
|
73
73
|
report.anomalies.length === 0 ? "Transcript report copied \u2014 no anomalies detected" : `Transcript report copied \u2014 ${report.anomalies.length} anomal${report.anomalies.length === 1 ? "y" : "ies"} flagged`
|
|
74
74
|
);
|
|
@@ -271,9 +271,9 @@ function BufferedObservationCard({
|
|
|
271
271
|
const [copied, setCopied] = useState(false);
|
|
272
272
|
const text = cycle.observations ?? "";
|
|
273
273
|
const hasText = text.length > 0;
|
|
274
|
-
const handleCopy = useCallback(() => {
|
|
274
|
+
const handleCopy = useCallback(async () => {
|
|
275
275
|
if (!hasText) return;
|
|
276
|
-
copyText(text);
|
|
276
|
+
if (!await copyText(text)) return;
|
|
277
277
|
setCopied(true);
|
|
278
278
|
setTimeout(() => setCopied(false), 1500);
|
|
279
279
|
}, [text, hasText]);
|
|
@@ -508,9 +508,9 @@ function TextPayload({
|
|
|
508
508
|
});
|
|
509
509
|
const [copied, setCopied] = useState(false);
|
|
510
510
|
const hasText = typeof text === "string" && text.length > 0;
|
|
511
|
-
const handleCopy = useCallback(() => {
|
|
511
|
+
const handleCopy = useCallback(async () => {
|
|
512
512
|
if (!text) return;
|
|
513
|
-
copyText(text);
|
|
513
|
+
if (!await copyText(text)) return;
|
|
514
514
|
setCopied(true);
|
|
515
515
|
setTimeout(() => setCopied(false), 1500);
|
|
516
516
|
}, [text]);
|
|
@@ -91,9 +91,9 @@ function DirectTestMode({
|
|
|
91
91
|
close,
|
|
92
92
|
conversationId
|
|
93
93
|
]);
|
|
94
|
-
const handleCopy = useCallback(() => {
|
|
94
|
+
const handleCopy = useCallback(async () => {
|
|
95
95
|
if (responseText) {
|
|
96
|
-
copyText(kindTextToMarkdown(responseText));
|
|
96
|
+
if (!await copyText(kindTextToMarkdown(responseText))) return;
|
|
97
97
|
setCopied(true);
|
|
98
98
|
setTimeout(() => setCopied(false), 2e3);
|
|
99
99
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useClipboard } from "@ai-matrx/kit/clipboard";
|
|
4
|
+
import { toast } from "../../../host/notify.js";
|
|
3
5
|
import { Badge, Button } from "@ai-matrx/design-system/controls";
|
|
4
6
|
import { useCallback, useMemo, useState } from "react";
|
|
5
7
|
import { Copy, Check } from "lucide-react";
|
|
@@ -119,6 +121,9 @@ function roledImagesOf(messages) {
|
|
|
119
121
|
return rows;
|
|
120
122
|
}
|
|
121
123
|
function PayloadTab({ conversationId }) {
|
|
124
|
+
const { copyText } = useClipboard({
|
|
125
|
+
notify: (message, kind) => kind === "error" ? toast.error(message) : toast.success(message)
|
|
126
|
+
});
|
|
122
127
|
const assembledRequestSelector = useMemo(
|
|
123
128
|
() => makeSelectAssembledRequest(conversationId),
|
|
124
129
|
[conversationId]
|
|
@@ -163,7 +168,8 @@ function PayloadTab({ conversationId }) {
|
|
|
163
168
|
if (!request) return;
|
|
164
169
|
try {
|
|
165
170
|
const text = JSON.stringify(request, null, 2);
|
|
166
|
-
void
|
|
171
|
+
void copyText(text).then((copied2) => {
|
|
172
|
+
if (!copied2) return;
|
|
167
173
|
setCopied(true);
|
|
168
174
|
window.setTimeout(() => setCopied(false), 1500);
|
|
169
175
|
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useClipboard } from "@ai-matrx/kit/clipboard";
|
|
4
|
+
import { toast } from "../../../../host/notify.js";
|
|
3
5
|
import { formatDurationSeconds } from "@ai-matrx/kit/format";
|
|
4
6
|
import { useState } from "react";
|
|
5
7
|
import { Copy, Check } from "lucide-react";
|
|
@@ -19,9 +21,13 @@ function CopyableValue({
|
|
|
19
21
|
mono = true,
|
|
20
22
|
className
|
|
21
23
|
}) {
|
|
24
|
+
const { copyText } = useClipboard({
|
|
25
|
+
notify: (message, kind) => kind === "error" ? toast.error(message) : toast.success(message)
|
|
26
|
+
});
|
|
22
27
|
const [copied, setCopied] = useState(false);
|
|
23
28
|
const handleCopy = () => {
|
|
24
|
-
void
|
|
29
|
+
void copyText(value).then((copied2) => {
|
|
30
|
+
if (!copied2) return;
|
|
25
31
|
setCopied(true);
|
|
26
32
|
setTimeout(() => setCopied(false), 1200);
|
|
27
33
|
});
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Badge, Button } from "@ai-matrx/design-system/controls";
|
|
4
4
|
import { useState } from "react";
|
|
5
|
-
import { Save, Loader2, AlertTriangle, Eye } from "lucide-react";
|
|
5
|
+
import { Save, Loader2, AlertTriangle, Eye, Undo2 } from "lucide-react";
|
|
6
|
+
import { useAppDispatch } from "../../../store/hooks.js";
|
|
7
|
+
import { resetAllAgentFields } from "../../redux/agent-definition/slice.js";
|
|
6
8
|
import { useChatCanvasTab } from "../../../host/canvas.js";
|
|
7
9
|
import { AGENT_UNSAVED_CHANGES_KIND } from "../../../host/canvas-tabs.js";
|
|
8
10
|
import { cn } from "@ai-matrx/design-system";
|
|
@@ -41,7 +43,9 @@ function AgentSaveStatus({
|
|
|
41
43
|
reachBadge,
|
|
42
44
|
available
|
|
43
45
|
} = useAgentSaveAction(agentId, { editModeOverride });
|
|
46
|
+
const dispatch = useAppDispatch();
|
|
44
47
|
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
48
|
+
const [confirmDiscardOpen, setConfirmDiscardOpen] = useState(false);
|
|
45
49
|
const diffTab = useChatCanvasTab({ kind: AGENT_UNSAVED_CHANGES_KIND, key: agentId });
|
|
46
50
|
const handleSelectModel = () => {
|
|
47
51
|
setShowModelWarning(false);
|
|
@@ -67,6 +71,7 @@ function AgentSaveStatus({
|
|
|
67
71
|
isEditMode && isDirty && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
68
72
|
/* @__PURE__ */ jsx(Badge, { tone: "warning", children: isNewRoute ? "Not saved" : "Unsaved" }),
|
|
69
73
|
/* @__PURE__ */ jsx(ErrorAlchemyMenu, {}),
|
|
74
|
+
!isNewRoute && /* @__PURE__ */ jsx(Button, { variant: "quiet", icon: /* @__PURE__ */ jsx(Undo2, {}), onClick: () => setConfirmDiscardOpen(true), disabled: isLoading, title: "Discard unsaved changes", "aria-label": "Discard unsaved changes" }),
|
|
70
75
|
!isNewRoute && /* @__PURE__ */ jsx(Button, { variant: "quiet", pressed: diffTab.isVisible, icon: /* @__PURE__ */ jsx(Eye, {}), onClick: () => diffTab.toggle({ title: "Unsaved changes", data: { agentId } }), title: "View unsaved changes", "aria-label": "View unsaved changes" })
|
|
71
76
|
] }),
|
|
72
77
|
isEditMode && /* @__PURE__ */ jsx(Button, { variant: "quiet", icon: isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "animate-spin" }) : /* @__PURE__ */ jsx(Save, {}), onClick: handleSave, disabled: !canSave, title: isReadOnlySave ? "View only \u2014 create your copy to save changes" : isNewRoute ? "Save new agent" : isDirty ? "Save changes" : "No unsaved changes", "aria-label": isReadOnlySave ? "View only \u2014 create your copy to save changes" : isNewRoute ? "Save new agent" : isDirty ? "Save changes" : "No unsaved changes" }),
|
|
@@ -90,6 +95,22 @@ function AgentSaveStatus({
|
|
|
90
95
|
/* @__PURE__ */ jsx(AlertDialogAction, { onClick: handleSelectModel, children: "Select a Model" })
|
|
91
96
|
] })
|
|
92
97
|
] }) }),
|
|
98
|
+
/* @__PURE__ */ jsx(AlertDialog, { open: confirmDiscardOpen, onOpenChange: setConfirmDiscardOpen, children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
|
|
99
|
+
/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
|
|
100
|
+
/* @__PURE__ */ jsx(AlertDialogTitle, { children: "Discard unsaved changes?" }),
|
|
101
|
+
/* @__PURE__ */ jsx(AlertDialogDescription, { children: "The agent goes back to its last saved version." })
|
|
102
|
+
] }),
|
|
103
|
+
/* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
|
|
104
|
+
/* @__PURE__ */ jsx(AlertDialogCancel, { children: "Keep editing" }),
|
|
105
|
+
/* @__PURE__ */ jsx(
|
|
106
|
+
AlertDialogAction,
|
|
107
|
+
{
|
|
108
|
+
onClick: () => dispatch(resetAllAgentFields({ id: agentId })),
|
|
109
|
+
children: "Discard"
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
] })
|
|
113
|
+
] }) }),
|
|
93
114
|
/* @__PURE__ */ jsx(
|
|
94
115
|
AgentSettingsModal,
|
|
95
116
|
{
|
|
@@ -8,7 +8,10 @@ import {
|
|
|
8
8
|
selectAgentIsReadOnly,
|
|
9
9
|
selectAgentAccessResolved
|
|
10
10
|
} from "../redux/agent-definition/selectors.js";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
resetAllAgentFields,
|
|
13
|
+
setAgentField
|
|
14
|
+
} from "../redux/agent-definition/slice.js";
|
|
12
15
|
import { readField } from "@ai-matrx/agents/field-flags";
|
|
13
16
|
import { toast } from "../../host/notify.js";
|
|
14
17
|
const STORAGE_PREFIX = "agent-autosave:";
|
|
@@ -65,7 +68,16 @@ function useAgentAutoSave(agentId) {
|
|
|
65
68
|
if (restored.length > 0) {
|
|
66
69
|
restoredRef.current = true;
|
|
67
70
|
toast.info(
|
|
68
|
-
`Restored unsaved changes to ${record.name || "this agent"} from this browser (${restored.join(", ")}). Save to keep them, or
|
|
71
|
+
`Restored unsaved changes to ${record.name || "this agent"} from this browser (${restored.join(", ")}). Save to keep them, or discard them.`,
|
|
72
|
+
{
|
|
73
|
+
id: `agent-autosave-restored:${agentId}`,
|
|
74
|
+
duration: 2e4,
|
|
75
|
+
action: {
|
|
76
|
+
label: "Discard",
|
|
77
|
+
// Back to the saved agent; the clean-state effect drops the backup.
|
|
78
|
+
onClick: () => dispatch(resetAllAgentFields({ id: agentId }))
|
|
79
|
+
}
|
|
80
|
+
}
|
|
69
81
|
);
|
|
70
82
|
}
|
|
71
83
|
}, [agentId, record, fetchStatus, dispatch]);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Cpu, Copy, RefreshCw, ExternalLink } from "lucide-react";
|
|
3
|
-
import {
|
|
3
|
+
import { copyToHostClipboard } from "../../host/clipboard.js";
|
|
4
4
|
import {
|
|
5
5
|
withAvailability
|
|
6
6
|
} from "../../context-menu/utils/availability.js";
|
|
@@ -30,8 +30,7 @@ function buildAgentMenuSection({
|
|
|
30
30
|
label: "Copy agent ID",
|
|
31
31
|
icon: Copy,
|
|
32
32
|
onSelect: () => {
|
|
33
|
-
void
|
|
34
|
-
toast.success("Agent ID copied");
|
|
33
|
+
void copyToHostClipboard(agentId, "Agent ID copied");
|
|
35
34
|
}
|
|
36
35
|
},
|
|
37
36
|
{
|
|
@@ -41,8 +40,7 @@ function buildAgentMenuSection({
|
|
|
41
40
|
icon: Copy,
|
|
42
41
|
disabled: !agentName,
|
|
43
42
|
onSelect: () => {
|
|
44
|
-
void
|
|
45
|
-
toast.success("Agent name copied");
|
|
43
|
+
void copyToHostClipboard(agentName ?? "", "Agent name copied");
|
|
46
44
|
}
|
|
47
45
|
},
|
|
48
46
|
{ kind: "separator", id: "agent-sep-1" },
|