@theoremjs/react 0.3.4-next.425.gd676bc4 → 0.3.4-next.427.g3ab5770
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/README.md +2 -0
- package/hooks/use-theorem-chat.d.ts +1 -0
- package/hooks/use-theorem-chat.js +1 -0
- package/package.json +3 -3
- package/ui/ChatComposerBar.js +3 -3
- package/ui/TheoremChat.js +2 -4
package/README.md
CHANGED
|
@@ -431,6 +431,8 @@ function MyChat() {
|
|
|
431
431
|
|
|
432
432
|
`chat.phase` is `'idle'`, `'streaming'`, or `'gated'`. The actions are `handleSubmit`, `handleStop`, `handleSendNow`, and `handleToolDecision`.
|
|
433
433
|
|
|
434
|
+
`handlePendingMove(id, direction)` moves a pending message among those of its kind. `ChatComposerBar` draws a move only when `composerPendingMoves` from `@theoremjs/agents/interface` says the message can go that way: a message alone in its kind has none.
|
|
435
|
+
|
|
434
436
|
To show the transcript and the composer, use `ChatTranscript` and `ChatComposerBar` from `/ui`. You can also draw your own from `chat.blocks`.
|
|
435
437
|
|
|
436
438
|
The hooks and the client write no English text. They return kinds, codes, and states. You write the words.
|
|
@@ -24,6 +24,7 @@ export declare function useTheoremChat(options: UseTheoremChatOptions): {
|
|
|
24
24
|
handleStop: () => void;
|
|
25
25
|
handleMenuAction: (action: import("../../../src/interface/composer-actions").ComposerMenuAction) => void;
|
|
26
26
|
handlePendingQueue: (id: string) => void;
|
|
27
|
+
handlePendingMove: (id: string, direction: "up" | "down") => void;
|
|
27
28
|
handlePendingRestore: (id: string) => Promise<void>;
|
|
28
29
|
handleSendNow: (source?: import("../../../src/interface/pending").ComposerPendingMessage) => Promise<void>;
|
|
29
30
|
handleToolDecision: (_index: number, action: ToolDecisionAction) => Promise<void>;
|
|
@@ -30,6 +30,7 @@ export function useTheoremChat(options) {
|
|
|
30
30
|
handleStop: chat.stop,
|
|
31
31
|
handleMenuAction: chat.menuAction,
|
|
32
32
|
handlePendingQueue: chat.queuePending,
|
|
33
|
+
handlePendingMove: chat.movePending,
|
|
33
34
|
handlePendingRestore: chat.restorePending,
|
|
34
35
|
handleSendNow: chat.sendNow,
|
|
35
36
|
handleToolDecision,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theoremjs/react",
|
|
3
|
-
"version": "0.3.4-next.
|
|
3
|
+
"version": "0.3.4-next.427.g3ab5770",
|
|
4
4
|
"description": "React bindings for Theorem: headless hooks + transport, an Astryx chat UI, and a Web-standard server handler.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"@stylexjs/stylex": "0.19.0",
|
|
61
61
|
"react": "^19.0.0",
|
|
62
62
|
"react-dom": "^19.0.0",
|
|
63
|
-
"@theoremjs/agents": "^0.3.4-next.
|
|
64
|
-
"@theoremjs/web": "^0.3.4-next.
|
|
63
|
+
"@theoremjs/agents": "^0.3.4-next.427.g3ab5770",
|
|
64
|
+
"@theoremjs/web": "^0.3.4-next.427.g3ab5770"
|
|
65
65
|
},
|
|
66
66
|
"peerDependenciesMeta": {
|
|
67
67
|
"@astryxdesign/core": {
|
package/ui/ChatComposerBar.js
CHANGED
|
@@ -14,7 +14,7 @@ import { Tooltip as HoverTip } from '@astryxdesign/core/Tooltip';
|
|
|
14
14
|
import { VStack } from '@astryxdesign/core/VStack';
|
|
15
15
|
import { IconAdjustmentsHorizontal, IconArchive, IconArrowBigRightLines, IconArrowDown, IconArrowUp, IconBrain, IconCornerDownLeft, IconInputAi, IconListNumbers, IconMicrophone, IconPaperclip, IconPencil, IconPlayerRecordFilled, IconSend, IconStack2, IconSteeringWheel, IconX, } from '@tabler/icons-react';
|
|
16
16
|
import { attachmentIssueText, labelText } from '@theoremjs/agents';
|
|
17
|
-
import { composerPendingPreview, effortSelectEnabled, interfaceEffortOptions, interfaceModelOptions, modelSelectEnabled, } from '@theoremjs/agents/interface';
|
|
17
|
+
import { composerPendingMoves, composerPendingPreview, effortSelectEnabled, interfaceEffortOptions, interfaceModelOptions, modelSelectEnabled, } from '@theoremjs/agents/interface';
|
|
18
18
|
import { composerActionState, composerDrawerSummary, isStashShortcut, resolveComposerHint, STASH_SHORTCUT, } from '@theoremjs/web/client';
|
|
19
19
|
import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
20
20
|
import { stageComposerFiles } from "../client/composer-attachments.js";
|
|
@@ -65,7 +65,7 @@ function PendingRow(props) {
|
|
|
65
65
|
const moveDown = t('@theorem.composer.pending.move_down');
|
|
66
66
|
const remove = t('@theorem.composer.pending.remove');
|
|
67
67
|
const Kind = SEND_ICON[message.kind];
|
|
68
|
-
return (_jsxs(HStack, { gap: 1, align: "center", width: "100%", children: [_jsx(HoverTip, { content: t(`@theorem.composer.pending.${message.kind}.description`), children: _jsx(Token, { label: t(`@theorem.composer.pending.${message.kind}`), isLabelHidden: true, color: message.kind === 'steer' ? 'blue' : 'default', icon: _jsx(Kind, { size: 14 }) }) }), _jsx(StackItem, { size: "fill", style: { width: 0 }, children: _jsx(Text, { size: "sm", maxLines: 1, hasTruncateTooltip: true, children: composerPendingPreview(message) }) }), _jsxs(HStack, { gap: 0.5, children: [_jsx(IconButton, { label: edit, tooltip: edit, size: "sm", variant: "ghost", icon: icon(IconPencil), onClick: () => props.onRestore(message.id) }), message.kind === 'stash' ? (_jsx(IconButton, { label: queue, tooltip: queue, size: "sm", variant: "ghost", icon: icon(IconCornerDownLeft), onClick: () => props.onQueue(message.id) })) : null, _jsx(IconButton, { label: sendNow, tooltip: sendNow, size: "sm", variant: "ghost", icon: icon(IconSend), onClick: () => props.onSendNow(message.id) }), _jsx(IconButton, { label: moveUp, tooltip: moveUp, size: "sm", variant: "ghost", icon: icon(IconArrowUp), onClick: () => props.onMove(message.id, 'up') }), _jsx(IconButton, { label: moveDown, tooltip: moveDown, size: "sm", variant: "ghost", icon: icon(IconArrowDown), onClick: () => props.onMove(message.id, 'down') }), _jsx(IconButton, { label: remove, tooltip: remove, size: "sm", variant: "ghost", icon: icon(IconX), onClick: () => props.onRemove(message.id) })] })] }));
|
|
68
|
+
return (_jsxs(HStack, { gap: 1, align: "center", width: "100%", children: [_jsx(HoverTip, { content: t(`@theorem.composer.pending.${message.kind}.description`), children: _jsx(Token, { label: t(`@theorem.composer.pending.${message.kind}`), isLabelHidden: true, color: message.kind === 'steer' ? 'blue' : 'default', icon: _jsx(Kind, { size: 14 }) }) }), _jsx(StackItem, { size: "fill", style: { width: 0 }, children: _jsx(Text, { size: "sm", maxLines: 1, hasTruncateTooltip: true, children: composerPendingPreview(message) }) }), _jsxs(HStack, { gap: 0.5, children: [_jsx(IconButton, { label: edit, tooltip: edit, size: "sm", variant: "ghost", icon: icon(IconPencil), onClick: () => props.onRestore(message.id) }), message.kind === 'stash' ? (_jsx(IconButton, { label: queue, tooltip: queue, size: "sm", variant: "ghost", icon: icon(IconCornerDownLeft), onClick: () => props.onQueue(message.id) })) : null, _jsx(IconButton, { label: sendNow, tooltip: sendNow, size: "sm", variant: "ghost", icon: icon(IconSend), onClick: () => props.onSendNow(message.id) }), props.moves.up ? (_jsx(IconButton, { label: moveUp, tooltip: moveUp, size: "sm", variant: "ghost", icon: icon(IconArrowUp), onClick: () => props.onMove(message.id, 'up') })) : null, props.moves.down ? (_jsx(IconButton, { label: moveDown, tooltip: moveDown, size: "sm", variant: "ghost", icon: icon(IconArrowDown), onClick: () => props.onMove(message.id, 'down') })) : null, _jsx(IconButton, { label: remove, tooltip: remove, size: "sm", variant: "ghost", icon: icon(IconX), onClick: () => props.onRemove(message.id) })] })] }));
|
|
69
69
|
}
|
|
70
70
|
/** The model and effort choices this profile offers; efforts only for a chosen model. */
|
|
71
71
|
function generationOptions(iface, selectedModel) {
|
|
@@ -119,7 +119,7 @@ function composerStatus(args) {
|
|
|
119
119
|
/** Pending messages, then two uniform rows: 64px tiles (images, voice notes), then file tokens. */
|
|
120
120
|
function PendingDrawer(props) {
|
|
121
121
|
const t = useLabels();
|
|
122
|
-
return (_jsx(ChatComposerDrawer, { count: props.summary.count, label: composerDrawerLabel(t, props.summary), children: _jsxs(VStack, { gap: 2, width: "100%", children: [props.messages.map((message) => (_jsx(PendingRow, { message: message, ...props.pendingActions }, message.id))), props.imageFiles.length + props.voiceFiles.length > 0 ? (_jsxs(HStack, { gap: 2, wrap: "wrap", vAlign: "center", children: [props.imageFiles.map(({ file, index, preview }) => (_jsx(Thumbnail, { src: preview, alt: file.name, label: file.name, onRemove: () => props.onAttachmentRemove(index) }, `${file.name}:${String(index)}`))), props.voiceFiles.map((file, index) => {
|
|
122
|
+
return (_jsx(ChatComposerDrawer, { count: props.summary.count, label: composerDrawerLabel(t, props.summary), children: _jsxs(VStack, { gap: 2, width: "100%", children: [props.messages.map((message) => (_jsx(PendingRow, { message: message, moves: composerPendingMoves(props.messages, message.id), ...props.pendingActions }, message.id))), props.imageFiles.length + props.voiceFiles.length > 0 ? (_jsxs(HStack, { gap: 2, wrap: "wrap", vAlign: "center", children: [props.imageFiles.map(({ file, index, preview }) => (_jsx(Thumbnail, { src: preview, alt: file.name, label: file.name, onRemove: () => props.onAttachmentRemove(index) }, `${file.name}:${String(index)}`))), props.voiceFiles.map((file, index) => {
|
|
123
123
|
const src = props.voiceUrls[index];
|
|
124
124
|
// why: An empty src makes the browser fetch the page again; a note draws once it has its URL.
|
|
125
125
|
return src === undefined ? null : (_jsx(VoiceNote, { src: src, mimeType: file.type || undefined, onRemove: props.onVoiceRemove }, `voice:${file.name}`));
|
package/ui/TheoremChat.js
CHANGED
|
@@ -5,7 +5,7 @@ import { ChatLayout } from '@astryxdesign/core/Chat';
|
|
|
5
5
|
import { Layout, LayoutContent } from '@astryxdesign/core/Layout';
|
|
6
6
|
import { Text } from '@astryxdesign/core/Text';
|
|
7
7
|
import { VStack } from '@astryxdesign/core/VStack';
|
|
8
|
-
import {
|
|
8
|
+
import { removeComposerPendingMessage, } from '@theoremjs/agents/interface';
|
|
9
9
|
import { createHttpTransport, } from '@theoremjs/web/client';
|
|
10
10
|
import { useImperativeHandle, useMemo, useRef, } from 'react';
|
|
11
11
|
import { parseAspectRatio } from "../client/image-output.js";
|
|
@@ -41,9 +41,7 @@ function ChatComposerForChat({ chat, iface, placeholder, inputRef, }) {
|
|
|
41
41
|
chat.setIssues([]);
|
|
42
42
|
}, onVoiceClear: () => chat.setPendingVoice([]), onSubmit: () => {
|
|
43
43
|
void chat.handleSubmit();
|
|
44
|
-
}, onStop: chat.handleStop, onMenuAction: chat.handleMenuAction, onGenerationChange: chat.handleGenerationChange, slotChoices: chat.slotChoices, onPendingMove: (id
|
|
45
|
-
chat.setPendingMessages((prev) => moveComposerPendingWithinKind(prev, id, direction));
|
|
46
|
-
}, onPendingRemove: (id) => {
|
|
44
|
+
}, onStop: chat.handleStop, onMenuAction: chat.handleMenuAction, onGenerationChange: chat.handleGenerationChange, slotChoices: chat.slotChoices, onPendingMove: chat.handlePendingMove, onPendingRemove: (id) => {
|
|
47
45
|
chat.setPendingMessages((prev) => removeComposerPendingMessage(prev, id));
|
|
48
46
|
}, onPendingQueue: chat.handlePendingQueue, onPendingRestore: (id) => {
|
|
49
47
|
void chat.handlePendingRestore(id);
|