@ai-matrx/chat 0.3.6 → 0.3.9
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/components/inputs/smart-input/InputActionButtons.d.ts +4 -0
- package/dist/agents/components/inputs/smart-input/InputActionButtons.js +16 -9
- package/dist/agents/components/inputs/smart-input/RunControlsMenu.d.ts +2 -0
- package/dist/agents/components/inputs/smart-input/RunControlsMenu.js +2 -0
- package/dist/agents/components/inputs/smart-input/SmartAgentInputStacked.js +1 -1
- package/dist/agents/components/inputs/smart-input/composer/ComposerAgentPill.js +4 -6
- package/dist/agents/components/inputs/smart-input/composer/ComposerOutput.js +9 -4
- package/dist/agents/components/inputs/smart-input/composer/ComposerPlusMenu.d.ts +3 -1
- package/dist/agents/components/inputs/smart-input/composer/ComposerPlusMenu.js +2 -2
- package/dist/agents/components/inputs/smart-input/composer/composer-types.d.ts +5 -0
- package/dist/agents/components/inputs/variable-input-variations/AgentVariableCards.js +1 -1
- package/dist/agents/components/shared/AgentOptionsMenu.js +2 -2
- package/dist/agents/redux/execution-system/message-crud/edit-message.thunk.js +3 -6
- package/dist/agents/redux/execution-system/message-crud/fork-and-resubmit-from-message.thunk.js +1 -1
- package/dist/compute/targets.d.ts +2 -6
- package/dist/context/sources/scopes.d.ts +3 -3
- package/dist/host/window-openers.d.ts +21 -5
- package/dist/voice-agent/relay/VoiceRelayBar.d.ts +7 -1
- package/dist/voice-agent/relay/VoiceRelayBar.js +90 -24
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @ai-matrx/chat
|
|
2
2
|
|
|
3
|
+
## 0.3.9
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/chat/v0.3.5..npm/chat/v0.3.9 -- apps/shared/chat`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## 0.3.8
|
|
10
|
+
|
|
11
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
12
|
+
`git diff npm/chat/v0.3.5..npm/chat/v0.3.8 -- apps/shared/chat`).
|
|
13
|
+
No source changes intended and no consumer action required.
|
|
14
|
+
|
|
15
|
+
## 0.3.7 — 2026-10-07
|
|
16
|
+
### Re-sync before matrx-frontend consumes the published package (P27)
|
|
17
|
+
|
|
18
|
+
- Carries the matrx-frontend `packages/chat` edits after `3d7ea46a26` not already mirrored here: composer
|
|
19
|
+
output, agent variable cards, agent options menu, edit/fork message thunks, compute targets, context
|
|
20
|
+
scopes, window openers.
|
|
21
|
+
- Consumer action: none.
|
|
22
|
+
|
|
3
23
|
## 0.3.6 — 2026-10-07
|
|
4
24
|
### Re-sync before matrx-frontend consumes the published package (P27)
|
|
5
25
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* the parent via `onVoiceBusyChange` so Enter-to-send is gated too.
|
|
11
11
|
*/
|
|
12
12
|
import React from "react";
|
|
13
|
+
import type { SourceFeature } from "@ai-matrx/agents/generated/source-attribution";
|
|
13
14
|
import type { ComposerMode, ComposerSize } from "./composer/composer-types.js";
|
|
14
15
|
/**
|
|
15
16
|
* Shared resting (idle) tint for every toolbar button in this row. Exported so
|
|
@@ -67,6 +68,9 @@ interface InputActionButtonsProps {
|
|
|
67
68
|
* Absent = Full's button row inside the card.
|
|
68
69
|
*/
|
|
69
70
|
part?: "send" | "controls" | "launcher";
|
|
71
|
+
/** Attribution for a Live audio session started here. Absent = "chat". */
|
|
72
|
+
sourceFeature?: SourceFeature;
|
|
73
|
+
liveAudioStartsOn?: boolean;
|
|
70
74
|
};
|
|
71
75
|
}
|
|
72
76
|
export declare function InputActionButtons({ conversationId, showSendButton, showVariableIcon, surfaceKey, disableSend, onVoiceBusyChange, extraRightControls, onRequestInputExpand, composer, }: InputActionButtonsProps): React.JSX.Element | null;
|
|
@@ -4,7 +4,6 @@ import { useCallback, useState } from "react";
|
|
|
4
4
|
import {
|
|
5
5
|
CornerDownLeft,
|
|
6
6
|
Braces,
|
|
7
|
-
AudioLines,
|
|
8
7
|
Loader2,
|
|
9
8
|
Square
|
|
10
9
|
} from "lucide-react";
|
|
@@ -14,7 +13,8 @@ import {
|
|
|
14
13
|
TooltipTrigger
|
|
15
14
|
} from "@ai-matrx/design-system";
|
|
16
15
|
import { useAppSelector, useAppDispatch } from "../../../../store/hooks.js";
|
|
17
|
-
import {
|
|
16
|
+
import { selectAgentIdFromInstance } from "../../../redux/execution-system/conversations/conversations.selectors.js";
|
|
17
|
+
import { VoiceRelayBar } from "../../../../voice-agent/relay/VoiceRelayBar.js";
|
|
18
18
|
import { AgentMicrophoneButton } from "./AgentMicrophoneButton.js";
|
|
19
19
|
import { RunControlsMenu } from "./RunControlsMenu.js";
|
|
20
20
|
import {
|
|
@@ -75,6 +75,8 @@ function InputActionButtons({
|
|
|
75
75
|
}) {
|
|
76
76
|
const dispatch = useAppDispatch();
|
|
77
77
|
const [voiceBusy, setVoiceBusy] = useState(false);
|
|
78
|
+
const [liveAudioOn, setLiveAudioOn] = useState(composer.liveAudioStartsOn ?? false);
|
|
79
|
+
const agentId = useAppSelector(selectAgentIdFromInstance(conversationId)) ?? null;
|
|
78
80
|
const { isExecuting, executingConversationId } = useSurfaceExecution(
|
|
79
81
|
conversationId,
|
|
80
82
|
surfaceKey
|
|
@@ -104,12 +106,16 @@ function InputActionButtons({
|
|
|
104
106
|
const handleStop = useCallback(() => {
|
|
105
107
|
dispatch(cancelExecution(executingConversationId ?? conversationId));
|
|
106
108
|
}, [executingConversationId, conversationId, dispatch]);
|
|
107
|
-
const liveAudioButton = showSendButton ? /* @__PURE__ */ jsx(
|
|
108
|
-
|
|
109
|
+
const liveAudioButton = showSendButton && agentId ? /* @__PURE__ */ jsx(
|
|
110
|
+
VoiceRelayBar,
|
|
109
111
|
{
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
variant: "composer",
|
|
113
|
+
enabled: liveAudioOn,
|
|
114
|
+
onEnabledChange: setLiveAudioOn,
|
|
115
|
+
primaryAgentId: agentId,
|
|
116
|
+
conversationId,
|
|
117
|
+
surfaceKey: surfaceKey ?? `composer:${conversationId}`,
|
|
118
|
+
sourceFeature: composer.sourceFeature ?? "chat"
|
|
113
119
|
}
|
|
114
120
|
) : null;
|
|
115
121
|
const variablesToggle = shouldShowVariables && showVariableIcon ? /* @__PURE__ */ jsx(
|
|
@@ -135,7 +141,8 @@ function InputActionButtons({
|
|
|
135
141
|
surfaceKey,
|
|
136
142
|
folded: composer.folded,
|
|
137
143
|
// Compact's live audio leaves the row when narrow and rides +.
|
|
138
|
-
foldLiveAudio: composer.folded && composer.part === "controls"
|
|
144
|
+
foldLiveAudio: composer.folded && composer.part === "controls" && Boolean(liveAudioButton),
|
|
145
|
+
onLiveAudio: () => setLiveAudioOn(true)
|
|
139
146
|
}
|
|
140
147
|
}
|
|
141
148
|
);
|
|
@@ -178,7 +185,7 @@ function InputActionButtons({
|
|
|
178
185
|
/* @__PURE__ */ jsx(DesktopPresenceIndicator, { conversationId }),
|
|
179
186
|
variablesToggle,
|
|
180
187
|
micGroup,
|
|
181
|
-
composer.folded ? null : liveAudioButton,
|
|
188
|
+
composer.folded && !liveAudioOn ? null : liveAudioButton,
|
|
182
189
|
composer.leading
|
|
183
190
|
] }),
|
|
184
191
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
@@ -26,6 +26,8 @@ export interface RunControlsMenuProps {
|
|
|
26
26
|
folded?: boolean;
|
|
27
27
|
/** Compact and narrow: live audio lives in the + menu too. */
|
|
28
28
|
foldLiveAudio?: boolean;
|
|
29
|
+
/** The + menu's Live audio row turns the composer's voice on. */
|
|
30
|
+
onLiveAudio?: () => void;
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
export declare function RunControlsMenu({ conversationId, variant, includeAttach, align, side, foldToolbarExtras, onRequestInputExpand, composer, }: RunControlsMenuProps): import("react").JSX.Element;
|
|
@@ -113,6 +113,7 @@ function RunControlsMenu({
|
|
|
113
113
|
size: composer.size,
|
|
114
114
|
folded: composer.folded,
|
|
115
115
|
foldLiveAudio: composer.foldLiveAudio,
|
|
116
|
+
onLiveAudio: composer.onLiveAudio,
|
|
116
117
|
side,
|
|
117
118
|
surfaceKey: composer.surfaceKey,
|
|
118
119
|
onRequestInputExpand
|
|
@@ -144,6 +145,7 @@ function RunControlsMenu({
|
|
|
144
145
|
size: composer.size,
|
|
145
146
|
folded: composer.folded,
|
|
146
147
|
foldLiveAudio: composer.foldLiveAudio,
|
|
148
|
+
onLiveAudio: composer.onLiveAudio,
|
|
147
149
|
side,
|
|
148
150
|
surfaceKey: composer.surfaceKey,
|
|
149
151
|
onRequestInputExpand,
|
|
@@ -179,7 +179,7 @@ function SmartAgentInputStacked({
|
|
|
179
179
|
surfaceKey,
|
|
180
180
|
disableSend: sendBlocked
|
|
181
181
|
};
|
|
182
|
-
const composerParts = { size: composer.size, mode: composer.mode, folded };
|
|
182
|
+
const composerParts = { size: composer.size, mode: composer.mode, folded, sourceFeature: composer.sourceFeature, liveAudioStartsOn: composer.liveAudioStartsOn };
|
|
183
183
|
if (composer.size === "launcher") {
|
|
184
184
|
return /* @__PURE__ */ jsx(
|
|
185
185
|
"div",
|
|
@@ -53,18 +53,16 @@ function ComposerAgentPill({ conversationId, mode, size, agentControl, menuSide,
|
|
|
53
53
|
const agentFilter = useComposerAgentFilter(conversationId);
|
|
54
54
|
const showOverride = info.modelOverridden && !info.isCustom && composerShows(mode, "agent.presets");
|
|
55
55
|
const overrideTitle = info.agentModelLabel ? `Agent's own model: ${info.agentModelLabel}` : "Not the agent's own model";
|
|
56
|
-
const pill = /* @__PURE__ */
|
|
56
|
+
const pill = /* @__PURE__ */ jsx(
|
|
57
57
|
Button,
|
|
58
58
|
{
|
|
59
59
|
variant: "quiet",
|
|
60
60
|
iconEnd: /* @__PURE__ */ jsx(ChevronDown, {}),
|
|
61
61
|
"aria-label": `Agent: ${label}${showOverride ? " (model changed)" : ""}`,
|
|
62
62
|
title: showOverride ? `${label} \u2014 ${overrideTitle}` : label,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
showOverride ? /* @__PURE__ */ jsx("span", { "data-testid": "composer-model-override-chip", children: " \xB7 changed" }) : null
|
|
67
|
-
]
|
|
63
|
+
"data-model-override": showOverride ? "" : void 0,
|
|
64
|
+
className: "min-w-0 shrink",
|
|
65
|
+
children: showOverride ? `${label} \xB7 changed` : label
|
|
68
66
|
}
|
|
69
67
|
);
|
|
70
68
|
if (folded) {
|
|
@@ -222,8 +222,8 @@ function ShapePicker({
|
|
|
222
222
|
if (lock.status === "reading") {
|
|
223
223
|
return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1 px-2.5 py-2", "aria-label": "Checking the agent's shape", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-full rounded-md" }) });
|
|
224
224
|
}
|
|
225
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-col", children: [
|
|
226
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-2.5 pb-1 pt-2", children: [
|
|
225
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [
|
|
226
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between gap-2 px-2.5 pb-1 pt-2", children: [
|
|
227
227
|
/* @__PURE__ */ jsx("span", { className: "truncate text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Shapes" }),
|
|
228
228
|
kinds.length > 0 ? /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-[11px] tabular-nums text-muted-foreground", children: [
|
|
229
229
|
kinds.length,
|
|
@@ -315,7 +315,7 @@ function ShapePicker({
|
|
|
315
315
|
}
|
|
316
316
|
function ComposerOutputPanel({ conversationId }) {
|
|
317
317
|
const output = useComposerOutput(conversationId);
|
|
318
|
-
return /* @__PURE__ */ jsxs("div", { className: "@container flex min-h-0 flex-col", children: [
|
|
318
|
+
return /* @__PURE__ */ jsxs("div", { className: "@container flex min-h-0 flex-1 flex-col", children: [
|
|
319
319
|
/* @__PURE__ */ jsx(ComposerMenuLabel, { children: "Output types" }),
|
|
320
320
|
/* @__PURE__ */ jsx(TypeGrid, { types: output.types, onToggle: output.toggleType }),
|
|
321
321
|
/* @__PURE__ */ jsx(ComposerMenuHelp, { children: "Narrows the agent list. Not sent to the model." }),
|
|
@@ -333,6 +333,7 @@ function ComposerOutputPill({
|
|
|
333
333
|
menuSide
|
|
334
334
|
}) {
|
|
335
335
|
const [open, setOpen] = useState(false);
|
|
336
|
+
const [roomierSide, setRoomierSide] = useState(null);
|
|
336
337
|
const output = useComposerOutput(conversationId);
|
|
337
338
|
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, modal: false, children: [
|
|
338
339
|
/* @__PURE__ */ jsxs(SplitButton, { className: "min-w-0", children: [
|
|
@@ -345,6 +346,10 @@ function ComposerOutputPill({
|
|
|
345
346
|
"aria-label": `Output: ${output.label}`,
|
|
346
347
|
title: output.lockWarning ?? void 0,
|
|
347
348
|
className: "min-w-0",
|
|
349
|
+
onClick: (event) => {
|
|
350
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
351
|
+
setRoomierSide(rect.top > window.innerHeight - rect.bottom ? "top" : "bottom");
|
|
352
|
+
},
|
|
348
353
|
children: output.label
|
|
349
354
|
}
|
|
350
355
|
) }),
|
|
@@ -353,7 +358,7 @@ function ComposerOutputPill({
|
|
|
353
358
|
/* @__PURE__ */ jsx(
|
|
354
359
|
PopoverContent,
|
|
355
360
|
{
|
|
356
|
-
side: menuSide,
|
|
361
|
+
side: roomierSide ?? menuSide,
|
|
357
362
|
align: "start",
|
|
358
363
|
sideOffset: 8,
|
|
359
364
|
className: "flex max-h-[var(--radix-popover-content-available-height)] w-[340px] max-w-[calc(100vw-1rem)] flex-col overflow-hidden p-1",
|
|
@@ -35,6 +35,8 @@ interface ComposerPlusMenuProps {
|
|
|
35
35
|
folded?: boolean;
|
|
36
36
|
/** Compact and narrow: live audio lives here too. */
|
|
37
37
|
foldLiveAudio?: boolean;
|
|
38
|
+
/** Turns the composer's Live audio on (the row is folded, so it lives here). */
|
|
39
|
+
onLiveAudio?: () => void;
|
|
38
40
|
side: "top" | "bottom";
|
|
39
41
|
/** The host's surface key — auto-clear keeps its display slot in step. */
|
|
40
42
|
surfaceKey?: string;
|
|
@@ -45,7 +47,7 @@ interface ComposerPlusMenuProps {
|
|
|
45
47
|
open?: boolean;
|
|
46
48
|
onOpenChange?: (open: boolean) => void;
|
|
47
49
|
}
|
|
48
|
-
export declare function ComposerPlusMenu({ conversationId, surfaceKey, trigger, mode, folded, foldLiveAudio, side, onRequestInputExpand, presentation, open: openProp, onOpenChange, }: ComposerPlusMenuProps): import("react").JSX.Element;
|
|
50
|
+
export declare function ComposerPlusMenu({ conversationId, surfaceKey, trigger, mode, folded, foldLiveAudio, onLiveAudio, side, onRequestInputExpand, presentation, open: openProp, onOpenChange, }: ComposerPlusMenuProps): import("react").JSX.Element;
|
|
49
51
|
/**
|
|
50
52
|
* Environment (brief §6) — where the agent runs, as ONE flat list: Cloud, then
|
|
51
53
|
* every computer and sandbox this person can use. One click chooses (Arman,
|
|
@@ -81,7 +81,6 @@ import {
|
|
|
81
81
|
ComposerMenuSwitchRow,
|
|
82
82
|
ComposerSubmenu
|
|
83
83
|
} from "./ComposerMenu.js";
|
|
84
|
-
import { announceComingSoon } from "../../../../../host/ui-slots.js";
|
|
85
84
|
import { ComposerMenuSheet } from "./ComposerMenuSheet.js";
|
|
86
85
|
import { composerShows } from "./composer-mode-visibility.js";
|
|
87
86
|
import { useTouchOnlyDevice } from "../../../../../ui/composer/useTouchOnlyDevice.js";
|
|
@@ -101,6 +100,7 @@ function ComposerPlusMenu({
|
|
|
101
100
|
mode,
|
|
102
101
|
folded = false,
|
|
103
102
|
foldLiveAudio = false,
|
|
103
|
+
onLiveAudio,
|
|
104
104
|
side,
|
|
105
105
|
onRequestInputExpand,
|
|
106
106
|
presentation = "popover",
|
|
@@ -360,7 +360,7 @@ function ComposerPlusMenu({
|
|
|
360
360
|
label: "Live audio",
|
|
361
361
|
onClick: () => {
|
|
362
362
|
close();
|
|
363
|
-
|
|
363
|
+
onLiveAudio?.();
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
) : null
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SourceFeature } from "@ai-matrx/agents/generated/source-attribution";
|
|
1
2
|
import type { AnyMandateKey } from "@ai-matrx/agents/mandates";
|
|
2
3
|
import type { EditableContextMenuProps } from "../../../../../host/ui-slots.js";
|
|
3
4
|
import type { ApplicationScope } from "../../../../types/scope.types.js";
|
|
@@ -83,4 +84,8 @@ export interface ComposerPresentation {
|
|
|
83
84
|
maxInputHeightPx?: number;
|
|
84
85
|
/** The right-click agent menu on the textarea. Absent = no menu. */
|
|
85
86
|
textMenu?: ComposerTextMenu;
|
|
87
|
+
/** Who started a Live audio session here (attribution). Absent = "chat". */
|
|
88
|
+
sourceFeature?: SourceFeature;
|
|
89
|
+
/** Live audio starts switched on (the person already chose to talk, e.g. a voice interview). */
|
|
90
|
+
liveAudioStartsOn?: boolean;
|
|
86
91
|
}
|
|
@@ -25,7 +25,7 @@ function AgentVariableInputCard({
|
|
|
25
25
|
}) {
|
|
26
26
|
const dispatch = useAppDispatch();
|
|
27
27
|
const userValues = useAppSelector(selectUserVariableValues(conversationId));
|
|
28
|
-
const currentValue = userValues[variable.name];
|
|
28
|
+
const currentValue = userValues[variable.name] ?? variable.defaultValue;
|
|
29
29
|
const comp = variable.customComponent;
|
|
30
30
|
const type = comp?.type ?? "textarea";
|
|
31
31
|
const setValue = (value) => {
|
|
@@ -274,7 +274,7 @@ function AgentOptionsMenu({
|
|
|
274
274
|
setOpen(false);
|
|
275
275
|
} else if (label === "Create App") {
|
|
276
276
|
console.log("[AGENT OPTIONS MENU] Creating app, Agent ID:", agentId);
|
|
277
|
-
openCreateApp(
|
|
277
|
+
openCreateApp();
|
|
278
278
|
setOpen(false);
|
|
279
279
|
} else if (label === "Add Data Storage Support") {
|
|
280
280
|
console.log(
|
|
@@ -618,7 +618,7 @@ function MobileMenuContent({
|
|
|
618
618
|
openFindUsages({ agentId: agentId ?? null });
|
|
619
619
|
onClose();
|
|
620
620
|
} else if (label === "Create App") {
|
|
621
|
-
openCreateApp(
|
|
621
|
+
openCreateApp();
|
|
622
622
|
onClose();
|
|
623
623
|
} else if (label === "Add Data Storage Support") {
|
|
624
624
|
openDataStorage({ agentId: agentId ?? null });
|
|
@@ -3,6 +3,7 @@ import { createAsyncThunk } from "@reduxjs/toolkit";
|
|
|
3
3
|
import { supabase } from "../../../../host/db.js";
|
|
4
4
|
import { updateMessageRecord } from "../messages/messages.slice.js";
|
|
5
5
|
import { extractFlatText } from "../messages/messages.selectors.js";
|
|
6
|
+
import { saveOutputFeedback } from "../../../../host/ui-slots.js";
|
|
6
7
|
import {
|
|
7
8
|
clearRequestEditedText,
|
|
8
9
|
setRequestEditedText
|
|
@@ -165,12 +166,8 @@ const editMessage = createAsyncThunk(
|
|
|
165
166
|
if (prevRecord.role === "assistant") {
|
|
166
167
|
void (async () => {
|
|
167
168
|
try {
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
import("../messages/messages.selectors.js")
|
|
171
|
-
]);
|
|
172
|
-
const originalText = extractFlatText2(prevRecord);
|
|
173
|
-
const correctedText = extractFlatText2({
|
|
169
|
+
const originalText = extractFlatText(prevRecord);
|
|
170
|
+
const correctedText = extractFlatText({
|
|
174
171
|
...prevRecord,
|
|
175
172
|
content: newContent
|
|
176
173
|
});
|
package/dist/agents/redux/execution-system/message-crud/fork-and-resubmit-from-message.thunk.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createAsyncThunk } from "@reduxjs/toolkit";
|
|
2
2
|
import { forkConversation } from "./fork-conversation.thunk.js";
|
|
3
3
|
import { mergeEditedText } from "./content-blocks.util.js";
|
|
4
|
+
import { toastDoor } from "../../../../host/ui-slots.js";
|
|
4
5
|
const forkAndResubmitFromMessage = createAsyncThunk(
|
|
5
6
|
"messages/forkAndResubmitFromMessage",
|
|
6
7
|
async ({ conversationId, messageId, newContent, surfaceKey }, { dispatch, getState, rejectWithValue }) => {
|
|
@@ -48,7 +49,6 @@ const forkAndResubmitFromMessage = createAsyncThunk(
|
|
|
48
49
|
);
|
|
49
50
|
} else {
|
|
50
51
|
const { toast } = await import("../../../../host/notify.js");
|
|
51
|
-
const { toastDoor } = await import("../../../../host/ui-slots.js");
|
|
52
52
|
toast.success("Branch created", {
|
|
53
53
|
action: toastDoor("conversation", newConversationId)
|
|
54
54
|
});
|
|
@@ -116,15 +116,13 @@ export interface ChatComputeTargetsSource {
|
|
|
116
116
|
error: string | null;
|
|
117
117
|
fetchInstances: (opts?: {
|
|
118
118
|
limit?: number;
|
|
119
|
-
[option: string]: unknown;
|
|
120
119
|
}) => Promise<unknown>;
|
|
121
120
|
createInstance: (request: {
|
|
122
121
|
organization_id: string;
|
|
123
122
|
template?: string;
|
|
124
|
-
tier
|
|
123
|
+
tier: "ec2" | "hosted";
|
|
125
124
|
ttl_seconds?: number;
|
|
126
125
|
labels?: Record<string, string>;
|
|
127
|
-
[field: string]: unknown;
|
|
128
126
|
}) => Promise<{
|
|
129
127
|
instance: SandboxInstance | null;
|
|
130
128
|
error: string | null;
|
|
@@ -190,15 +188,13 @@ export declare const useSandboxInstances: () => {
|
|
|
190
188
|
error: string | null;
|
|
191
189
|
fetchInstances: (opts?: {
|
|
192
190
|
limit?: number;
|
|
193
|
-
[option: string]: unknown;
|
|
194
191
|
}) => Promise<unknown>;
|
|
195
192
|
createInstance: (request: {
|
|
196
193
|
organization_id: string;
|
|
197
194
|
template?: string;
|
|
198
|
-
tier
|
|
195
|
+
tier: "ec2" | "hosted";
|
|
199
196
|
ttl_seconds?: number;
|
|
200
197
|
labels?: Record<string, string>;
|
|
201
|
-
[field: string]: unknown;
|
|
202
198
|
}) => Promise<{
|
|
203
199
|
instance: SandboxInstance | null;
|
|
204
200
|
error: string | null;
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* have no honest default and throw, naming themselves.
|
|
18
18
|
*/
|
|
19
19
|
import type { ComponentType } from "react";
|
|
20
|
+
import type { AssociationSourceEdge, AssociationTargetEdge } from "@ai-matrx/associations";
|
|
20
21
|
import type { ChatDatabase, Json } from "../../host/db-types.js";
|
|
21
22
|
import { type AnyComponent, type AnyFn } from "../../host/registered-source.js";
|
|
22
23
|
export type ContextItemRow = ChatDatabase["context"]["Tables"]["context_items"]["Row"];
|
|
@@ -61,7 +62,6 @@ export interface ScopeTreeOrganization {
|
|
|
61
62
|
projects?: Array<{
|
|
62
63
|
id: string;
|
|
63
64
|
name: string;
|
|
64
|
-
[field: string]: unknown;
|
|
65
65
|
}>;
|
|
66
66
|
}
|
|
67
67
|
export interface ContextItemValue {
|
|
@@ -175,10 +175,10 @@ export interface AssociationEdgeRow {
|
|
|
175
175
|
}
|
|
176
176
|
export interface ChatAssociationsService {
|
|
177
177
|
listForTargets(targetType: string, targetIds: string[], ...rest: any[]): Promise<ScopesRpcResult<{
|
|
178
|
-
edges:
|
|
178
|
+
edges: AssociationTargetEdge[];
|
|
179
179
|
}>>;
|
|
180
180
|
listForSources(sourceType: string, sourceIds: string[], ...rest: any[]): Promise<ScopesRpcResult<{
|
|
181
|
-
edges:
|
|
181
|
+
edges: AssociationSourceEdge[];
|
|
182
182
|
}>>;
|
|
183
183
|
add(input: any): Promise<ScopesRpcResult<any>>;
|
|
184
184
|
remove(input: any): Promise<ScopesRpcResult<any>>;
|
|
@@ -27,7 +27,7 @@ export interface OpenAgentIdWindowOptions {
|
|
|
27
27
|
agentId?: string | null;
|
|
28
28
|
}
|
|
29
29
|
export type OpenAgentAdminFindUsagesWindowOptions = OpenAgentIdWindowOptions;
|
|
30
|
-
export type OpenAgentCreateAppWindowOptions =
|
|
30
|
+
export type OpenAgentCreateAppWindowOptions = Record<string, never>;
|
|
31
31
|
export type OpenAgentDataStorageWindowOptions = OpenAgentIdWindowOptions;
|
|
32
32
|
export type OpenAgentFindUsagesWindowOptions = OpenAgentIdWindowOptions;
|
|
33
33
|
export type OpenAgentInterfaceVariationsWindowOptions = OpenAgentIdWindowOptions;
|
|
@@ -222,7 +222,7 @@ export interface EditorPrimaryAction {
|
|
|
222
222
|
label: string;
|
|
223
223
|
variant?: "default" | "secondary" | "outline" | "destructive" | "ghost" | "link";
|
|
224
224
|
}
|
|
225
|
-
|
|
225
|
+
interface OpenFullScreenMarkdownEditorOptionsBase {
|
|
226
226
|
instanceId?: string;
|
|
227
227
|
content?: string;
|
|
228
228
|
mode?: unknown;
|
|
@@ -236,14 +236,29 @@ export interface OpenFullScreenMarkdownEditorOptions {
|
|
|
236
236
|
showSaveButton?: boolean;
|
|
237
237
|
showCopyButton?: boolean;
|
|
238
238
|
primaryActions?: EditorPrimaryAction[];
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
}
|
|
240
|
+
type OpenFullScreenMarkdownEditorHandlers = {
|
|
241
|
+
onSave: (content: string) => Promise<void>;
|
|
242
|
+
onAction?: never;
|
|
241
243
|
onEvent?: (event: {
|
|
242
244
|
type: "save";
|
|
243
245
|
content: string;
|
|
244
246
|
action?: string;
|
|
245
247
|
}) => void | Promise<void>;
|
|
246
|
-
}
|
|
248
|
+
} | {
|
|
249
|
+
onSave?: never;
|
|
250
|
+
onAction: (action: string, content: string) => Promise<void>;
|
|
251
|
+
onEvent?: (event: {
|
|
252
|
+
type: "save";
|
|
253
|
+
content: string;
|
|
254
|
+
action?: string;
|
|
255
|
+
}) => void | Promise<void>;
|
|
256
|
+
} | {
|
|
257
|
+
onSave?: undefined;
|
|
258
|
+
onAction?: undefined;
|
|
259
|
+
onEvent?: undefined;
|
|
260
|
+
};
|
|
261
|
+
export type OpenFullScreenMarkdownEditorOptions = OpenFullScreenMarkdownEditorOptionsBase & OpenFullScreenMarkdownEditorHandlers;
|
|
247
262
|
export interface ChatFullScreenEditorHandle {
|
|
248
263
|
instanceId: string;
|
|
249
264
|
callbackGroupId: string | null;
|
|
@@ -361,3 +376,4 @@ export declare function useOpenTopicalMapWindow(): (opts: OpenTopicalMapWindowOp
|
|
|
361
376
|
export declare function useOpenScratchpadPanel(): (opts?: OpenScratchpadPanelOptions) => ChatWindowHandle;
|
|
362
377
|
export declare function useOpenWorkingDocumentPanel(): (opts: OpenWorkingDocumentPanelOptions) => ChatWindowHandle;
|
|
363
378
|
export declare function useOpenWorkingDocumentWindow(): (opts: OpenWorkingDocumentWindowOptions) => ChatInstanceWindowHandle;
|
|
379
|
+
export {};
|
|
@@ -16,7 +16,13 @@ export interface VoiceRelayBarProps {
|
|
|
16
16
|
/**
|
|
17
17
|
* `bar` draws the standalone section chrome. `toolbar` embeds the same
|
|
18
18
|
* controls in an existing toolbar without adding another layout row.
|
|
19
|
+
* `composer` is the Smart Agent Input's "Live audio": idle it is ONE icon
|
|
20
|
+
* button beside the mic (no word, no extra width); pressed, the same live
|
|
21
|
+
* controls as `toolbar` (Arman, 2026-10-07: one voice control per surface).
|
|
19
22
|
*/
|
|
20
|
-
variant?: "bar" | "toolbar";
|
|
23
|
+
variant?: "bar" | "toolbar" | "composer";
|
|
24
|
+
/** Controlled on/off (the composer's + menu turns it on when the row is folded). */
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
onEnabledChange?: (enabled: boolean) => void;
|
|
21
27
|
}
|
|
22
28
|
export declare function VoiceRelayBar(props: VoiceRelayBarProps): import("react").JSX.Element;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState } from "react";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { useAppSelector } from "../../store/hooks.js";
|
|
5
|
+
import { cn } from "@ai-matrx/design-system";
|
|
6
|
+
import { selectVoiceInstructions } from "../state/selectors.js";
|
|
4
7
|
import { Mic, Square, AudioLines } from "lucide-react";
|
|
5
8
|
import { Button } from "@ai-matrx/design-system/controls";
|
|
6
9
|
import { useMandate } from "../../mandates/useMandate.js";
|
|
@@ -16,7 +19,10 @@ function ActiveVoiceRelay({
|
|
|
16
19
|
conversationId,
|
|
17
20
|
surfaceKey,
|
|
18
21
|
sourceFeature,
|
|
19
|
-
questionPacing
|
|
22
|
+
questionPacing,
|
|
23
|
+
onEnd,
|
|
24
|
+
autoStart,
|
|
25
|
+
variant
|
|
20
26
|
}) {
|
|
21
27
|
const relay = useVoiceRelaySession({
|
|
22
28
|
communicatorAgentId,
|
|
@@ -27,19 +33,26 @@ function ActiveVoiceRelay({
|
|
|
27
33
|
questionPacing
|
|
28
34
|
});
|
|
29
35
|
const live = relay.status !== "idle" && relay.status !== "error";
|
|
36
|
+
const instructionsReady = useAppSelector(
|
|
37
|
+
(state) => (selectVoiceInstructions(state, relay.instanceId) ?? "").trim().length > 0
|
|
38
|
+
);
|
|
39
|
+
const started = useRef(false);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (!autoStart || !instructionsReady || started.current) return;
|
|
42
|
+
started.current = true;
|
|
43
|
+
relay.toggle();
|
|
44
|
+
}, [autoStart, instructionsReady, relay]);
|
|
30
45
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
31
46
|
/* @__PURE__ */ jsx(
|
|
32
47
|
Button,
|
|
33
48
|
{
|
|
34
49
|
variant: live ? "danger" : "primary",
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
" Talk"
|
|
42
|
-
] })
|
|
50
|
+
icon: live ? /* @__PURE__ */ jsx(Square, {}) : /* @__PURE__ */ jsx(Mic, {}),
|
|
51
|
+
onClick: () => {
|
|
52
|
+
relay.toggle();
|
|
53
|
+
if (live) onEnd?.();
|
|
54
|
+
},
|
|
55
|
+
children: live ? "End voice" : "Talk"
|
|
43
56
|
}
|
|
44
57
|
),
|
|
45
58
|
live ? (
|
|
@@ -53,33 +66,86 @@ function ActiveVoiceRelay({
|
|
|
53
66
|
}
|
|
54
67
|
)
|
|
55
68
|
) : null,
|
|
56
|
-
|
|
69
|
+
relay.error || relay.brainBusy || relay.status !== "idle" ? (
|
|
70
|
+
// In the composer's row it is ONE line: the full sentence on hover.
|
|
71
|
+
/* @__PURE__ */ jsx(
|
|
72
|
+
"span",
|
|
73
|
+
{
|
|
74
|
+
className: cn(
|
|
75
|
+
"text-xs",
|
|
76
|
+
relay.error ? "text-destructive" : "text-muted-foreground",
|
|
77
|
+
variant === "composer" && "min-w-0 max-w-[14rem] truncate"
|
|
78
|
+
),
|
|
79
|
+
title: relay.error?.message,
|
|
80
|
+
children: relay.error ? variant === "composer" ? "Voice did not start" : relay.error.message : relay.brainBusy ? "thinking\u2026" : relay.status
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
) : null
|
|
57
84
|
] });
|
|
58
85
|
}
|
|
59
86
|
function VoiceRelayBar(props) {
|
|
60
|
-
const [
|
|
61
|
-
const
|
|
87
|
+
const [ownEnabled, setOwnEnabled] = useState(false);
|
|
88
|
+
const enabled = props.enabled ?? ownEnabled;
|
|
89
|
+
const setEnabled = (next) => {
|
|
90
|
+
if (props.enabled === void 0) setOwnEnabled(next);
|
|
91
|
+
props.onEnabledChange?.(next);
|
|
92
|
+
};
|
|
93
|
+
if (!enabled && props.variant === "composer") {
|
|
94
|
+
return /* @__PURE__ */ jsx(
|
|
95
|
+
Button,
|
|
96
|
+
{
|
|
97
|
+
variant: "quiet",
|
|
98
|
+
icon: /* @__PURE__ */ jsx(AudioLines, {}),
|
|
99
|
+
"aria-label": "Live audio",
|
|
100
|
+
title: "Live audio \u2014 talk and hear the answer",
|
|
101
|
+
onClick: () => setEnabled(true)
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
}
|
|
62
105
|
return /* @__PURE__ */ jsx(
|
|
63
106
|
"div",
|
|
64
107
|
{
|
|
65
|
-
className: props.variant === "toolbar" ? "flex items-center gap-1" : "flex items-center gap-2 border-b border-border px-3 py-1.5",
|
|
66
|
-
children: !enabled ? /* @__PURE__ */ jsx(Button, { icon: /* @__PURE__ */ jsx(AudioLines, {}), variant: "quiet", onClick: () => setEnabled(true), children: " Voice" }) :
|
|
67
|
-
|
|
68
|
-
/* @__PURE__ */ jsxs("span", { className: "text-xs text-destructive", children: [
|
|
69
|
-
"Voice is unavailable: ",
|
|
70
|
-
communicator.error ?? "no Communicator bound",
|
|
71
|
-
/* @__PURE__ */ jsx(ErrorAlchemyMenu, { error: communicator.error })
|
|
72
|
-
] })
|
|
73
|
-
) : /* @__PURE__ */ jsx(
|
|
74
|
-
ActiveVoiceRelay,
|
|
108
|
+
className: props.variant === "toolbar" || props.variant === "composer" ? "flex items-center gap-1" : "flex items-center gap-2 border-b border-border px-3 py-1.5",
|
|
109
|
+
children: !enabled ? /* @__PURE__ */ jsx(Button, { icon: /* @__PURE__ */ jsx(AudioLines, {}), variant: "quiet", onClick: () => setEnabled(true), children: " Voice" }) : /* @__PURE__ */ jsx(
|
|
110
|
+
EnabledVoiceRelay,
|
|
75
111
|
{
|
|
76
112
|
...props,
|
|
77
|
-
|
|
113
|
+
onEnd: props.variant === "composer" ? () => setEnabled(false) : void 0
|
|
78
114
|
}
|
|
79
115
|
)
|
|
80
116
|
}
|
|
81
117
|
);
|
|
82
118
|
}
|
|
119
|
+
function EnabledVoiceRelay(props) {
|
|
120
|
+
const communicator = useMandate(VOICE_COMMUNICATOR_MANDATE_KEY);
|
|
121
|
+
if (communicator.loading) {
|
|
122
|
+
return /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: "Connecting the voice layer\u2026" });
|
|
123
|
+
}
|
|
124
|
+
if (communicator.error || !communicator.mandate) {
|
|
125
|
+
return /* @__PURE__ */ jsxs(
|
|
126
|
+
"span",
|
|
127
|
+
{
|
|
128
|
+
className: cn(
|
|
129
|
+
"flex min-w-0 items-center gap-1 text-xs text-destructive",
|
|
130
|
+
props.variant === "composer" && "max-w-[14rem]"
|
|
131
|
+
),
|
|
132
|
+
title: `Voice is unavailable: ${communicator.error ?? "no Communicator bound"}`,
|
|
133
|
+
children: [
|
|
134
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: props.variant === "composer" ? "Voice is unavailable" : `Voice is unavailable: ${communicator.error ?? "no Communicator bound"}` }),
|
|
135
|
+
/* @__PURE__ */ jsx(ErrorAlchemyMenu, { error: communicator.error })
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
return /* @__PURE__ */ jsx(
|
|
141
|
+
ActiveVoiceRelay,
|
|
142
|
+
{
|
|
143
|
+
...props,
|
|
144
|
+
communicatorAgentId: communicator.mandate.agentId,
|
|
145
|
+
autoStart: props.variant === "composer"
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
}
|
|
83
149
|
export {
|
|
84
150
|
VoiceRelayBar
|
|
85
151
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-matrx/chat",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
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",
|
|
@@ -202,23 +202,23 @@
|
|
|
202
202
|
"uuid": "^14.0.2",
|
|
203
203
|
"zod": "^4.6.5",
|
|
204
204
|
"@ai-matrx/agents": "latest",
|
|
205
|
-
"@ai-matrx/associations": "latest",
|
|
206
205
|
"@ai-matrx/alchemy": "latest",
|
|
207
|
-
"@ai-matrx/
|
|
206
|
+
"@ai-matrx/associations": "latest",
|
|
208
207
|
"@ai-matrx/canvas": "latest",
|
|
208
|
+
"@ai-matrx/browser-audio": "latest",
|
|
209
209
|
"@ai-matrx/content-ir-react": "latest",
|
|
210
|
-
"@ai-matrx/
|
|
210
|
+
"@ai-matrx/content-ir": "latest",
|
|
211
211
|
"@ai-matrx/data": "latest",
|
|
212
|
-
"@ai-matrx/icons": "latest",
|
|
213
212
|
"@ai-matrx/design-system": "latest",
|
|
214
|
-
"@ai-matrx/
|
|
213
|
+
"@ai-matrx/diff": "latest",
|
|
214
|
+
"@ai-matrx/icons": "latest",
|
|
215
215
|
"@ai-matrx/kit": "latest",
|
|
216
|
-
"@ai-matrx/
|
|
216
|
+
"@ai-matrx/media": "latest",
|
|
217
217
|
"@ai-matrx/realtime": "latest",
|
|
218
218
|
"@ai-matrx/records": "latest",
|
|
219
219
|
"@ai-matrx/records-ui": "latest",
|
|
220
220
|
"@ai-matrx/tap-target": "latest",
|
|
221
|
-
"@ai-matrx/
|
|
221
|
+
"@ai-matrx/print": "latest"
|
|
222
222
|
},
|
|
223
223
|
"devDependencies": {
|
|
224
224
|
"@arethetypeswrong/cli": "^0.18.5",
|