@ai-matrx/chat 0.3.4 → 0.3.5
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 +13 -0
- package/dist/agents/components/inputs/smart-input/RunControlsMenu.js +1 -1
- package/dist/agents/components/inputs/smart-input/composer/ComposerAgentPeek.d.ts +4 -0
- package/dist/agents/components/inputs/smart-input/composer/ComposerAgentPeek.js +50 -0
- package/dist/agents/components/inputs/smart-input/composer/ComposerAgentPill.js +16 -1
- package/dist/agents/components/shared/AgentPeekDuplicateButton.d.ts +5 -0
- package/dist/agents/components/shared/AgentPeekDuplicateButton.js +65 -0
- package/dist/window-panels/windows/agents/RunControlsWindow.js +19 -6
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @ai-matrx/chat
|
|
2
2
|
|
|
3
|
+
## 0.3.5 — 2026-10-07
|
|
4
|
+
### Chat mode opens the agent itself; Duplicate opens the copy in a new tab
|
|
5
|
+
|
|
6
|
+
- The Chat-mode agent pill's menu starts with "This chat's agent": its row opens the agent menu's own
|
|
7
|
+
peek card (`AgentDetailCard`) — view, open, Sneak Peek, and Duplicate when the agent is not yours.
|
|
8
|
+
- `agents/components/shared/AgentPeekDuplicateButton` moved here from matrx-frontend (one Duplicate for
|
|
9
|
+
every peek). It now opens the copy's page in a NEW TAB instead of navigating away from the chat.
|
|
10
|
+
- Needs `@ai-matrx/agents` 0.49.0.
|
|
11
|
+
- The composer's + (Chat Options) is tinted only when something was added — no longer blue on every fresh
|
|
12
|
+
chat. The Chat Options window lists its sections as start-aligned rows (`Tile`), not centred buttons.
|
|
13
|
+
- Consumer action: import `AgentPeekDuplicateButton` from
|
|
14
|
+
`@ai-matrx/chat/agents/components/shared/AgentPeekDuplicateButton` and delete the app's copy.
|
|
15
|
+
|
|
3
16
|
## 0.3.4 — 2026-10-07
|
|
4
17
|
### Re-sync before matrx-frontend consumes the published package (P27)
|
|
5
18
|
|
|
@@ -89,7 +89,7 @@ function RunControlsMenu({
|
|
|
89
89
|
Button,
|
|
90
90
|
{
|
|
91
91
|
variant: "quiet",
|
|
92
|
-
tone: rc.addedCount > 0
|
|
92
|
+
tone: rc.addedCount > 0 ? "primary" : void 0,
|
|
93
93
|
icon: /* @__PURE__ */ jsx(TriggerIcon, {}),
|
|
94
94
|
tabIndex: variant === "plus" ? -1 : void 0,
|
|
95
95
|
title: "Chat Options",
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { AgentDetailCard, useAgentCatalogState } from "@ai-matrx/agents/catalog/react";
|
|
5
|
+
import { useAppDispatch, useAppSelector } from "../../../../../store/hooks.js";
|
|
6
|
+
import { selectAgentById, selectAgentReadyForBuilder } from "../../../../redux/agent-definition/selectors.js";
|
|
7
|
+
import { fetchFullAgent } from "../../../../redux/agent-definition/thunks.js";
|
|
8
|
+
import { AgentPeekDuplicateButton } from "../../../shared/AgentPeekDuplicateButton.js";
|
|
9
|
+
function ComposerAgentPeek({ agentId, onDone }) {
|
|
10
|
+
const dispatch = useAppDispatch();
|
|
11
|
+
const row = useAgentCatalogState((state) => state.byId[agentId]);
|
|
12
|
+
const record = useAppSelector((state) => selectAgentById(state, agentId));
|
|
13
|
+
const isReady = useAppSelector((state) => selectAgentReadyForBuilder(state, agentId));
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (!isReady) void dispatch(fetchFullAgent(agentId)).unwrap().catch(() => void 0);
|
|
16
|
+
}, [dispatch, agentId, isReady]);
|
|
17
|
+
const agent = row ?? (record ? {
|
|
18
|
+
id: record.id,
|
|
19
|
+
name: record.name,
|
|
20
|
+
description: record.description,
|
|
21
|
+
category: record.category,
|
|
22
|
+
tags: record.tags,
|
|
23
|
+
agentType: record.agentType,
|
|
24
|
+
modelId: record.modelId,
|
|
25
|
+
isActive: record.isActive,
|
|
26
|
+
isArchived: record.isArchived,
|
|
27
|
+
isFavorite: record.isFavorite,
|
|
28
|
+
createdBy: record.createdBy,
|
|
29
|
+
organizationId: record.organizationId,
|
|
30
|
+
taskId: record.taskId,
|
|
31
|
+
sourceAgentId: record.sourceAgentId,
|
|
32
|
+
createdAt: record.createdAt,
|
|
33
|
+
updatedAt: record.updatedAt,
|
|
34
|
+
isOwner: record.isOwner,
|
|
35
|
+
accessLevel: record.accessLevel,
|
|
36
|
+
sharedByEmail: record.sharedByEmail,
|
|
37
|
+
orchestra: null
|
|
38
|
+
} : null);
|
|
39
|
+
if (!agent) return null;
|
|
40
|
+
return /* @__PURE__ */ jsx(
|
|
41
|
+
AgentDetailCard,
|
|
42
|
+
{
|
|
43
|
+
agent,
|
|
44
|
+
actions: /* @__PURE__ */ jsx(AgentPeekDuplicateButton, { agentId, onDuplicated: onDone })
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
ComposerAgentPeek
|
|
50
|
+
};
|
|
@@ -36,6 +36,7 @@ import { composerShows } from "./composer-mode-visibility.js";
|
|
|
36
36
|
import { composerPillClass } from "./composer-chip.js";
|
|
37
37
|
import { useComposerAgent, useEffectiveModelId } from "./useComposerAgent.js";
|
|
38
38
|
import { useComposerAgentFilter } from "./useComposerAgentFilter.js";
|
|
39
|
+
import { ComposerAgentPeek } from "./ComposerAgentPeek.js";
|
|
39
40
|
import { presentOrganizationRefusal } from "../../../../../host/org.js";
|
|
40
41
|
import { ensureOrgId, isOrganizationSelectionCancelled } from "../../../../../host/org.js";
|
|
41
42
|
function pillLabel(info, mode) {
|
|
@@ -150,6 +151,17 @@ function ComposerAgentPill({ conversationId, mode, size, agentControl, menuSide,
|
|
|
150
151
|
)
|
|
151
152
|
] });
|
|
152
153
|
}
|
|
154
|
+
function ThisAgentRow({ info, close }) {
|
|
155
|
+
if (!info.agentId) return null;
|
|
156
|
+
return /* @__PURE__ */ jsx(
|
|
157
|
+
ComposerSubmenu,
|
|
158
|
+
{
|
|
159
|
+
row: { icon: Webhook, label: info.agentName ?? "Agent", description: "View, open or duplicate" },
|
|
160
|
+
panelClassName: "w-[340px] h-[420px] p-0",
|
|
161
|
+
children: /* @__PURE__ */ jsx(ComposerAgentPeek, { agentId: info.agentId, onDone: close })
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
153
165
|
function ChatPresetsPanel({
|
|
154
166
|
conversationId,
|
|
155
167
|
info,
|
|
@@ -169,7 +181,7 @@ function ChatPresetsPanel({
|
|
|
169
181
|
if (!onSelectAgent) {
|
|
170
182
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
171
183
|
/* @__PURE__ */ jsx(ComposerMenuLabel, { children: "Agent" }),
|
|
172
|
-
/* @__PURE__ */ jsx(
|
|
184
|
+
/* @__PURE__ */ jsx(ThisAgentRow, { info, close }),
|
|
173
185
|
/* @__PURE__ */ jsx(ComposerMenuHelp, { children: "This page always answers with this agent." }),
|
|
174
186
|
/* @__PURE__ */ jsx(ComposerMenuDivider, {}),
|
|
175
187
|
/* @__PURE__ */ jsx(ComposerMenuLabel, { children: "Model for this chat" }),
|
|
@@ -229,6 +241,9 @@ function ChatPresetsPanel({
|
|
|
229
241
|
void savePersonalDefault("chat_default_offering", offeringId ?? "");
|
|
230
242
|
};
|
|
231
243
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
244
|
+
/* @__PURE__ */ jsx(ComposerMenuLabel, { children: "This chat's agent" }),
|
|
245
|
+
/* @__PURE__ */ jsx(ThisAgentRow, { info, close }),
|
|
246
|
+
/* @__PURE__ */ jsx(ComposerMenuDivider, {}),
|
|
232
247
|
/* @__PURE__ */ jsx(ComposerMenuLabel, { children: "Chat agents" }),
|
|
233
248
|
info.presets.map((preset) => /* @__PURE__ */ jsx(
|
|
234
249
|
ComposerMenuRow,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { CopyPlus, Loader2 } from "lucide-react";
|
|
5
|
+
import { Button } from "@ai-matrx/design-system/controls";
|
|
6
|
+
import { getUserMessage } from "@ai-matrx/agents/matrx";
|
|
7
|
+
import { useAppDispatch, useAppSelector } from "../../../store/hooks.js";
|
|
8
|
+
import { selectUserId } from "../../../host/identity.js";
|
|
9
|
+
import { getBuilderDoor } from "../../../host/builder-door.js";
|
|
10
|
+
import { toast } from "../../../host/notify.js";
|
|
11
|
+
import { isOrganizationSelectionCancelled } from "../../../host/org.js";
|
|
12
|
+
import { selectAgentById, selectAgentReadyForBuilder } from "../../redux/agent-definition/selectors.js";
|
|
13
|
+
import { agentGoHref } from "../../addressing/agentAddress.js";
|
|
14
|
+
function AgentPeekDuplicateButton({
|
|
15
|
+
agentId,
|
|
16
|
+
onDuplicated
|
|
17
|
+
}) {
|
|
18
|
+
const dispatch = useAppDispatch();
|
|
19
|
+
const userId = useAppSelector(selectUserId);
|
|
20
|
+
const record = useAppSelector((state) => selectAgentById(state, agentId));
|
|
21
|
+
const isReady = useAppSelector((state) => selectAgentReadyForBuilder(state, agentId));
|
|
22
|
+
const [busy, setBusy] = useState(false);
|
|
23
|
+
const door = getBuilderDoor();
|
|
24
|
+
if (!door || !isReady || !record) return null;
|
|
25
|
+
const ownsIt = record.isOwner === true || record.createdBy != null && record.createdBy === userId;
|
|
26
|
+
if (ownsIt) return null;
|
|
27
|
+
const duplicate = async () => {
|
|
28
|
+
if (busy) return;
|
|
29
|
+
setBusy(true);
|
|
30
|
+
const tab = window.open("about:blank", "_blank");
|
|
31
|
+
try {
|
|
32
|
+
const newId = await dispatch(door.duplicateAgent(agentId)).unwrap();
|
|
33
|
+
const href = agentGoHref(newId, "/build");
|
|
34
|
+
if (tab) {
|
|
35
|
+
tab.opener = null;
|
|
36
|
+
tab.location.href = href;
|
|
37
|
+
} else {
|
|
38
|
+
window.open(href, "_blank", "noopener");
|
|
39
|
+
}
|
|
40
|
+
toast.success(`Duplicated "${record.name}" \u2014 opened in a new tab`);
|
|
41
|
+
onDuplicated?.();
|
|
42
|
+
} catch (err) {
|
|
43
|
+
tab?.close();
|
|
44
|
+
if (!isOrganizationSelectionCancelled(err)) {
|
|
45
|
+
toast.error("Could not duplicate agent", { description: getUserMessage(err) });
|
|
46
|
+
}
|
|
47
|
+
} finally {
|
|
48
|
+
setBusy(false);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
return /* @__PURE__ */ jsx(
|
|
52
|
+
Button,
|
|
53
|
+
{
|
|
54
|
+
icon: busy ? /* @__PURE__ */ jsx(Loader2, { className: "animate-spin" }) : /* @__PURE__ */ jsx(CopyPlus, {}),
|
|
55
|
+
variant: "outline",
|
|
56
|
+
onClick: duplicate,
|
|
57
|
+
disabled: busy,
|
|
58
|
+
title: "Make your own copy of this agent, in a new tab",
|
|
59
|
+
children: "Duplicate"
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
AgentPeekDuplicateButton
|
|
65
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { useAppDispatch } from "../../../store/hooks.js";
|
|
5
5
|
import { closeOverlay, CHAT_WINDOWS } from "../../../host/windows.js";
|
|
@@ -20,7 +20,7 @@ import { selectInstanceAgentId } from "../../../agents/redux/execution-system/in
|
|
|
20
20
|
import { selectAgentName } from "../../../agents/redux/agent-definition/selectors.js";
|
|
21
21
|
import { NonEditableContextMenu } from "../../../host/ui-slots.js";
|
|
22
22
|
import { buildAgentMenuSection, agentEntityRef } from "../../../agents/menu/agent-actions.js";
|
|
23
|
-
import {
|
|
23
|
+
import { Tile } from "@ai-matrx/design-system/controls";
|
|
24
24
|
const OVERLAY_ID = CHAT_WINDOWS.runControlsWindow;
|
|
25
25
|
function RunControlsWindowInner({
|
|
26
26
|
conversationId,
|
|
@@ -104,10 +104,23 @@ function RunControlsWindowInner({
|
|
|
104
104
|
children: rc.tabs.map((t) => {
|
|
105
105
|
const Icon = t.icon;
|
|
106
106
|
const on = activeTab === t.id;
|
|
107
|
-
return
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
return (
|
|
108
|
+
// A list of sections is rows, start-aligned — never centred buttons.
|
|
109
|
+
/* @__PURE__ */ jsx(
|
|
110
|
+
Tile,
|
|
111
|
+
{
|
|
112
|
+
variant: "quiet",
|
|
113
|
+
selected: on,
|
|
114
|
+
icon: /* @__PURE__ */ jsx(Icon, {}),
|
|
115
|
+
title: t.label,
|
|
116
|
+
end: rc.tabTrailing(t.id),
|
|
117
|
+
role: "tab",
|
|
118
|
+
"aria-selected": on,
|
|
119
|
+
onClick: () => setTab(t.id)
|
|
120
|
+
},
|
|
121
|
+
t.id
|
|
122
|
+
)
|
|
123
|
+
);
|
|
111
124
|
})
|
|
112
125
|
}
|
|
113
126
|
),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-matrx/chat",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
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",
|
|
@@ -201,22 +201,22 @@
|
|
|
201
201
|
"server-only": "^0.0.1",
|
|
202
202
|
"uuid": "^14.0.2",
|
|
203
203
|
"zod": "^4.6.5",
|
|
204
|
-
"@ai-matrx/alchemy": "latest",
|
|
205
204
|
"@ai-matrx/agents": "latest",
|
|
205
|
+
"@ai-matrx/alchemy": "latest",
|
|
206
|
+
"@ai-matrx/associations": "latest",
|
|
206
207
|
"@ai-matrx/browser-audio": "latest",
|
|
207
208
|
"@ai-matrx/canvas": "latest",
|
|
208
209
|
"@ai-matrx/content-ir": "latest",
|
|
209
210
|
"@ai-matrx/content-ir-react": "latest",
|
|
210
211
|
"@ai-matrx/data": "latest",
|
|
211
212
|
"@ai-matrx/design-system": "latest",
|
|
212
|
-
"@ai-matrx/associations": "latest",
|
|
213
213
|
"@ai-matrx/diff": "latest",
|
|
214
|
+
"@ai-matrx/icons": "latest",
|
|
214
215
|
"@ai-matrx/kit": "latest",
|
|
215
216
|
"@ai-matrx/media": "latest",
|
|
216
|
-
"@ai-matrx/
|
|
217
|
+
"@ai-matrx/print": "latest",
|
|
217
218
|
"@ai-matrx/realtime": "latest",
|
|
218
219
|
"@ai-matrx/records": "latest",
|
|
219
|
-
"@ai-matrx/print": "latest",
|
|
220
220
|
"@ai-matrx/records-ui": "latest",
|
|
221
221
|
"@ai-matrx/tap-target": "latest"
|
|
222
222
|
},
|