@djangocfg/ui-tools 2.1.380 → 2.1.382
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 +132 -899
- package/dist/ChatRoot-6IZFM5HM.mjs +5 -0
- package/dist/{ChatRoot-EJC5Y2YM.cjs.map → ChatRoot-6IZFM5HM.mjs.map} +1 -1
- package/dist/ChatRoot-LW4XNIKP.cjs +14 -0
- package/dist/{ChatRoot-QOSKJPM6.mjs.map → ChatRoot-LW4XNIKP.cjs.map} +1 -1
- package/dist/DictationField-2ZLQWLYV.mjs +4 -0
- package/dist/DictationField-2ZLQWLYV.mjs.map +1 -0
- package/dist/DictationField-IPPJ54CU.cjs +13 -0
- package/dist/DictationField-IPPJ54CU.cjs.map +1 -0
- package/dist/{DocsLayout-2YKPXZYO.mjs → DocsLayout-2P3ONDWJ.mjs} +3 -3
- package/dist/{DocsLayout-2YKPXZYO.mjs.map → DocsLayout-2P3ONDWJ.mjs.map} +1 -1
- package/dist/{DocsLayout-Q4KS3QWW.cjs → DocsLayout-2YZNS5VK.cjs} +8 -8
- package/dist/{DocsLayout-Q4KS3QWW.cjs.map → DocsLayout-2YZNS5VK.cjs.map} +1 -1
- package/dist/chunk-4LXG3NBV.mjs +833 -0
- package/dist/chunk-4LXG3NBV.mjs.map +1 -0
- package/dist/{chunk-XACCHZH2.cjs → chunk-FIRK5CEH.cjs} +42 -4
- package/dist/chunk-FIRK5CEH.cjs.map +1 -0
- package/dist/{chunk-NWUT327A.mjs → chunk-HIK6BPL7.mjs} +38 -5
- package/dist/chunk-HIK6BPL7.mjs.map +1 -0
- package/dist/chunk-KMSBGNVC.cjs +835 -0
- package/dist/chunk-KMSBGNVC.cjs.map +1 -0
- package/dist/chunk-OZAU3QWD.cjs +2493 -0
- package/dist/chunk-OZAU3QWD.cjs.map +1 -0
- package/dist/chunk-UWVP6LCW.mjs +2447 -0
- package/dist/chunk-UWVP6LCW.mjs.map +1 -0
- package/dist/index.cjs +1532 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1148 -107
- package/dist/index.d.ts +1148 -107
- package/dist/index.mjs +1421 -51
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -8
- package/src/audio-assets.d.ts +8 -0
- package/src/components/markdown/MarkdownMessage/CollapseToggle.tsx +3 -1
- package/src/components/markdown/MarkdownMessage/components.tsx +2 -5
- package/src/stories/index.ts +32 -2
- package/src/tools/Chat/README.md +347 -530
- package/src/tools/Chat/components/Attachments.tsx +6 -1
- package/src/tools/Chat/components/ChatRoot.tsx +30 -2
- package/src/tools/Chat/components/Composer.tsx +20 -3
- package/src/tools/Chat/components/ErrorBanner.tsx +7 -3
- package/src/tools/Chat/components/MessageActions.tsx +3 -1
- package/src/tools/Chat/components/MessageBubble.tsx +6 -5
- package/src/tools/Chat/components/MessageList.tsx +87 -1
- package/src/tools/Chat/components/ToolCalls.tsx +21 -3
- package/src/tools/Chat/context/ChatProvider.tsx +21 -3
- package/src/tools/Chat/core/audio/audioBus.ts +10 -163
- package/src/tools/Chat/core/audio/defaults.ts +43 -0
- package/src/tools/Chat/core/audio/index.ts +1 -0
- package/src/tools/Chat/core/audio/preferences.ts +5 -59
- package/src/tools/Chat/core/audio/sounds/error.mp3 +0 -0
- package/src/tools/Chat/core/audio/sounds/mention.mp3 +0 -0
- package/src/tools/Chat/core/audio/sounds/notification.mp3 +0 -0
- package/src/tools/Chat/core/audio/sounds/received.mp3 +0 -0
- package/src/tools/Chat/core/audio/sounds/sent.mp3 +0 -0
- package/src/tools/Chat/core/audio/sounds/start.mp3 +0 -0
- package/src/tools/Chat/core/audio/types.ts +28 -0
- package/src/tools/Chat/core/reducer.ts +33 -0
- package/src/tools/Chat/core/transport/index.ts +13 -0
- package/src/tools/Chat/core/transport/mappers/index.ts +6 -0
- package/src/tools/Chat/core/transport/mappers/pydantic-ai.ts +142 -0
- package/src/tools/Chat/core/transport/pydantic-ai-transport.ts +208 -0
- package/src/tools/Chat/core/transport/sse.ts +18 -5
- package/src/tools/Chat/hooks/index.ts +25 -0
- package/src/tools/Chat/hooks/useAutoFocusOnStreamEnd.ts +5 -3
- package/src/tools/Chat/hooks/useChat.ts +28 -0
- package/src/tools/Chat/hooks/useChatAudio.ts +59 -180
- package/src/tools/Chat/hooks/useChatDockPrefs.ts +74 -0
- package/src/tools/Chat/hooks/useChatReset.ts +70 -0
- package/src/tools/Chat/hooks/useChatUnread.ts +87 -0
- package/src/tools/Chat/hooks/useFocusOnEmptyClick.ts +111 -0
- package/src/tools/Chat/hooks/useVisitorFingerprint.ts +48 -0
- package/src/tools/Chat/index.ts +69 -1
- package/src/tools/Chat/launcher/ChatDock.tsx +263 -0
- package/src/tools/Chat/launcher/ChatFAB.tsx +349 -0
- package/src/tools/Chat/launcher/ChatGreeting.tsx +200 -0
- package/src/tools/Chat/launcher/ChatHeader.tsx +76 -0
- package/src/tools/Chat/launcher/ChatHeaderActionButton.tsx +87 -0
- package/src/tools/Chat/launcher/ChatHeaderAudioToggle.tsx +47 -0
- package/src/tools/Chat/launcher/ChatHeaderLanguageButton.tsx +179 -0
- package/src/tools/Chat/launcher/ChatHeaderModeToggle.tsx +57 -0
- package/src/tools/Chat/launcher/ChatHeaderResetButton.tsx +93 -0
- package/src/tools/Chat/launcher/ChatLauncher.tsx +321 -0
- package/src/tools/Chat/launcher/ChatUnreadPreview.tsx +197 -0
- package/src/tools/Chat/launcher/index.ts +46 -0
- package/src/tools/Chat/launcher/useChatPresence.ts +44 -0
- package/src/tools/Chat/stories/01-basic.story.tsx +64 -0
- package/src/tools/Chat/stories/02-bubbles.story.tsx +21 -0
- package/src/tools/Chat/stories/03-tool-calls.story.tsx +59 -0
- package/src/tools/Chat/stories/04-personas.story.tsx +78 -0
- package/src/tools/Chat/stories/05-launcher.story.tsx +321 -0
- package/src/tools/Chat/stories/06-header.story.tsx +147 -0
- package/src/tools/Chat/stories/07-audio-actions.story.tsx +112 -0
- package/src/tools/Chat/stories/shared/Frame.tsx +21 -0
- package/src/tools/Chat/stories/shared/index.ts +5 -0
- package/src/tools/Chat/stories/shared/messages.ts +39 -0
- package/src/tools/Chat/stories/shared/personas.ts +13 -0
- package/src/tools/Chat/stories/shared/seeds.ts +92 -0
- package/src/tools/Chat/stories/shared/transports.ts +36 -0
- package/src/tools/Chat/styles/bubbleTokens.ts +71 -0
- package/src/tools/Chat/styles/index.ts +16 -0
- package/src/tools/Chat/styles/useChatStyles.ts +101 -0
- package/src/tools/Chat/types/attachment.ts +25 -0
- package/src/tools/Chat/types/config.ts +48 -0
- package/src/tools/Chat/types/events.ts +35 -0
- package/src/tools/Chat/types/index.ts +34 -0
- package/src/tools/Chat/types/labels.ts +38 -0
- package/src/tools/Chat/types/message.ts +32 -0
- package/src/tools/Chat/types/persona.ts +31 -0
- package/src/tools/Chat/types/session.ts +43 -0
- package/src/tools/Chat/types/tool-call.ts +17 -0
- package/src/tools/Chat/types/transport.ts +28 -0
- package/src/tools/Chat/types.ts +5 -240
- package/src/tools/MarkdownEditor/MarkdownEditor.tsx +50 -14
- package/src/tools/MarkdownEditor/index.ts +1 -1
- package/src/tools/SpeechRecognition/README.md +336 -0
- package/src/tools/SpeechRecognition/__tests__/ids.test.ts +15 -0
- package/src/tools/SpeechRecognition/__tests__/language.test.ts +59 -0
- package/src/tools/SpeechRecognition/__tests__/reducer.test.ts +71 -0
- package/src/tools/SpeechRecognition/__tests__/transcript.test.ts +52 -0
- package/src/tools/SpeechRecognition/components/DevicePicker.tsx +49 -0
- package/src/tools/SpeechRecognition/components/DictationButton.tsx +93 -0
- package/src/tools/SpeechRecognition/components/EngineBadge.tsx +30 -0
- package/src/tools/SpeechRecognition/components/ErrorBanner.tsx +52 -0
- package/src/tools/SpeechRecognition/components/LanguagePicker.tsx +63 -0
- package/src/tools/SpeechRecognition/components/MicMeter.tsx +63 -0
- package/src/tools/SpeechRecognition/components/PushToTalkHint.tsx +51 -0
- package/src/tools/SpeechRecognition/components/TranscriptView.tsx +55 -0
- package/src/tools/SpeechRecognition/components/index.ts +16 -0
- package/src/tools/SpeechRecognition/context/SpeechRecognitionProvider.tsx +47 -0
- package/src/tools/SpeechRecognition/context/index.ts +6 -0
- package/src/tools/SpeechRecognition/core/audio/defaults.ts +24 -0
- package/src/tools/SpeechRecognition/core/engine/external.ts +222 -0
- package/src/tools/SpeechRecognition/core/engine/http.ts +147 -0
- package/src/tools/SpeechRecognition/core/engine/index.ts +52 -0
- package/src/tools/SpeechRecognition/core/engine/mediarecorder.ts +105 -0
- package/src/tools/SpeechRecognition/core/engine/websocket.ts +211 -0
- package/src/tools/SpeechRecognition/core/engine/webspeech.ts +188 -0
- package/src/tools/SpeechRecognition/core/ids.ts +11 -0
- package/src/tools/SpeechRecognition/core/index.ts +14 -0
- package/src/tools/SpeechRecognition/core/language.ts +78 -0
- package/src/tools/SpeechRecognition/core/languages-catalog.ts +229 -0
- package/src/tools/SpeechRecognition/core/logger.ts +3 -0
- package/src/tools/SpeechRecognition/core/reducer.ts +105 -0
- package/src/tools/SpeechRecognition/core/transcript.ts +36 -0
- package/src/tools/SpeechRecognition/hooks/index.ts +14 -0
- package/src/tools/SpeechRecognition/hooks/useDictation.ts +59 -0
- package/src/tools/SpeechRecognition/hooks/useEnginePrefs.ts +15 -0
- package/src/tools/SpeechRecognition/hooks/useMicDevices.ts +57 -0
- package/src/tools/SpeechRecognition/hooks/useMicLevel.ts +52 -0
- package/src/tools/SpeechRecognition/hooks/usePushToTalk.ts +85 -0
- package/src/tools/SpeechRecognition/hooks/useResolvedLanguage.ts +28 -0
- package/src/tools/SpeechRecognition/hooks/useSpeechLanguageInfo.ts +108 -0
- package/src/tools/SpeechRecognition/hooks/useSpeechRecognition.ts +188 -0
- package/src/tools/SpeechRecognition/hooks/useVoiceSupport.ts +78 -0
- package/src/tools/SpeechRecognition/index.ts +82 -0
- package/src/tools/SpeechRecognition/lazy.tsx +19 -0
- package/src/tools/SpeechRecognition/store/index.ts +2 -0
- package/src/tools/SpeechRecognition/store/prefsStore.ts +54 -0
- package/src/tools/SpeechRecognition/stories/01-basic.story.tsx +32 -0
- package/src/tools/SpeechRecognition/stories/02-dictation-field.story.tsx +32 -0
- package/src/tools/SpeechRecognition/stories/03-push-to-talk.story.tsx +27 -0
- package/src/tools/SpeechRecognition/stories/04-mic-meter.story.tsx +35 -0
- package/src/tools/SpeechRecognition/stories/05-custom-engine-http.story.tsx +40 -0
- package/src/tools/SpeechRecognition/stories/06-custom-engine-ws.story.tsx +48 -0
- package/src/tools/SpeechRecognition/stories/07-language-device.story.tsx +57 -0
- package/src/tools/SpeechRecognition/stories/08-errors-permissions.story.tsx +25 -0
- package/src/tools/SpeechRecognition/stories/09-chat-voice.story.tsx +90 -0
- package/src/tools/SpeechRecognition/stories/shared.tsx +123 -0
- package/src/tools/SpeechRecognition/types.ts +133 -0
- package/src/tools/SpeechRecognition/widgets/DictationField.tsx +105 -0
- package/src/tools/SpeechRecognition/widgets/VoiceComposerSlot.tsx +305 -0
- package/src/tools/SpeechRecognition/widgets/VoiceMessageRecorder.tsx +88 -0
- package/src/tools/SpeechRecognition/widgets/index.ts +6 -0
- package/dist/ChatRoot-EJC5Y2YM.cjs +0 -14
- package/dist/ChatRoot-QOSKJPM6.mjs +0 -5
- package/dist/chunk-NWUT327A.mjs.map +0 -1
- package/dist/chunk-QLMKCSR6.mjs +0 -2420
- package/dist/chunk-QLMKCSR6.mjs.map +0 -1
- package/dist/chunk-SI5RD2GD.cjs +0 -2460
- package/dist/chunk-SI5RD2GD.cjs.map +0 -1
- package/dist/chunk-XACCHZH2.cjs.map +0 -1
- package/src/tools/Chat/Chat.story.tsx +0 -1457
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI label strings — i18n is the host's job. Pass overrides via
|
|
3
|
+
* `ChatConfig.labels` and merge with `DEFAULT_LABELS`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ChatLabels {
|
|
7
|
+
send: string;
|
|
8
|
+
cancel: string;
|
|
9
|
+
copy: string;
|
|
10
|
+
regenerate: string;
|
|
11
|
+
edit: string;
|
|
12
|
+
delete: string;
|
|
13
|
+
retry: string;
|
|
14
|
+
newChat: string;
|
|
15
|
+
loadMore: string;
|
|
16
|
+
jumpToLatest: string;
|
|
17
|
+
attach: string;
|
|
18
|
+
voice: string;
|
|
19
|
+
errorGeneric: string;
|
|
20
|
+
cancelledSuffix: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const DEFAULT_LABELS: ChatLabels = {
|
|
24
|
+
send: 'Send',
|
|
25
|
+
cancel: 'Stop',
|
|
26
|
+
copy: 'Copy',
|
|
27
|
+
regenerate: 'Regenerate',
|
|
28
|
+
edit: 'Edit',
|
|
29
|
+
delete: 'Delete',
|
|
30
|
+
retry: 'Retry',
|
|
31
|
+
newChat: 'New chat',
|
|
32
|
+
loadMore: 'Load more',
|
|
33
|
+
jumpToLatest: 'Jump to latest',
|
|
34
|
+
attach: 'Attach files',
|
|
35
|
+
voice: 'Voice input',
|
|
36
|
+
errorGeneric: 'Something went wrong',
|
|
37
|
+
cancelledSuffix: '[cancelled]',
|
|
38
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The atomic unit — a single message in a chat session.
|
|
3
|
+
*
|
|
4
|
+
* Composed of role + content + optional rich-data slots (attachments,
|
|
5
|
+
* sources, tool calls). Serializable: no Date, no Map.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ChatAttachment, ChatSource } from './attachment';
|
|
9
|
+
import type { ChatPersona, ChatRole } from './persona';
|
|
10
|
+
import type { ChatToolCall } from './tool-call';
|
|
11
|
+
|
|
12
|
+
export interface ChatMessage {
|
|
13
|
+
id: string;
|
|
14
|
+
role: ChatRole;
|
|
15
|
+
content: string;
|
|
16
|
+
/** epoch ms — serializable. */
|
|
17
|
+
createdAt: number;
|
|
18
|
+
isStreaming?: boolean;
|
|
19
|
+
isError?: boolean;
|
|
20
|
+
/** Bumps on edit so memo keys invalidate. */
|
|
21
|
+
version?: number;
|
|
22
|
+
/** Per-message persona override (multi-user / multi-bot). Falls back to
|
|
23
|
+
* `ChatConfig.user` / `ChatConfig.assistant` when absent. */
|
|
24
|
+
sender?: ChatPersona;
|
|
25
|
+
/** Simple status indicator above message ("Searching knowledge base..."). */
|
|
26
|
+
toolActivity?: string;
|
|
27
|
+
toolCalls?: ChatToolCall[];
|
|
28
|
+
attachments?: ChatAttachment[];
|
|
29
|
+
sources?: ChatSource[];
|
|
30
|
+
tokensIn?: number;
|
|
31
|
+
tokensOut?: number;
|
|
32
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persona — display identity attached to messages and config.
|
|
3
|
+
*
|
|
4
|
+
* Used by `ChatMessage.sender`, `ChatConfig.user`, `ChatConfig.assistant`.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type ChatRole = 'user' | 'assistant' | 'system';
|
|
8
|
+
|
|
9
|
+
export interface ChatPersona {
|
|
10
|
+
/** Display name. */
|
|
11
|
+
name?: string;
|
|
12
|
+
/** Avatar image URL. */
|
|
13
|
+
avatarUrl?: string;
|
|
14
|
+
/** Initials fallback when no avatar. Auto-derived from `name` if absent. */
|
|
15
|
+
initials?: string;
|
|
16
|
+
/** Tooltip / aria description. */
|
|
17
|
+
description?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ChatUserContext extends ChatPersona {
|
|
21
|
+
email?: string;
|
|
22
|
+
language?: string;
|
|
23
|
+
role?: string;
|
|
24
|
+
/** Free-form custom data forwarded to transport metadata. */
|
|
25
|
+
custom?: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ChatAssistantContext extends ChatPersona {
|
|
29
|
+
/** Model identifier (gpt-4o, claude-opus, …). */
|
|
30
|
+
model?: string;
|
|
31
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session info + history page shapes returned by transports.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ChatAttachment } from './attachment';
|
|
6
|
+
import type { ChatMessage } from './message';
|
|
7
|
+
|
|
8
|
+
export interface CreateSessionOptions {
|
|
9
|
+
metadata?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SessionInfo {
|
|
13
|
+
sessionId: string;
|
|
14
|
+
/** If the server resumed an existing session, it may return prior messages. */
|
|
15
|
+
messages?: ChatMessage[];
|
|
16
|
+
hasMore?: boolean;
|
|
17
|
+
cursor?: string | null;
|
|
18
|
+
resumed?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Optional human-readable title (typically derived from the first
|
|
21
|
+
* user message). Hosts that render a session-list sidebar can read
|
|
22
|
+
* this directly instead of crawling messages. Plan64.
|
|
23
|
+
*/
|
|
24
|
+
title?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface HistoryPage {
|
|
28
|
+
messages: ChatMessage[];
|
|
29
|
+
hasMore: boolean;
|
|
30
|
+
nextCursor: string | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface StreamOptions {
|
|
34
|
+
signal: AbortSignal;
|
|
35
|
+
attachments?: ChatAttachment[];
|
|
36
|
+
metadata?: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SendOptions {
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
attachments?: ChatAttachment[];
|
|
42
|
+
metadata?: Record<string, unknown>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool calls — assistant-initiated function/tool invocations during a turn.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ChatToolCall {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
input: unknown;
|
|
9
|
+
output?: unknown;
|
|
10
|
+
/** Live buffer accumulated during streaming. Replaced by `output` on completion. */
|
|
11
|
+
streamingText?: string;
|
|
12
|
+
status: 'running' | 'success' | 'error' | 'cancelled';
|
|
13
|
+
startedAt: number;
|
|
14
|
+
endedAt?: number;
|
|
15
|
+
/** Optional grouping label for parallel/fan-out execution. */
|
|
16
|
+
sourceHostname?: string;
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport interface — what every chat backend adapter implements.
|
|
3
|
+
*
|
|
4
|
+
* Default web implementation lives in `core/transport/http.ts`.
|
|
5
|
+
* Pydantic-AI adapter lives in `core/transport/pydantic-ai-transport.ts`.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ChatMessage } from './message';
|
|
9
|
+
import type { ChatStreamEvent } from './events';
|
|
10
|
+
import type {
|
|
11
|
+
CreateSessionOptions,
|
|
12
|
+
HistoryPage,
|
|
13
|
+
SendOptions,
|
|
14
|
+
SessionInfo,
|
|
15
|
+
StreamOptions,
|
|
16
|
+
} from './session';
|
|
17
|
+
|
|
18
|
+
export interface ChatTransport {
|
|
19
|
+
createSession(opts?: CreateSessionOptions): Promise<SessionInfo>;
|
|
20
|
+
loadHistory(sessionId: string, cursor?: string | null, limit?: number): Promise<HistoryPage>;
|
|
21
|
+
stream(
|
|
22
|
+
sessionId: string,
|
|
23
|
+
content: string,
|
|
24
|
+
options: StreamOptions,
|
|
25
|
+
): AsyncGenerator<ChatStreamEvent, void, void>;
|
|
26
|
+
send(sessionId: string, content: string, options?: SendOptions): Promise<ChatMessage>;
|
|
27
|
+
closeSession(sessionId: string): Promise<void>;
|
|
28
|
+
}
|
package/src/tools/Chat/types.ts
CHANGED
|
@@ -1,244 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Backwards-compatibility re-export.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Types live in `./types/` (one file per domain). Import directly from
|
|
5
|
+
* `@djangocfg/ui-tools/Chat` in new code; this barrel exists so old
|
|
6
|
+
* `import … from '.../types'` paths keep working.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
export interface ChatToolCall {
|
|
11
|
-
id: string;
|
|
12
|
-
name: string;
|
|
13
|
-
input: unknown;
|
|
14
|
-
output?: unknown;
|
|
15
|
-
/** Live buffer accumulated during streaming. Replaced by `output` on completion. */
|
|
16
|
-
streamingText?: string;
|
|
17
|
-
status: 'running' | 'success' | 'error' | 'cancelled';
|
|
18
|
-
startedAt: number;
|
|
19
|
-
endedAt?: number;
|
|
20
|
-
/** Optional grouping label for parallel/fan-out execution. */
|
|
21
|
-
sourceHostname?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface ChatAttachment {
|
|
25
|
-
id: string;
|
|
26
|
-
type: 'image' | 'file' | 'audio' | 'video';
|
|
27
|
-
url: string;
|
|
28
|
-
thumbnailUrl?: string;
|
|
29
|
-
name?: string;
|
|
30
|
-
mimeType?: string;
|
|
31
|
-
sizeBytes?: number;
|
|
32
|
-
status?: 'uploading' | 'ready' | 'error';
|
|
33
|
-
/** 0..1 while uploading. */
|
|
34
|
-
progress?: number;
|
|
35
|
-
/** Extracted text from images (OCR). */
|
|
36
|
-
ocrText?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface ChatSource {
|
|
40
|
-
title: string;
|
|
41
|
-
url: string;
|
|
42
|
-
snippet?: string;
|
|
43
|
-
chunkIndex?: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface ChatPersona {
|
|
47
|
-
/** Display name. */
|
|
48
|
-
name?: string;
|
|
49
|
-
/** Avatar image URL. */
|
|
50
|
-
avatarUrl?: string;
|
|
51
|
-
/** Initials fallback when no avatar. Auto-derived from `name` if absent. */
|
|
52
|
-
initials?: string;
|
|
53
|
-
/** Tooltip / aria description. */
|
|
54
|
-
description?: string;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface ChatMessage {
|
|
58
|
-
id: string;
|
|
59
|
-
role: ChatRole;
|
|
60
|
-
content: string;
|
|
61
|
-
/** epoch ms — serializable. */
|
|
62
|
-
createdAt: number;
|
|
63
|
-
isStreaming?: boolean;
|
|
64
|
-
isError?: boolean;
|
|
65
|
-
/** Bumps on edit so memo keys invalidate. */
|
|
66
|
-
version?: number;
|
|
67
|
-
/** Per-message persona override (multi-user / multi-bot). Falls back to
|
|
68
|
-
* `ChatConfig.user` / `ChatConfig.assistant` when absent. */
|
|
69
|
-
sender?: ChatPersona;
|
|
70
|
-
/** Simple status indicator above message ("Searching knowledge base..."). */
|
|
71
|
-
toolActivity?: string;
|
|
72
|
-
toolCalls?: ChatToolCall[];
|
|
73
|
-
attachments?: ChatAttachment[];
|
|
74
|
-
sources?: ChatSource[];
|
|
75
|
-
tokensIn?: number;
|
|
76
|
-
tokensOut?: number;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export type ChatDisplayMode = 'closed' | 'embedded' | 'floating' | 'sidebar' | 'fullscreen';
|
|
80
|
-
|
|
81
|
-
export interface ChatUserContext extends ChatPersona {
|
|
82
|
-
email?: string;
|
|
83
|
-
language?: string;
|
|
84
|
-
role?: string;
|
|
85
|
-
/** Free-form custom data forwarded to transport metadata. */
|
|
86
|
-
custom?: Record<string, unknown>;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export interface ChatAssistantContext extends ChatPersona {
|
|
90
|
-
/** Model identifier (gpt-4o, claude-opus, …). */
|
|
91
|
-
model?: string;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export interface ChatPrefs {
|
|
95
|
-
/** Submit hotkey for the composer. */
|
|
96
|
-
submitOn?: 'enter' | 'cmd+enter';
|
|
97
|
-
/** UI density. */
|
|
98
|
-
density?: 'comfortable' | 'compact';
|
|
99
|
-
/** Locale forwarded to transport metadata. */
|
|
100
|
-
locale?: string;
|
|
101
|
-
/** Show timestamps on each bubble. */
|
|
102
|
-
showTimestamps?: boolean;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export interface ChatConfig {
|
|
106
|
-
/** Window title / aria-label. */
|
|
107
|
-
title?: string;
|
|
108
|
-
/** Composer placeholder. */
|
|
109
|
-
placeholder?: string;
|
|
110
|
-
/** Empty-state greeting. */
|
|
111
|
-
greeting?: string;
|
|
112
|
-
/** Empty-state description. */
|
|
113
|
-
description?: string;
|
|
114
|
-
/** Suggested prompts shown on empty conversation. */
|
|
115
|
-
suggestions?: Array<{ label: string; prompt: string }>;
|
|
116
|
-
/** Locale forwarded to the transport via stream metadata. */
|
|
117
|
-
locale?: string;
|
|
118
|
-
/** Project / chat slug forwarded to the transport. */
|
|
119
|
-
slug?: string;
|
|
120
|
-
/** UI density. Use `prefs.density` for the same effect; this stays for
|
|
121
|
-
* backwards compatibility. */
|
|
122
|
-
density?: 'comfortable' | 'compact';
|
|
123
|
-
/** Identity of the human author. Renders avatar / name on user bubbles
|
|
124
|
-
* and gets stamped on outgoing messages as `message.sender`. */
|
|
125
|
-
user?: ChatUserContext;
|
|
126
|
-
/** Identity of the assistant. Renders avatar / name on assistant bubbles. */
|
|
127
|
-
assistant?: ChatAssistantContext;
|
|
128
|
-
/** UI preferences. */
|
|
129
|
-
prefs?: ChatPrefs;
|
|
130
|
-
/** Visual labels (i18n is the host's job). */
|
|
131
|
-
labels?: Partial<ChatLabels>;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export interface ChatLabels {
|
|
135
|
-
send: string;
|
|
136
|
-
cancel: string;
|
|
137
|
-
copy: string;
|
|
138
|
-
regenerate: string;
|
|
139
|
-
edit: string;
|
|
140
|
-
delete: string;
|
|
141
|
-
retry: string;
|
|
142
|
-
newChat: string;
|
|
143
|
-
loadMore: string;
|
|
144
|
-
jumpToLatest: string;
|
|
145
|
-
attach: string;
|
|
146
|
-
voice: string;
|
|
147
|
-
errorGeneric: string;
|
|
148
|
-
cancelledSuffix: string;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export const DEFAULT_LABELS: ChatLabels = {
|
|
152
|
-
send: 'Send',
|
|
153
|
-
cancel: 'Stop',
|
|
154
|
-
copy: 'Copy',
|
|
155
|
-
regenerate: 'Regenerate',
|
|
156
|
-
edit: 'Edit',
|
|
157
|
-
delete: 'Delete',
|
|
158
|
-
retry: 'Retry',
|
|
159
|
-
newChat: 'New chat',
|
|
160
|
-
loadMore: 'Load more',
|
|
161
|
-
jumpToLatest: 'Jump to latest',
|
|
162
|
-
attach: 'Attach files',
|
|
163
|
-
voice: 'Voice input',
|
|
164
|
-
errorGeneric: 'Something went wrong',
|
|
165
|
-
cancelledSuffix: '[cancelled]',
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
// ---- Transport ------------------------------------------------------------
|
|
169
|
-
|
|
170
|
-
export interface CreateSessionOptions {
|
|
171
|
-
metadata?: Record<string, unknown>;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export interface SessionInfo {
|
|
175
|
-
sessionId: string;
|
|
176
|
-
/** If the server resumed an existing session, it may return prior messages. */
|
|
177
|
-
messages?: ChatMessage[];
|
|
178
|
-
hasMore?: boolean;
|
|
179
|
-
cursor?: string | null;
|
|
180
|
-
resumed?: boolean;
|
|
181
|
-
/**
|
|
182
|
-
* Optional human-readable title (typically derived from the first
|
|
183
|
-
* user message). Hosts that render a session-list sidebar can read
|
|
184
|
-
* this directly instead of crawling messages. Plan64.
|
|
185
|
-
*/
|
|
186
|
-
title?: string;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export interface HistoryPage {
|
|
190
|
-
messages: ChatMessage[];
|
|
191
|
-
hasMore: boolean;
|
|
192
|
-
nextCursor: string | null;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
export interface StreamOptions {
|
|
196
|
-
signal: AbortSignal;
|
|
197
|
-
attachments?: ChatAttachment[];
|
|
198
|
-
metadata?: Record<string, unknown>;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export interface SendOptions {
|
|
202
|
-
signal?: AbortSignal;
|
|
203
|
-
attachments?: ChatAttachment[];
|
|
204
|
-
metadata?: Record<string, unknown>;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export type ChatStreamEvent =
|
|
208
|
-
| { type: 'message_start'; messageId: string; sessionId: string }
|
|
209
|
-
| { type: 'resume_start' }
|
|
210
|
-
| { type: 'chunk'; delta: string }
|
|
211
|
-
| { type: 'tool_activity'; tool: string; status: string }
|
|
212
|
-
| {
|
|
213
|
-
type: 'tool_call_start';
|
|
214
|
-
toolId: string;
|
|
215
|
-
name: string;
|
|
216
|
-
input: unknown;
|
|
217
|
-
sourceHostname?: string;
|
|
218
|
-
}
|
|
219
|
-
| { type: 'tool_call_delta'; toolId: string; delta: string }
|
|
220
|
-
| {
|
|
221
|
-
type: 'tool_call_end';
|
|
222
|
-
toolId: string;
|
|
223
|
-
output: unknown;
|
|
224
|
-
status: 'success' | 'error';
|
|
225
|
-
}
|
|
226
|
-
| {
|
|
227
|
-
type: 'message_end';
|
|
228
|
-
tokensIn?: number;
|
|
229
|
-
tokensOut?: number;
|
|
230
|
-
sources?: ChatSource[];
|
|
231
|
-
}
|
|
232
|
-
| { type: 'error'; code: string; message: string };
|
|
233
|
-
|
|
234
|
-
export interface ChatTransport {
|
|
235
|
-
createSession(opts?: CreateSessionOptions): Promise<SessionInfo>;
|
|
236
|
-
loadHistory(sessionId: string, cursor?: string | null, limit?: number): Promise<HistoryPage>;
|
|
237
|
-
stream(
|
|
238
|
-
sessionId: string,
|
|
239
|
-
content: string,
|
|
240
|
-
options: StreamOptions,
|
|
241
|
-
): AsyncGenerator<ChatStreamEvent, void, void>;
|
|
242
|
-
send(sessionId: string, content: string, options?: SendOptions): Promise<ChatMessage>;
|
|
243
|
-
closeSession(sessionId: string): Promise<void>;
|
|
244
|
-
}
|
|
9
|
+
export * from './types/index';
|
|
@@ -6,7 +6,7 @@ import Placeholder from '@tiptap/extension-placeholder';
|
|
|
6
6
|
import Mention from '@tiptap/extension-mention';
|
|
7
7
|
import { Markdown } from '@tiptap/markdown';
|
|
8
8
|
import type { AnyExtension } from '@tiptap/core';
|
|
9
|
-
import { useEffect,
|
|
9
|
+
import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
|
|
10
10
|
import {
|
|
11
11
|
Bold, Italic, Strikethrough, Heading1, Heading2, Heading3,
|
|
12
12
|
List, ListOrdered, Quote, Minus, Code, type LucideIcon,
|
|
@@ -90,20 +90,39 @@ export interface MarkdownEditorProps {
|
|
|
90
90
|
onSubmit?: () => boolean | void;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Imperative handle exposed via `ref`. Matches `ComposerHandle` from
|
|
95
|
+
* `@djangocfg/ui-tools/chat` so consumers can forward it straight into
|
|
96
|
+
* `useRegisterComposer({ focus, moveCursorToEnd })` — that's what makes
|
|
97
|
+
* voice dictation (`VoiceComposerSlot`) push live text into a TipTap
|
|
98
|
+
* composer.
|
|
99
|
+
*/
|
|
100
|
+
export interface MarkdownEditorHandle {
|
|
101
|
+
/** Move keyboard focus into the editor. */
|
|
102
|
+
focus: () => void;
|
|
103
|
+
/** Place the caret at the end of the document (and focus). */
|
|
104
|
+
moveCursorToEnd: () => void;
|
|
105
|
+
/** Escape hatch — the underlying TipTap `Editor` instance. */
|
|
106
|
+
getEditor: () => Editor | null;
|
|
107
|
+
}
|
|
108
|
+
|
|
93
109
|
// ── Component ──
|
|
94
110
|
|
|
95
|
-
export function MarkdownEditor(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
export const MarkdownEditor = forwardRef<MarkdownEditorHandle, MarkdownEditorProps>(function MarkdownEditor(
|
|
112
|
+
{
|
|
113
|
+
value,
|
|
114
|
+
onChange,
|
|
115
|
+
placeholder = 'Write markdown...',
|
|
116
|
+
minHeight = 120,
|
|
117
|
+
className = '',
|
|
118
|
+
disabled = false,
|
|
119
|
+
showToolbar = true,
|
|
120
|
+
mentions,
|
|
121
|
+
onMentionIdsChange,
|
|
122
|
+
onSubmit,
|
|
123
|
+
},
|
|
124
|
+
ref,
|
|
125
|
+
) {
|
|
107
126
|
// Keep the latest onSubmit in a ref so the Tiptap extension's
|
|
108
127
|
// keymap closure always calls the freshest handler — Tiptap's
|
|
109
128
|
// useEditor initialises extensions ONCE on first render. Without
|
|
@@ -244,6 +263,23 @@ export function MarkdownEditor({
|
|
|
244
263
|
}
|
|
245
264
|
}, [value, editor]);
|
|
246
265
|
|
|
266
|
+
// Imperative API for hosts that drive the editor without owning a
|
|
267
|
+
// TipTap ref directly — chat composer registration, voice slot,
|
|
268
|
+
// focus-on-stream-end.
|
|
269
|
+
useImperativeHandle(
|
|
270
|
+
ref,
|
|
271
|
+
(): MarkdownEditorHandle => ({
|
|
272
|
+
focus: () => {
|
|
273
|
+
editor?.commands.focus();
|
|
274
|
+
},
|
|
275
|
+
moveCursorToEnd: () => {
|
|
276
|
+
editor?.commands.focus('end');
|
|
277
|
+
},
|
|
278
|
+
getEditor: () => editor ?? null,
|
|
279
|
+
}),
|
|
280
|
+
[editor],
|
|
281
|
+
);
|
|
282
|
+
|
|
247
283
|
const wrapperClass = `markdown-editor rounded-md border border-input bg-background ${disabled ? 'opacity-60' : ''} ${className}`.trim();
|
|
248
284
|
|
|
249
285
|
return (
|
|
@@ -254,7 +290,7 @@ export function MarkdownEditor({
|
|
|
254
290
|
</div>
|
|
255
291
|
</div>
|
|
256
292
|
);
|
|
257
|
-
}
|
|
293
|
+
});
|
|
258
294
|
|
|
259
295
|
// ── Toolbar ──
|
|
260
296
|
|